import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog"; import { Key, Trash2, Copy, Check, Ticket, RotateCw } from "lucide-react"; import { cn } from "@/lib/utils"; interface Token { id: string; name: string; tokenPrefix?: string; expiresAt: string | null; lastUsedAt: string | null; createdAt: string; } interface TokensManagerProps { initialTokens: Token[]; } export default function TokensManager({ initialTokens }: TokensManagerProps) { const [tokens, setTokens] = useState(initialTokens); const [isCreateOpen, setIsCreateOpen] = useState(false); const [isSuccessOpen, setIsSuccessOpen] = useState(false); const [newToken, setNewToken] = useState(""); const [loading, setLoading] = useState(false); // Form state const [name, setName] = useState(""); const [expiresIn, setExpiresIn] = useState("30d"); // Deletion state const [tokenToDelete, setTokenToDelete] = useState(null); const handleCreate = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); try { const res = await fetch("/api/user/tokens", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name, expiresIn }), }); const data = await res.json(); if (res.ok) { setNewToken(data.data.token.token); setIsCreateOpen(false); setIsSuccessOpen(true); const createdToken: Token = { id: data.data.token.id, name: data.data.token.name, tokenPrefix: "och_" + data.data.token.token.substring(4, 12) + "...", expiresAt: data.data.token.expiresAt, createdAt: data.data.token.createdAt, lastUsedAt: null }; setTokens([createdToken, ...tokens]); setName(""); setExpiresIn("30d"); } else { alert(data.error?.message || "Failed to create token"); } } catch (err) { console.error(err); alert("An error occurred"); } finally { setLoading(false); } }; const handleDelete = async () => { if (!tokenToDelete) return; try { const res = await fetch(`/api/user/tokens/${tokenToDelete}`, { method: "DELETE", }); if (res.ok) { setTokens(tokens.filter((t) => t.id !== tokenToDelete)); } else { alert("Failed to delete token"); } } catch (err) { console.error(err); } finally { setTokenToDelete(null); } }; const [copied, setCopied] = useState(false); const copyToken = () => { navigator.clipboard.writeText(newToken); setCopied(true); setTimeout(() => setCopied(false), 2000); }; return (
{/* Header */}

Access Tokens

Tokens for API and Git over HTTPS authentication.

Generate New Token Create a new personal access token.
setName(e.target.value)} required />
{/* Success Modal */}
Token Generated! Copy your token now. You won't see it again!
{newToken}
{/* List */}
{tokens.length > 0 ? (
{tokens.map((token) => (

{token.name}

Created {new Date(token.createdAt).toLocaleDateString()} {token.expiresAt && ( {new Date(token.expiresAt) < new Date() ? "Expired" : `Expires ${new Date(token.expiresAt).toLocaleDateString()}`} )}
Are you absolutely sure? This action cannot be undone. This will permanently delete the token "{token.name}" and any applications using it will lose access. Cancel Delete Token
))}
) : (

No tokens yet

Generate a token to access the API.

)}
); }