Imporve the role based forntend protected roles
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
import React from 'react';
|
||||
import { Navigate, useLocation } from 'react-router-dom';
|
||||
import { useAuthUser, useIsAuthenticated, useAuthLoading } from '../stores';
|
||||
import { useCurrentTenantAccess, useTenantPermissions } from '../stores/tenant.store';
|
||||
import { RouteConfig, canAccessRoute, ROUTES } from './routes.config';
|
||||
|
||||
interface ProtectedRouteProps {
|
||||
@@ -126,6 +127,8 @@ export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
|
||||
const user = useAuthUser();
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
const isLoading = useAuthLoading();
|
||||
const currentTenantAccess = useCurrentTenantAccess();
|
||||
const { hasPermission } = useTenantPermissions();
|
||||
const location = useLocation();
|
||||
|
||||
// Note: Onboarding routes are now properly protected and require authentication
|
||||
@@ -160,16 +163,21 @@ export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
|
||||
}
|
||||
|
||||
// Get user roles and permissions
|
||||
const userRoles = user?.role ? [user.role] : [];
|
||||
const userPermissions: string[] = [];
|
||||
const globalUserRoles = user?.role ? [user.role] : [];
|
||||
const tenantRole = currentTenantAccess?.role;
|
||||
const tenantRoles = tenantRole ? [tenantRole] : [];
|
||||
|
||||
// Combine global and tenant roles for comprehensive access control
|
||||
const allUserRoles = [...globalUserRoles, ...tenantRoles];
|
||||
const tenantPermissions = currentTenantAccess?.permissions || [];
|
||||
|
||||
// Check if user can access this route
|
||||
const canAccess = canAccessRoute(route, isAuthenticated, userRoles, userPermissions);
|
||||
const canAccess = canAccessRoute(route, isAuthenticated, allUserRoles, tenantPermissions);
|
||||
|
||||
if (!canAccess) {
|
||||
// Check if it's a permission issue or role issue
|
||||
const hasRequiredRoles = !route.requiredRoles ||
|
||||
route.requiredRoles.some(role => userRoles.includes(role));
|
||||
route.requiredRoles.some(role => allUserRoles.includes(role as string));
|
||||
|
||||
if (!hasRequiredRoles) {
|
||||
return <UnauthorizedPage />;
|
||||
@@ -211,22 +219,29 @@ export const useRouteAccess = (route: RouteConfig) => {
|
||||
const user = useAuthUser();
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
const isLoading = useAuthLoading();
|
||||
const currentTenantAccess = useCurrentTenantAccess();
|
||||
|
||||
const userRoles = user?.role ? [user.role] : [];
|
||||
const userPermissions: string[] = [];
|
||||
const globalUserRoles = user?.role ? [user.role as string] : [];
|
||||
const tenantRole = currentTenantAccess?.role;
|
||||
const tenantRoles = tenantRole ? [tenantRole as string] : [];
|
||||
const allUserRoles = [...globalUserRoles, ...tenantRoles];
|
||||
const tenantPermissions = currentTenantAccess?.permissions || [];
|
||||
|
||||
const canAccess = canAccessRoute(route, isAuthenticated, userRoles, userPermissions);
|
||||
const canAccess = canAccessRoute(route, isAuthenticated, allUserRoles, tenantPermissions);
|
||||
|
||||
return {
|
||||
canAccess,
|
||||
isLoading,
|
||||
isAuthenticated,
|
||||
userRoles,
|
||||
userPermissions,
|
||||
globalUserRoles,
|
||||
tenantRoles,
|
||||
allUserRoles,
|
||||
tenantPermissions,
|
||||
currentTenantAccess,
|
||||
hasRequiredRoles: !route.requiredRoles ||
|
||||
route.requiredRoles.some(role => userRoles.includes(role)),
|
||||
route.requiredRoles.some(role => allUserRoles.includes(role as string)),
|
||||
hasRequiredPermissions: !route.requiredPermissions ||
|
||||
route.requiredPermissions.every(permission => userPermissions.includes(permission)),
|
||||
route.requiredPermissions.every(permission => tenantPermissions.includes(permission)),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -248,21 +263,25 @@ export const ConditionalRender: React.FC<ConditionalRenderProps> = ({
|
||||
}) => {
|
||||
const user = useAuthUser();
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
const currentTenantAccess = useCurrentTenantAccess();
|
||||
|
||||
if (!isAuthenticated || !user) {
|
||||
return <>{fallback}</>;
|
||||
}
|
||||
|
||||
const userRoles = user.role ? [user.role] : [];
|
||||
const userPermissions: string[] = [];
|
||||
const globalUserRoles = user.role ? [user.role as string] : [];
|
||||
const tenantRole = currentTenantAccess?.role;
|
||||
const tenantRoles = tenantRole ? [tenantRole as string] : [];
|
||||
const allUserRoles = [...globalUserRoles, ...tenantRoles];
|
||||
const tenantPermissions = currentTenantAccess?.permissions || [];
|
||||
|
||||
// Check roles
|
||||
let hasRoles = true;
|
||||
if (requiredRoles.length > 0) {
|
||||
if (requireAll) {
|
||||
hasRoles = requiredRoles.every(role => userRoles.includes(role));
|
||||
hasRoles = requiredRoles.every(role => allUserRoles.includes(role as string));
|
||||
} else {
|
||||
hasRoles = requiredRoles.some(role => userRoles.includes(role));
|
||||
hasRoles = requiredRoles.some(role => allUserRoles.includes(role as string));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,9 +289,9 @@ export const ConditionalRender: React.FC<ConditionalRenderProps> = ({
|
||||
let hasPermissions = true;
|
||||
if (requiredPermissions.length > 0) {
|
||||
if (requireAll) {
|
||||
hasPermissions = requiredPermissions.every(permission => userPermissions.includes(permission));
|
||||
hasPermissions = requiredPermissions.every(permission => tenantPermissions.includes(permission));
|
||||
} else {
|
||||
hasPermissions = requiredPermissions.some(permission => userPermissions.includes(permission));
|
||||
hasPermissions = requiredPermissions.some(permission => tenantPermissions.includes(permission));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,11 +302,11 @@ export const ConditionalRender: React.FC<ConditionalRenderProps> = ({
|
||||
return <>{fallback}</>;
|
||||
};
|
||||
|
||||
// Route guard for admin-only routes
|
||||
// Route guard for admin-only routes (global admin or tenant owner/admin)
|
||||
export const AdminRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
return (
|
||||
<ConditionalRender
|
||||
requiredRoles={['admin', 'super_admin']}
|
||||
requiredRoles={['admin', 'super_admin', 'owner']}
|
||||
requireAll={false}
|
||||
fallback={<UnauthorizedPage />}
|
||||
>
|
||||
@@ -296,11 +315,24 @@ export const AdminRoute: React.FC<{ children: React.ReactNode }> = ({ children }
|
||||
);
|
||||
};
|
||||
|
||||
// Route guard for manager-level routes
|
||||
// Route guard for manager-level routes (global admin/manager or tenant admin/owner)
|
||||
export const ManagerRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
return (
|
||||
<ConditionalRender
|
||||
requiredRoles={['admin', 'super_admin', 'manager']}
|
||||
requiredRoles={['admin', 'super_admin', 'manager', 'owner']}
|
||||
requireAll={false}
|
||||
fallback={<UnauthorizedPage />}
|
||||
>
|
||||
{children}
|
||||
</ConditionalRender>
|
||||
);
|
||||
};
|
||||
|
||||
// Route guard for tenant owner-only routes
|
||||
export const OwnerRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
return (
|
||||
<ConditionalRender
|
||||
requiredRoles={['super_admin', 'owner']}
|
||||
requireAll={false}
|
||||
fallback={<UnauthorizedPage />}
|
||||
>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* Route configuration for the bakery management application
|
||||
*/
|
||||
|
||||
import { ROLE_COMBINATIONS } from '../types/roles';
|
||||
|
||||
export interface RouteConfig {
|
||||
path: string;
|
||||
name: string;
|
||||
@@ -286,7 +288,7 @@ export const routesConfig: RouteConfig[] = [
|
||||
title: 'Analytics',
|
||||
icon: 'sales',
|
||||
requiresAuth: true,
|
||||
requiredRoles: ['admin', 'manager'],
|
||||
requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS,
|
||||
showInNavigation: true,
|
||||
children: [
|
||||
{
|
||||
@@ -296,7 +298,7 @@ export const routesConfig: RouteConfig[] = [
|
||||
title: 'Pronósticos',
|
||||
icon: 'forecasting',
|
||||
requiresAuth: true,
|
||||
requiredRoles: ['admin', 'manager'],
|
||||
requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS,
|
||||
showInNavigation: true,
|
||||
showInBreadcrumbs: true,
|
||||
},
|
||||
@@ -307,7 +309,7 @@ export const routesConfig: RouteConfig[] = [
|
||||
title: 'Análisis de Ventas',
|
||||
icon: 'sales',
|
||||
requiresAuth: true,
|
||||
requiredRoles: ['admin', 'manager'],
|
||||
requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS,
|
||||
showInNavigation: true,
|
||||
showInBreadcrumbs: true,
|
||||
},
|
||||
@@ -318,7 +320,7 @@ export const routesConfig: RouteConfig[] = [
|
||||
title: 'Análisis de Rendimiento',
|
||||
icon: 'sales',
|
||||
requiresAuth: true,
|
||||
requiredRoles: ['admin', 'manager'],
|
||||
requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS,
|
||||
showInNavigation: true,
|
||||
showInBreadcrumbs: true,
|
||||
},
|
||||
@@ -329,7 +331,7 @@ export const routesConfig: RouteConfig[] = [
|
||||
title: 'Insights de IA',
|
||||
icon: 'forecasting',
|
||||
requiresAuth: true,
|
||||
requiredRoles: ['admin', 'manager'],
|
||||
requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS,
|
||||
showInNavigation: true,
|
||||
showInBreadcrumbs: true,
|
||||
},
|
||||
@@ -363,7 +365,7 @@ export const routesConfig: RouteConfig[] = [
|
||||
title: 'Configuración de Panadería',
|
||||
icon: 'settings',
|
||||
requiresAuth: true,
|
||||
requiredRoles: ['admin'],
|
||||
requiredRoles: ROLE_COMBINATIONS.ADMIN_ACCESS,
|
||||
showInNavigation: true,
|
||||
showInBreadcrumbs: true,
|
||||
},
|
||||
@@ -374,7 +376,7 @@ export const routesConfig: RouteConfig[] = [
|
||||
title: 'Gestión de Equipo',
|
||||
icon: 'settings',
|
||||
requiresAuth: true,
|
||||
requiredRoles: ['admin', 'manager'],
|
||||
requiredRoles: ROLE_COMBINATIONS.ADMIN_ACCESS,
|
||||
showInNavigation: true,
|
||||
showInBreadcrumbs: true,
|
||||
},
|
||||
@@ -385,7 +387,7 @@ export const routesConfig: RouteConfig[] = [
|
||||
title: 'Suscripción y Facturación',
|
||||
icon: 'credit-card',
|
||||
requiresAuth: true,
|
||||
requiredRoles: ['admin', 'owner'],
|
||||
requiredRoles: ROLE_COMBINATIONS.ADMIN_ACCESS,
|
||||
showInNavigation: true,
|
||||
showInBreadcrumbs: true,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user