2025-12-03 21:56:50 +00:00
|
|
|
import { Navigate } from 'react-router-dom';
|
|
|
|
|
import { useAuth } from '@/features/auth/hooks/useAuth';
|
2025-12-17 14:15:45 +00:00
|
|
|
import { TokenStorage } from '@/services/tokenStorage';
|
|
|
|
|
import { useEffect, useState } from 'react';
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
interface ProtectedRouteProps {
|
|
|
|
|
children: React.ReactNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Composant de protection des routes authentifiées.
|
|
|
|
|
* Redirige vers /login si l'utilisateur n'est pas authentifié.
|
2025-12-17 14:15:45 +00:00
|
|
|
* Vérifie à la fois le store et le token dans localStorage pour éviter les problèmes de timing.
|
2025-12-03 21:56:50 +00:00
|
|
|
*/
|
|
|
|
|
export function ProtectedRoute({ children }: ProtectedRouteProps) {
|
2025-12-17 14:15:45 +00:00
|
|
|
const { isAuthenticated, user } = useAuth();
|
|
|
|
|
const [isChecking, setIsChecking] = useState(true);
|
|
|
|
|
const hasToken = !!TokenStorage.getAccessToken();
|
2025-12-03 21:56:50 +00:00
|
|
|
|
2025-12-17 14:15:45 +00:00
|
|
|
useEffect(() => {
|
|
|
|
|
// Donner un peu de temps pour que le store se hydrate
|
|
|
|
|
const timer = setTimeout(() => {
|
|
|
|
|
setIsChecking(false);
|
|
|
|
|
}, 100);
|
|
|
|
|
return () => clearTimeout(timer);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// Si on vérifie encore, attendre un peu
|
|
|
|
|
if (isChecking) {
|
|
|
|
|
return null; // ou un spinner
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Vérifier à la fois le store et le token
|
|
|
|
|
// Si le token existe mais le store n'est pas encore hydraté, on attend
|
|
|
|
|
const isAuth = isAuthenticated || (hasToken && user);
|
|
|
|
|
|
|
|
|
|
if (!isAuth) {
|
2025-12-03 21:56:50 +00:00
|
|
|
return <Navigate to="/login" replace />;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return <>{children}</>;
|
2025-12-13 02:34:34 +00:00
|
|
|
}
|