/**
* ProtectedRoute Component
* Guards routes that require authentication with role-based access control
* Based on gamilit implementation
*/
import { Navigate, useLocation } from 'react-router-dom';
import { useAuthStore } from '../../stores/authStore';
import { LoadingSpinner } from '../common/LoadingSpinner';
interface ProtectedRouteProps {
children: React.ReactNode;
/** Roles allowed to access this route */
allowedRoles?: string[];
/** Custom redirect path for unauthenticated users */
redirectTo?: string;
}
export function ProtectedRoute({
children,
allowedRoles,
redirectTo = '/auth/login',
}: ProtectedRouteProps) {
const user = useAuthStore((state) => state.user);
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
const isLoading = useAuthStore((state) => state.isLoading);
const isInitialized = useAuthStore((state) => state.isInitialized);
const checkSession = useAuthStore((state) => state.checkSession);
const location = useLocation();
// Show loading while checking auth state
if (isLoading || !isInitialized) {
return (
);
}
// Check if session is still valid
const sessionValid = checkSession();
// Not authenticated - redirect to login
if (!isAuthenticated || !sessionValid) {
return (
);
}
// Check role-based access if roles are specified
if (allowedRoles && allowedRoles.length > 0) {
const userRole = user?.role || '';
const hasRequiredRole = allowedRoles.includes(userRole);
if (!hasRequiredRole) {
// User doesn't have required role - redirect to unauthorized page
return (
);
}
}
// User is authenticated and has required role
return <>{children}>;
}
/**
* PublicRoute Component
* Redirects authenticated users away from public pages (login, register)
*/
interface PublicRouteProps {
children: React.ReactNode;
/** Where to redirect authenticated users */
redirectTo?: string;
}
export function PublicRoute({
children,
redirectTo = '/admin/dashboard',
}: PublicRouteProps) {
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
const isLoading = useAuthStore((state) => state.isLoading);
const isInitialized = useAuthStore((state) => state.isInitialized);
const location = useLocation();
// Show loading while checking auth state
if (isLoading || !isInitialized) {
return (
);
}
// If user is already authenticated, redirect to dashboard
if (isAuthenticated) {
// Check if there's a "from" location to redirect back to
const from = (location.state as { from?: Location })?.from?.pathname || redirectTo;
return ;
}
return <>{children}>;
}
export default ProtectedRoute;