/** * AuthSplash — full-screen auth interstitial (D-10 + D-11, Plan 06-05). * * Replaces the optimistic calendar/skeleton/alert renders while auth state is * unknown (loading) or failing (redirecting), and surfaces the session-expired * interstitial for mid-use 401s. * * States: * loading — initial cold load; meQuery is still pending. Spin + "Signing you in". * redirecting — meQuery failed (cold load OR session-expiry); maybeRedirectToLogin() * already fired (or the session-expiry handler fired it). Spin + * heading/body driven by `copy` prop (defaults to cold-load copy). * dead-end — one-shot guard has already fired; redirect failed or guard is exhausted. * No spinner; "Sign-in required. Tap here to try again." * * Copy contract (UI-SPEC §Copywriting Contract §Surface 1 + §Surface 2): * loading: heading="Signing you in" body="Taking you to the sign-in page…" * redirecting: same defaults (or "Session expired" / "Signing you back in…" via props) * dead-end: "Sign-in required. Tap here to try again." (tap calls clearLoginRedirect + maybeRedirectToLogin) * * Layout analog: SkeletonCalendar.tsx — full-screen centered column, inline styles only. */ import { Loader2 } from 'lucide-react'; import { clearLoginRedirect, maybeRedirectToLogin } from '../lib/loginRedirect.js'; export type AuthSplashState = 'loading' | 'redirecting' | 'dead-end'; export interface AuthSplashProps { state: AuthSplashState; /** * Override the heading for the loading/redirecting states. * Defaults to "Signing you in" (cold-load copy per UI-SPEC §Surface 1). */ heading?: string; /** * Override the body text for the loading/redirecting states. * Defaults to "Taking you to the sign-in page…" (cold-load copy per UI-SPEC §Surface 1). */ body?: string; /** * When true, renders with position:fixed inset:0 z-index:999 so the splash * covers the entire viewport including the persistent AppNav (FIX 3). * Use this when CalendarShell (a child of the app shell) needs to show an * auth interstitial that hides the nav chrome. */ overlay?: boolean; } export function AuthSplash({ state, heading = 'Signing you in', body = 'Taking you to the sign-in page…', overlay = false, }: AuthSplashProps) { const isDeadEnd = state === 'dead-end'; const showSpinner = !isDeadEnd; return (
{showSpinner && (
); }