fix: duplicate templates (#1104)

## Description

Fix the issue where duplicate templates can be created

## Changes Made

- Prevent duplicate templates by correctly disabling elements
- Clear the PDF when the form is reset
- General UI changes to new template dialog for consistency
- Add description for new template dialog
- Add close button for new template dialog

## Testing Performed

Manual testing

## Checklist

- [X] I have tested these changes locally and they work as expected.
- [X] I have followed the project's coding style guidelines.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Introduced new components in the template creation dialog for better
usability: `DialogClose`, `DialogDescription`, and `DialogFooter`.
	- Enhanced file upload handling and display.
- Added a cancel button and a create template button to the dialog
footer for improved navigation.

- **Refactor**
- Updated the dialog content and form layout for a more intuitive user
experience.
	- Refactored form structure and labels for clarity.

- **Removed Features**
	- Removed the `Label` component from the dialog.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
David Nguyen
2024-04-17 19:13:54 +07:00
committed by GitHub
parent 18b39eb538
commit 8fe67e167c

View File

@ -18,7 +18,10 @@ import { Button } from '@documenso/ui/primitives/button';
import { Card, CardContent } from '@documenso/ui/primitives/card'; import { Card, CardContent } from '@documenso/ui/primitives/card';
import { import {
Dialog, Dialog,
DialogClose,
DialogContent, DialogContent,
DialogDescription,
DialogFooter,
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
@ -34,7 +37,6 @@ import {
FormMessage, FormMessage,
} from '@documenso/ui/primitives/form/form'; } from '@documenso/ui/primitives/form/form';
import { Input } from '@documenso/ui/primitives/input'; import { Input } from '@documenso/ui/primitives/input';
import { Label } from '@documenso/ui/primitives/label';
import { useToast } from '@documenso/ui/primitives/use-toast'; import { useToast } from '@documenso/ui/primitives/use-toast';
const ZCreateTemplateFormSchema = z.object({ const ZCreateTemplateFormSchema = z.object({
@ -61,8 +63,7 @@ export const NewTemplateDialog = ({ teamId, templateRootPath }: NewTemplateDialo
resolver: zodResolver(ZCreateTemplateFormSchema), resolver: zodResolver(ZCreateTemplateFormSchema),
}); });
const { mutateAsync: createTemplate, isLoading: isCreatingTemplate } = const { mutateAsync: createTemplate } = trpc.template.createTemplate.useMutation();
trpc.template.createTemplate.useMutation();
const [showNewTemplateDialog, setShowNewTemplateDialog] = useState(false); const [showNewTemplateDialog, setShowNewTemplateDialog] = useState(false);
const [uploadedFile, setUploadedFile] = useState<{ file: File; fileBase64: string } | null>(); const [uploadedFile, setUploadedFile] = useState<{ file: File; fileBase64: string } | null>();
@ -140,6 +141,7 @@ export const NewTemplateDialog = ({ teamId, templateRootPath }: NewTemplateDialo
useEffect(() => { useEffect(() => {
if (!showNewTemplateDialog) { if (!showNewTemplateDialog) {
form.reset(); form.reset();
setUploadedFile(null);
} }
}, [form, showNewTemplateDialog]); }, [form, showNewTemplateDialog]);
@ -154,20 +156,23 @@ export const NewTemplateDialog = ({ teamId, templateRootPath }: NewTemplateDialo
<DialogContent className="w-full max-w-xl"> <DialogContent className="w-full max-w-xl">
<DialogHeader> <DialogHeader>
<DialogTitle className="mb-4">New Template</DialogTitle> <DialogTitle>New Template</DialogTitle>
<DialogDescription>
Templates allow you to quickly generate documents with pre-filled recipients and fields.
</DialogDescription>
</DialogHeader> </DialogHeader>
<div> <Form {...form}>
<Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col gap-y-4"> <fieldset disabled={form.formState.isSubmitting} className="flex flex-col gap-y-4">
<FormField <FormField
control={form.control} control={form.control}
name="name" name="name"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Name your template</FormLabel> <FormLabel>Template name</FormLabel>
<FormControl> <FormControl>
<Input id="email" type="text" className="bg-background mt-1.5" {...field} /> <Input {...field} />
</FormControl> </FormControl>
<FormDescription> <FormDescription>
<span className="text-muted-foreground text-xs"> <span className="text-muted-foreground text-xs">
@ -180,55 +185,57 @@ export const NewTemplateDialog = ({ teamId, templateRootPath }: NewTemplateDialo
)} )}
/> />
<div> <div className="mt-1.5">
<Label htmlFor="template">Upload a Document</Label> {uploadedFile ? (
<Card gradient className="h-[40vh]">
<CardContent className="flex h-full flex-col items-center justify-center p-2">
<button
onClick={() => resetForm()}
title="Remove Template"
className="text-muted-foreground absolute right-2.5 top-2.5 rounded-sm opacity-60 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
>
<X className="h-6 w-6" />
<span className="sr-only">Remove Template</span>
</button>
<div className="my-3"> <div className="border-muted-foreground/20 group-hover:border-documenso/80 dark:bg-muted/80 z-10 flex aspect-[3/4] w-24 flex-col gap-y-1 rounded-lg border bg-white/80 px-2 py-4 backdrop-blur-sm">
{uploadedFile ? ( <div className="bg-muted-foreground/20 group-hover:bg-documenso h-2 w-full rounded-[2px]" />
<Card gradient className="h-[40vh]"> <div className="bg-muted-foreground/20 group-hover:bg-documenso h-2 w-5/6 rounded-[2px]" />
<CardContent className="flex h-full flex-col items-center justify-center p-2"> <div className="bg-muted-foreground/20 group-hover:bg-documenso h-2 w-full rounded-[2px]" />
<button </div>
onClick={() => resetForm()}
title="Remove Template"
className="text-muted-foreground absolute right-2.5 top-2.5 rounded-sm opacity-60 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
>
<X className="h-6 w-6" />
<span className="sr-only">Remove Template</span>
</button>
<div className="border-muted-foreground/20 group-hover:border-documenso/80 dark:bg-muted/80 z-10 flex aspect-[3/4] w-24 flex-col gap-y-1 rounded-lg border bg-white/80 px-2 py-4 backdrop-blur-sm"> <p className="group-hover:text-foreground text-muted-foreground mt-4 font-medium">
<div className="bg-muted-foreground/20 group-hover:bg-documenso h-2 w-full rounded-[2px]" /> Uploaded Document
<div className="bg-muted-foreground/20 group-hover:bg-documenso h-2 w-5/6 rounded-[2px]" /> </p>
<div className="bg-muted-foreground/20 group-hover:bg-documenso h-2 w-full rounded-[2px]" />
</div>
<p className="group-hover:text-foreground text-muted-foreground mt-4 font-medium"> <span className="text-muted-foreground/80 mt-1 text-sm">
Uploaded Document {uploadedFile.file.name}
</p> </span>
</CardContent>
<span className="text-muted-foreground/80 mt-1 text-sm"> </Card>
{uploadedFile.file.name} ) : (
</span> <DocumentDropzone className="h-[40vh]" onDrop={onFileDrop} type="template" />
</CardContent> )}
</Card>
) : (
<DocumentDropzone
className="mt-1.5 h-[40vh]"
onDrop={onFileDrop}
type="template"
/>
)}
</div>
</div> </div>
<div className="flex w-full justify-end"> <DialogFooter>
<Button loading={isCreatingTemplate} type="submit"> <DialogClose asChild>
Create Template <Button type="button" variant="secondary">
Cancel
</Button>
</DialogClose>
<Button
loading={form.formState.isSubmitting}
disabled={!uploadedFile}
type="submit"
>
Create template
</Button> </Button>
</div> </DialogFooter>
</form> </fieldset>
</Form> </form>
</div> </Form>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
); );