import { useCallback, useEffect, useRef, useState } from "react"; import { ExternalLink, Loader2, LogOut, Shield } from "lucide-react"; import { useSearchParams } from "react-router-dom"; import { DomainManager } from "@/client/components/admin/domain-manager"; import { PermanentInboxList } from "@/client/components/admin/permanent-inbox-list"; import { TempInboxList } from "@/client/components/admin/temp-inbox-list"; import { toast } from "@/client/components/toast"; import { Button, Card, ErrorBanner, buttonClasses } from "@/client/components/ui"; import { ApiError, adminLogout, adminSignInUrl, clearAdminBookmark, getErrorMessage, isAdminAccessDisabledError, listAdminDomains, listAdminInboxes, type AdminDomain, type AdminInbox, } from "@/client/lib/api"; const ERROR_COPY: Record = { ADMIN_ACCESS_DISABLED: "Admin access is unavailable because tessera OIDC is not configured or cannot be discovered.", invalid_request: "Sign-in request was missing required parameters.", invalid_state: "Sign-in handshake state was invalid or expired. Try signing in again.", missing_state: "Sign-in handshake cookie was missing. Try signing in again.", token_exchange_failed: "tessera rejected the authorization code. Try signing in again.", invalid_id_token: "tessera returned an unexpected ID token. Try signing in again.", not_operator: "This tessera account is not authorized for admin access.", session_create_failed: "Could not create the admin session. Try signing in again.", }; function describeError(code: string | null) { if (!code) { return null; } return ERROR_COPY[code] ?? "Sign-in failed. Try again."; } export function AdminLogin() { const [searchParams, setSearchParams] = useSearchParams(); const initialError = describeError(searchParams.get("error")); const initialErrorRef = useRef(initialError); const [authenticated, setAuthenticated] = useState(false); const [bootLoading, setBootLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [accessDisabled, setAccessDisabled] = useState(false); const [error, setError] = useState(initialError); const [domains, setDomains] = useState([]); const [inboxes, setInboxes] = useState([]); const reload = useCallback(async () => { const [nextDomains, nextInboxes] = await Promise.all([listAdminDomains(), listAdminInboxes()]); setDomains(nextDomains); setInboxes(nextInboxes); }, []); const reset = useCallback((message?: string) => { clearAdminBookmark(); setAuthenticated(false); setDomains([]); setInboxes([]); setError(message ?? null); }, []); useEffect(() => { let active = true; const boot = async () => { try { await reload(); if (!active) return; setAuthenticated(true); setError(null); } catch (nextError) { if (!active) return; if (isAdminAccessDisabledError(nextError)) { setAccessDisabled(true); reset(getErrorMessage(nextError)); return; } if (nextError instanceof ApiError && (nextError.status === 401 || nextError.status === 403)) { // Cookie missing or rejected; keep the existing error from // ?error= if present, otherwise stay quiet. reset(initialErrorRef.current ?? undefined); return; } reset(getErrorMessage(nextError)); } finally { if (active) { setBootLoading(false); } } }; void boot(); return () => { active = false; }; }, [reload, reset]); // Drop ?error= from the URL once we have rendered it once so a refresh // after a successful sign-in does not re-show the banner. useEffect(() => { if (!searchParams.get("error")) { return; } const next = new URLSearchParams(searchParams); next.delete("error"); setSearchParams(next, { replace: true }); }, [searchParams, setSearchParams]); const handleReload = useCallback(async () => { setRefreshing(true); try { await reload(); setError(null); setAccessDisabled(false); } catch (nextError) { if (isAdminAccessDisabledError(nextError)) { setAccessDisabled(true); reset(getErrorMessage(nextError)); throw nextError; } if (nextError instanceof ApiError && (nextError.status === 401 || nextError.status === 403)) { reset(); throw nextError; } setError(getErrorMessage(nextError)); throw nextError; } finally { setRefreshing(false); } }, [reload, reset]); const handleLogout = useCallback(async () => { try { await adminLogout(); reset(); toast.info("Admin session cleared"); } catch (nextError) { toast.error(getErrorMessage(nextError)); } }, [reset]); if (bootLoading) { return (
Loading admin console...
); } return (
{authenticated ? (

Admin console

Authenticated via tessera
) : (
Reserved Access

Admin console

Sign in with tessera to manage domains, inspect temporary inboxes, and browse permanent inboxes.

Admin access is limited to operators allowlisted in tessera.

{accessDisabled ? ( ) : ( Sign in with tessera )} {error ? {error} : null}
)} {authenticated ? (
) : null}
); }