mirror of
https://github.com/documenso/documenso.git
synced 2025-11-14 16:51:38 +10:00
chore: disable form on last signer
This commit is contained in:
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
|
||||
46
packages/lib/server-only/recipient/get-is-last-recipient.ts
Normal file
46
packages/lib/server-only/recipient/get-is-last-recipient.ts
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user