'use client'; import { useEffect, useState } from 'react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { base64 } from '@documenso/lib/universal/base64'; import { putFile } from '@documenso/lib/universal/upload/put-file'; import { Field, Prisma, Recipient } from '@documenso/prisma/client'; import { Card, CardContent } from '@documenso/ui/primitives/card'; import { DocumentDropzone } from '@documenso/ui/primitives/document-dropzone'; import { AddFieldsFormPartial } from '@documenso/ui/primitives/document-flow/add-fields'; import { TAddFieldsFormSchema } from '@documenso/ui/primitives/document-flow/add-fields.types'; import { AddSignatureFormPartial } from '@documenso/ui/primitives/document-flow/add-signature'; import { TAddSignatureFormSchema } from '@documenso/ui/primitives/document-flow/add-signature.types'; import { DocumentFlowFormContainer, DocumentFlowFormContainerHeader, } from '@documenso/ui/primitives/document-flow/document-flow-root'; import { DocumentFlowStep } from '@documenso/ui/primitives/document-flow/types'; import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer'; import { useToast } from '@documenso/ui/primitives/use-toast'; import { createSinglePlayerDocument } from '~/components/(marketing)/single-player-mode/create-single-player-document.action'; type SinglePlayerModeStep = 'fields' | 'sign'; export default function SinglePlayerModePage() { const analytics = useAnalytics(); const router = useRouter(); const { toast } = useToast(); const [uploadedFile, setUploadedFile] = useState<{ file: File; fileBase64: string } | null>(); const [step, setStep] = useState('fields'); const [fields, setFields] = useState([]); const documentFlow: Record = { fields: { title: 'Add document', description: 'Upload a document and add fields.', stepIndex: 1, onBackStep: uploadedFile ? () => { setUploadedFile(null); setFields([]); } : undefined, onNextStep: () => setStep('sign'), }, sign: { title: 'Sign', description: 'Enter your details.', stepIndex: 2, onBackStep: () => setStep('fields'), }, }; const currentDocumentFlow = documentFlow[step]; useEffect(() => { analytics.startSessionRecording('marketing_session_recording_spm'); return () => { analytics.stopSessionRecording(); }; }, [analytics]); /** * Insert the selected fields into the local state. */ const onFieldsSubmit = (data: TAddFieldsFormSchema) => { if (!uploadedFile) { return; } setFields( data.fields.map((field, i) => ({ id: i, documentId: -1, recipientId: -1, type: field.type, page: field.pageNumber, positionX: new Prisma.Decimal(field.pageX), positionY: new Prisma.Decimal(field.pageY), width: new Prisma.Decimal(field.pageWidth), height: new Prisma.Decimal(field.pageHeight), customText: '', inserted: false, })), ); analytics.capture('Marketing: SPM - Fields added'); documentFlow.fields.onNextStep?.(); }; /** * Upload, create, sign and send the document. */ const onSignSubmit = async (data: TAddSignatureFormSchema) => { if (!uploadedFile) { return; } try { const putFileData = await putFile(uploadedFile.file); const documentToken = await createSinglePlayerDocument({ documentData: { type: putFileData.type, data: putFileData.data, }, documentName: uploadedFile.file.name, signer: data, fields: fields.map((field) => ({ page: field.page, type: field.type, positionX: field.positionX.toNumber(), positionY: field.positionY.toNumber(), width: field.width.toNumber(), height: field.height.toNumber(), })), }); analytics.capture('Marketing: SPM - Document signed', { signer: data.email, }); router.push(`/single-player-mode/${documentToken}/success`); } catch { toast({ title: 'Something went wrong', description: 'Please try again later.', variant: 'destructive', }); } }; const placeholderRecipient: Recipient = { id: -1, documentId: -1, email: '', name: '', token: '', expired: null, signedAt: null, readStatus: 'OPENED', signingStatus: 'NOT_SIGNED', sendStatus: 'NOT_SENT', }; const onFileDrop = async (file: File) => { try { const arrayBuffer = await file.arrayBuffer(); const base64String = base64.encode(new Uint8Array(arrayBuffer)); setUploadedFile({ file, fileBase64: `data:application/pdf;base64,${base64String}`, }); analytics.capture('Marketing: SPM - Document uploaded'); } catch { toast({ title: 'Something went wrong', description: 'Please try again later.', variant: 'destructive', }); } }; return (

Single Player Mode

View our{' '} community plan {' '} for exclusive features, including the ability to collaborate with multiple signers.

{uploadedFile ? ( ) : ( )}
e.preventDefault()}> {/* Add fields to PDF page. */} {step === 'fields' && (
)} {/* Enter user details and signature. */} {step === 'sign' && ( field.type === 'NAME'))} requireSignature={Boolean(fields.find((field) => field.type === 'SIGNATURE'))} /> )}
); }