import { useMemo, useState } from 'react'; import { zodResolver } from '@hookform/resolvers/zod'; import { useLingui } from '@lingui/react/macro'; import { Trans } from '@lingui/react/macro'; import { DocumentDistributionMethod, DocumentStatus, EnvelopeType, type Field, FieldType, type Recipient, RecipientRole, } from '@prisma/client'; import { AnimatePresence, motion } from 'framer-motion'; import { InfoIcon } from 'lucide-react'; import { useForm } from 'react-hook-form'; import * as z from 'zod'; import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation'; import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles'; import type { TEnvelope } from '@documenso/lib/types/envelope'; import { formatSigningLink } from '@documenso/lib/utils/recipients'; import { trpc, trpc as trpcReact } from '@documenso/trpc/react'; import { CopyTextButton } from '@documenso/ui/components/common/copy-text-button'; import { DocumentSendEmailMessageHelper } from '@documenso/ui/components/document/document-send-email-message-helper'; import { Alert, AlertDescription } from '@documenso/ui/primitives/alert'; import { AvatarWithText } from '@documenso/ui/primitives/avatar'; import { Button } from '@documenso/ui/primitives/button'; import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@documenso/ui/primitives/dialog'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from '@documenso/ui/primitives/form/form'; import { Input } from '@documenso/ui/primitives/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@documenso/ui/primitives/select'; import { Tabs, TabsList, TabsTrigger } from '@documenso/ui/primitives/tabs'; import { Textarea } from '@documenso/ui/primitives/textarea'; import { Tooltip, TooltipContent, TooltipTrigger } from '@documenso/ui/primitives/tooltip'; import { useToast } from '@documenso/ui/primitives/use-toast'; export type EnvelopeDistributeDialogProps = { envelope: Pick & { recipients: Recipient[]; fields: Field[]; }; trigger?: React.ReactNode; }; export const ZEnvelopeDistributeFormSchema = z.object({ meta: z.object({ emailId: z.string().nullable(), emailReplyTo: z.preprocess( (val) => (val === '' ? undefined : val), z.string().email().optional(), ), subject: z.string(), message: z.string(), distributionMethod: z .nativeEnum(DocumentDistributionMethod) .optional() .default(DocumentDistributionMethod.EMAIL), }), }); export type TEnvelopeDistributeFormSchema = z.infer; export const EnvelopeDistributeDialog = ({ envelope, trigger }: EnvelopeDistributeDialogProps) => { const organisation = useCurrentOrganisation(); const recipients = envelope.recipients; const { toast } = useToast(); const { t } = useLingui(); const [isOpen, setIsOpen] = useState(false); const { mutateAsync: distributeEnvelope } = trpcReact.envelope.distribute.useMutation(); const form = useForm({ defaultValues: { meta: { emailId: envelope.documentMeta?.emailId ?? null, emailReplyTo: envelope.documentMeta?.emailReplyTo || undefined, subject: envelope.documentMeta?.subject ?? '', message: envelope.documentMeta?.message ?? '', distributionMethod: envelope.documentMeta?.distributionMethod || DocumentDistributionMethod.EMAIL, }, }, resolver: zodResolver(ZEnvelopeDistributeFormSchema), }); const { handleSubmit, setValue, watch, formState: { isSubmitting }, } = form; const { data: emailData, isLoading: isLoadingEmails } = trpc.enterprise.organisation.email.find.useQuery({ organisationId: organisation.id, perPage: 100, }); const emails = emailData?.data || []; const distributionMethod = watch('meta.distributionMethod'); const everySignerHasSignature = useMemo( () => envelope.recipients .filter((recipient) => recipient.role === RecipientRole.SIGNER) .every((recipient) => envelope.fields.some( (field) => field.type === FieldType.SIGNATURE && field.recipientId === recipient.id, ), ), [envelope.recipients, envelope.fields], ); const onFormSubmit = async ({ meta }: TEnvelopeDistributeFormSchema) => { try { await distributeEnvelope({ envelopeId: envelope.id, meta }); toast({ title: t`Envelope distributed`, description: t`Your envelope has been distributed successfully.`, duration: 5000, }); setIsOpen(false); } catch (err) { toast({ title: t`Something went wrong`, description: t`This envelope could not be distributed at this time. Please try again.`, variant: 'destructive', duration: 7500, }); } }; if (envelope.status !== DocumentStatus.DRAFT || envelope.type !== EnvelopeType.DOCUMENT) { return null; } return ( {trigger} Send Document Recipients will be able to sign the document once sent {everySignerHasSignature ? (
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions setValue('meta.distributionMethod', value as DocumentDistributionMethod) } value={distributionMethod} className="mb-2" > Email None
{distributionMethod === DocumentDistributionMethod.EMAIL && (
{organisation.organisationClaim.flags.emailDomains && ( ( Email Sender )} /> )} ( Reply To Email{' '} (Optional) )} /> ( Subject{' '} (Optional) )} /> ( Message{' '} (Optional)