Merge branch 'main' into feat/document-2fa-redo

This commit is contained in:
Ephraim Atta-Duncan
2025-08-01 09:00:30 +00:00
167 changed files with 6918 additions and 1245 deletions

View File

@ -5,13 +5,31 @@ import { Trans } from '@lingui/react/macro';
import type { Field, Recipient } from '@prisma/client';
import { DocumentDistributionMethod, DocumentStatus, RecipientRole } from '@prisma/client';
import { AnimatePresence, motion } from 'framer-motion';
import { InfoIcon } from 'lucide-react';
import { useForm } from 'react-hook-form';
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
import type { TDocument } from '@documenso/lib/types/document';
import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';
import { formatSigningLink } from '@documenso/lib/utils/recipients';
import { trpc } from '@documenso/trpc/react';
import { DocumentSendEmailMessageHelper } from '@documenso/ui/components/document/document-send-email-message-helper';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@documenso/ui/primitives/form/form';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@documenso/ui/primitives/select';
import { Tabs, TabsList, TabsTrigger } from '@documenso/ui/primitives/tabs';
import { CopyTextButton } from '../../components/common/copy-text-button';
@ -21,11 +39,10 @@ import {
mapFieldsWithRecipients,
} from '../../components/document/document-read-only-fields';
import { AvatarWithText } from '../avatar';
import { FormErrorMessage } from '../form/form-error-message';
import { Input } from '../input';
import { Label } from '../label';
import { useStep } from '../stepper';
import { Textarea } from '../textarea';
import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip';
import { toast } from '../use-toast';
import { type TAddSubjectFormSchema, ZAddSubjectFormSchema } from './add-subject.types';
import {
@ -56,15 +73,14 @@ export const AddSubjectFormPartial = ({
}: AddSubjectFormProps) => {
const { _ } = useLingui();
const {
register,
handleSubmit,
setValue,
watch,
formState: { errors, isSubmitting },
} = useForm<TAddSubjectFormSchema>({
const organisation = useCurrentOrganisation();
const form = useForm<TAddSubjectFormSchema>({
defaultValues: {
meta: {
emailId: document.documentMeta?.emailId ?? null,
emailReplyTo: document.documentMeta?.emailReplyTo || undefined,
// emailReplyName: document.documentMeta?.emailReplyName || undefined,
subject: document.documentMeta?.subject ?? '',
message: document.documentMeta?.message ?? '',
distributionMethod:
@ -75,6 +91,21 @@ export const AddSubjectFormPartial = ({
resolver: zodResolver(ZAddSubjectFormSchema),
});
const {
handleSubmit,
setValue,
watch,
formState: { isSubmitting },
} = form;
const { data: emailData, isLoading: isLoadingEmails } =
trpc.enterprise.organisation.email.find.useQuery({
organisationId: organisation.id,
perPage: 100,
});
const emails = emailData?.data || [];
const GoNextLabel = {
[DocumentDistributionMethod.EMAIL]: {
[DocumentStatus.DRAFT]: msg`Send`,
@ -139,54 +170,141 @@ export const AddSubjectFormPartial = ({
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0, transition: { duration: 0.3 } }}
exit={{ opacity: 0, transition: { duration: 0.15 } }}
className="flex flex-col gap-y-4 rounded-lg border p-4"
>
<div>
<Label htmlFor="subject">
<Trans>
Subject <span className="text-muted-foreground">(Optional)</span>
</Trans>
</Label>
<Form {...form}>
<fieldset
className="flex flex-col gap-y-4 rounded-lg border p-4"
disabled={form.formState.isSubmitting}
>
{organisation.organisationClaim.flags.emailDomains && (
<FormField
control={form.control}
name="meta.emailId"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans>Email Sender</Trans>
</FormLabel>
<Input
id="subject"
className="bg-background mt-2"
disabled={isSubmitting}
{...register('meta.subject')}
/>
<FormControl>
<Select
{...field}
value={field.value === null ? '-1' : field.value}
onValueChange={(value) =>
field.onChange(value === '-1' ? null : value)
}
>
<SelectTrigger loading={isLoadingEmails} className="bg-background">
<SelectValue />
</SelectTrigger>
<FormErrorMessage className="mt-2" error={errors.meta?.subject} />
</div>
<SelectContent>
{emails.map((email) => (
<SelectItem key={email.id} value={email.id}>
{email.email}
</SelectItem>
))}
<div>
<Label htmlFor="message">
<Trans>
Message <span className="text-muted-foreground">(Optional)</span>
</Trans>
</Label>
<SelectItem value={'-1'}>Documenso</SelectItem>
</SelectContent>
</Select>
</FormControl>
<Textarea
id="message"
className="bg-background mt-2 h-32 resize-none"
disabled={isSubmitting}
{...register('meta.message')}
/>
<FormMessage />
</FormItem>
)}
/>
)}
<FormErrorMessage
className="mt-2"
error={
typeof errors.meta?.message !== 'string' ? errors.meta?.message : undefined
}
/>
</div>
<FormField
control={form.control}
name="meta.emailReplyTo"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans>Reply To Email</Trans>{' '}
<span className="text-muted-foreground">(Optional)</span>
</FormLabel>
<DocumentSendEmailMessageHelper />
<FormControl>
<Input {...field} />
</FormControl>
<DocumentEmailCheckboxes
className="mt-2"
value={emailSettings}
onChange={(value) => setValue('meta.emailSettings', value)}
/>
<FormMessage />
</FormItem>
)}
/>
{/* <FormField
control={form.control}
name="meta.emailReplyName"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans>Reply To Name</Trans>{' '}
<span className="text-muted-foreground">(Optional)</span>
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/> */}
<FormField
control={form.control}
name="meta.subject"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans>Subject</Trans>{' '}
<span className="text-muted-foreground">(Optional)</span>
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="meta.message"
render={({ field }) => (
<FormItem>
<FormLabel className="flex flex-row items-center">
<Trans>Message</Trans>{' '}
<span className="text-muted-foreground">(Optional)</span>
<Tooltip>
<TooltipTrigger>
<InfoIcon className="mx-2 h-4 w-4" />
</TooltipTrigger>
<TooltipContent className="text-muted-foreground p-4">
<DocumentSendEmailMessageHelper />
</TooltipContent>
</Tooltip>
</FormLabel>
<FormControl>
<Textarea className="bg-background mt-2 h-16 resize-none" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<DocumentEmailCheckboxes
className="mt-2"
value={emailSettings}
onChange={(value) => setValue('meta.emailSettings', value)}
/>
</fieldset>
</Form>
</motion.div>
)}
@ -206,8 +324,8 @@ export const AddSubjectFormPartial = ({
<p className="mt-2">
<Trans>
We will generate signing links for you, which you can send to the
recipients through your method of choice.
We will generate signing links for you, which you can send to the recipients
through your method of choice.
</Trans>
</p>
</div>

View File

@ -5,6 +5,9 @@ import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-emai
export const ZAddSubjectFormSchema = z.object({
meta: z.object({
emailId: z.string().nullable(),
emailReplyTo: z.string().email().optional(),
// emailReplyName: z.string().optional(),
subject: z.string(),
message: z.string(),
distributionMethod: z

View File

@ -27,7 +27,7 @@ type FieldIconProps = {
fieldMeta?: TFieldMetaSchema | null;
signature?: Signature | null;
};
documentMeta?: DocumentMeta | TemplateMeta;
documentMeta?: Pick<DocumentMeta | TemplateMeta, 'dateFormat'>;
};
/**