diff --git a/src/app/api/v1/interests/[id]/external-eoi/route.ts b/src/app/api/v1/interests/[id]/external-eoi/route.ts index b0261fa7..1ad770a0 100644 --- a/src/app/api/v1/interests/[id]/external-eoi/route.ts +++ b/src/app/api/v1/interests/[id]/external-eoi/route.ts @@ -79,6 +79,13 @@ export const POST = withAuth( (form.get('cancelActiveDocumentId') as string | null) ?? null; const cancelActiveDocumentId = cancelActiveDocumentIdRaw?.trim() || undefined; + // Which signed doc this is. Defaults to 'eoi' (legacy callers); the + // reservation/contract tabs post their own type so it files correctly. + const docTypeRaw = (form.get('docType') as string | null)?.trim() ?? 'eoi'; + const docType = ( + ['eoi', 'reservation', 'contract'].includes(docTypeRaw) ? docTypeRaw : 'eoi' + ) as 'eoi' | 'reservation' | 'contract'; + const result = await uploadExternallySignedEoi({ interestId, portId: ctx.portId, @@ -94,6 +101,7 @@ export const POST = withAuth( signatories, notes, cancelActiveDocumentId, + docType, meta: { userId: ctx.userId, portId: ctx.portId, diff --git a/src/components/interests/external-eoi-upload-dialog.tsx b/src/components/interests/external-eoi-upload-dialog.tsx index cdccbfab..4ac1028a 100644 --- a/src/components/interests/external-eoi-upload-dialog.tsx +++ b/src/components/interests/external-eoi-upload-dialog.tsx @@ -55,6 +55,10 @@ interface Props { * from the active Documenso EOI's signers). Falls through to the * client-only seed when omitted or empty. */ prefillSignatories?: SignatoryRow[]; + /** Which signed document this upload is for. Defaults to 'eoi'; the + * reservation/contract tabs pass their own type so the file is filed + + * the deal advanced under the right kind (EOI-specific UI is hidden). */ + docType?: 'eoi' | 'reservation' | 'contract'; } export function ExternalEoiUploadDialog({ @@ -63,7 +67,15 @@ export function ExternalEoiUploadDialog({ interestId, onSuccess, prefillSignatories, + docType = 'eoi', }: Props) { + const DOC_LABEL = + docType === 'reservation' + ? 'reservation agreement' + : docType === 'contract' + ? 'contract' + : 'EOI'; + const isEoi = docType === 'eoi'; const qc = useQueryClient(); const [file, setFile] = useState(null); const [title, setTitle] = useState(''); @@ -173,7 +185,7 @@ export function ExternalEoiUploadDialog({ apiFetch<{ data: Array<{ id: string; status: string; title: string; createdAt: string }>; }>(`/api/v1/documents?interestId=${interestId}&documentType=eoi`), - enabled: open, + enabled: open && isEoi, staleTime: 30_000, }); const activeEoi = useMemo( @@ -191,12 +203,12 @@ export function ExternalEoiUploadDialog({ .filter((m): m is string => !!m); const berthLabel = moorings.length > 0 ? formatBerthRange(moorings) : null; const clientName = interestData?.clientName ?? null; - const parts = ['External EOI']; + const parts = [`External ${DOC_LABEL}`]; if (clientName) parts.push(clientName); if (berthLabel) parts.push(berthLabel); parts.push(date); return parts.join(' - '); - }, [interestData, berthsData, signedAt]); + }, [interestData, berthsData, signedAt, DOC_LABEL]); // The title input is controlled with `displayTitle` (derived from // either the rep's typed value or the auto-derived default). Reps @@ -226,7 +238,8 @@ export function ExternalEoiUploadDialog({ // When a generated EOI is active AND the rep didn't opt out via the // Advanced toggle, tell the server to cancel it as part of this // upload so the deal carries one canonical EOI. - if (activeEoi && replaceMode === 'replace') { + form.append('docType', docType); + if (isEoi && activeEoi && replaceMode === 'replace') { form.append('cancelActiveDocumentId', activeEoi.id); } const res = await fetch(`/api/v1/interests/${interestId}/external-eoi`, { @@ -250,7 +263,7 @@ export function ExternalEoiUploadDialog({ // sync are skipped. Failures here don't undo the upload (the doc // is already filed) but surface as a non-blocking toast so the // rep knows the flag didn't propagate. - if (inBundleBerths.length > 0) { + if (isEoi && inBundleBerths.length > 0) { const targets = inBundleBerths.filter((b) => b.isSpecificInterest !== publicFlagChecked); if (targets.length > 0) { try { @@ -270,8 +283,8 @@ export function ExternalEoiUploadDialog({ } toast.success( stageChanged - ? 'External EOI uploaded. Stage advanced to EOI Signed.' - : 'External EOI uploaded. Filed against this deal (stage unchanged).', + ? `Signed ${DOC_LABEL} uploaded. Pipeline stage advanced.` + : `Signed ${DOC_LABEL} uploaded. Filed against this deal (stage unchanged).`, ); qc.invalidateQueries({ queryKey: ['interests', interestId] }); qc.invalidateQueries({ queryKey: ['interests'] }); @@ -293,16 +306,16 @@ export function ExternalEoiUploadDialog({ - Upload externally-signed EOI + Upload externally-signed {DOC_LABEL} - For EOIs signed outside our signing service (paper, in person, alternate e-sign vendor). - The uploaded PDF is filed against this interest and the pipeline stage is advanced to - EOI Signed. + For a {DOC_LABEL} signed outside our signing service (paper, in person, alternate e-sign + vendor). The uploaded PDF is filed against this interest and the pipeline stage is + advanced accordingly.
- {activeEoi ? ( + {isEoi && activeEoi ? (

A generated EOI is already in flight on this deal. @@ -466,7 +479,7 @@ export function ExternalEoiUploadDialog({ className="mt-1" />

- {inBundleBerths.length > 0 ? ( + {isEoi && inBundleBerths.length > 0 ? (