diff --git a/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx b/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx index 98ffd07e3..4d57652f3 100644 --- a/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx +++ b/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx @@ -19,6 +19,7 @@ import * as z from 'zod'; import { useCurrentEnvelopeEditor } from '@documenso/lib/client-only/providers/envelope-editor-provider'; import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation'; +import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth'; import { trpc, trpc as trpcReact } from '@documenso/trpc/react'; import { DocumentSendEmailMessageHelper } from '@documenso/ui/components/document/document-send-email-message-helper'; import { cn } from '@documenso/ui/lib/utils'; @@ -129,18 +130,43 @@ export const EnvelopeDistributeDialog = ({ const distributionMethod = watch('meta.distributionMethod'); + const recipientsWithIndex = useMemo( + () => + envelope.recipients.map((recipient, index) => ({ + ...recipient, + index, + })), + [envelope.recipients], + ); + const recipientsMissingSignatureFields = useMemo( () => - envelope.recipients.filter( + recipientsWithIndex.filter( (recipient) => recipient.role === RecipientRole.SIGNER && !envelope.fields.some( (field) => field.type === FieldType.SIGNATURE && field.recipientId === recipient.id, ), ), - [envelope.recipients, envelope.fields], + [recipientsWithIndex, envelope.fields], ); + /** + * List of recipients who must have an email due to having auth enabled. + */ + const recipientsMissingRequiredEmail = useMemo(() => { + return recipientsWithIndex.filter((recipient) => { + const auth = extractDocumentAuthMethods({ + documentAuth: envelope.authOptions, + recipientAuth: recipient.authOptions, + }); + + return ( + (auth.recipientAccessAuthRequired || auth.recipientActionAuthRequired) && !recipient.email + ); + }); + }, [recipientsWithIndex, envelope.authOptions]); + const invalidEnvelopeCode = useMemo(() => { if (recipientsMissingSignatureFields.length > 0) { return 'MISSING_SIGNATURES'; @@ -150,8 +176,12 @@ export const EnvelopeDistributeDialog = ({ return 'MISSING_RECIPIENTS'; } + if (recipientsMissingRequiredEmail.length > 0) { + return 'MISSING_REQUIRED_EMAIL'; + } + return null; - }, [envelope.recipients, envelope.fields, recipientsMissingSignatureFields]); + }, [envelope.recipients, recipientsMissingRequiredEmail, recipientsMissingSignatureFields]); const onFormSubmit = async ({ meta }: TEnvelopeDistributeFormSchema) => { try { @@ -444,7 +474,22 @@ export const EnvelopeDistributeDialog = ({ + + )) + .with('MISSING_REQUIRED_EMAIL', () => ( + + The following recipients require an email address: + + diff --git a/apps/remix/app/components/dialogs/sign-field-email-dialog.tsx b/apps/remix/app/components/dialogs/sign-field-email-dialog.tsx index ff82cf10d..8ec170b16 100644 --- a/apps/remix/app/components/dialogs/sign-field-email-dialog.tsx +++ b/apps/remix/app/components/dialogs/sign-field-email-dialog.tsx @@ -24,7 +24,10 @@ import { import { Input } from '@documenso/ui/primitives/input'; const ZSignFieldEmailFormSchema = z.object({ - email: z.string().min(1, { message: msg`Email is required`.id }), + email: z + .string() + .email() + .min(1, { message: msg`Email is required`.id }), }); type TSignFieldEmailFormSchema = z.infer; diff --git a/apps/remix/app/components/dialogs/template-use-dialog.tsx b/apps/remix/app/components/dialogs/template-use-dialog.tsx index 129132dd4..9fd507c63 100644 --- a/apps/remix/app/components/dialogs/template-use-dialog.tsx +++ b/apps/remix/app/components/dialogs/template-use-dialog.tsx @@ -21,6 +21,7 @@ import { SKIP_QUERY_BATCH_META, } from '@documenso/lib/constants/trpc'; import { AppError } from '@documenso/lib/errors/app-error'; +import { ZRecipientEmailSchema } from '@documenso/lib/types/recipient'; import { putPdfFile } from '@documenso/lib/universal/upload/put-file'; import { trpc } from '@documenso/trpc/react'; import { cn } from '@documenso/ui/lib/utils'; @@ -65,7 +66,7 @@ const ZAddRecipientsForNewDocumentSchema = z.object({ recipients: z.array( z.object({ id: z.number(), - email: z.string().email(), + email: ZRecipientEmailSchema, name: z.string(), signingOrder: z.number().optional(), }), @@ -100,12 +101,29 @@ export function TemplateUseDialog({ const [open, setOpen] = useState(false); - const form = useForm({ - resolver: zodResolver(ZAddRecipientsForNewDocumentSchema), - defaultValues: { + const { data: response, isLoading: isLoadingEnvelopeItems } = trpc.envelope.item.getMany.useQuery( + { + envelopeId, + }, + { + placeholderData: (previousData) => previousData, + ...SKIP_QUERY_BATCH_META, + ...DO_NOT_INVALIDATE_QUERY_ON_MUTATION, + enabled: open, + }, + ); + + const envelopeItems = response?.data ?? []; + + const generateDefaultFormValues = () => { + return { distributeDocument: false, useCustomDocument: false, - customDocumentData: [], + customDocumentData: envelopeItems.map((item) => ({ + title: item.title, + data: undefined, + envelopeItemId: item.id, + })), recipients: recipients .sort((a, b) => (a.signingOrder || 0) - (b.signingOrder || 0)) .map((recipient) => { @@ -124,7 +142,12 @@ export function TemplateUseDialog({ signingOrder: recipient.signingOrder ?? undefined, }; }), - }, + }; + }; + + const form = useForm({ + resolver: zodResolver(ZAddRecipientsForNewDocumentSchema), + defaultValues: generateDefaultFormValues(), }); const { replace, fields: localCustomDocumentData } = useFieldArray({ @@ -132,19 +155,6 @@ export function TemplateUseDialog({ name: 'customDocumentData', }); - const { data: response, isLoading: isLoadingEnvelopeItems } = trpc.envelope.item.getMany.useQuery( - { - envelopeId, - }, - { - placeholderData: (previousData) => previousData, - ...SKIP_QUERY_BATCH_META, - ...DO_NOT_INVALIDATE_QUERY_ON_MUTATION, - }, - ); - - const envelopeItems = response?.data ?? []; - const { mutateAsync: createDocumentFromTemplate } = trpc.template.createDocumentFromTemplate.useMutation(); @@ -214,8 +224,8 @@ export function TemplateUseDialog({ }); useEffect(() => { - if (!open) { - form.reset(); + if (open) { + form.reset(generateDefaultFormValues()); } }, [open, form]); @@ -322,7 +332,7 @@ export function TemplateUseDialog({ @@ -349,7 +359,7 @@ export function TemplateUseDialog({ {documentDistributionMethod === DocumentDistributionMethod.EMAIL && (