feat(documents): create-document wizard MVP + service dispatch
Implements createFromWizard and createFromUpload service paths covering the documenso-template, in-app, and upload pathways. Persists subject FK, signers, watchers, and the per-document reminder controls (remindersDisabled / reminderCadenceOverride) introduced in PR1. New POST /api/v1/documents/wizard route and a functional /documents/new UI with type/source/template/signers/reminders sections. Drag-handle reorder, watcher autocomplete picker, and PDF preview defer to the PR10 polish sweep. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,58 @@ export const updateDocumentSchema = z.object({
|
||||
status: z.enum(DOCUMENT_STATUSES).optional(),
|
||||
});
|
||||
|
||||
const wizardSignerSchema = z.object({
|
||||
signerName: z.string().min(1),
|
||||
signerEmail: z.string().email(),
|
||||
signerRole: z.enum(['client', 'sales', 'approver', 'developer', 'other']),
|
||||
signingOrder: z.number().int().min(1),
|
||||
});
|
||||
|
||||
export const createDocumentWizardSchema = z
|
||||
.object({
|
||||
source: z.enum(['template', 'upload']).default('template'),
|
||||
templateId: z.string().optional(),
|
||||
uploadedFileId: z.string().optional(),
|
||||
|
||||
documentType: z.enum(DOCUMENT_TYPES),
|
||||
title: z.string().min(1).max(200),
|
||||
notes: z.string().optional(),
|
||||
|
||||
interestId: z.string().optional(),
|
||||
reservationId: z.string().optional(),
|
||||
clientId: z.string().optional(),
|
||||
companyId: z.string().optional(),
|
||||
yachtId: z.string().optional(),
|
||||
|
||||
signers: z.array(wizardSignerSchema).optional(),
|
||||
signingMode: z.enum(['sequential', 'parallel']).default('sequential'),
|
||||
pathway: z.enum(['documenso-template', 'inapp', 'upload']).default('documenso-template'),
|
||||
|
||||
watchers: z.array(z.string()).default([]),
|
||||
|
||||
reminderCadenceOverride: z.number().int().min(1).max(365).nullable().optional(),
|
||||
remindersDisabled: z.boolean().default(false),
|
||||
|
||||
autoPlaceFields: z.boolean().default(true),
|
||||
sendImmediately: z.boolean().default(true),
|
||||
})
|
||||
.refine(
|
||||
(d) =>
|
||||
[d.interestId, d.reservationId, d.clientId, d.companyId, d.yachtId].filter(Boolean).length ===
|
||||
1,
|
||||
{ message: 'Exactly one subject (interest/reservation/client/company/yacht) is required' },
|
||||
)
|
||||
.refine((d) => d.source !== 'template' || Boolean(d.templateId), {
|
||||
path: ['templateId'],
|
||||
message: 'templateId is required when source=template',
|
||||
})
|
||||
.refine((d) => d.source !== 'upload' || Boolean(d.uploadedFileId), {
|
||||
path: ['uploadedFileId'],
|
||||
message: 'uploadedFileId is required when source=upload',
|
||||
});
|
||||
|
||||
export type CreateDocumentWizardInput = z.infer<typeof createDocumentWizardSchema>;
|
||||
|
||||
export const documentsHubTabs = [
|
||||
'all',
|
||||
'awaiting_them',
|
||||
|
||||
Reference in New Issue
Block a user