diff --git a/apps/web/src/app/(dashboard)/settings/tokens/page.tsx b/apps/web/src/app/(dashboard)/settings/tokens/page.tsx index 86143c633..8951098c4 100644 --- a/apps/web/src/app/(dashboard)/settings/tokens/page.tsx +++ b/apps/web/src/app/(dashboard)/settings/tokens/page.tsx @@ -48,9 +48,15 @@ export default async function ApiTokensPage() {

Created on

-

- Expires on -

+ {token.expires ? ( +

+ Expires on +

+ ) : ( +

+ Token doesn't have an expiration date +

+ )}
diff --git a/apps/web/src/components/(dashboard)/settings/token/contants.ts b/apps/web/src/components/(dashboard)/settings/token/contants.ts new file mode 100644 index 000000000..232c37644 --- /dev/null +++ b/apps/web/src/components/(dashboard)/settings/token/contants.ts @@ -0,0 +1,7 @@ +export const EXPIRATION_DATES = { + ONE_WEEK: '7 days', + ONE_MONTH: '1 month', + THREE_MONTHS: '3 months', + SIX_MONTHS: '6 months', + ONE_YEAR: '12 months', +} as const; diff --git a/apps/web/src/components/forms/token.tsx b/apps/web/src/components/forms/token.tsx index 97e1c17ad..688ff47ca 100644 --- a/apps/web/src/components/forms/token.tsx +++ b/apps/web/src/components/forms/token.tsx @@ -1,12 +1,12 @@ 'use client'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; -import type { z } from 'zod'; +import { z } from 'zod'; import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard'; import { TRPCClientError } from '@documenso/trpc/client'; @@ -26,9 +26,21 @@ import { FormMessage, } from '@documenso/ui/primitives/form/form'; import { Input } from '@documenso/ui/primitives/input'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@documenso/ui/primitives/select'; +import { Switch } from '@documenso/ui/primitives/switch'; import { useToast } from '@documenso/ui/primitives/use-toast'; -const ZCreateTokenFormSchema = ZCreateTokenMutationSchema; +import { EXPIRATION_DATES } from '../(dashboard)/settings/token/contants'; + +const ZCreateTokenFormSchema = ZCreateTokenMutationSchema.extend({ + enabled: z.boolean(), +}); type TCreateTokenFormSchema = z.infer; @@ -43,6 +55,7 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { const { toast } = useToast(); const [newlyCreatedToken, setNewlyCreatedToken] = useState(''); + const [noExpirationDate, setNoExpirationDate] = useState(false); const { mutateAsync: createTokenMutation } = trpc.apiToken.createToken.useMutation({ onSuccess(data) { @@ -54,9 +67,21 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { resolver: zodResolver(ZCreateTokenFormSchema), defaultValues: { tokenName: '', + expirationDate: '', + enabled: false, }, }); + useEffect(() => { + if (newlyCreatedToken) { + const timer = setTimeout(() => { + setNewlyCreatedToken(''); + }, 30000); + + return () => clearTimeout(timer); + } + }, [newlyCreatedToken]); + const copyToken = async (token: string) => { try { const copied = await copy(token); @@ -78,10 +103,11 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { } }; - const onSubmit = async ({ tokenName }: TCreateTokenMutationSchema) => { + const onSubmit = async ({ tokenName, expirationDate }: TCreateTokenMutationSchema) => { try { await createTokenMutation({ tokenName, + expirationDate: noExpirationDate ? null : expirationDate, }); toast({ @@ -116,30 +142,21 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => {
-
+
( - Token Name + Token name
- -
- + Please enter a meaningful name for your token. This will help you identify it later. @@ -149,6 +166,65 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => { )} /> + ( + + Token expiration date + +
+ + + +
+ + +
+ )} + /> + + ( + + Never expire + + { + setNoExpirationDate((prev) => !prev); + field.onChange(val); + }} + /> + + + + )} + /> + + +