import { ReactNode, useEffect, useRef, useState } from "react"; import { Link, NavLink, useNavigate } from "react-router-dom"; import { useAuth } from "../context/AuthContext"; import { useNotifications } from "../context/NotificationsContext"; import { NotificationBell } from "./NotificationBell"; import { Sheet } from "./Sheet"; import { AgentsIcon, BellIcon, HomeIcon, LogOutIcon, RequestsIcon, SettingsIcon, ShieldIcon, } from "./icons"; const navItems = [ { to: "/", label: "Dashboard", end: true }, { to: "/requests", label: "Requests" }, { to: "/agents", label: "Agents" }, { to: "/settings", label: "Settings" }, ]; const tabs = [ { to: "/", label: "Home", Icon: HomeIcon, end: true }, { to: "/requests", label: "Requests", Icon: RequestsIcon }, { to: "/agents", label: "Agents", Icon: AgentsIcon }, { to: "/notifications", label: "Alerts", Icon: BellIcon, badge: true }, { to: "/settings", label: "Settings", Icon: SettingsIcon }, ]; export function Layout({ children }: { children: ReactNode }) { const { user } = useAuth(); return (
PatchPass
{/* Below md the bell is replaced by the Alerts tab. */}
{children}
{/* Keeps the last of the page clear of the fixed tab bar. */}
); } function BottomTabs() { const { unreadCount } = useNotifications(); return ( ); } function AccountMenu() { const { user, logout } = useAuth(); const navigate = useNavigate(); const [open, setOpen] = useState(false); const ref = useRef(null); useEffect(() => { if (!open) return; const onDown = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false); }; document.addEventListener("mousedown", onDown); return () => document.removeEventListener("mousedown", onDown); }, [open]); const signOut = async () => { setOpen(false); await logout(); navigate("/login"); }; const initial = user?.display_name?.[0]?.toUpperCase() ?? "?"; return (
{/* Desktop: dropdown. */} {open && (
setOpen(false)}> Settings {user?.role === "ADMIN" && ( setOpen(false)} accent> Admin )}
)} {/* Mobile: bottom sheet, which is reachable one-handed. */}
setOpen(false)} padded={false}>
{initial}

{user?.display_name}

@{user?.username}

} label="Settings" onClick={() => { setOpen(false); navigate("/settings"); }} /> {user?.role === "ADMIN" && ( } label="Admin" accent onClick={() => { setOpen(false); navigate("/admin"); }} /> )} } label="Log out" danger onClick={signOut} />
); } function MenuLink({ to, onClick, accent, children, }: { to: string; onClick: () => void; accent?: boolean; children: ReactNode; }) { return ( {children} ); } function SheetRow({ icon, label, onClick, accent, danger, }: { icon: ReactNode; label: string; onClick: () => void; accent?: boolean; danger?: boolean; }) { return ( ); }