From 6a5fc7a5fb89a7df84e0a743fe3a7a37fc551f30 Mon Sep 17 00:00:00 2001 From: Catalin Pit Date: Tue, 28 Nov 2023 12:37:01 +0200 Subject: [PATCH] feat: confirm to delete dialog --- .../settings/token/delete-token-dialog.tsx | 167 ++++++++++++++++++ apps/web/src/components/forms/token.tsx | 82 ++------- 2 files changed, 177 insertions(+), 72 deletions(-) create mode 100644 apps/web/src/components/(dashboard)/settings/token/delete-token-dialog.tsx diff --git a/apps/web/src/components/(dashboard)/settings/token/delete-token-dialog.tsx b/apps/web/src/components/(dashboard)/settings/token/delete-token-dialog.tsx new file mode 100644 index 000000000..d73a3a786 --- /dev/null +++ b/apps/web/src/components/(dashboard)/settings/token/delete-token-dialog.tsx @@ -0,0 +1,167 @@ +'use client'; + +import { useEffect, useState } from 'react'; + +import { useRouter } from 'next/navigation'; + +import { zodResolver } from '@hookform/resolvers/zod'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; + +import { trpc } from '@documenso/trpc/react'; +import { Button } from '@documenso/ui/primitives/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@documenso/ui/primitives/dialog'; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@documenso/ui/primitives/form/form'; +import { Input } from '@documenso/ui/primitives/input'; +import { useToast } from '@documenso/ui/primitives/use-toast'; + +export type DeleteTokenDialogProps = { + trigger?: React.ReactNode; + tokenId: number; + tokenName: string; +}; + +export default function DeleteTokenDialog({ trigger, tokenId, tokenName }: DeleteTokenDialogProps) { + const router = useRouter(); + const { toast } = useToast(); + const [isOpen, setIsOpen] = useState(false); + + const deleteMessage = `delete ${tokenName}`; + + const ZDeleteTokenDialogSchema = z.object({ + tokenName: z.literal(deleteMessage, { + errorMap: () => ({ message: `You must enter '${deleteMessage}' to proceed` }), + }), + }); + + type TDeleteTokenByIdMutationSchema = z.infer; + + const { mutateAsync: deleteTokenMutation } = trpc.apiToken.deleteTokenById.useMutation(); + + const form = useForm({ + resolver: zodResolver(ZDeleteTokenDialogSchema), + values: { + tokenName: '', + }, + }); + + const onSubmit = async () => { + try { + await deleteTokenMutation({ + id: tokenId, + }); + + toast({ + title: 'Token deleted', + description: 'The token was deleted successfully.', + duration: 5000, + }); + + setIsOpen(false); + router.push('/settings/token'); + } catch (error) { + toast({ + title: 'An unknown error occurred', + variant: 'destructive', + duration: 5000, + description: + 'We encountered an unknown error while attempting to delete this team. Please try again later.', + }); + } + }; + + useEffect(() => { + if (!open) { + form.reset(); + } + }, [open, form]); + + return ( + !form.formState.isSubmitting && setIsOpen(value)} + > + + {trigger ?? ( + + )} + + + + Are you sure you want to delete this token? + + + Please note that this action is irreversible. Once confirmed, your token will be + permanently deleted. + + + +
+ +
+ ( + + + Confirm by typing + + {deleteMessage} + + + + + + + + )} + /> + +
+ + + +
+
+
+
+ +
+
+ ); +} diff --git a/apps/web/src/components/forms/token.tsx b/apps/web/src/components/forms/token.tsx index 0daacf060..131e90a7d 100644 --- a/apps/web/src/components/forms/token.tsx +++ b/apps/web/src/components/forms/token.tsx @@ -1,7 +1,5 @@ 'use client'; -import { useState } from 'react'; - import { useRouter } from 'next/navigation'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -14,14 +12,6 @@ import { trpc } from '@documenso/trpc/react'; import { ZCreateTokenMutationSchema } from '@documenso/trpc/server/api-token-router/schema'; import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from '@documenso/ui/primitives/dialog'; import { Form, FormControl, @@ -33,6 +23,8 @@ import { import { Input } from '@documenso/ui/primitives/input'; import { useToast } from '@documenso/ui/primitives/use-toast'; +import DeleteTokenDialog from '~/components/(dashboard)/settings/token/delete-token-dialog'; + export type ApiTokenFormProps = { className?: string; }; @@ -43,12 +35,9 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { const router = useRouter(); const [, copy] = useCopyToClipboard(); const { toast } = useToast(); - const [isOpen, setIsOpen] = useState(false); - const [tokenIdToDelete, setTokenIdToDelete] = useState(0); const { data: tokens } = trpc.apiToken.getTokens.useQuery(); const { mutateAsync: createTokenMutation } = trpc.apiToken.createToken.useMutation(); - const { mutateAsync: deleteTokenMutation } = trpc.apiToken.deleteTokenById.useMutation(); const form = useForm({ resolver: zodResolver(ZCreateTokenMutationSchema), @@ -57,25 +46,6 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { }, }); - const deleteToken = async (id: number) => { - try { - await deleteTokenMutation({ - id, - }); - - toast({ - title: 'Token deleted', - description: 'The token was deleted successfully.', - duration: 5000, - }); - - setIsOpen(false); - router.refresh(); - } catch (error) { - console.error(error); - } - }; - const copyToken = (token: string) => { void copy(token).then(() => { toast({ @@ -97,6 +67,7 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { duration: 5000, }); + form.reset(); router.refresh(); } catch (error) { if (error instanceof TRPCClientError && error.data?.code === 'BAD_REQUEST') { @@ -109,6 +80,7 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { toast({ title: 'An unknown error occurred', variant: 'destructive', + duration: 5000, description: 'We encountered an unknown error while attempting create the new token. Please try again later.', }); @@ -118,35 +90,6 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { return (
- - - - Are you sure you want to delete this token? - - - Please note that this action is irreversible. Once confirmed, your token will be - permanently deleted. - - - - -
- - - -
-
-
-

Your existing tokens

    {tokens?.map((token) => ( @@ -181,16 +124,7 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { }) : 'N/A'}

    - + @@ -217,7 +151,11 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { />
    -