'use client'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; import { zodResolver } from '@hookform/resolvers/zod'; import { Loader } from 'lucide-react'; import { DateTime } from 'luxon'; import { useForm } from 'react-hook-form'; import type { z } from 'zod'; import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard'; import { TRPCClientError } from '@documenso/trpc/client'; 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 { 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'; import DeleteTokenDialog from '~/components/(dashboard)/settings/token/delete-token-dialog'; export type ApiTokenFormProps = { className?: string; }; type TCreateTokenMutationSchema = z.infer; export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { const router = useRouter(); const [, copy] = useCopyToClipboard(); const { toast } = useToast(); const [newlyCreatedToken, setNewlyCreatedToken] = useState({ id: 0, token: '' }); const [showNewToken, setShowNewToken] = useState(false); const { data: tokens, isLoading: isTokensLoading } = trpc.apiToken.getTokens.useQuery(); const { mutateAsync: createTokenMutation } = trpc.apiToken.createToken.useMutation({ onSuccess(data) { setNewlyCreatedToken({ id: data.id, token: data.token }); }, }); const form = useForm({ resolver: zodResolver(ZCreateTokenMutationSchema), values: { tokenName: '', }, }); /* This method is called in "delete-token-dialog.tsx" after a successful mutation to avoid deleting the snippet with the newly created token from the screen when users delete any of their tokens except the newly created one. */ const onDelete = (tokenId: number) => { if (tokenId === newlyCreatedToken.id) { setShowNewToken(false); } }; const copyToken = async (token: string) => { try { const copied = await copy(token); if (!copied) { throw new Error('Unable to copy the token'); } toast({ title: 'Token copied to clipboard', description: 'The token was copied to your clipboard.', }); } catch (error) { toast({ title: 'Unable to copy token', description: 'We were unable to copy the token to your clipboard. Please try again.', variant: 'destructive', }); } }; const onSubmit = async ({ tokenName }: TCreateTokenMutationSchema) => { try { await createTokenMutation({ tokenName, }); toast({ title: 'Token created', description: 'A new token was created successfully.', duration: 5000, }); setShowNewToken(true); form.reset(); router.refresh(); } catch (error) { if (error instanceof TRPCClientError && error.data?.code === 'BAD_REQUEST') { toast({ title: 'An error occurred', description: error.message, variant: 'destructive', }); } else { 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.', }); } } }; return (

Your existing tokens

{tokens?.length === 0 ? (

Your tokens will be shown here once you create them.

) : (
)} {!tokens && isTokensLoading ? (
) : (
    {tokens?.map((token) => (
  • {token.name} ({token.algorithm})

    Created:{' '} {token.createdAt ? DateTime.fromJSDate(token.createdAt).toLocaleString(DateTime.DATETIME_FULL) : 'N/A'}

    Expires:{' '} {token.expires ? DateTime.fromJSDate(token.expires).toLocaleString(DateTime.DATETIME_FULL) : 'N/A'}

    onDelete(token.id)} />
  • ))}
)} {newlyCreatedToken.token && showNewToken && (

Your token was created successfully! Make sure to copy it because you won't be able to see it again!

{newlyCreatedToken.token}

)}

Create a new token

Enter a representative name for your new token.

( Token Name )} />
); };