diff --git a/apps/pwa/src/components/CalendarShell.tsx b/apps/pwa/src/components/CalendarShell.tsx index 009f324..3f4ef37 100644 --- a/apps/pwa/src/components/CalendarShell.tsx +++ b/apps/pwa/src/components/CalendarShell.tsx @@ -43,6 +43,7 @@ import { Plus } from 'lucide-react' import { fetchMe, fetchEvents } from '../api/client.js' import { hydrateEvents } from '../lib/hydrateEvents.js' +import { maybeRedirectToLogin, clearLoginRedirect } from '../lib/loginRedirect.js' import { buildCalendarConfig, SX_FIRST_DAY_OF_WEEK } from '../lib/calendarConfig.js' import { useCalendarStore } from '../store/calendarStore.js' import { EventDetailPopover } from './EventDetailPopover.js' @@ -174,6 +175,26 @@ export function CalendarShell() { eventsService.set(sxEvents as Parameters[0]) }, [eventsQuery.data, eventsService]) + // Auth redirect — one-shot full-page nav to /api/login when /api/me fails. + // If this is the first failure, maybeRedirectToLogin() sets a sessionStorage + // flag and navigates the browser to /api/login (top-level nav, no CORS block). + // The page will unmount as the browser navigates. If the flag is already set + // (already bounced through login once and still failing), returns false and the + // existing "Sign-in required" branch below renders. + useEffect(() => { + if (meQuery.isError) { + maybeRedirectToLogin() + } + }, [meQuery.isError]) + + // Clear the one-shot flag on a successful /api/me load so a later session + // expiry can trigger another redirect instead of showing "Sign-in required". + useEffect(() => { + if (meQuery.isSuccess) { + clearLoginRedirect() + } + }, [meQuery.isSuccess]) + // ── Render helpers ──────────────────────────────────────────────────────── // Determine which content to show in the calendar area