diff --git a/susconecta/components/ProtectedRoute.tsx b/susconecta/components/ProtectedRoute.tsx index 31e9633..5f7945b 100644 --- a/susconecta/components/ProtectedRoute.tsx +++ b/susconecta/components/ProtectedRoute.tsx @@ -8,16 +8,54 @@ import { USER_TYPE_ROUTES, LOGIN_ROUTES, AUTH_STORAGE_KEYS } from '@/types/auth' interface ProtectedRouteProps { children: React.ReactNode requiredUserType?: UserType[] + requiredRoles?: string[] } export default function ProtectedRoute({ children, - requiredUserType + requiredUserType, + requiredRoles }: ProtectedRouteProps) { const { authStatus, user } = useAuth() const router = useRouter() const isRedirecting = useRef(false) const [mounted, setMounted] = useState(false) + const [accessDenied, setAccessDenied] = useState(false) + + // Computa permissões de forma síncrona a partir do user e dos roles/userType + const computeHasPermission = () => { + // sem requisitos, permite + if ((!requiredUserType || requiredUserType.length === 0) && (!requiredRoles || requiredRoles.length === 0)) return true + if (!user) return false + + const userRoles = (user as any).roles || [] + + // checa requiredRoles (strings arbitrárias de papéis) + const rolesOk = requiredRoles && requiredRoles.length > 0 + ? requiredRoles.some((req: string) => { + if (user.userType === req) return true + if (req === 'profissional' && (userRoles.includes('medico') || userRoles.includes('enfermeiro'))) return true + if (req === 'administrador' && (userRoles.includes('admin') || userRoles.includes('gestor') || userRoles.includes('secretaria'))) return true + if (req === 'paciente' && userRoles.includes('paciente')) return true + return userRoles.includes(req) + }) + : false + + // checa requiredUserType (compatibilidade com tipos altos do sistema) + const userTypeOk = requiredUserType && requiredUserType.length > 0 + ? requiredUserType.some((req: UserType) => { + if (user.userType === req) return true + if (req === 'profissional' && (userRoles.includes('medico') || userRoles.includes('enfermeiro'))) return true + if (req === 'administrador' && (userRoles.includes('admin') || userRoles.includes('gestor') || userRoles.includes('secretaria'))) return true + if (req === 'paciente' && userRoles.includes('paciente')) return true + return userRoles.includes(req) + }) + : false + + return rolesOk || userTypeOk + } + + const hasPermission = computeHasPermission() useEffect(() => { // marca que o componente já montou no cliente @@ -61,18 +99,15 @@ export default function ProtectedRoute({ } // Se autenticado mas não tem permissão para esta página - if (authStatus === 'authenticated' && user && requiredUserType && !requiredUserType.includes(user.userType)) { - isRedirecting.current = true - - console.log('[PROTECTED-ROUTE] Usuário SEM permissão para esta página', { + if (authStatus === 'authenticated' && user && requiredUserType && !hasPermission) { + console.log('[PROTECTED-ROUTE] Usuário SEM permissão para esta página (accessDenied)', { userType: user.userType, + userRoles: (user as any).roles || [], requiredTypes: requiredUserType }) - - const correctRoute = USER_TYPE_ROUTES[user.userType] - console.log('[PROTECTED-ROUTE] Redirecionando para área correta:', correctRoute) - - router.push(correctRoute) + + // Marcar acesso negado para renderizar fallback sem redirecionamentos/speinners infinitos + setAccessDenied(true) return } @@ -85,7 +120,7 @@ export default function ProtectedRoute({ }) isRedirecting.current = false } - }, [authStatus, user, requiredUserType, router]) + }, [authStatus, user, requiredUserType, router, hasPermission]) // Durante loading, mostrar spinner if (authStatus === 'loading') { @@ -102,8 +137,8 @@ export default function ProtectedRoute({ ) } - // Se não autenticado ou redirecionando, mostrar spinner - if (authStatus === 'unauthenticated' || isRedirecting.current) { + // Se não autenticado ou redirecionando para login, mostrar spinner + if (authStatus === 'unauthenticated' || (isRedirecting.current && !accessDenied)) { // evitar render no servidor para não causar mismatch de hidratação if (!mounted) return null @@ -117,8 +152,8 @@ export default function ProtectedRoute({ ) } - // Se usuário não tem permissão, mostrar fallback (não deveria chegar aqui devido ao useEffect) - if (requiredUserType && user && !requiredUserType.includes(user.userType)) { + // Se usuário não tem permissão, mostrar fallback (baseado em hasPermission) + if (requiredUserType && user && !hasPermission) { return (