Files
pn-new-crm/src/lib/pdf/templates/interest-summary-template.ts
Matt Ciaccio 8699f81879
Some checks failed
Build & Push Docker Images / lint (push) Failing after 1m18s
Build & Push Docker Images / build-and-push (push) Has been skipped
chore(style): codebase em-dash sweep + minor layout polish
Replaces every em-dash and en-dash with regular ASCII hyphens
across comments, JSX strings, and dev-facing logs. Mostly cosmetic
but stops the inconsistent mix that crept in over the last few
months (some files used em-dashes in comments, others didn't,
some used both).

Bundles two small dashboard-layout tweaks that touch a couple of
already-modified files:
- (dashboard)/layout.tsx main padding goes from p-6 to pt-3 px-6
  pb-6 so page content sits closer to the topbar.
- Sidebar now receives the ports list it needs for the footer
  port switcher.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 22:57:01 +02:00

165 lines
4.8 KiB
TypeScript

import type { Template } from '@pdfme/common';
export const interestSummaryTemplate: Template = {
basePdf: 'BLANK_PDF' as unknown as string,
schemas: [
[
{
name: 'portName',
type: 'text',
position: { x: 20, y: 15 },
width: 100,
height: 10,
fontSize: 16,
},
{
name: 'title',
type: 'text',
position: { x: 20, y: 30 },
width: 170,
height: 8,
fontSize: 14,
},
{
name: 'clientInfo',
type: 'text',
position: { x: 20, y: 45 },
width: 80,
height: 30,
fontSize: 9,
},
{
name: 'berthInfo',
type: 'text',
position: { x: 110, y: 45 },
width: 80,
height: 30,
fontSize: 9,
},
{
name: 'stageAndCategory',
type: 'text',
position: { x: 20, y: 80 },
width: 170,
height: 15,
fontSize: 9,
},
{
name: 'milestones',
type: 'text',
position: { x: 20, y: 100 },
width: 170,
height: 40,
fontSize: 8,
},
{
name: 'notes',
type: 'text',
position: { x: 20, y: 145 },
width: 170,
height: 30,
fontSize: 9,
},
{
name: 'recentTimeline',
type: 'text',
position: { x: 20, y: 180 },
width: 170,
height: 85,
fontSize: 8,
},
{
name: 'generatedAt',
type: 'text',
position: { x: 20, y: 275 },
width: 170,
height: 6,
fontSize: 7,
},
],
],
};
function formatDate(d: Date | string | null | undefined): string {
if (!d) return 'N/A';
return new Date(d).toLocaleDateString('en-GB');
}
export function buildInterestSummaryInputs(
interest: Record<string, unknown>,
client: Record<string, unknown>,
yacht: Record<string, unknown> | null,
berth: Record<string, unknown> | null,
timeline: Record<string, unknown>[],
port: Record<string, unknown>,
): Record<string, string> {
const clientInfo = [
`Name: ${client?.fullName ?? 'N/A'}`,
yacht?.name ? `Yacht: ${yacht.name}` : null,
yacht?.lengthFt
? `Length: ${yacht.lengthFt}ft${yacht.lengthM ? ` / ${yacht.lengthM}m` : ''}`
: null,
]
.filter(Boolean)
.join('\n');
const berthInfo = berth
? [
`Mooring: ${berth.mooringNumber}`,
berth.area ? `Area: ${berth.area}` : null,
berth.lengthFt ? `Length: ${berth.lengthFt}ft` : null,
berth.price
? `Price: ${berth.priceCurrency ?? 'USD'} ${Number(berth.price).toLocaleString()}`
: null,
`Status: ${berth.status ?? 'available'}`,
]
.filter(Boolean)
.join('\n')
: 'No berth linked';
const stageAndCategory = [
`Stage: ${interest.pipelineStage ?? 'open'}`,
interest.leadCategory ? `Category: ${interest.leadCategory}` : null,
interest.source ? `Source: ${interest.source}` : null,
interest.eoiStatus ? `EOI status: ${interest.eoiStatus}` : null,
interest.contractStatus ? `Contract: ${interest.contractStatus}` : null,
interest.depositStatus ? `Deposit: ${interest.depositStatus}` : null,
]
.filter(Boolean)
.join(' | ');
const milestones = [
`First contact: ${formatDate(interest.dateFirstContact as Date | string | null | undefined)}`,
`Last contact: ${formatDate(interest.dateLastContact as Date | string | null | undefined)}`,
`EOI sent: ${formatDate(interest.dateEoiSent as Date | string | null | undefined)}`,
`EOI signed: ${formatDate(interest.dateEoiSigned as Date | string | null | undefined)}`,
`Contract sent: ${formatDate(interest.dateContractSent as Date | string | null | undefined)}`,
`Contract signed: ${formatDate(interest.dateContractSigned as Date | string | null | undefined)}`,
`Deposit received: ${formatDate(interest.dateDepositReceived as Date | string | null | undefined)}`,
].join('\n');
const notesText = interest.notes ? `Notes:\n${interest.notes}` : 'No notes';
const timelineText =
timeline.length > 0
? timeline
.map(
(e) =>
`${formatDate(e.createdAt as Date | string | null | undefined)} ${e.action ?? e.eventType ?? 'event'} ${e.entityType ?? e.type ?? ''}${e.fieldChanged ? ` [${e.fieldChanged}]` : ''}`,
)
.join('\n')
: 'No timeline events';
return {
portName: (port?.name as string) ?? 'Port Nimara',
title: `Interest Summary - ${client?.fullName ?? 'Unknown Client'}`,
clientInfo,
berthInfo,
stageAndCategory,
milestones: `Milestones:\n${milestones}`,
notes: notesText,
recentTimeline: `Recent Timeline (last ${timeline.length}):\n${timelineText}`,
generatedAt: `Generated: ${new Date().toLocaleString('en-GB')}`,
};
}