73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
import React, { useEffect } from 'react';
|
|
import { Navigate } from 'react-router-dom';
|
|
import useAuthStore from '../../../store/useAuthStore';
|
|
import { useAuthModal } from '../contexts/AuthModalContext';
|
|
|
|
interface AdminRouteProps {
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
/**
|
|
* SECURITY NOTE: This component performs CLIENT-SIDE authorization checks only.
|
|
* These checks are for UX purposes (showing/hiding UI elements).
|
|
*
|
|
* ALL authorization must be enforced server-side. Client-side checks can be bypassed
|
|
* by modifying localStorage or browser DevTools. The backend API must validate
|
|
* user roles and permissions for every request.
|
|
*/
|
|
const AdminRoute: React.FC<AdminRouteProps> = ({
|
|
children
|
|
}) => {
|
|
const { isAuthenticated, userInfo, isLoading } = useAuthStore();
|
|
const { openModal } = useAuthModal();
|
|
|
|
// SECURITY: Client-side role check - backend must also validate
|
|
useEffect(() => {
|
|
if (!isLoading && !isAuthenticated) {
|
|
openModal('login');
|
|
}
|
|
}, [isLoading, isAuthenticated, openModal]);
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div
|
|
className="min-h-screen flex items-center
|
|
justify-center bg-gray-50"
|
|
>
|
|
<div className="text-center">
|
|
<div
|
|
className="animate-spin rounded-full h-12 w-12
|
|
border-b-2 border-indigo-600 mx-auto"
|
|
/>
|
|
<p className="mt-4 text-gray-600">
|
|
Authenticating...
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
|
|
if (!isAuthenticated) {
|
|
return null; // Modal will be shown by AuthModalManager
|
|
}
|
|
|
|
|
|
// SECURITY: Client-side role check - MUST be validated server-side
|
|
// This check can be bypassed by modifying localStorage
|
|
const isAdmin = userInfo?.role === 'admin';
|
|
if (!isAdmin) {
|
|
// Redirect to appropriate dashboard based on role
|
|
if (userInfo?.role === 'staff') {
|
|
return <Navigate to="/staff/dashboard" replace />;
|
|
} else if (userInfo?.role === 'accountant') {
|
|
return <Navigate to="/accountant/dashboard" replace />;
|
|
}
|
|
return <Navigate to="/" replace />;
|
|
}
|
|
|
|
return <>{children}</>;
|
|
};
|
|
|
|
export default AdminRoute;
|