import * as React from 'react'; import { useAuth } from './AuthProvider'; export interface ProtectedRouteProps { children: React.ReactNode; /** Component to render while loading */ fallback?: React.ReactNode; /** Component to render if not authenticated */ unauthorized?: React.ReactNode; /** Required role(s) - user must have at least one */ roles?: string[]; /** Required scope(s) - user must have at least one */ scopes?: string[]; /** Redirect path for unauthorized access (alternative to unauthorized component) */ redirectTo?: string; /** Custom redirect function (e.g., router.push). Falls back to window.location.href. */ onRedirect?: (path: string) => void; } /** * ProtectedRoute guards routes that require authentication. * * @example * // Basic protection * * * * } /> * * @example * // With role requirement * * * * } /> * * @example * // With custom unauthorized view * } * fallback={} * > * * */ export function ProtectedRoute({ children, fallback = , unauthorized = , roles, scopes, redirectTo, onRedirect, }: ProtectedRouteProps) { const { isLoading, isAuthenticated, user } = useAuth(); // Show loading state if (isLoading) { return <>{fallback}; } // Not authenticated if (!isAuthenticated) { if (redirectTo) { if (onRedirect) { onRedirect(redirectTo); } else { window.location.href = redirectTo; } return null; } return <>{unauthorized}; } // Check role requirements if (roles && roles.length > 0) { const hasRequiredRole = roles.some((role) => user?.roles?.includes(role)); if (!hasRequiredRole) { return <>{unauthorized}; } } // Check scope requirements if (scopes && scopes.length > 0) { const hasRequiredScope = scopes.some((scope) => user?.scopes?.includes(scope)); if (!hasRequiredScope) { return <>{unauthorized}; } } return <>{children}; } // Default loading component function DefaultLoading() { return (
Loading...
); } // Default unauthorized component function DefaultUnauthorized() { return (

Access Denied

You don't have permission to view this page.

); }