"use client"; import React from "react"; import { useRouter } from "next/navigation"; import { getMe } from "@/lib/frontend/apiClient"; import { buildLoginUrl, LOGIN_REASONS } from "@/lib/frontend/authRedirect"; import { AuthProvider as AuthContextProvider } from "@/components/auth/authContext"; /** * AuthProvider (RHL-020 / RHL-032) * * RHL-032 improvement: * - When revalidating while already authenticated, we keep: * - status="authenticated" * - user != null * - and only flip `isValidating=true` * * This prevents AuthGate from rendering the "Sitzung wird geprüft" content card * during fast navigations (branch switch), eliminating flicker. */ export default function AuthProvider({ children }) { const router = useRouter(); // Prevent double redirects in quick re-renders. const didRedirectRef = React.useRef(false); // Auth state exposed via context. const [auth, setAuth] = React.useState({ status: "loading", user: null, error: null, isValidating: false, }); // Retry tick triggers a refetch without tying auth checks to route changes. const [retryTick, setRetryTick] = React.useState(0); const retry = React.useCallback(() => { setRetryTick((n) => n + 1); }, []); React.useEffect(() => { let cancelled = false; async function runSessionCheck() { // If we already have a valid authenticated session, revalidate in the background: // keep content stable and only set isValidating=true. setAuth((prev) => { const hasUser = prev.status === "authenticated" && prev.user; if (hasUser) { return { ...prev, error: null, isValidating: true }; } return { status: "loading", user: null, error: null, isValidating: false, }; }); try { const res = await getMe(); if (cancelled) return; if (res?.user) { didRedirectRef.current = false; setAuth({ status: "authenticated", user: res.user, error: null, isValidating: false, }); return; } // Unauthenticated session (frontend-friendly endpoint returns 200 + user:null). setAuth({ status: "unauthenticated", user: null, error: null, isValidating: false, }); if (!didRedirectRef.current) { didRedirectRef.current = true; const next = typeof window !== "undefined" ? `${window.location.pathname}${window.location.search}` : "/"; const loginUrl = buildLoginUrl({ reason: LOGIN_REASONS.EXPIRED, next, }); router.replace(loginUrl); } } catch (err) { if (cancelled) return; // If we were already authenticated, fail open: // keep the last known user/session and just end validating. setAuth((prev) => { const hasUser = prev.status === "authenticated" && prev.user; if (hasUser) { return { ...prev, isValidating: false }; } // Initial load failed -> show error state (AuthGate handles it). return { status: "error", user: null, error: "Sitzung konnte nicht geprüft werden. Bitte erneut versuchen.", isValidating: false, }; }); } } runSessionCheck(); return () => { cancelled = true; }; }, [router, retryTick]); return ( {children} ); }