From 096d6c99b1b3dd0d7f24620b6d099f9f57565900 Mon Sep 17 00:00:00 2001 From: alphaeusmote <41258468-alphaeusmote@users.noreply.replit.com> Date: Fri, 11 Apr 2025 17:14:04 +0000 Subject: [PATCH] Enhance API token management by adding custom expiration date/time selection. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9111ef36-26c8-4085-84ca-a35dc1fec1b5 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7083d608-d6d3-4a6a-9a27-6286c5109627/cb03c6a4-753d-4c14-9c5d-1ddb6ed4807f.jpg --- client/src/pages/api-tokens.tsx | 161 +++++++++++++++++++++++++++----- 1 file changed, 139 insertions(+), 22 deletions(-) diff --git a/client/src/pages/api-tokens.tsx b/client/src/pages/api-tokens.tsx index 602a383..15d3fc8 100644 --- a/client/src/pages/api-tokens.tsx +++ b/client/src/pages/api-tokens.tsx @@ -6,7 +6,8 @@ import { useAuth } from "@/hooks/use-auth"; import { useOrganization } from "@/context/organization-context"; import { apiRequest, queryClient } from "@/lib/queryClient"; import { useToast } from "@/hooks/use-toast"; -import { useForm } from "react-hook-form"; +import { useForm, useWatch } from "react-hook-form"; +import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { @@ -61,6 +62,7 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Checkbox } from "@/components/ui/checkbox"; +import { Calendar } from "@/components/ui/calendar"; import { Select, SelectContent, @@ -68,7 +70,7 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { Loader2, Key, MoreVertical, Calendar, Copy, Info } from "lucide-react"; +import { Loader2, Key, MoreVertical, CalendarIcon, Copy, Info, Clock } from "lucide-react"; import { formatDistanceToNow, format } from "date-fns"; // Token form schema @@ -126,25 +128,44 @@ export default function ApiTokensPage() { if (data.expiresIn && data.expiresIn !== 'never') { const now = new Date(); - switch (data.expiresIn) { - case '1hour': - tokenData.expiresAt = new Date(now.getTime() + 60 * 60 * 1000); - break; - case '1day': - tokenData.expiresAt = new Date(now.getTime() + 24 * 60 * 60 * 1000); - break; - case '7days': - tokenData.expiresAt = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); - break; - case '30days': - tokenData.expiresAt = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); - break; - case '90days': - tokenData.expiresAt = new Date(now.getTime() + 90 * 24 * 60 * 60 * 1000); - break; - case '1year': - tokenData.expiresAt = new Date(now.getTime() + 365 * 24 * 60 * 60 * 1000); - break; + if (data.expiresIn === 'custom' && data.customDate) { + // For custom date/time + if (data.customDate) { + const customDate = new Date(data.customDate); + + // If time was selected, add it to the date + if (data.customTime) { + const [hours, minutes] = data.customTime.split(':').map(Number); + customDate.setHours(hours, minutes, 0, 0); + } else { + // Default to end of day if no time selected + customDate.setHours(23, 59, 59, 999); + } + + tokenData.expiresAt = customDate; + } + } else { + // For preset expiration options + switch (data.expiresIn) { + case '1hour': + tokenData.expiresAt = new Date(now.getTime() + 60 * 60 * 1000); + break; + case '1day': + tokenData.expiresAt = new Date(now.getTime() + 24 * 60 * 60 * 1000); + break; + case '7days': + tokenData.expiresAt = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); + break; + case '30days': + tokenData.expiresAt = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); + break; + case '90days': + tokenData.expiresAt = new Date(now.getTime() + 90 * 24 * 60 * 60 * 1000); + break; + case '1year': + tokenData.expiresAt = new Date(now.getTime() + 365 * 24 * 60 * 60 * 1000); + break; + } } } @@ -281,7 +302,7 @@ export default function ApiTokensPage() { {token.expiresAt ? (
- + 30 days 90 days 1 year + Custom date/time @@ -445,6 +467,101 @@ export default function ApiTokensPage() { )} /> + {/* Custom date and time fields - show only when custom expiration is selected */} + {form.watch("expiresIn") === "custom" && ( +
+ ( + + Custom Date + + + + + + + + date < new Date()} + initialFocus + /> + + + + The date when the token will expire + + + + )} + /> + + ( + + Custom Time + + + The time when the token will expire + + + + )} + /> +
+ )} +