'use client'; import { useState } from 'react'; import { zodResolver } from '@hookform/resolvers/zod'; import { DateTime } from 'luxon'; import { useForm } from 'react-hook-form'; import { match } from 'ts-pattern'; import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer'; import { FieldType } from '@documenso/prisma/client'; import { FieldWithSignature } from '@documenso/prisma/types/field-with-signature'; import { cn } from '@documenso/ui/lib/utils'; import { Card, CardContent } from '@documenso/ui/primitives/card'; import { TAddSignatureFormSchema } from '@documenso/ui/primitives/document-flow/add-signature.types'; import { DocumentFlowFormContainerActions, DocumentFlowFormContainerContent, DocumentFlowFormContainerFooter, DocumentFlowFormContainerStep, } from '@documenso/ui/primitives/document-flow/document-flow-root'; import { DocumentFlowStep } from '@documenso/ui/primitives/document-flow/types'; import { ElementVisible } from '@documenso/ui/primitives/element-visible'; import { Input } from '@documenso/ui/primitives/input'; import { SignaturePad } from '@documenso/ui/primitives/signature-pad'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '../form/form'; import { ZAddSignatureFormSchema } from './add-signature.types'; import { SinglePlayerModeCustomTextField, SinglePlayerModeSignatureField, } from './single-player-mode-fields'; export type AddSignatureFormProps = { defaultValues?: TAddSignatureFormSchema; documentFlow: DocumentFlowStep; fields: FieldWithSignature[]; numberOfSteps: number; onSubmit: (_data: TAddSignatureFormSchema) => Promise | void; requireName?: boolean; requireSignature?: boolean; }; export const AddSignatureFormPartial = ({ defaultValues, documentFlow, fields, numberOfSteps, onSubmit, requireName = false, requireSignature = true, }: AddSignatureFormProps) => { // Refined schema which takes into account whether to allow an empty name or signature. const refinedSchema = ZAddSignatureFormSchema.superRefine((val, ctx) => { if (requireName && val.name.length === 0) { ctx.addIssue({ path: ['name'], code: 'custom', message: 'Name is required', }); } if (requireSignature && val.signature.length === 0) { ctx.addIssue({ path: ['signature'], code: 'custom', message: 'Signature is required', }); } }); const form = useForm({ resolver: zodResolver(refinedSchema), defaultValues: defaultValues ?? { name: '', email: '', signature: '', }, }); /** * A local copy of the provided fields to modify. */ const [localFields, setLocalFields] = useState( fields.map((field) => { let customText = field.customText; if (field.type === FieldType.DATE) { customText = DateTime.now().toFormat('yyyy-MM-dd hh:mm a'); } const inserted = match(field.type) .with(FieldType.DATE, () => true) .with(FieldType.NAME, () => form.getValues('name').length > 0) .with(FieldType.EMAIL, () => form.getValues('email').length > 0) .with(FieldType.SIGNATURE, () => form.getValues('signature').length > 0) .otherwise(() => true); return { ...field, inserted, customText }; }), ); const onEmailInputBlur = () => { setLocalFields((prev) => prev.map((field) => { if (field.type !== FieldType.EMAIL) { return field; } const value = form.getValues('email'); return { ...field, customText: value, inserted: value.length > 0, }; }), ); }; const onNameInputBlur = () => { setLocalFields((prev) => prev.map((field) => { if (field.type !== FieldType.NAME) { return field; } const value = form.getValues('name'); return { ...field, customText: value, inserted: value.length > 0, }; }), ); }; const onSignatureInputChange = (value: string) => { setLocalFields((prev) => prev.map((field) => { if (field.type !== FieldType.SIGNATURE) { return field; } return { ...field, value: value ?? '', inserted: true, Signature: { id: -1, recipientId: -1, fieldId: -1, created: new Date(), signatureImageAsBase64: value, typedSignature: null, }, }; }), ); }; return (
( Email { field.onBlur(); onEmailInputBlur(); }} /> )} /> {requireName && ( ( Name { field.onBlur(); onNameInputBlur(); }} /> )} /> )} {requireSignature && ( ( Signature { field.onChange(value ?? ''); onSignatureInputChange(value ?? ''); }} /> )} /> )}
await form.handleSubmit(onSubmit)()} />
{localFields.map((field) => match(field.type) .with(FieldType.DATE, FieldType.EMAIL, FieldType.NAME, () => { return ; }) .with(FieldType.SIGNATURE, () => ( )) .otherwise(() => { return null; }), )}
); };