diff --git a/src/components/AdminShell.tsx b/src/components/AdminShell.tsx index 470f346..bb27423 100644 --- a/src/components/AdminShell.tsx +++ b/src/components/AdminShell.tsx @@ -14,6 +14,7 @@ import AdminSidebar from "./AdminSidebar"; import { isExternalIdentity } from "~/lib/admin-auth"; import { clearAdminSession, hasAdminSession, setAdminSession } from "~/lib/admin-session"; import { normalizeAllowedModules } from "~/lib/admin/module-access"; +import { sessionExpired, clearSessionExpired, installSessionExpiryWatcher } from "~/lib/session-expired"; type Tab = { href: string; label: string; exact?: boolean }; type SearchResult = { id: string; title: string; subtitle: string; href: string }; @@ -476,7 +477,21 @@ export default function AdminShell(props: { children: JSX.Element }) { } }); + const goToLoginAfterExpiry = () => { + clearSessionExpired(); + if (typeof sessionStorage !== "undefined") { + sessionStorage.removeItem("nxtgauge_admin_access_token"); + sessionStorage.removeItem("nxtgauge_admin_preview"); + } + clearAdminSession(); + navigate(`/login?from=${encodeURIComponent(location.pathname + location.search)}`, { + replace: true, + }); + }; + onMount(() => { + installSessionExpiryWatcher(); + const savedTheme = ( typeof localStorage !== "undefined" ? localStorage.getItem("nxtgauge_admin_theme") : null ) as "light" | "dark" | null; @@ -667,6 +682,41 @@ export default function AdminShell(props: { children: JSX.Element }) { color: isDark() ? "#E5E7EB" : "#0D0D2A", }} > + +
+
+

+ You have been logged out +

+

+ Your session has expired for security reasons. Please log in again to continue. +

+ +
+
+
+ ) => { + const response = await originalFetch(...args); + if (response.status === 401) { + const hadToken = + typeof sessionStorage !== 'undefined' && + Boolean(sessionStorage.getItem('nxtgauge_admin_access_token')); + // Only treat this as a session expiry if we were actually holding a token — + // otherwise this is just a normal pre-login 401 (e.g. a failed login attempt). + if (hadToken) markSessionExpired(); + } + return response; + }; +}