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 + + + + )} + /> +
+ )} +