import { lazy, useEffect, useMemo, useState } from 'react'; import { faker } from '@faker-js/faker/locale/en'; import { Trans } from '@lingui/react/macro'; import { FieldType, SigningStatus } from '@prisma/client'; import { FileTextIcon } from 'lucide-react'; import { match } from 'ts-pattern'; import { useCurrentEnvelopeEditor } from '@documenso/lib/client-only/providers/envelope-editor-provider'; import { EnvelopeRenderProvider, useCurrentEnvelopeRender, } from '@documenso/lib/client-only/providers/envelope-render-provider'; import { ZFieldAndMetaSchema } from '@documenso/lib/types/field-meta'; import { extractFieldInsertionValues } from '@documenso/lib/utils/envelope-signing'; import { toCheckboxCustomText } from '@documenso/lib/utils/fields'; import { extractInitials } from '@documenso/lib/utils/recipient-formatter'; import { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out'; import PDFViewerKonvaLazy from '@documenso/ui/components/pdf-viewer/pdf-viewer-konva-lazy'; import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert'; import { RecipientSelector } from '@documenso/ui/primitives/recipient-selector'; import { Separator } from '@documenso/ui/primitives/separator'; import { EnvelopeRendererFileSelector } from './envelope-file-selector'; const EnvelopeGenericPageRenderer = lazy(async () => import('./envelope-generic-page-renderer')); // Todo: Envelopes - Dynamically import faker export const EnvelopeEditorPreviewPage = () => { const { envelope, editorFields } = useCurrentEnvelopeEditor(); const { currentEnvelopeItem, fields } = useCurrentEnvelopeRender(); const [selectedPreviewMode, setSelectedPreviewMode] = useState<'recipient' | 'signed'>( 'recipient', ); const fieldsWithPlaceholders = useMemo(() => { return fields.map((field) => { const fieldMeta = ZFieldAndMetaSchema.parse(field); const recipient = envelope.recipients.find((recipient) => recipient.id === field.recipientId); if (!recipient) { throw new Error('Recipient not found'); } faker.seed(recipient.id); const recipientName = recipient.name || faker.person.fullName(); const recipientEmail = recipient.email || faker.internet.email(); faker.seed(recipient.id + field.id); return { ...field, inserted: true, ...match(fieldMeta) .with({ type: FieldType.TEXT }, ({ fieldMeta }) => { let text = fieldMeta?.text || faker.lorem.words(5); if (fieldMeta?.characterLimit) { text = text.slice(0, fieldMeta?.characterLimit); } return { customText: text, }; }) .with({ type: FieldType.NUMBER }, ({ fieldMeta }) => { let number = fieldMeta?.value ?? ''; if (number === '') { number = faker.number .int({ min: fieldMeta?.minValue ?? 0, max: fieldMeta?.maxValue ?? 1000, }) .toString(); } return { customText: number, }; }) .with({ type: FieldType.DATE }, () => { const date = extractFieldInsertionValues({ fieldValue: { type: FieldType.DATE, value: true, }, field, documentMeta: envelope.documentMeta, }); return { customText: date.customText, }; }) .with({ type: FieldType.EMAIL }, () => { return { customText: recipientEmail, }; }) .with({ type: FieldType.NAME }, () => { return { customText: recipientName, }; }) .with({ type: FieldType.INITIALS }, () => { return { customText: extractInitials(recipientName), }; }) .with({ type: FieldType.RADIO }, ({ fieldMeta }) => { const values = fieldMeta?.values ?? []; if (values.length === 0) { return ''; } let customText = ''; const preselectedValue = values.findIndex((value) => value.checked); if (preselectedValue !== -1) { customText = preselectedValue.toString(); } else { const randomIndex = faker.number.int({ min: 0, max: values.length - 1 }); customText = randomIndex.toString(); } return { customText, }; }) .with({ type: FieldType.CHECKBOX }, ({ fieldMeta }) => { let checkedValues: number[] = []; const values = fieldMeta?.values ?? []; values.forEach((value, index) => { if (value.checked) { checkedValues.push(index); } }); if (checkedValues.length === 0 && values.length > 0) { const numberOfValues = fieldMeta?.validationLength || 1; checkedValues = Array.from({ length: numberOfValues }, (_, index) => index); } return { customText: toCheckboxCustomText(checkedValues), }; }) .with({ type: FieldType.DROPDOWN }, ({ fieldMeta }) => { const values = fieldMeta?.values ?? []; let customText = fieldMeta?.defaultValue || ''; if (!customText && values.length > 0) { const randomIndex = faker.number.int({ min: 0, max: values.length - 1 }); customText = values[randomIndex].value; } return { customText, }; }) .with({ type: FieldType.SIGNATURE }, () => { return { customText: '', signature: { signatureImageAsBase64: '', typedSignature: recipientName, }, }; }) .with({ type: FieldType.FREE_SIGNATURE }, () => { return { customText: '', }; }) .exhaustive(), }; }); }, [fields, envelope, envelope.recipients, envelope.documentMeta]); /** * Set the selected recipient to the first recipient in the envelope. */ useEffect(() => { editorFields.setSelectedRecipient(envelope.recipients[0]?.id ?? null); }, []); // Override the parent renderer provider so we can inject custom fields. return ( ({ ...recipient, signingStatus: SigningStatus.SIGNED, }))} overrideSettings={{ mode: 'export', }} >
{/* Horizontal envelope item selector */} {/* Document View */}
Preview Mode Preview what the signed document will look like with placeholder data {currentEnvelopeItem !== null ? ( ) : (

No documents found

Please upload a document to continue

)}
{/* Right Section - Form Fields Panel */} {currentEnvelopeItem && false && (
{/* Add fields section. */}
{/*

Preivew Mode

*/} Preview Mode Preview what the signed document will look like with placeholder data {/* setSelectedPreviewMode(value as 'recipient' | 'signed')} >
Preview what a recipient will see
Preview the signed document
*/}
{false && ( {selectedPreviewMode === 'recipient' && ( <> {/* Recipient selector section. */}

Selected Recipient

editorFields.setSelectedRecipient(recipient.id) } recipients={envelope.recipients} className="w-full" align="end" />
)}
)}
)}
); };