'use client'; import { KeyRound, LogOut, RefreshCw } from 'lucide-react'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; import { type ReactNode, useState } from 'react'; import { Container } from '@/components/ui/section'; import { ADMIN_MODULES, setAdminToken, useAdminToken } from '@/lib/admin'; import { cn } from '@/lib/cn'; /** Token gate + module navigation. The token never leaves localStorage except as the `X-CA-Admin-Token` header. */ export function AdminShell({ children, title, onRefresh, refreshing }: { children: ReactNode; title: string; onRefresh?: () => void; refreshing?: boolean }) { const token = useAdminToken(); const pathname = usePathname(); const [draft, setDraft] = useState(''); if (token === undefined) return Loading…; if (!token) return (

Admin

Operator console

Enter the admin token (`CA_ADMIN_TOKEN`). It is stored in this browser only and sent as X-CA-Admin-Token to same-origin API calls.

{ e.preventDefault(); if (draft.trim()) setAdminToken(draft.trim()); }} > setDraft(e.target.value)} className="field flex-1" placeholder="admin token" autoComplete="off" data-admin-token />
); return (

{title}

{onRefresh && ( )}
{children}
); } export function AdminError({ error }: { error: string | null }) { if (!error) return null; return (

{error} {/401|403/.test(error) ? ' — the token was rejected. Sign out and enter it again.' : ''}

); } export function AdminTable({ head, children, className }: { head: ReactNode; children: ReactNode; className?: string }) { return (
{head}{children}
); } export function KpiRow({ items }: { items: { label: string; value: ReactNode; hint?: ReactNode; tone?: 'positive' | 'warning' | 'danger' }[] }) { return (
{items.map((i) => (

{i.label}

{i.value}

{i.hint &&

{i.hint}

}
))}
); }