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>
165 lines
4.8 KiB
TypeScript
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')}`,
|
|
};
|
|
}
|