CI / quality (push) Waiting to run
- Add src/core/ (config, errors, events, http, observability, storage, query) - Add src/Spreadsheet/ engine with native POI backend and Excel bridge - Add Envelope C spreadsheet flow and tender bidding envelope modules - Consolidate components into src/components/, remove legacy Component/ and Hooks/ - Add registration state/validation, auth session guard, profile edit modules - Add unit tests across axios, redux, bidding, registration, encryption, core - Add CI workflow, docs (architecture, audit, DSC API spec), keystore example - Remove tracked keystore binary; ignore scripts.zip Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
33 lines
1.2 KiB
TypeScript
33 lines
1.2 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
import { useSelector } from 'react-redux';
|
|
import { selectIsAuthenticated } from '../Redux/Slices/Token';
|
|
import NavigationString from '../Constant/NavigationString';
|
|
import { resetAndNavigate } from './NavigationService';
|
|
import { logger } from '../core/observability/logger';
|
|
|
|
/**
|
|
* Declarative auth gate: whenever an existing session ends — a 401 clearing
|
|
* the token via the auth/unauthorized event, an explicit logout, or a
|
|
* keychain wipe — reset navigation to Login.
|
|
*
|
|
* Historically a mid-session 401 cleared the token but left the user
|
|
* stranded on an authenticated screen where every request failed silently.
|
|
* Renders nothing; mount once inside the Redux provider.
|
|
*/
|
|
const AuthSessionGuard = () => {
|
|
const isAuthenticated = useSelector(selectIsAuthenticated);
|
|
const wasAuthenticated = useRef(isAuthenticated);
|
|
|
|
useEffect(() => {
|
|
if (wasAuthenticated.current && !isAuthenticated) {
|
|
logger.info('auth', 'session ended — routing to Login');
|
|
resetAndNavigate(NavigationString.Login);
|
|
}
|
|
wasAuthenticated.current = isAuthenticated;
|
|
}, [isAuthenticated]);
|
|
|
|
return null;
|
|
};
|
|
|
|
export default AuthSessionGuard;
|