mirror of
https://github.com/documenso/documenso.git
synced 2025-11-14 00:32:43 +10:00
243 lines
7.9 KiB
TypeScript
243 lines
7.9 KiB
TypeScript
import { useRouter } from 'next/navigation';
|
|
|
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
import { Plus } from 'lucide-react';
|
|
import { Controller, useFieldArray, useForm } from 'react-hook-form';
|
|
import * as z from 'zod';
|
|
|
|
import type { Recipient } from '@documenso/prisma/client';
|
|
import { RecipientRole } from '@documenso/prisma/client';
|
|
import { trpc } from '@documenso/trpc/react';
|
|
import { Button } from '@documenso/ui/primitives/button';
|
|
import {
|
|
Dialog,
|
|
DialogClose,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
} from '@documenso/ui/primitives/dialog';
|
|
import { FormErrorMessage } from '@documenso/ui/primitives/form/form-error-message';
|
|
import { Input } from '@documenso/ui/primitives/input';
|
|
import { Label } from '@documenso/ui/primitives/label';
|
|
import { ROLE_ICONS } from '@documenso/ui/primitives/recipient-role-icons';
|
|
import { Select, SelectContent, SelectItem, SelectTrigger } from '@documenso/ui/primitives/select';
|
|
import { useToast } from '@documenso/ui/primitives/use-toast';
|
|
|
|
const ZAddRecipientsForNewDocumentSchema = z.object({
|
|
recipients: z.array(
|
|
z.object({
|
|
email: z.string().email(),
|
|
name: z.string(),
|
|
role: z.nativeEnum(RecipientRole),
|
|
}),
|
|
),
|
|
});
|
|
|
|
type TAddRecipientsForNewDocumentSchema = z.infer<typeof ZAddRecipientsForNewDocumentSchema>;
|
|
|
|
export type UseTemplateDialogProps = {
|
|
templateId: number;
|
|
recipients: Recipient[];
|
|
documentRootPath: string;
|
|
};
|
|
|
|
export function UseTemplateDialog({
|
|
recipients,
|
|
documentRootPath,
|
|
templateId,
|
|
}: UseTemplateDialogProps) {
|
|
const router = useRouter();
|
|
const { toast } = useToast();
|
|
|
|
const {
|
|
control,
|
|
handleSubmit,
|
|
formState: { errors, isSubmitting },
|
|
} = useForm<TAddRecipientsForNewDocumentSchema>({
|
|
resolver: zodResolver(ZAddRecipientsForNewDocumentSchema),
|
|
defaultValues: {
|
|
recipients:
|
|
recipients.length > 0
|
|
? recipients.map((recipient) => ({
|
|
nativeId: recipient.id,
|
|
formId: String(recipient.id),
|
|
name: recipient.name,
|
|
email: recipient.email,
|
|
role: recipient.role,
|
|
}))
|
|
: [
|
|
{
|
|
name: '',
|
|
email: '',
|
|
role: RecipientRole.SIGNER,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
const { mutateAsync: createDocumentFromTemplate, isLoading: isCreatingDocumentFromTemplate } =
|
|
trpc.template.createDocumentFromTemplate.useMutation();
|
|
|
|
const onSubmit = async (data: TAddRecipientsForNewDocumentSchema) => {
|
|
try {
|
|
const { id } = await createDocumentFromTemplate({
|
|
templateId,
|
|
recipients: data.recipients,
|
|
});
|
|
|
|
toast({
|
|
title: 'Document created',
|
|
description: 'Your document has been created from the template successfully.',
|
|
duration: 5000,
|
|
});
|
|
|
|
router.push(`${documentRootPath}/${id}`);
|
|
} catch (err) {
|
|
toast({
|
|
title: 'Error',
|
|
description: 'An error occurred while creating document from template.',
|
|
variant: 'destructive',
|
|
});
|
|
}
|
|
};
|
|
|
|
const onCreateDocumentFromTemplate = handleSubmit(onSubmit);
|
|
|
|
const { fields: formRecipients } = useFieldArray({
|
|
control,
|
|
name: 'recipients',
|
|
});
|
|
|
|
return (
|
|
<Dialog>
|
|
<DialogTrigger asChild>
|
|
<Button className="cursor-pointer">
|
|
<Plus className="-ml-1 mr-2 h-4 w-4" />
|
|
Use Template
|
|
</Button>
|
|
</DialogTrigger>
|
|
<DialogContent className="sm:max-w-lg">
|
|
<DialogHeader>
|
|
<DialogTitle>Document Recipients</DialogTitle>
|
|
<DialogDescription>Add the recipients to create the template with.</DialogDescription>
|
|
</DialogHeader>
|
|
<div className="flex flex-col space-y-4">
|
|
{formRecipients.map((recipient, index) => (
|
|
<div
|
|
key={recipient.id}
|
|
data-native-id={recipient.id}
|
|
className="flex flex-wrap items-end gap-x-4"
|
|
>
|
|
<div className="flex-1">
|
|
<Label htmlFor={`recipient-${recipient.id}-email`}>
|
|
Email
|
|
<span className="text-destructive ml-1 inline-block font-medium">*</span>
|
|
</Label>
|
|
|
|
<Controller
|
|
control={control}
|
|
name={`recipients.${index}.email`}
|
|
render={({ field }) => (
|
|
<Input
|
|
id={`recipient-${recipient.id}-email`}
|
|
type="email"
|
|
className="bg-background mt-2"
|
|
disabled={isSubmitting}
|
|
{...field}
|
|
/>
|
|
)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex-1">
|
|
<Label htmlFor={`recipient-${recipient.id}-name`}>Name</Label>
|
|
|
|
<Controller
|
|
control={control}
|
|
name={`recipients.${index}.name`}
|
|
render={({ field }) => (
|
|
<Input
|
|
id={`recipient-${recipient.id}-name`}
|
|
type="text"
|
|
className="bg-background mt-2"
|
|
disabled={isSubmitting}
|
|
{...field}
|
|
/>
|
|
)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="w-[60px]">
|
|
<Controller
|
|
control={control}
|
|
name={`recipients.${index}.role`}
|
|
render={({ field: { value, onChange } }) => (
|
|
<Select value={value} onValueChange={(x) => onChange(x)}>
|
|
<SelectTrigger className="bg-background">{ROLE_ICONS[value]}</SelectTrigger>
|
|
|
|
<SelectContent className="" align="end">
|
|
<SelectItem value={RecipientRole.SIGNER}>
|
|
<div className="flex items-center">
|
|
<span className="mr-2">{ROLE_ICONS[RecipientRole.SIGNER]}</span>
|
|
Signer
|
|
</div>
|
|
</SelectItem>
|
|
|
|
<SelectItem value={RecipientRole.CC}>
|
|
<div className="flex items-center">
|
|
<span className="mr-2">{ROLE_ICONS[RecipientRole.CC]}</span>
|
|
Receives copy
|
|
</div>
|
|
</SelectItem>
|
|
|
|
<SelectItem value={RecipientRole.APPROVER}>
|
|
<div className="flex items-center">
|
|
<span className="mr-2">{ROLE_ICONS[RecipientRole.APPROVER]}</span>
|
|
Approver
|
|
</div>
|
|
</SelectItem>
|
|
|
|
<SelectItem value={RecipientRole.VIEWER}>
|
|
<div className="flex items-center">
|
|
<span className="mr-2">{ROLE_ICONS[RecipientRole.VIEWER]}</span>
|
|
Viewer
|
|
</div>
|
|
</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="w-full">
|
|
<FormErrorMessage className="mt-2" error={errors.recipients?.[index]?.email} />
|
|
<FormErrorMessage className="mt-2" error={errors.recipients?.[index]?.name} />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<DialogFooter className="justify-end">
|
|
<DialogClose asChild>
|
|
<Button type="button" variant="secondary">
|
|
Close
|
|
</Button>
|
|
</DialogClose>
|
|
|
|
<Button
|
|
type="button"
|
|
loading={isCreatingDocumentFromTemplate}
|
|
disabled={isCreatingDocumentFromTemplate}
|
|
onClick={onCreateDocumentFromTemplate}
|
|
>
|
|
Create Document
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|