'use client'; import React from 'react'; import { useAuth } from '../contexts/AuthContext'; import { useKeycloak } from '../contexts/KeycloakContext'; import LoadingSpinner from './ui/LoadingSpinner'; import { useRouter, useSearchParams, usePathname } from 'next/navigation'; import { useEffect, useRef, useMemo } from 'react'; interface ProtectedLayoutProps { children: React.ReactNode; requiredRoles?: string[]; requiredPermissions?: string[]; } const ProtectedLayout: React.FC = ({ children, requiredRoles = [], requiredPermissions = [] }) => { const { isAuthenticated, isLoading, user, hasRole, hasPermission } = useAuth(); const { keycloak } = useKeycloak(); const router = useRouter(); const searchParams = useSearchParams(); const pathname = usePathname(); const redirectedRef = useRef(false); // Vérifier s'il y a un code d'autorisation dans l'URL // Utiliser useMemo pour éviter les re-rendus inutiles const hasAuthCode = useMemo(() => { return searchParams.get('code') !== null; }, [searchParams]); useEffect(() => { console.log('🔍 ProtectedLayout useEffect:', { isLoading, isAuthenticated, hasAuthCode, pathname, redirected: redirectedRef.current }); // Ne rediriger qu'une seule fois pour éviter les boucles if (redirectedRef.current) { console.log('⏭️ ProtectedLayout: Redirection déjà effectuée, skip'); return; } if (!isLoading && !isAuthenticated && !hasAuthCode) { // Marquer comme redirigé pour éviter les boucles redirectedRef.current = true; // Rediriger vers Keycloak avec l'URL de retour console.log('🔒 ProtectedLayout: Redirection vers Keycloak'); if (keycloak) { const searchParamsStr = searchParams.toString(); const currentPath = pathname + (searchParamsStr ? `?${searchParamsStr}` : ''); const redirectUri = currentPath && currentPath !== '/' ? `${window.location.origin}${currentPath}` : `${window.location.origin}/dashboard`; keycloak.login({ redirectUri }); } } else if (hasAuthCode) { console.log('🔓 ProtectedLayout: Code d\'autorisation détecté, pas de redirection'); } else if (isAuthenticated) { console.log('✅ ProtectedLayout: Utilisateur authentifié, pas de redirection'); } else if (isLoading) { console.log('⏳ ProtectedLayout: Chargement en cours, pas de redirection'); } }, [isAuthenticated, isLoading, hasAuthCode, pathname, keycloak]); useEffect(() => { if (isAuthenticated && user) { // Vérifier les rôles requis if (requiredRoles.length > 0) { const hasRequiredRole = requiredRoles.some(role => hasRole(role)); if (!hasRequiredRole) { router.push('/'); return; } } // Vérifier les permissions requises if (requiredPermissions.length > 0) { const hasRequiredPermission = requiredPermissions.some(permission => hasPermission(permission)); if (!hasRequiredPermission) { router.push('/'); return; } } } }, [isAuthenticated, user, requiredRoles, requiredPermissions, hasRole, hasPermission, router]); // Affichage pendant le chargement if (isLoading) { return (

Chargement...

); } // Si pas authentifié, vérifier s'il y a un code d'autorisation en cours if (!isAuthenticated) { if (hasAuthCode) { console.log('🔓 ProtectedLayout: Autorisant le rendu car code d\'autorisation présent'); // Laisser le composant se charger pour traiter l'authentification } else { // Pas de code d'autorisation, afficher le message de redirection return (

Redirection vers la connexion...

); } } // Si authentifié mais pas les bonnes permissions, ne rien afficher (redirection en cours) if (user) { if (requiredRoles.length > 0) { const hasRequiredRole = requiredRoles.some(role => hasRole(role)); if (!hasRequiredRole) { return (

Vérification des permissions...

); } } if (requiredPermissions.length > 0) { const hasRequiredPermission = requiredPermissions.some(permission => hasPermission(permission)); if (!hasRequiredPermission) { return (

Vérification des permissions...

); } } } // Afficher le contenu si tout est OK return <>{children}; }; export default ProtectedLayout;