"use client"; import { useState, useTransition } from "react"; import { Check, Copy, KeyRound } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { createApiTokenAction, revokeApiTokenAction } from "@/app/settings/actions"; import type { HouseholdApiTokenStatus } from "@/modules/_core/api-token"; export function ApiTokenSettings({ status }: { status: HouseholdApiTokenStatus }) { const [tokenStatus, setTokenStatus] = useState(status); const [rawToken, setRawToken] = useState(null); const [dialogOpen, setDialogOpen] = useState(false); const [copied, setCopied] = useState(false); const [isPending, startTransition] = useTransition(); function generateToken() { startTransition(async () => { try { const result = await createApiTokenAction(); setRawToken(result.token); setDialogOpen(true); setTokenStatus({ hasActiveToken: true, lastUsedAt: null, createdAt: new Date(), }); } catch (err) { toast.error(err instanceof Error ? err.message : "Failed to generate token"); } }); } function revokeToken() { startTransition(async () => { try { await revokeApiTokenAction(); setTokenStatus({ hasActiveToken: false, lastUsedAt: null, createdAt: null }); toast.success("API token revoked"); } catch (err) { toast.error(err instanceof Error ? err.message : "Failed to revoke token"); } }); } function copyToken() { if (!rawToken) return; navigator.clipboard.writeText(rawToken).then(() => { setCopied(true); toast.success("Copied to clipboard"); setTimeout(() => setCopied(false), 2000); }); } return ( <>
API token
{tokenStatus.hasActiveToken ? ( <> Active {tokenStatus.createdAt && ( <> · created {tokenStatus.createdAt.toLocaleDateString()} )} {tokenStatus.lastUsedAt && ( <> · last used {tokenStatus.lastUsedAt.toLocaleString()} )} {!tokenStatus.lastUsedAt && <> · never used} ) : ( <>No active token — generate one for scripts and automations )}
{tokenStatus.hasActiveToken ? ( ) : null}
API token created Copy this token now — it will not be shown again. Use it as{" "} Authorization: Bearer <token> on{" "} /api/v1/ requests.
); }