import { useMemo, useState } from 'react'; import { Trans } from '@lingui/react/macro'; import { type Field, FieldType, type Recipient, RecipientRole } from '@prisma/client'; import { useForm } from 'react-hook-form'; import { useNavigate } from 'react-router'; import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { useOptionalSession } from '@documenso/lib/client-only/providers/session'; import type { DocumentAndSender } from '@documenso/lib/server-only/document/get-document-by-token'; import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth'; import { isFieldUnsignedAndRequired } from '@documenso/lib/utils/advanced-fields-helpers'; import { sortFieldsByPosition, validateFieldsInserted } from '@documenso/lib/utils/fields'; import { trpc } from '@documenso/trpc/react'; import { FieldToolTip } from '@documenso/ui/components/field/field-tooltip'; import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; import { Card, CardContent } from '@documenso/ui/primitives/card'; import { Input } from '@documenso/ui/primitives/input'; import { Label } from '@documenso/ui/primitives/label'; import { SignaturePad } from '@documenso/ui/primitives/signature-pad'; import { DocumentSigningCompleteDialog } from './document-signing-complete-dialog'; import { useRequiredDocumentSigningContext } from './document-signing-provider'; export type DocumentSigningFormProps = { document: DocumentAndSender; recipient: Recipient; fields: Field[]; redirectUrl?: string | null; isRecipientsTurn: boolean; }; export const DocumentSigningForm = ({ document, recipient, fields, redirectUrl, isRecipientsTurn, }: DocumentSigningFormProps) => { const navigate = useNavigate(); const analytics = useAnalytics(); const { user } = useOptionalSession(); const { fullName, signature, setFullName, setSignature, signatureValid, setSignatureValid } = useRequiredDocumentSigningContext(); const [validateUninsertedFields, setValidateUninsertedFields] = useState(false); const { mutateAsync: completeDocumentWithToken } = trpc.recipient.completeDocumentWithToken.useMutation(); const { handleSubmit, formState } = useForm(); // Keep the loading state going if successful since the redirect may take some time. const isSubmitting = formState.isSubmitting || formState.isSubmitSuccessful; const fieldsRequiringValidation = useMemo( () => fields.filter(isFieldUnsignedAndRequired), [fields], ); const hasSignatureField = fields.some((field) => field.type === FieldType.SIGNATURE); const uninsertedFields = useMemo(() => { return sortFieldsByPosition(fieldsRequiringValidation.filter((field) => !field.inserted)); }, [fields]); const fieldsValidated = () => { setValidateUninsertedFields(true); validateFieldsInserted(fieldsRequiringValidation); }; const onFormSubmit = async () => { setValidateUninsertedFields(true); const isFieldsValid = validateFieldsInserted(fieldsRequiringValidation); if (hasSignatureField && !signatureValid) { return; } if (!isFieldsValid) { return; } await completeDocument(); // Reauth is currently not required for completing the document. // await executeActionAuthProcedure({ // onReauthFormSubmit: completeDocument, // actionTarget: 'DOCUMENT', // }); }; const completeDocument = async (authOptions?: TRecipientActionAuth) => { await completeDocumentWithToken({ token: recipient.token, documentId: document.id, authOptions, }); analytics.capture('App: Recipient has completed signing', { signerId: recipient.id, documentId: document.id, timestamp: new Date().toISOString(), }); if (redirectUrl) { window.location.href = redirectUrl; } else { await navigate(`/sign/${recipient.token}/complete`); } }; return (
{validateUninsertedFields && uninsertedFields[0] && ( Click to insert field )}

{recipient.role === RecipientRole.VIEWER && View Document} {recipient.role === RecipientRole.SIGNER && Sign Document} {recipient.role === RecipientRole.APPROVER && Approve Document}

{recipient.role === RecipientRole.VIEWER ? ( <>

Please mark as viewed to complete


) : ( <>

Please review the document before signing.


setFullName(e.target.value.trimStart())} />
{ setSignatureValid(isValid); }} onChange={(value) => { if (signatureValid) { setSignature(value); } }} allowTypedSignature={document.documentMeta?.typedSignatureEnabled} /> {hasSignatureField && !signatureValid && (
Signature is too small. Please provide a more complete signature.
)}
)}
); };