'use client'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; import Link from 'next/link'; import { ArrowLeft, Plus, Trash2 } from 'lucide-react'; import { toast } from 'sonner'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { PageHeader } from '@/components/shared/page-header'; import { apiFetch } from '@/lib/api/client'; import { DOCUMENT_TYPES } from '@/lib/constants'; const SIGNER_ROLES = ['client', 'sales', 'approver', 'developer', 'other'] as const; const SUBJECT_TYPES = [ { key: 'interest', label: 'Interest', field: 'interestId' as const }, { key: 'reservation', label: 'Reservation', field: 'reservationId' as const }, { key: 'client', label: 'Client', field: 'clientId' as const }, { key: 'company', label: 'Company', field: 'companyId' as const }, { key: 'yacht', label: 'Yacht', field: 'yachtId' as const }, ] as const; interface SignerRow { signerName: string; signerEmail: string; signerRole: (typeof SIGNER_ROLES)[number]; signingOrder: number; } interface CreateDocumentWizardProps { portSlug: string; } export function CreateDocumentWizard({ portSlug }: CreateDocumentWizardProps) { const router = useRouter(); const [source, setSource] = useState<'template' | 'upload'>('template'); const [pathway, setPathway] = useState<'documenso-template' | 'inapp' | 'upload'>( 'documenso-template', ); const [templateId, setTemplateId] = useState(''); const [uploadedFileId, setUploadedFileId] = useState(''); const [documentType, setDocumentType] = useState<(typeof DOCUMENT_TYPES)[number]>('eoi'); const [title, setTitle] = useState(''); const [notes, setNotes] = useState(''); const [subjectType, setSubjectType] = useState<(typeof SUBJECT_TYPES)[number]['key']>('interest'); const [subjectId, setSubjectId] = useState(''); const [signers, setSigners] = useState([ { signerName: '', signerEmail: '', signerRole: 'client', signingOrder: 1 }, ]); const [signingMode, setSigningMode] = useState<'sequential' | 'parallel'>('sequential'); const [reminderMode, setReminderMode] = useState<'default' | 'override' | 'disabled'>('default'); const [reminderDays, setReminderDays] = useState(7); const [submitting, setSubmitting] = useState(false); const subjectField = SUBJECT_TYPES.find((s) => s.key === subjectType)!.field; const setSourceAndPathway = (next: 'template' | 'upload'): void => { setSource(next); if (next === 'upload') { setPathway('upload'); } else if (pathway === 'upload') { setPathway('documenso-template'); } }; const updateSigner = (idx: number, patch: Partial): void => { setSigners((current) => current.map((s, i) => (i === idx ? { ...s, ...patch } : s))); }; const addSigner = (): void => { setSigners((current) => [ ...current, { signerName: '', signerEmail: '', signerRole: 'other', signingOrder: current.length + 1, }, ]); }; const removeSigner = (idx: number): void => { setSigners((current) => current.filter((_, i) => i !== idx).map((s, i) => ({ ...s, signingOrder: i + 1 })), ); }; const handleSubmit = async (): Promise => { if (!title.trim()) { toast.error('Title is required'); return; } if (!subjectId.trim()) { toast.error(`Provide a ${subjectType} id`); return; } if (source === 'template' && !templateId.trim()) { toast.error('Pick a template'); return; } if (source === 'upload' && !uploadedFileId.trim()) { toast.error('Provide an uploaded file id'); return; } const cleanSigners = signers.filter((s) => s.signerEmail.trim() && s.signerName.trim()); if (source === 'upload' && cleanSigners.length === 0) { toast.error('Upload path requires at least one signer'); return; } setSubmitting(true); try { const body: Record = { source, pathway, documentType, title: title.trim(), notes: notes.trim() || undefined, [subjectField]: subjectId.trim(), signingMode, watchers: [], autoPlaceFields: true, sendImmediately: false, remindersDisabled: reminderMode === 'disabled', }; if (source === 'template') body.templateId = templateId.trim(); if (source === 'upload') { body.uploadedFileId = uploadedFileId.trim(); body.signers = cleanSigners; } else if (cleanSigners.length > 0) { body.signers = cleanSigners; } if (reminderMode === 'override') { body.reminderCadenceOverride = reminderDays; } const res = await apiFetch<{ data: { id: string } }>('/api/v1/documents/wizard', { method: 'POST', body, }); toast.success('Document created'); router.push(`/${portSlug}/documents/${res.data.id}`); } catch (err) { toast.error(err instanceof Error ? err.message : 'Failed to create document'); setSubmitting(false); } }; return (
Back } />

Source

{source === 'template' ? ( <>
setTemplateId(e.target.value)} placeholder="Template UUID" />
) : (
setUploadedFileId(e.target.value)} placeholder="File UUID from /api/v1/files upload" />

Upload via the existing file uploader, then paste the returned id here.

)}

Document

setTitle(e.target.value)} />
setNotes(e.target.value)} />
setSubjectId(e.target.value)} placeholder={`${subjectType} id`} />

Signers

    {signers.map((s, idx) => (
  • #{s.signingOrder} updateSigner(idx, { signerName: e.target.value })} placeholder="Name" /> updateSigner(idx, { signerEmail: e.target.value })} placeholder="Email" />
  • ))}

Reminders

); }