Files
pn-new-crm/src/lib/pdf/tiptap-validation.ts

72 lines
2.5 KiB
TypeScript
Raw Normal View History

feat(document-templates): delete TipTap-to-pdfme bridge Phase 1 / commit 12 of 14 — strips out the 571-line tiptap-to-pdfme serializer and every code path that depended on it. TipTap document templates remain as Documenso-template seed bodies; the CRM no longer renders them to PDF in-app. Deleted: src/lib/pdf/tiptap-to-pdfme.ts (571 LOC) src/lib/pdf/templates/eoi-standard-inapp.ts (337 LOC) src/app/api/v1/admin/templates/preview/route.ts src/app/api/v1/document-templates/[id]/generate/route.ts src/app/api/v1/document-templates/[id]/generate-and-send/route.ts src/lib/services/document-templates.ts:generateFromTemplate (~140 LOC) src/lib/services/document-templates.ts:generateAndSend (~40 LOC) src/lib/validators/document-templates.ts:generateAndSendSchema src/lib/validators/document-templates.ts:previewAdminTemplateSchema tests/unit/tiptap-serializer.test.ts (old bridge tests) Preserved as src/lib/pdf/tiptap-validation.ts (~70 LOC): - validateTipTapDocument() — still used to reject unsupported nodes on save in the admin template editor - TEMPLATE_VARIABLES — drives the merge-token picker in the admin template form + preview UI generateAndSign() now throws a clear ValidationError when a non-EOI template tries the in-app pathway. Use a Documenso template, or wait for the deferred AcroForm-fill admin-upload feature. seed-data.ts: "Standard EOI (in-app)" template row now seeds with stub bodyHtml + small MERGE_FIELDS array; the deleted HTML helper was never actually rendered (in-app EOI is pdf-lib AcroForm fill on the source PDF — generateEoiPdfFromTemplate, unchanged). After this commit, pdfme has zero callers left. Commit 14 drops the deps and the generate.ts shim. 1298/1298 vitest green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 21:11:23 +02:00
/**
* TipTap content validation helpers shared by the admin template editor
* and the document-template service. Surfaces unsupported node types so
* the admin gets a clear validation error before saving, and exports the
* `TEMPLATE_VARIABLES` catalog so the editor can offer token suggestions.
*
* Note: this file was the remaining sliver of the legacy 571-line
* `tiptap-to-pdfme.ts` bridge. The pdfme rendering path it once fed has
* been removed (see the PDF stack overhaul spec); only the validation +
* variable catalog survive because they're still useful for the
* Documenso-template-body editor UX.
*/
export interface TipTapMark {
type: string;
attrs?: Record<string, unknown>;
}
export interface TipTapNode {
type: string;
content?: TipTapNode[];
text?: string;
marks?: TipTapMark[];
attrs?: Record<string, unknown>;
}
const UNSUPPORTED_NODES = new Set([
'blockquote',
'codeBlock',
'horizontalRule',
'taskList',
'taskItem',
]);
export const TEMPLATE_VARIABLES: Array<{ key: string; label: string; example: string }> = [
{ key: 'client.name', label: 'Client Full Name', example: 'John Smith' },
{ key: 'client.company', label: 'Company Name', example: 'Smith Holdings' },
{ key: 'client.email', label: 'Client Email', example: 'john@smithholdings.com' },
{ key: 'client.phone', label: 'Client Phone', example: '+61 400 000 000' },
{ key: 'interest.stage', label: 'Pipeline Stage', example: 'Signed EOI/NDA' },
{ key: 'interest.berthNumber', label: 'Berth Number (from interest)', example: 'A23' },
{ key: 'berth.mooring_number', label: 'Berth Number', example: 'A23' },
{ key: 'berth.price', label: 'Berth Price', example: '$45,000' },
{ key: 'berth.tenure_type', label: 'Tenure Type', example: 'Freehold' },
{ key: 'port.name', label: 'Port Name', example: 'Port Nimara' },
{ key: 'port.currency', label: 'Port Currency', example: 'AUD' },
{ key: 'date.today', label: "Today's Date", example: '2026-03-15' },
{ key: 'date.year', label: 'Current Year', example: '2026' },
];
/**
* Recursively walks a TipTap node tree and collects any unsupported node types.
* Returns an array of unsupported type names found, or empty array if valid.
*/
export function validateTipTapDocument(doc: TipTapNode): string[] {
const found = new Set<string>();
function walk(node: TipTapNode): void {
if (UNSUPPORTED_NODES.has(node.type)) {
found.add(node.type);
}
if (node.content) {
for (const child of node.content) {
walk(child);
}
}
}
walk(doc);
return Array.from(found);
}