chore: merge main, resolve biome formatting conflicts

Merge origin/main into feat/external-2fa-codes. Resolve formatting
conflicts caused by biome rollout; preserve both feature streams:
PR's external 2FA token + signing-session 2FA proof additions plus
main's RateLimit/RecipientExpired/signingReminders/date-auto-insert.

In complete-document-with-token.ts, drop the duplicate early
field-fetching block introduced when main moved that logic later
with date auto-insert support; keep the EXTERNAL_TWO_FACTOR_AUTH
check using derivedRecipientActionAuth.
This commit is contained in:
ephraimduncan
2026-05-12 11:46:11 +00:00
parent 9194884fbe
commit 138d663c25
1959 changed files with 93477 additions and 47027 deletions
@@ -1,19 +1,7 @@
import { useMemo, useState } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { Trans, useLingui } from '@lingui/react/macro';
import type { Field, Recipient } from '@prisma/client';
import { RecipientRole } from '@prisma/client';
import { useForm } from 'react-hook-form';
import { match } from 'ts-pattern';
import { z } from 'zod';
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import {
type TRecipientAccessAuth,
ZDocumentAccessAuthSchema,
} from '@documenso/lib/types/document-auth';
import { type TRecipientAccessAuth, ZDocumentAccessAuthSchema } from '@documenso/lib/types/document-auth';
import { fieldsContainUnsignedRequiredField } from '@documenso/lib/utils/advanced-fields-helpers';
import { zEmail } from '@documenso/lib/utils/zod';
import { Button } from '@documenso/ui/primitives/button';
import {
Dialog,
@@ -24,15 +12,16 @@ import {
DialogTitle,
DialogTrigger,
} from '@documenso/ui/primitives/dialog';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@documenso/ui/primitives/form/form';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
import { Input } from '@documenso/ui/primitives/input';
import { zodResolver } from '@hookform/resolvers/zod';
import { Trans, useLingui } from '@lingui/react/macro';
import type { Field, Recipient } from '@prisma/client';
import { RecipientRole } from '@prisma/client';
import { useMemo, useState } from 'react';
import { useForm } from 'react-hook-form';
import { match } from 'ts-pattern';
import { z } from 'zod';
import { useEmbedSigningContext } from '~/components/embed/embed-signing-context';
import { AccessAuth2FAForm } from '~/components/general/document-signing/access-auth-2fa-form';
@@ -68,7 +57,7 @@ export type DocumentSigningCompleteDialogProps = {
const ZNextSignerFormSchema = z.object({
name: z.string().min(1, 'Name is required'),
email: z.string().email('Invalid email address'),
email: zEmail('Invalid email address'),
accessAuthOptions: ZDocumentAccessAuthSchema.optional(),
});
@@ -76,7 +65,7 @@ type TNextSignerFormSchema = z.infer<typeof ZNextSignerFormSchema>;
const ZDirectRecipientFormSchema = z.object({
name: z.string(),
email: z.string().email('Invalid email address'),
email: zEmail('Invalid email address'),
});
type TDirectRecipientFormSchema = z.infer<typeof ZDirectRecipientFormSchema>;
@@ -117,7 +106,7 @@ export const DocumentSigningCompleteDialog = ({
const recipientForm = useForm<TDirectRecipientFormSchema>({
resolver: zodResolver(ZDirectRecipientFormSchema),
defaultValues: {
values: {
name: recipientPayload?.name ?? '',
email: recipientPayload?.email ?? '',
},
@@ -157,6 +146,10 @@ export const DocumentSigningCompleteDialog = ({
}
recipientOverridePayload = recipientForm.getValues();
} else if (recipientPayload && recipientPayload.email && !recipient.email) {
// Form is hidden because we have an email (e.g. from embed context),
// but the DB recipient doesn't have one yet — send the override.
recipientOverridePayload = recipientPayload;
}
// Check if 2FA is required
@@ -166,9 +159,7 @@ export const DocumentSigningCompleteDialog = ({
}
const nextSigner =
allowDictateNextSigner && data.name && data.email
? { name: data.name, email: data.email }
: undefined;
allowDictateNextSigner && data.name && data.email ? { name: data.name, email: data.email } : undefined;
await onSignatureComplete(nextSigner, data.accessAuthOptions, recipientOverridePayload);
} catch (error) {
@@ -210,9 +201,7 @@ export const DocumentSigningCompleteDialog = ({
{match({ isComplete, role: recipient.role })
.with({ isComplete: false }, () => <Trans>Next Field</Trans>)
.with({ isComplete: true, role: RecipientRole.APPROVER }, () => <Trans>Approve</Trans>)
.with({ isComplete: true, role: RecipientRole.VIEWER }, () => (
<Trans>Mark as viewed</Trans>
))
.with({ isComplete: true, role: RecipientRole.VIEWER }, () => <Trans>Mark as viewed</Trans>)
.with({ isComplete: true }, () => <Trans>Complete</Trans>)
.exhaustive()}
</Button>
@@ -253,31 +242,78 @@ export const DocumentSigningCompleteDialog = ({
</DialogHeader>
<div className="rounded-lg border border-border bg-muted/50 p-4 text-center">
<p className="text-sm font-medium text-muted-foreground">{documentTitle}</p>
<p className="font-medium text-muted-foreground text-sm">{documentTitle}</p>
</div>
{!showTwoFactorForm && (
<>
<fieldset disabled={form.formState.isSubmitting} className="border-none p-0">
{recipientPayload && !recipientPayload.email && (
<Form {...recipientForm}>
<fieldset disabled={form.formState.isSubmitting} className="border-none p-0">
{recipientPayload && !recipientPayload.email && (
<Form {...recipientForm}>
<div className="mb-4 flex flex-col gap-4">
<div className="flex flex-col gap-4 md:flex-row">
<FormField
control={recipientForm.control}
name="name"
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>
<Trans>Your Name</Trans>
</FormLabel>
<FormControl>
<Input
{...field}
className="mt-2"
placeholder={t`Enter your name`}
disabled={isNameLocked || disableNameInput}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={recipientForm.control}
name="email"
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>
<Trans>Your Email</Trans>
</FormLabel>
<FormControl>
<Input
{...field}
type="email"
className="mt-2"
placeholder={t`Enter your email`}
disabled={!!field.value && isEmailLocked}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
</Form>
)}
<Form {...form}>
<form onSubmit={form.handleSubmit(onFormSubmit)}>
{allowDictateNextSigner && defaultNextSigner && (
<div className="mb-4 flex flex-col gap-4">
<div className="flex flex-col gap-4 md:flex-row">
<FormField
control={recipientForm.control}
control={form.control}
name="name"
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>
<Trans>Your Name</Trans>
<Trans>Next Recipient Name</Trans>
</FormLabel>
<FormControl>
<Input
{...field}
className="mt-2"
placeholder={t`Enter your name`}
disabled={isNameLocked || disableNameInput}
/>
<Input {...field} className="mt-2" placeholder={t`Enter the next signer's name`} />
</FormControl>
<FormMessage />
@@ -286,20 +322,19 @@ export const DocumentSigningCompleteDialog = ({
/>
<FormField
control={recipientForm.control}
control={form.control}
name="email"
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>
<Trans>Your Email</Trans>
<Trans>Next Recipient Email</Trans>
</FormLabel>
<FormControl>
<Input
{...field}
type="email"
className="mt-2"
placeholder={t`Enter your email`}
disabled={!!field.value && isEmailLocked}
placeholder={t`Enter the next signer's email`}
/>
</FormControl>
<FormMessage />
@@ -308,89 +343,33 @@ export const DocumentSigningCompleteDialog = ({
/>
</div>
</div>
</Form>
)}
)}
<Form {...form}>
<form onSubmit={form.handleSubmit(onFormSubmit)}>
{allowDictateNextSigner && defaultNextSigner && (
<div className="mb-4 flex flex-col gap-4">
<div className="flex flex-col gap-4 md:flex-row">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>
<Trans>Next Recipient Name</Trans>
</FormLabel>
<FormControl>
<Input
{...field}
className="mt-2"
placeholder={t`Enter the next signer's name`}
/>
</FormControl>
<DocumentSigningDisclosure />
<FormMessage />
</FormItem>
)}
/>
<DialogFooter className="mt-4">
<Button
type="button"
variant="secondary"
onClick={() => setShowDialog(false)}
disabled={form.formState.isSubmitting}
>
<Trans>Cancel</Trans>
</Button>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>
<Trans>Next Recipient Email</Trans>
</FormLabel>
<FormControl>
<Input
{...field}
type="email"
className="mt-2"
placeholder={t`Enter the next signer's email`}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
)}
<DocumentSigningDisclosure />
<DialogFooter className="mt-4">
<Button
type="button"
variant="secondary"
onClick={() => setShowDialog(false)}
disabled={form.formState.isSubmitting}
>
<Trans>Cancel</Trans>
</Button>
<Button
type="submit"
disabled={!isComplete}
loading={form.formState.isSubmitting}
>
{match(recipient.role)
.with(RecipientRole.VIEWER, () => <Trans>Mark as Viewed</Trans>)
.with(RecipientRole.SIGNER, () => <Trans>Sign</Trans>)
.with(RecipientRole.APPROVER, () => <Trans>Approve</Trans>)
.with(RecipientRole.CC, () => <Trans>Mark as Viewed</Trans>)
.with(RecipientRole.ASSISTANT, () => <Trans>Complete</Trans>)
.exhaustive()}
</Button>
</DialogFooter>
</form>
</Form>
</fieldset>
</>
<Button type="submit" disabled={!isComplete} loading={form.formState.isSubmitting}>
{match(recipient.role)
.with(RecipientRole.VIEWER, () => <Trans>Mark as Viewed</Trans>)
.with(RecipientRole.SIGNER, () => <Trans>Sign</Trans>)
.with(RecipientRole.APPROVER, () => <Trans>Approve</Trans>)
.with(RecipientRole.CC, () => <Trans>Mark as Viewed</Trans>)
.with(RecipientRole.ASSISTANT, () => <Trans>Complete</Trans>)
.exhaustive()}
</Button>
</DialogFooter>
</form>
</Form>
</fieldset>
)}
{showTwoFactorForm && (