diff --git a/apps/backoffice/src/app/router/LandingRoute.tsx b/apps/backoffice/src/app/router/LandingRoute.tsx index 776bf01f8..c353e91d5 100644 --- a/apps/backoffice/src/app/router/LandingRoute.tsx +++ b/apps/backoffice/src/app/router/LandingRoute.tsx @@ -1,13 +1,12 @@ -import Cookies from 'js-cookie'; import { LandingPage } from '@ema-platform/ui'; -import { authStorage } from '@ema-platform/auth'; +import { useAuthToken } from '@ema-platform/auth'; /** * Public `/` — mounts the shared landing page. Backoffice has no /signup * (enableSignup: false) and no /verify route, so those props are omitted. */ export function LandingRoute() { - const token = authStorage.getToken() ?? Cookies.get('auth-token'); + const token = useAuthToken(); return ; } diff --git a/apps/portal/src/app/components/LandingRoute.tsx b/apps/portal/src/app/components/LandingRoute.tsx index 39f419253..8bab1d394 100644 --- a/apps/portal/src/app/components/LandingRoute.tsx +++ b/apps/portal/src/app/components/LandingRoute.tsx @@ -1,15 +1,14 @@ -import Cookies from 'js-cookie'; import { LandingPage } from '@ema-platform/ui'; -import { authStorage } from '@ema-platform/auth'; +import { useAuthToken } from '@ema-platform/auth'; /** * Public `/` — mounts the shared landing page with portal-specific routes. - * Auth state is read the same way ProtectedRoute does (token cookie or - * storage fallback) so the header can show "Go to dashboard" instead of - * Login/Sign Up without gating the route itself. + * Auth state is read via `useAuthToken`, the same hook ProtectedRoute uses, + * so the header can show "Go to dashboard" instead of Login/Sign Up without + * gating the route itself. */ export function LandingRoute() { - const token = authStorage.getToken() ?? Cookies.get('auth-token'); + const token = useAuthToken(); return ; } diff --git a/libs/auth/src/index.ts b/libs/auth/src/index.ts index 886e79d3b..a0f46f25f 100644 --- a/libs/auth/src/index.ts +++ b/libs/auth/src/index.ts @@ -25,6 +25,7 @@ export { resetSignup, } from "./lib/store/signup.slice"; export { usePermissions } from "./lib/hooks/usePermissions"; +export { useAuthToken } from "./lib/hooks/useAuthToken"; export type { PermissionSet } from "./lib/hooks/usePermissions"; export { RequirePermission } from "./lib/components/RequirePermission"; export { diff --git a/libs/auth/src/lib/components/ProtectedRoute.tsx b/libs/auth/src/lib/components/ProtectedRoute.tsx index 9c55d85ee..5321a5889 100644 --- a/libs/auth/src/lib/components/ProtectedRoute.tsx +++ b/libs/auth/src/lib/components/ProtectedRoute.tsx @@ -1,7 +1,6 @@ -import Cookies from 'js-cookie'; import { Navigate, Outlet, useLocation } from 'react-router-dom'; import type { ReactNode } from 'react'; -import { authStorage } from '../utils/auth-storage'; +import { useAuthToken } from '../hooks/useAuthToken'; interface ProtectedRouteProps { children?: ReactNode; @@ -10,7 +9,7 @@ interface ProtectedRouteProps { export function ProtectedRoute({ children, loginPath = '/login' }: ProtectedRouteProps) { const location = useLocation(); - const token = authStorage.getToken() ?? Cookies.get('auth-token'); + const token = useAuthToken(); if (!token) { return ; diff --git a/libs/auth/src/lib/hooks/useAuthToken.ts b/libs/auth/src/lib/hooks/useAuthToken.ts new file mode 100644 index 000000000..c6b75bdb9 --- /dev/null +++ b/libs/auth/src/lib/hooks/useAuthToken.ts @@ -0,0 +1,15 @@ +import { useSelector } from 'react-redux'; +import { authStorage } from '../utils/auth-storage'; +import type { AuthState } from '../types/auth.types'; + +/** + * The current auth token, preferring Redux so components re-render on login + * and logout. Falls back to storage for the one case Redux misses: both + * `hydrateAuth` and the stores' `preloadedState` only populate `auth.token` + * when a token *and* a cached user are present, so a session with a token but + * no cached user would otherwise read as signed out. + */ +export function useAuthToken(): string | undefined { + const token = useSelector((state: { auth: AuthState }) => state.auth.token); + return token ?? authStorage.getToken(); +}