import { zodResolver } from '@hookform/resolvers/zod'; import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react'; import { Trans } from '@lingui/react/macro'; import { File as FileIcon, Upload, X } from 'lucide-react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { trpc } from '@documenso/trpc/react'; import { Button } from '@documenso/ui/primitives/button'; import { Checkbox } from '@documenso/ui/primitives/checkbox'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@documenso/ui/primitives/dialog'; import { Form, FormControl, FormField, FormItem } from '@documenso/ui/primitives/form/form'; import { useToast } from '@documenso/ui/primitives/use-toast'; import { useCurrentTeam } from '~/providers/team'; const ZBulkSendFormSchema = z.object({ file: z.instanceof(File), sendImmediately: z.boolean().default(false), }); type TBulkSendFormSchema = z.infer; export type TemplateBulkSendDialogProps = { templateId: number; recipients: Array<{ email: string; name?: string | null }>; trigger?: React.ReactNode; onSuccess?: () => void; }; export const TemplateBulkSendDialog = ({ templateId, recipients, trigger, onSuccess, }: TemplateBulkSendDialogProps) => { const { _ } = useLingui(); const { toast } = useToast(); const team = useCurrentTeam(); const form = useForm({ resolver: zodResolver(ZBulkSendFormSchema), defaultValues: { sendImmediately: false, }, }); const { mutateAsync: uploadBulkSend } = trpc.template.uploadBulkSend.useMutation(); const onDownloadTemplate = () => { const headers = recipients.flatMap((_, index) => [ `recipient_${index + 1}_email`, `recipient_${index + 1}_name`, ]); const exampleRow = recipients.flatMap((recipient) => [recipient.email, recipient.name || '']); const csv = [headers.join(','), exampleRow.join(',')].join('\n'); const blob = new Blob([csv], { type: 'text/csv' }); const url = window.URL.createObjectURL(blob); const a = Object.assign(document.createElement('a'), { href: url, download: 'template.csv', }); a.click(); window.URL.revokeObjectURL(url); }; const onSubmit = async (values: TBulkSendFormSchema) => { try { const csv = await values.file.text(); await uploadBulkSend({ templateId, teamId: team?.id, csv: csv, sendImmediately: values.sendImmediately, }); toast({ title: _(msg`Success`), description: _( msg`Your bulk send has been initiated. You will receive an email notification upon completion.`, ), }); form.reset(); onSuccess?.(); } catch (err) { console.error(err); toast({ title: 'Error', description: 'Failed to upload CSV. Please check the file format and try again.', variant: 'destructive', }); } }; return ( {trigger ?? ( )} Bulk Send Template via CSV Upload a CSV file to create multiple documents from this template. Each row represents one document with its recipient details.

CSV Structure

For each recipient, provide their email (required) and name (optional) in separate columns. Download the template CSV below for the correct format.

Current recipients:

    {recipients.map((recipient, index) => (
  • {recipient.name ? `${recipient.name} (${recipient.email})` : recipient.email}
  • ))}

Pre-formatted CSV template with example data.

( {!value ? ( ) : (
{value.name}
)}
{error &&

{error.message}

}

Maximum file size: 4MB. Maximum 100 rows per upload. Blank values will use template defaults.

)} /> (
)} />
); };