mirror of
https://github.com/documenso/documenso.git
synced 2025-11-15 09:12:02 +10:00
feat: remove email requirement for recipients (#2040)
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
@ -61,7 +62,10 @@ import type { FieldFormType } from '../document-flow/add-fields';
|
||||
import { FieldAdvancedSettings } from '../document-flow/field-item-advanced-settings';
|
||||
import { Form } from '../form/form';
|
||||
import { useStep } from '../stepper';
|
||||
import type { TAddTemplateFieldsFormSchema } from './add-template-fields.types';
|
||||
import {
|
||||
type TAddTemplateFieldsFormSchema,
|
||||
ZAddTemplateFieldsFormSchema,
|
||||
} from './add-template-fields.types';
|
||||
|
||||
const MIN_HEIGHT_PX = 12;
|
||||
const MIN_WIDTH_PX = 36;
|
||||
@ -112,7 +116,7 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
pageY: Number(field.positionY),
|
||||
pageWidth: Number(field.width),
|
||||
pageHeight: Number(field.height),
|
||||
signerId: field.recipientId ?? -1,
|
||||
recipientId: field.recipientId ?? -1,
|
||||
signerEmail:
|
||||
recipients.find((recipient) => recipient.id === field.recipientId)?.email ?? '',
|
||||
signerToken:
|
||||
@ -120,6 +124,7 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
fieldMeta: field.fieldMeta ? ZFieldMetaSchema.parse(field.fieldMeta) : undefined,
|
||||
})),
|
||||
},
|
||||
resolver: zodResolver(ZAddTemplateFieldsFormSchema),
|
||||
});
|
||||
|
||||
const onFormSubmit = form.handleSubmit(onSubmit);
|
||||
@ -170,7 +175,7 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
nativeId: undefined,
|
||||
formId: nanoid(12),
|
||||
signerEmail: selectedSigner?.email ?? lastActiveField.signerEmail,
|
||||
signerId: selectedSigner?.id ?? lastActiveField.signerId,
|
||||
recipientId: selectedSigner?.id ?? lastActiveField.recipientId,
|
||||
signerToken: selectedSigner?.token ?? lastActiveField.signerToken,
|
||||
pageX: lastActiveField.pageX + 3,
|
||||
pageY: lastActiveField.pageY + 3,
|
||||
@ -197,7 +202,7 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
nativeId: undefined,
|
||||
formId: nanoid(12),
|
||||
signerEmail: selectedSigner?.email ?? lastActiveField.signerEmail,
|
||||
signerId: selectedSigner?.id ?? lastActiveField.signerId,
|
||||
recipientId: selectedSigner?.id ?? lastActiveField.recipientId,
|
||||
signerToken: selectedSigner?.token ?? lastActiveField.signerToken,
|
||||
pageNumber,
|
||||
};
|
||||
@ -240,7 +245,7 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
formId: nanoid(12),
|
||||
nativeId: undefined,
|
||||
signerEmail: selectedSigner?.email ?? copiedField.signerEmail,
|
||||
signerId: selectedSigner?.id ?? copiedField.signerId,
|
||||
recipientId: selectedSigner?.id ?? copiedField.recipientId,
|
||||
signerToken: selectedSigner?.token ?? copiedField.signerToken,
|
||||
pageX: copiedField.pageX + 3,
|
||||
pageY: copiedField.pageY + 3,
|
||||
@ -371,7 +376,7 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
pageWidth: fieldPageWidth,
|
||||
pageHeight: fieldPageHeight,
|
||||
signerEmail: selectedSigner.email,
|
||||
signerId: selectedSigner.id,
|
||||
recipientId: selectedSigner.id,
|
||||
signerToken: selectedSigner.token ?? '',
|
||||
fieldMeta: undefined,
|
||||
};
|
||||
@ -597,14 +602,14 @@ export const AddTemplateFieldsFormPartial = ({
|
||||
)}
|
||||
|
||||
{localFields.map((field, index) => {
|
||||
const recipientIndex = recipients.findIndex((r) => r.email === field.signerEmail);
|
||||
const recipientIndex = recipients.findIndex((r) => r.id === field.recipientId);
|
||||
|
||||
return (
|
||||
<FieldItem
|
||||
key={index}
|
||||
recipientIndex={recipientIndex === -1 ? 0 : recipientIndex}
|
||||
field={field}
|
||||
disabled={selectedSigner?.email !== field.signerEmail}
|
||||
disabled={selectedSigner?.id !== field.recipientId}
|
||||
minHeight={MIN_HEIGHT_PX}
|
||||
minWidth={MIN_WIDTH_PX}
|
||||
defaultHeight={DEFAULT_HEIGHT_PX}
|
||||
|
||||
@ -10,8 +10,8 @@ export const ZAddTemplateFieldsFormSchema = z.object({
|
||||
nativeId: z.number().optional(),
|
||||
type: z.nativeEnum(FieldType),
|
||||
signerEmail: z.string().min(1),
|
||||
recipientId: z.number().min(1),
|
||||
signerToken: z.string(),
|
||||
signerId: z.number().optional(),
|
||||
pageNumber: z.number().min(1),
|
||||
pageX: z.number().min(0),
|
||||
pageY: z.number().min(0),
|
||||
|
||||
@ -48,6 +48,10 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip';
|
||||
import type { TAddTemplatePlacholderRecipientsFormSchema } from './add-template-placeholder-recipients.types';
|
||||
import { ZAddTemplatePlacholderRecipientsFormSchema } from './add-template-placeholder-recipients.types';
|
||||
|
||||
type AutoSaveResponse = {
|
||||
recipients: Recipient[];
|
||||
};
|
||||
|
||||
export type AddTemplatePlaceholderRecipientsFormProps = {
|
||||
documentFlow: DocumentFlowStep;
|
||||
recipients: Recipient[];
|
||||
@ -56,7 +60,7 @@ export type AddTemplatePlaceholderRecipientsFormProps = {
|
||||
allowDictateNextSigner?: boolean;
|
||||
templateDirectLink?: TemplateDirectLink | null;
|
||||
onSubmit: (_data: TAddTemplatePlacholderRecipientsFormSchema) => void;
|
||||
onAutoSave: (_data: TAddTemplatePlacholderRecipientsFormSchema) => Promise<void>;
|
||||
onAutoSave: (_data: TAddTemplatePlacholderRecipientsFormSchema) => Promise<AutoSaveResponse>;
|
||||
isDocumentPdfLoaded: boolean;
|
||||
};
|
||||
|
||||
@ -146,7 +150,44 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
|
||||
const formData = form.getValues();
|
||||
|
||||
scheduleSave(formData);
|
||||
scheduleSave(formData, (response) => {
|
||||
// Sync the response recipients back to form state to prevent duplicates
|
||||
if (response?.recipients) {
|
||||
const currentSigners = form.getValues('signers');
|
||||
const updatedSigners = currentSigners.map((signer) => {
|
||||
// Find the matching recipient from the response using nativeId
|
||||
const matchingRecipient = response.recipients.find(
|
||||
(recipient) => recipient.id === signer.nativeId,
|
||||
);
|
||||
|
||||
if (matchingRecipient) {
|
||||
// Update the signer with the server-returned data, especially the ID
|
||||
return {
|
||||
...signer,
|
||||
nativeId: matchingRecipient.id,
|
||||
};
|
||||
}
|
||||
|
||||
// For new signers without nativeId, match by email and update with server ID
|
||||
if (!signer.nativeId) {
|
||||
const newRecipient = response.recipients.find(
|
||||
(recipient) => recipient.email === signer.email,
|
||||
);
|
||||
if (newRecipient) {
|
||||
return {
|
||||
...signer,
|
||||
nativeId: newRecipient.id,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return signer;
|
||||
});
|
||||
|
||||
// Update the form state with the synced data
|
||||
form.setValue('signers', updatedSigners, { shouldValidate: false });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// useEffect(() => {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { DocumentSigningOrder, RecipientRole } from '@prisma/client';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { TEMPLATE_RECIPIENT_EMAIL_PLACEHOLDER_REGEX } from '@documenso/lib/constants/template';
|
||||
import { ZRecipientActionAuthTypesSchema } from '@documenso/lib/types/document-auth';
|
||||
|
||||
export const ZAddTemplatePlacholderRecipientsFormSchema = z
|
||||
@ -20,17 +19,7 @@ export const ZAddTemplatePlacholderRecipientsFormSchema = z
|
||||
signingOrder: z.nativeEnum(DocumentSigningOrder),
|
||||
allowDictateNextSigner: z.boolean().default(false),
|
||||
})
|
||||
.refine(
|
||||
(schema) => {
|
||||
const nonPlaceholderEmails = schema.signers
|
||||
.map((signer) => signer.email.toLowerCase())
|
||||
.filter((email) => !TEMPLATE_RECIPIENT_EMAIL_PLACEHOLDER_REGEX.test(email));
|
||||
|
||||
return new Set(nonPlaceholderEmails).size === nonPlaceholderEmails.length;
|
||||
},
|
||||
// Dirty hack to handle errors when .root is populated for an array type
|
||||
{ message: 'Signers must have unique emails', path: ['signers__root'] },
|
||||
)
|
||||
.refine(
|
||||
/*
|
||||
Since placeholder emails are empty, we need to check that the names are unique.
|
||||
|
||||
Reference in New Issue
Block a user