import { Navigate, NavLink, Outlet, useLocation } from 'react-router-dom' import { useAuth } from '../contexts/AuthContext' import { ADMIN_BATCH_JOBS, ADMIN_LIGHTHOUSE_REPORT } from '../utils/adminPaths' function tabCls({ isActive }: { isActive: boolean }) { return [ 'inline-flex items-center gap-1.5 border-b-2 px-2.5 py-1.5 text-sm font-medium transition-colors', isActive ? 'border-teal-600 text-teal-800' : 'border-transparent text-slate-600 hover:border-slate-300 hover:text-slate-900', ].join(' ') } export default function AdminLayout() { const { pathname } = useLocation() const { user, isLoading } = useAuth() // Admin-only area: wait for auth to resolve, then bounce non-admins home so // the route can't be reached by typing the URL even though the menu link is // hidden. This is a UX gate, not a security boundary — the underlying // lighthouse/batch-job data endpoints are not yet auth-protected. if (isLoading) { return (
Loading…
) } if (!user?.is_admin) { return } const onLighthouseReport = pathname === ADMIN_LIGHTHOUSE_REPORT || pathname.startsWith(`${ADMIN_LIGHTHOUSE_REPORT}/`) const onBatchJobs = pathname === ADMIN_BATCH_JOBS || pathname.startsWith(`${ADMIN_BATCH_JOBS}/`) return (

Admin

Operational tooling — data-quality Lighthouse scores and live batch-job progress for the caption / analyze pipelines.

{(onLighthouseReport || onBatchJobs) && (

{onLighthouseReport ? 'Scores and warnings are read from the latest `bronze.bronze_jurisdiction_website_lighthouse` row for the URL you enter (after accessibility lighthouse ingest).' : 'Live caption/analyze batch progress from Postgres (`bronze.youtube_batch_job_runs`) via SSE. Click a jurisdiction for per-video outcomes.'}

)}
{/* Workspace: mid-slate so white cards read clearly. */}
) }