import { useEffect, useRef } from 'react'; import { Navigate } from 'react-router-dom'; import { useAuthStore } from '../store/auth'; interface Props { children: React.ReactNode; requireAdmin?: boolean; requireTeamAdmin?: boolean; requireTeamMember?: boolean; } export function ProtectedRoute({ children, requireAdmin, requireTeamAdmin, requireTeamMember }: Props) { const isAuthenticated = useAuthStore((s) => s.isAuthenticated); const isLoading = useAuthStore((s) => s.isLoading); const user = useAuthStore((s) => s.user); const mustChangePassword = useAuthStore((s) => s.mustChangePassword); const fetchUserInfo = useAuthStore((s) => s.fetchUserInfo); const retrying = useRef(false); // If we have a token but user info hasn't loaded, keep retrying useEffect(() => { if (!isAuthenticated || user || isLoading) return; if (retrying.current) return; retrying.current = true; let cancelled = false; const retry = async () => { let delay = 500; while (!cancelled) { try { await fetchUserInfo(); break; // success } catch { await new Promise(r => setTimeout(r, delay)); delay = Math.min(delay * 2, 3000); } } retrying.current = false; }; retry(); return () => { cancelled = true; }; }, [isAuthenticated, user, isLoading, fetchUserInfo]); if (isLoading || (isAuthenticated && !user)) { return (
加载中...
); } if (!isAuthenticated) { return ; } if (mustChangePassword) { return ; } if (requireAdmin && user?.role !== 'super_admin') { return ; } if (requireTeamAdmin && user?.role !== 'team_admin') { return ; } // requireTeamMember: must have a team (team_admin or member) if (requireTeamMember && user?.role === 'super_admin') { return ; } return <>{children}; }