import { useQuery } from "@tanstack/react-query"; import { BadgeCheck, ChevronDown, ClipboardCheck, LayoutDashboard, LogOut, Moon, NotebookTabs, ShieldHalf, Sun, User as UserIcon, } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { useAuth } from "react-oidc-context"; import { NavLink, Outlet, useLocation, useNavigate } from "react-router-dom"; import { fetchMe } from "../../features/auth/authApi"; import { t } from "../../lib/i18n"; import { resolveProfileRole } from "../../lib/role"; import { shouldAttemptSlidingSessionRenew, shouldAttemptUnlimitedSessionRenew, } from "../../lib/sessionSliding"; import { applyShellTheme, buildShellProfileSummary, buildShellSessionStatus, readShellSessionExpiryEnabled, readShellTheme, shellLayoutClasses, writeShellSessionExpiryEnabled, } from "../../../../common/shell"; import LanguageSelector from "../common/LanguageSelector"; import { Toaster } from "../ui/toaster"; const navItems = [ { labelKey: "ui.dev.nav.overview", labelFallback: "Overview", to: "/", icon: LayoutDashboard, }, { labelKey: "ui.dev.nav.clients", labelFallback: "Clients", to: "/clients", icon: ShieldHalf, }, { labelKey: "ui.dev.nav.developer_request", labelFallback: "Developer Access Request", to: "/developer-requests", icon: ClipboardCheck, }, { labelKey: "ui.dev.nav.audit_logs", labelFallback: "Audit Logs", to: "/audit-logs", icon: NotebookTabs, }, ]; function AppLayout() { const auth = useAuth(); const location = useLocation(); const navigate = useNavigate(); const profileMenuRef = useRef(null); const isRenewInFlightRef = useRef(false); const lastRenewAttemptAtRef = useRef(0); const lastVisitedRouteRef = useRef(null); const [theme, setTheme] = useState<"light" | "dark">(readShellTheme); const [isProfileMenuOpen, setIsProfileMenuOpen] = useState(false); const [isSessionExpiryEnabled, setIsSessionExpiryEnabled] = useState( readShellSessionExpiryEnabled, ); const [nowMs, setNowMs] = useState(() => Date.now()); const hasAccessToken = Boolean(auth.user?.access_token); const { data: profile } = useQuery({ queryKey: ["userMe"], queryFn: fetchMe, enabled: hasAccessToken, }); const handleLogout = () => { if ( window.confirm( t("msg.dev.logout_confirm", "Are you sure you want to log out?"), ) ) { auth.removeUser(); navigate("/login"); } }; useEffect(() => { applyShellTheme(theme); }, [theme]); useEffect(() => { const timer = window.setInterval(() => { setNowMs(Date.now()); }, 1000); return () => { window.clearInterval(timer); }; }, []); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( profileMenuRef.current && !profileMenuRef.current.contains(event.target as Node) ) { setIsProfileMenuOpen(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, []); useEffect(() => { const maybeRenewSession = async () => { const now = Date.now(); if ( !shouldAttemptSlidingSessionRenew({ expiresAtSec: auth.user?.expires_at, nowMs: now, isEnabled: isSessionExpiryEnabled, isAuthenticated: auth.isAuthenticated, isLoading: auth.isLoading, isRenewInFlight: isRenewInFlightRef.current, lastAttemptAtMs: lastRenewAttemptAtRef.current, }) ) { return; } isRenewInFlightRef.current = true; lastRenewAttemptAtRef.current = now; try { await auth.signinSilent(); } catch (error) { console.error("Silent session renewal failed.", error); } finally { isRenewInFlightRef.current = false; } }; const handleUserAction = () => { void maybeRenewSession(); }; window.addEventListener("pointerdown", handleUserAction); window.addEventListener("keydown", handleUserAction); return () => { window.removeEventListener("pointerdown", handleUserAction); window.removeEventListener("keydown", handleUserAction); }; }, [ auth, auth.isAuthenticated, auth.isLoading, auth.user?.expires_at, isSessionExpiryEnabled, ]); useEffect(() => { const maybeKeepSessionAlive = async () => { const now = Date.now(); if ( !shouldAttemptUnlimitedSessionRenew({ expiresAtSec: auth.user?.expires_at, nowMs: now, isEnabled: isSessionExpiryEnabled, isAuthenticated: auth.isAuthenticated, isLoading: auth.isLoading, isRenewInFlight: isRenewInFlightRef.current, lastAttemptAtMs: lastRenewAttemptAtRef.current, }) ) { return; } isRenewInFlightRef.current = true; lastRenewAttemptAtRef.current = now; try { await auth.signinSilent(); } catch (error) { console.error("Unlimited session keepalive renewal failed.", error); } finally { isRenewInFlightRef.current = false; } }; const timer = window.setInterval(() => { void maybeKeepSessionAlive(); }, 30_000); void maybeKeepSessionAlive(); return () => { window.clearInterval(timer); }; }, [ auth, auth.isAuthenticated, auth.isLoading, auth.user?.expires_at, isSessionExpiryEnabled, ]); useEffect(() => { const routeKey = `${location.pathname}${location.search}${location.hash}`; if (lastVisitedRouteRef.current === null) { lastVisitedRouteRef.current = routeKey; return; } if (lastVisitedRouteRef.current === routeKey) { return; } lastVisitedRouteRef.current = routeKey; const now = Date.now(); if ( !shouldAttemptSlidingSessionRenew({ expiresAtSec: auth.user?.expires_at, nowMs: now, isEnabled: isSessionExpiryEnabled, isAuthenticated: auth.isAuthenticated, isLoading: auth.isLoading, isRenewInFlight: isRenewInFlightRef.current, lastAttemptAtMs: lastRenewAttemptAtRef.current, }) ) { return; } isRenewInFlightRef.current = true; lastRenewAttemptAtRef.current = now; void auth .signinSilent() .catch((error) => { console.error("Silent session renewal failed.", error); }) .finally(() => { isRenewInFlightRef.current = false; }); }, [ auth, auth.isAuthenticated, auth.isLoading, auth.user?.expires_at, isSessionExpiryEnabled, location.hash, location.pathname, location.search, ]); const toggleTheme = () => { setTheme((prev) => (prev === "light" ? "dark" : "light")); }; const profileSummary = buildShellProfileSummary({ profileName: profile?.name || auth.user?.profile?.name?.toString() || auth.user?.profile?.preferred_username?.toString() || auth.user?.profile?.nickname?.toString(), profileEmail: profile?.email || auth.user?.profile?.email?.toString(), fallbackName: t("ui.dev.profile.unknown_name", "Unknown User"), fallbackEmail: t("ui.dev.profile.unknown_email", "unknown@example.com"), }); const currentRole = resolveProfileRole( auth.user?.profile as Record | undefined, ); const displayRoleKey = profile?.role || currentRole; const sessionStatus = buildShellSessionStatus({ expiresAtSec: auth.user?.expires_at, nowMs, t, }); const handleSessionExpiryToggle = () => { setIsSessionExpiryEnabled((prev) => { const next = !prev; writeShellSessionExpiryEnabled(next); return next; }); }; return (

{t("ui.dev.header.plane", "Dev Plane")}

{t("ui.dev.header.subtitle", "Manage your applications")}
{isSessionExpiryEnabled ? ( {sessionStatus.text} ) : null}
{isProfileMenuOpen ? (

{t("ui.dev.profile.menu_title", "Account")}

{profileSummary.name}

{profileSummary.email}

{t( `ui.admin.role.${displayRoleKey}`, displayRoleKey.toUpperCase(), )}

{t("ui.dev.session.auto_extend", "Session expiry")}

{isSessionExpiryEnabled ? sessionStatus.text : t( "ui.dev.session.disabled", "Session expiry disabled", )}

) : null}
); } export default AppLayout;