mirror of
https://github.com/documenso/documenso.git
synced 2026-09-29 16:24:30 +10:00
fix: reviewed
This commit is contained in:
+8
-5
@@ -323,14 +323,17 @@ export const EnvelopeEditorRecipientForm = () => {
|
||||
|
||||
const { data } = validatedFormValues;
|
||||
|
||||
// Weird edge case where the whole envelope is created via API
|
||||
// with no signing order. If they come to this page it will show an error
|
||||
// since they aren't equal and the recipient is no longer editable.
|
||||
// Locked recipients hold persisted values the server refuses to rewrite,
|
||||
// e.g. an envelope created via API with no signing order where a recipient
|
||||
// has already signed. Restore their PERSISTED order so form normalization
|
||||
// drift never submits a "changed" locked recipient the server rejects.
|
||||
const envelopeRecipients = data.signers.map((recipient) => {
|
||||
if (!canRecipientBeModified(recipient.id)) {
|
||||
const persistedRecipient = recipients.find((envelopeRecipient) => envelopeRecipient.id === recipient.id);
|
||||
|
||||
return {
|
||||
...recipient,
|
||||
signingOrder: recipient.signingOrder,
|
||||
signingOrder: persistedRecipient?.signingOrder ?? undefined,
|
||||
};
|
||||
}
|
||||
return recipient;
|
||||
@@ -356,7 +359,7 @@ export const EnvelopeEditorRecipientForm = () => {
|
||||
signer.email !== recipient.email ||
|
||||
signer.name !== recipient.name ||
|
||||
signer.role !== recipient.role ||
|
||||
signer.signingOrder !== recipient.signingOrder ||
|
||||
(signer.signingOrder ?? null) !== (recipient.signingOrder ?? null) ||
|
||||
!isDeepEqual(signerActionAuth, recipientActionAuth)
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3,14 +3,14 @@ import { ZRecipientActionAuthTypesSchema, ZRecipientAuthOptionsSchema } from '@d
|
||||
import type { TEditorEnvelope } from '@documenso/lib/types/envelope-editor';
|
||||
import { ZRecipientEmailSchema } from '@documenso/lib/types/recipient';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { DocumentSigningOrder, RecipientRole } from '@prisma/client';
|
||||
import { DocumentSigningOrder, EnvelopeType, RecipientRole } from '@prisma/client';
|
||||
import { useId } from 'react';
|
||||
import type { UseFormReturn } from 'react-hook-form';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { normalizeGroupedSigningOrders } from '../../utils/recipient-groups';
|
||||
import { isCcRecipient, sortRecipientsForSigningOrder } from '../../utils/recipients';
|
||||
import { canRecipientBeModified, isCcRecipient, sortRecipientsForSigningOrder } from '../../utils/recipients';
|
||||
|
||||
const LocalRecipientSchema = z.object({
|
||||
formId: z.string().min(1),
|
||||
@@ -154,6 +154,24 @@ export const useEditorRecipients = ({ envelope }: EditorRecipientsProps): UseEdi
|
||||
|
||||
const sourceRecipients = sortRecipientsForSigningOrder(recipients || envelope.recipients);
|
||||
|
||||
// Locked recipients hold persisted values the server refuses to rewrite.
|
||||
// Initialization must never assign or renumber their signing orders —
|
||||
// doing so makes the very first autosave submit a "changed" locked
|
||||
// recipient, which the server rejects on every subsequent save.
|
||||
const isRecipientLocked = (recipientId: number) => {
|
||||
if (envelope.type === EnvelopeType.TEMPLATE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const persistedRecipient = sourceRecipients.find((recipient) => recipient.id === recipientId);
|
||||
|
||||
if (!persistedRecipient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !canRecipientBeModified(persistedRecipient, envelope.fields);
|
||||
};
|
||||
|
||||
// A recipient without a persisted order means "last" everywhere else — the
|
||||
// server sorts NULLS LAST. Continue numbering after the highest existing
|
||||
// order rather than guessing from array position: a guess can land on a
|
||||
@@ -170,6 +188,10 @@ export const useEditorRecipients = ({ envelope }: EditorRecipientsProps): UseEdi
|
||||
signingOrderByRecipientId.set(recipient.id, undefined);
|
||||
} else if (typeof recipient.signingOrder === 'number') {
|
||||
signingOrderByRecipientId.set(recipient.id, recipient.signingOrder);
|
||||
} else if (isRecipientLocked(recipient.id)) {
|
||||
// A locked null order must round-trip as-is: a synthetic number would
|
||||
// read as a change to a recipient the server refuses to modify.
|
||||
signingOrderByRecipientId.set(recipient.id, undefined);
|
||||
} else {
|
||||
fallbackOrder += 1;
|
||||
signingOrderByRecipientId.set(recipient.id, fallbackOrder);
|
||||
@@ -188,7 +210,7 @@ export const useEditorRecipients = ({ envelope }: EditorRecipientsProps): UseEdi
|
||||
|
||||
const signers: TLocalRecipient[] =
|
||||
formRecipients.length > 0
|
||||
? normalizeGroupedSigningOrders(formRecipients)
|
||||
? normalizeGroupedSigningOrders(formRecipients, (formRecipient) => !isRecipientLocked(formRecipient.id))
|
||||
: [
|
||||
{
|
||||
formId: initialId,
|
||||
|
||||
@@ -348,7 +348,9 @@ const hasRecipientBeenChanged = (recipient: Recipient, newRecipientData: Recipie
|
||||
recipient.email !== newRecipientData.email ||
|
||||
recipient.name !== newRecipientData.name ||
|
||||
recipient.role !== newRecipientData.role ||
|
||||
recipient.signingOrder !== newRecipientData.signingOrder ||
|
||||
// Null and undefined both mean "no order": the request schema cannot
|
||||
// carry null, so a persisted null arrives as undefined
|
||||
(recipient.signingOrder ?? null) !== (newRecipientData.signingOrder ?? null) ||
|
||||
!isDeepEqual(authOptions.accessAuth, newRecipientAccessAuth) ||
|
||||
!isDeepEqual(authOptions.actionAuth, newRecipientActionAuth)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user