import {useEffect, useRef} from 'react'; import {Navigate, Outlet, useLocation} from 'react-router-dom'; import useSessionExpired from '../hooks/useSessionExpired.js'; import {sessionEvents} from '../utils/api.js'; import {hasSession} from '../utils/auth.js'; /** * Layout route of the pages that need a login. Without a session it opens the login page, which comes back here; * a 401 on one of these pages ends the session (see apiFetch). */ export default function RequireSession() { const {pathname, search} = useLocation(); const expireSession = useSessionExpired(); // In a ref, so the listener is added once and not again on every navigation. const expireRef = useRef(expireSession); expireRef.current = expireSession; // A render before the login page shows must not redirect again without the "session expired" state. const expiring = useRef(false); useEffect(() => { // Parallel requests each fire; only the first ends the session. Another tab may have removed the flag already. const onExpired = () => { if (expiring.current) return; expiring.current = true; expireRef.current(); }; sessionEvents.addEventListener('expired', onExpired); return () => sessionEvents.removeEventListener('expired', onExpired); }, []); return hasSession() || expiring.current ? : ; }