'use client'; import React, { useEffect, useId, useMemo, useState } from 'react'; import { zodResolver } from '@hookform/resolvers/zod'; import { Trans, msg } from '@lingui/macro'; import { useLingui } from '@lingui/react'; import { motion } from 'framer-motion'; import { Link2Icon, Plus, Trash } from 'lucide-react'; import { useSession } from 'next-auth/react'; import { useFieldArray, useForm } from 'react-hook-form'; import { ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth'; import { nanoid } from '@documenso/lib/universal/id'; import { generateRecipientPlaceholder } from '@documenso/lib/utils/templates'; import type { TemplateDirectLink } from '@documenso/prisma/client'; import { type Field, type Recipient, RecipientRole } from '@documenso/prisma/client'; import { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out'; import { RecipientActionAuthSelect } from '@documenso/ui/components/recipient/recipient-action-auth-select'; import { RecipientRoleSelect } from '@documenso/ui/components/recipient/recipient-role-select'; import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; import { FormErrorMessage } from '@documenso/ui/primitives/form/form-error-message'; import { Input } from '@documenso/ui/primitives/input'; import { Checkbox } from '../checkbox'; import { DocumentFlowFormContainerActions, DocumentFlowFormContainerContent, DocumentFlowFormContainerFooter, DocumentFlowFormContainerHeader, DocumentFlowFormContainerStep, } from '../document-flow/document-flow-root'; import { ShowFieldItem } from '../document-flow/show-field-item'; import type { DocumentFlowStep } from '../document-flow/types'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '../form/form'; import { useStep } from '../stepper'; import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip'; import type { TAddTemplatePlacholderRecipientsFormSchema } from './add-template-placeholder-recipients.types'; import { ZAddTemplatePlacholderRecipientsFormSchema } from './add-template-placeholder-recipients.types'; export type AddTemplatePlaceholderRecipientsFormProps = { documentFlow: DocumentFlowStep; recipients: Recipient[]; fields: Field[]; templateDirectLink: TemplateDirectLink | null; isEnterprise: boolean; isDocumentPdfLoaded: boolean; onSubmit: (_data: TAddTemplatePlacholderRecipientsFormSchema) => void; }; export const AddTemplatePlaceholderRecipientsFormPartial = ({ documentFlow, isEnterprise, recipients, templateDirectLink, fields, isDocumentPdfLoaded, onSubmit, }: AddTemplatePlaceholderRecipientsFormProps) => { const initialId = useId(); const { _ } = useLingui(); const { data: session } = useSession(); const user = session?.user; const [placeholderRecipientCount, setPlaceholderRecipientCount] = useState(() => recipients.length > 1 ? recipients.length + 1 : 2, ); const { currentStep, totalSteps, previousStep } = useStep(); const generateDefaultFormSigners = () => { if (recipients.length === 0) { return [ { formId: initialId, role: RecipientRole.SIGNER, actionAuth: undefined, ...generateRecipientPlaceholder(1), }, ]; } return recipients.map((recipient) => ({ nativeId: recipient.id, formId: String(recipient.id), name: recipient.name, email: recipient.email, role: recipient.role, actionAuth: ZRecipientAuthOptionsSchema.parse(recipient.authOptions)?.actionAuth ?? undefined, })); }; const form = useForm({ resolver: zodResolver(ZAddTemplatePlacholderRecipientsFormSchema), defaultValues: { signers: generateDefaultFormSigners(), }, }); useEffect(() => { form.reset({ signers: generateDefaultFormSigners(), }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [recipients]); // Always show advanced settings if any recipient has auth options. const alwaysShowAdvancedSettings = useMemo(() => { const recipientHasAuthOptions = recipients.find((recipient) => { const recipientAuthOptions = ZRecipientAuthOptionsSchema.parse(recipient.authOptions); return recipientAuthOptions?.accessAuth || recipientAuthOptions?.actionAuth; }); const formHasActionAuth = form.getValues('signers').find((signer) => signer.actionAuth); return recipientHasAuthOptions !== undefined || formHasActionAuth !== undefined; }, [recipients, form]); const [showAdvancedSettings, setShowAdvancedSettings] = useState(alwaysShowAdvancedSettings); const { formState: { errors, isSubmitting }, control, } = form; const onFormSubmit = form.handleSubmit(onSubmit); const { append: appendSigner, fields: signers, remove: removeSigner, } = useFieldArray({ control, name: 'signers', }); const onAddPlaceholderSelfRecipient = () => { appendSigner({ formId: nanoid(12), name: user?.name ?? '', email: user?.email ?? '', role: RecipientRole.SIGNER, }); }; const onAddPlaceholderRecipient = () => { appendSigner({ formId: nanoid(12), role: RecipientRole.SIGNER, ...generateRecipientPlaceholder(placeholderRecipientCount), }); setPlaceholderRecipientCount((count) => count + 1); }; const onRemoveSigner = (index: number) => { removeSigner(index); }; const isSignerDirectRecipient = ( signer: TAddTemplatePlacholderRecipientsFormSchema['signers'][number], ): boolean => { return ( templateDirectLink !== null && signer.nativeId === templateDirectLink?.directTemplateRecipientId ); }; return ( <> {isDocumentPdfLoaded && fields.map((field, index) => ( ))}
{signers.map((signer, index) => ( ( {!showAdvancedSettings && index === 0 && ( Email )} )} /> ( {!showAdvancedSettings && index === 0 && ( Name )} )} /> {showAdvancedSettings && isEnterprise && ( ( )} /> )} ( )} /> {isSignerDirectRecipient(signer) ? (

Direct link receiver

This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them.

) : ( )}
))}
{!alwaysShowAdvancedSettings && isEnterprise && (
setShowAdvancedSettings(Boolean(value))} />
)}
1} onGoBackClick={() => previousStep()} onGoNextClick={() => void onFormSubmit()} /> ); };