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() {
+ 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) => {