"use client"; import { useState } from "react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; type ApiKey = { id: string; name: string; lastUsedAt: string | null; createdAt: string; }; type CreateApiKeyResponse = { id: string; name: string; key: string; createdAt: string; }; function formatDate(iso: string) { return new Date(iso).toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric", }); } export function ApiKeysManager({ initialKeys }: { initialKeys: ApiKey[] }) { const [keys, setKeys] = useState(initialKeys); const [name, setName] = useState(""); const [creating, setCreating] = useState(false); const [newKey, setNewKey] = useState(null); const [copied, setCopied] = useState(false); async function handleCreate(e: React.FormEvent) { e.preventDefault(); if (!name.trim()) return; setCreating(true); try { const res = await fetch("/api/v1/api-keys", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: name.trim() }), }); if (!res.ok) { const data = await res.json() as { error?: string }; throw new Error(data.error ?? "Failed to create API key"); } const data = await res.json() as CreateApiKeyResponse; setNewKey(data.key); setKeys((prev) => [ { id: data.id, name: data.name, lastUsedAt: null, createdAt: data.createdAt }, ...prev, ]); setName(""); } catch (err) { toast.error(err instanceof Error ? err.message : "Failed to create API key"); } finally { setCreating(false); } } async function handleRevoke(id: string) { try { const res = await fetch(`/api/v1/api-keys/${id}`, { method: "DELETE" }); if (!res.ok) { const data = await res.json() as { error?: string }; throw new Error(data.error ?? "Failed to revoke API key"); } setKeys((prev) => prev.filter((k) => k.id !== id)); } catch (err) { toast.error(err instanceof Error ? err.message : "Failed to revoke API key"); } } async function handleCopy() { if (!newKey) return; try { await navigator.clipboard.writeText(newKey); setCopied(true); setTimeout(() => setCopied(false), 2000); } catch { toast.error("Failed to copy to clipboard"); } } return (
{/* Create form */}
setName(e.target.value)} maxLength={100} required />
{/* New key reveal */} {newKey && (

Save this key — it will not be shown again.

{newKey}
)} {/* Keys list */} {keys.length === 0 ? (

No API keys yet.

) : (
{keys.map((k) => (

{k.name}

Created {formatDate(k.createdAt)} · {k.lastUsedAt ? ( Last used {formatDate(k.lastUsedAt)} ) : ( Never used )}
))}
)}
); }