import { z } from 'zod'; import { baseListQuerySchema } from '@/lib/api/route-helpers'; import { VALID_MERGE_TOKENS } from '@/lib/templates/merge-fields'; const mergeFieldsSchema = z .array(z.string()) .optional() .default([]) .refine( (tokens) => tokens.every((t) => VALID_MERGE_TOKENS.has(t)), (tokens) => { const unknown = tokens?.filter((t) => !VALID_MERGE_TOKENS.has(t)) ?? []; return { message: `Unknown merge tokens: ${unknown.join(', ')}` }; }, ); export const templateFormats = ['html', 'pdf_form', 'pdf_overlay', 'documenso_render'] as const; const createTemplateBaseSchema = z.object({ name: z.string().min(1).max(200), description: z.string().max(500).optional(), templateType: z.enum([ 'eoi', 'welcome_letter', 'handover_checklist', 'acknowledgment', 'correspondence', 'custom', ]), templateFormat: z.enum(templateFormats).default('html'), bodyHtml: z.string().min(1).optional(), mergeFields: mergeFieldsSchema, isActive: z.boolean().default(true), }); export const createTemplateSchema = createTemplateBaseSchema.refine( (data) => data.templateFormat !== 'html' || (data.bodyHtml && data.bodyHtml.length > 0), { path: ['bodyHtml'], message: 'bodyHtml is required when templateFormat is html' }, ); export const updateTemplateSchema = createTemplateBaseSchema.partial(); export const listTemplatesSchema = baseListQuerySchema.extend({ templateType: z.string().optional(), isActive: z .enum(['true', 'false']) .transform((v) => v === 'true') .optional(), }); export const generateSchema = z.object({ clientId: z.string().optional(), interestId: z.string().optional(), berthId: z.string().optional(), }); export const generateAndSendSchema = generateSchema.extend({ recipientEmail: z.string().email(), }); export const generateAndSignSchema = generateSchema.extend({ pathway: z.enum(['inapp', 'documenso-template']).default('inapp'), signers: z .array( z.object({ name: z.string().min(1), email: z.string().email(), role: z.string().min(1), signingOrder: z.number().int().min(1), }), ) .optional() .default([]), }); export type CreateTemplateInput = z.infer; export type UpdateTemplateInput = z.infer; export type ListTemplatesInput = z.infer; export type GenerateInput = z.infer; export type GenerateAndSendInput = z.infer; export type GenerateAndSignInput = z.infer; // ─── TipTap-based Admin Template Schemas ───────────────────────────────────── // Used by /api/v1/admin/templates — the TipTap JSON document store. export const tiptapDocumentTypes = [ 'eoi', 'contract', 'nda', 'reservation_agreement', 'letter', 'other', ] as const; export const createAdminTemplateSchema = z.object({ name: z.string().min(1).max(200), type: z.enum(tiptapDocumentTypes), content: z.record(z.unknown()), // TipTap JSON document }); export const updateAdminTemplateSchema = z.object({ name: z.string().min(1).max(200).optional(), content: z.record(z.unknown()).optional(), isActive: z.boolean().optional(), }); export const previewAdminTemplateSchema = z.object({ content: z.record(z.unknown()), sampleData: z.record(z.string()).optional(), }); export const rollbackAdminTemplateSchema = z.object({ version: z.number().int().min(1), }); export const listAdminTemplatesSchema = baseListQuerySchema.extend({ type: z.enum(tiptapDocumentTypes).optional(), isActive: z .enum(['true', 'false']) .transform((v) => v === 'true') .optional(), }); export type CreateAdminTemplateInput = z.infer; export type UpdateAdminTemplateInput = z.infer; export type PreviewAdminTemplateInput = z.infer; export type RollbackAdminTemplateInput = z.infer; export type ListAdminTemplatesInput = z.infer;