Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM, PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source files covering clients, berths, interests/pipeline, documents/EOI, expenses/invoices, email, notifications, dashboard, admin, and client portal. CI/CD via Gitea Actions with Docker builds. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
45
src/lib/pdf/templates/eoi-template.ts
Normal file
45
src/lib/pdf/templates/eoi-template.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import type { Template } from '@pdfme/common';
|
||||
|
||||
export const eoiTemplate: Template = {
|
||||
basePdf: 'BLANK_PDF' as any,
|
||||
schemas: [
|
||||
[
|
||||
{ name: 'portName', type: 'text', position: { x: 20, y: 20 }, width: 170, height: 10, fontSize: 18 },
|
||||
{ name: 'title', type: 'text', position: { x: 20, y: 40 }, width: 170, height: 8, fontSize: 14 },
|
||||
{ name: 'clientName', type: 'text', position: { x: 20, y: 60 }, width: 80, height: 6 },
|
||||
{ name: 'clientEmail', type: 'text', position: { x: 20, y: 68 }, width: 80, height: 6 },
|
||||
{ name: 'yachtName', type: 'text', position: { x: 20, y: 80 }, width: 80, height: 6 },
|
||||
{ name: 'yachtDimensions', type: 'text', position: { x: 20, y: 88 }, width: 80, height: 6 },
|
||||
{ name: 'berthNumber', type: 'text', position: { x: 110, y: 60 }, width: 80, height: 6 },
|
||||
{ name: 'berthDimensions', type: 'text', position: { x: 110, y: 68 }, width: 80, height: 6 },
|
||||
{ name: 'berthPrice', type: 'text', position: { x: 110, y: 76 }, width: 80, height: 6 },
|
||||
{ name: 'date', type: 'text', position: { x: 20, y: 110 }, width: 80, height: 6 },
|
||||
{ name: 'terms', type: 'text', position: { x: 20, y: 130 }, width: 170, height: 100, fontSize: 9 },
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
export function buildEoiInputs(
|
||||
interest: Record<string, unknown>,
|
||||
client: Record<string, unknown>,
|
||||
berth: Record<string, unknown>,
|
||||
port: Record<string, unknown>,
|
||||
): Record<string, string> {
|
||||
const contacts = (client.contacts as Array<{ channel: string; value: string }> | undefined) ?? [];
|
||||
const emailContact = contacts.find((c) => c.channel === 'email');
|
||||
|
||||
return {
|
||||
portName: (port.name as string) ?? 'Port Nimara',
|
||||
title: 'Expression of Interest',
|
||||
clientName: `Client: ${client.fullName as string}`,
|
||||
clientEmail: `Email: ${emailContact?.value ?? 'N/A'}`,
|
||||
yachtName: `Yacht: ${(client.yachtName as string) ?? 'N/A'}`,
|
||||
yachtDimensions: `LOA: ${(client.yachtLengthFt as string) ?? '?'}ft × Beam: ${(client.yachtWidthFt as string) ?? '?'}ft × Draft: ${(client.yachtDraftFt as string) ?? '?'}ft`,
|
||||
berthNumber: `Berth: ${berth.mooringNumber as string}`,
|
||||
berthDimensions: `${(berth.lengthFt as string) ?? '?'}ft × ${(berth.widthFt as string) ?? '?'}ft`,
|
||||
berthPrice: `Price: ${(berth.priceCurrency as string) ?? 'USD'} ${(berth.price as string) ?? 'TBD'}`,
|
||||
date: `Date: ${new Date().toLocaleDateString('en-GB')}`,
|
||||
terms:
|
||||
"This Expression of Interest confirms the above-named client's interest in the specified berth. This document is non-binding until signed by all parties. Upon signing, the client agrees to proceed with the berth acquisition process as outlined in the full terms and conditions provided separately.",
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user