import { useEffect } from 'react'; import { Navigate, Outlet, useLocation } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { useAuth } from '@/hooks/useAuth'; import { useToast } from '@/hooks/useToast'; import type { Role } from '@/api/types'; import { LoadingState } from './LoadingState'; interface ProtectedRouteProps { /** Allowed roles. If omitted, any authenticated user passes. */ roles?: Role[]; /** Where to send users who lack the required role. */ redirectOnRoleDenied?: string; } /** * Gate component: handles auth + role checks before rendering nested routes. * - No token / no user → /login * - Wrong role → redirect + "Accès refusé" toast (AC-3.7) */ export function ProtectedRoute({ roles, redirectOnRoleDenied = '/engagements', }: ProtectedRouteProps): JSX.Element { const { user, status } = useAuth(); const { push } = useToast(); const { t } = useTranslation(); const location = useLocation(); const roleDenied = Boolean( status === 'authenticated' && user && roles && !roles.includes(user.role), ); useEffect(() => { if (roleDenied) { push(t('auth.forbidden'), 'error'); } }, [roleDenied, push, t]); if (status === 'loading') { return ; } if (status === 'unauthenticated' || !user) { return ; } if (roleDenied) { return ; } return ; }