chore: disable form on last signer

This commit is contained in:
Ephraim Atta-Duncan
2025-02-14 12:18:19 +00:00
parent 4189a34de0
commit 1e90ca45a6
5 changed files with 66 additions and 30 deletions

View File

@ -45,6 +45,7 @@ export type SigningFormProps = {
isRecipientsTurn: boolean;
allRecipients?: RecipientWithFields[];
setSelectedSignerId?: (id: number | null) => void;
isLastRecipient: boolean;
};
type SigningFormData = {
@ -60,6 +61,7 @@ export const SigningForm = ({
isRecipientsTurn,
allRecipients = [],
setSelectedSignerId,
isLastRecipient,
}: SigningFormProps) => {
const { _ } = useLingui();
const { toast } = useToast();
@ -252,7 +254,8 @@ export const SigningForm = ({
disabled={!isRecipientsTurn}
canModifyNextSigner={
document.documentMeta?.modifyNextSigner &&
document.documentMeta?.signingOrder === DocumentSigningOrder.SEQUENTIAL
document.documentMeta?.signingOrder === DocumentSigningOrder.SEQUENTIAL &&
!isLastRecipient
}
/>
</div>
@ -435,7 +438,8 @@ export const SigningForm = ({
disabled={!isRecipientsTurn}
canModifyNextSigner={
document.documentMeta?.modifyNextSigner &&
document.documentMeta?.signingOrder === DocumentSigningOrder.SEQUENTIAL
document.documentMeta?.signingOrder === DocumentSigningOrder.SEQUENTIAL &&
!isLastRecipient
}
/>
</div>

View File

@ -9,6 +9,7 @@ import { isRecipientAuthorized } from '@documenso/lib/server-only/document/is-re
import { viewedDocument } from '@documenso/lib/server-only/document/viewed-document';
import { getCompletedFieldsForToken } from '@documenso/lib/server-only/field/get-completed-fields-for-token';
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
import { getIsLastRecipient } from '@documenso/lib/server-only/recipient/get-is-last-recipient';
import { getIsRecipientsTurnToSign } from '@documenso/lib/server-only/recipient/get-is-recipient-turn';
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
import { getRecipientSignatures } from '@documenso/lib/server-only/recipient/get-recipient-signatures';
@ -44,7 +45,7 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
const requestMetadata = extractNextHeaderRequestMetadata(requestHeaders);
const [document, recipient, fields, completedFields] = await Promise.all([
const [document, recipient, fields, completedFields, isLastRecipient] = await Promise.all([
getDocumentAndSenderByToken({
token,
userId: user?.id,
@ -53,6 +54,7 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
getRecipientByToken({ token }).catch(() => null),
getFieldsForToken({ token }),
getCompletedFieldsForToken({ token }),
getIsLastRecipient({ token }),
]);
if (
@ -169,6 +171,7 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
completedFields={completedFields}
isRecipientsTurn={isRecipientsTurn}
allRecipients={allRecipients}
isLastRecipient={isLastRecipient}
/>
</DocumentAuthProvider>
</SigningProvider>

View File

@ -38,7 +38,7 @@ export type SignDialogProps = {
documentTitle: string;
fields: Field[];
fieldsValidated: () => void | Promise<void>;
onSignatureComplete: (nextSigner?: { email: string; name: string }) => void | Promise<void>;
onSignatureComplete: (nextSigner?: { email?: string; name?: string }) => void | Promise<void>;
role: RecipientRole;
disabled?: boolean;
canModifyNextSigner?: boolean;
@ -48,20 +48,10 @@ const formSchema = z.object({
nextSigner: z
.object({
email: z.string().email({ message: 'Please enter a valid email address' }).optional(),
name: z.string().min(1, { message: 'Name is required' }).optional(),
name: z.string().optional(),
})
.refine(
(data) => {
if (data.name) {
return !!data.email;
}
return true;
},
{
message: 'Email is required when name is provided',
path: ['email'],
},
),
.optional()
.default({}),
});
type TFormSchema = z.infer<typeof formSchema>;
@ -99,26 +89,15 @@ export function SignDialog({
const form = useForm<TFormSchema>({
resolver: zodResolver(formSchema),
defaultValues: {
nextSigner: {
email: '',
name: '',
},
},
});
const onFormSubmit = async (data: TFormSchema) => {
try {
await fieldsValidated();
if (!canModifyNextSigner || !data.nextSigner.email) {
await onSignatureComplete();
return;
}
await onSignatureComplete({
email: data.nextSigner.email.trim().toLowerCase(),
name: data.nextSigner.name?.trim() ?? '',
email: data.nextSigner.email?.trim().toLowerCase(),
name: data.nextSigner.name?.trim(),
});
setShowDialog(false);
@ -378,6 +357,7 @@ export function SignDialog({
Cancel
</Button>
</DialogClose>
{step === 1 && (
<Button className="group" type="button" onClick={handleContinue}>
Next

View File

@ -49,6 +49,7 @@ export type SigningPageViewProps = {
completedFields: CompletedField[];
isRecipientsTurn: boolean;
allRecipients?: RecipientWithFields[];
isLastRecipient: boolean;
};
export const SigningPageView = ({
@ -58,6 +59,7 @@ export const SigningPageView = ({
completedFields,
isRecipientsTurn,
allRecipients = [],
isLastRecipient,
}: SigningPageViewProps) => {
const { documentData, documentMeta } = document;
@ -159,6 +161,7 @@ export const SigningPageView = ({
redirectUrl={documentMeta?.redirectUrl}
isRecipientsTurn={isRecipientsTurn}
allRecipients={allRecipients}
isLastRecipient={isLastRecipient}
setSelectedSignerId={setSelectedSignerId}
/>
</div>

View File

@ -0,0 +1,46 @@
import { prisma } from '@documenso/prisma';
import { DocumentSigningOrder, RecipientRole, SigningStatus } from '@documenso/prisma/client';
export type GetIsLastRecipientOptions = {
token: string;
};
export async function getIsLastRecipient({ token }: GetIsLastRecipientOptions) {
const document = await prisma.document.findFirstOrThrow({
where: {
recipients: {
some: {
token,
},
},
},
include: {
documentMeta: true,
recipients: {
where: {
role: {
not: RecipientRole.CC,
},
},
orderBy: [{ signingOrder: { sort: 'asc', nulls: 'last' } }, { id: 'asc' }],
},
},
});
if (document.documentMeta?.signingOrder !== DocumentSigningOrder.SEQUENTIAL) {
const unsignedRecipients = document.recipients.filter(
(recipient) => recipient.signingStatus !== SigningStatus.SIGNED,
);
return unsignedRecipients.length <= 1;
}
const { recipients } = document;
const currentRecipientIndex = recipients.findIndex((r) => r.token === token);
if (currentRecipientIndex === -1) {
return false;
}
return currentRecipientIndex === recipients.length - 1;
}