2025-08-28 10:41:04 +02:00
|
|
|
/**
|
|
|
|
|
* Route configuration for the bakery management application
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
export interface RouteConfig {
|
|
|
|
|
path: string;
|
|
|
|
|
name: string;
|
|
|
|
|
component: string;
|
|
|
|
|
title: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
icon?: string;
|
|
|
|
|
requiresAuth: boolean;
|
|
|
|
|
requiredRoles?: string[];
|
|
|
|
|
requiredPermissions?: string[];
|
|
|
|
|
showInNavigation?: boolean;
|
|
|
|
|
showInBreadcrumbs?: boolean;
|
|
|
|
|
children?: RouteConfig[];
|
|
|
|
|
meta?: {
|
|
|
|
|
layout?: 'default' | 'auth' | 'minimal';
|
|
|
|
|
headerTitle?: string;
|
|
|
|
|
breadcrumbTitle?: string;
|
|
|
|
|
hideHeader?: boolean;
|
|
|
|
|
hideSidebar?: boolean;
|
|
|
|
|
fullScreen?: boolean;
|
|
|
|
|
scrollToTop?: boolean;
|
|
|
|
|
preload?: boolean;
|
|
|
|
|
cache?: boolean;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Route paths as constants
|
|
|
|
|
export const ROUTES = {
|
|
|
|
|
// Public routes
|
|
|
|
|
HOME: '/',
|
|
|
|
|
LOGIN: '/login',
|
|
|
|
|
REGISTER: '/register',
|
|
|
|
|
FORGOT_PASSWORD: '/forgot-password',
|
|
|
|
|
RESET_PASSWORD: '/reset-password',
|
|
|
|
|
VERIFY_EMAIL: '/verify-email',
|
|
|
|
|
|
|
|
|
|
// Dashboard
|
|
|
|
|
DASHBOARD: '/app/dashboard',
|
|
|
|
|
|
|
|
|
|
// Inventory Management
|
|
|
|
|
INVENTORY: '/app/operations/inventory',
|
|
|
|
|
INVENTORY_INGREDIENTS: '/inventory/ingredients',
|
|
|
|
|
INVENTORY_STOCK: '/inventory/stock',
|
|
|
|
|
INVENTORY_MOVEMENTS: '/inventory/movements',
|
|
|
|
|
INVENTORY_ALERTS: '/inventory/alerts',
|
|
|
|
|
INVENTORY_QUALITY: '/inventory/quality',
|
|
|
|
|
INVENTORY_REPORTS: '/inventory/reports',
|
|
|
|
|
|
|
|
|
|
// Production Management
|
|
|
|
|
PRODUCTION: '/app/operations/production',
|
|
|
|
|
PRODUCTION_BATCHES: '/production/batches',
|
|
|
|
|
PRODUCTION_RECIPES: '/production/recipes',
|
|
|
|
|
PRODUCTION_SCHEDULE: '/production/schedule',
|
|
|
|
|
PRODUCTION_QUALITY: '/production/quality',
|
|
|
|
|
PRODUCTION_REPORTS: '/production/reports',
|
|
|
|
|
|
|
|
|
|
// Sales & Analytics
|
|
|
|
|
SALES: '/sales',
|
|
|
|
|
SALES_DATA: '/sales/data',
|
|
|
|
|
SALES_ANALYTICS: '/sales/analytics',
|
|
|
|
|
SALES_REPORTS: '/sales/reports',
|
|
|
|
|
SALES_FORECASTING: '/sales/forecasting',
|
|
|
|
|
|
|
|
|
|
// Forecasting & ML
|
|
|
|
|
FORECASTING: '/forecasting',
|
|
|
|
|
FORECASTING_MODELS: '/forecasting/models',
|
|
|
|
|
FORECASTING_PREDICTIONS: '/forecasting/predictions',
|
|
|
|
|
FORECASTING_TRAINING: '/forecasting/training',
|
|
|
|
|
FORECASTING_ANALYTICS: '/forecasting/analytics',
|
|
|
|
|
|
|
|
|
|
// Orders Management
|
|
|
|
|
ORDERS: '/orders',
|
|
|
|
|
ORDERS_LIST: '/orders/list',
|
|
|
|
|
ORDERS_QUEUE: '/orders/queue',
|
|
|
|
|
ORDERS_HISTORY: '/orders/history',
|
|
|
|
|
ORDERS_CUSTOMERS: '/orders/customers',
|
|
|
|
|
|
|
|
|
|
// Procurement
|
|
|
|
|
PROCUREMENT: '/procurement',
|
|
|
|
|
PROCUREMENT_ORDERS: '/procurement/orders',
|
|
|
|
|
PROCUREMENT_SUPPLIERS: '/procurement/suppliers',
|
|
|
|
|
PROCUREMENT_DELIVERIES: '/procurement/deliveries',
|
|
|
|
|
PROCUREMENT_ANALYTICS: '/procurement/analytics',
|
|
|
|
|
|
|
|
|
|
// Point of Sale
|
|
|
|
|
POS: '/pos',
|
|
|
|
|
POS_INTEGRATION: '/pos/integration',
|
|
|
|
|
POS_TRANSACTIONS: '/pos/transactions',
|
|
|
|
|
POS_WEBHOOKS: '/pos/webhooks',
|
|
|
|
|
POS_SETTINGS: '/pos/settings',
|
|
|
|
|
|
|
|
|
|
// Data Management
|
|
|
|
|
DATA: '/data',
|
|
|
|
|
DATA_IMPORT: '/data/import',
|
|
|
|
|
DATA_EXPORT: '/data/export',
|
|
|
|
|
DATA_EXTERNAL: '/data/external',
|
|
|
|
|
DATA_WEATHER: '/data/weather',
|
|
|
|
|
DATA_EVENTS: '/data/events',
|
|
|
|
|
|
|
|
|
|
// Training & ML
|
|
|
|
|
TRAINING: '/training',
|
|
|
|
|
TRAINING_MODELS: '/training/models',
|
|
|
|
|
TRAINING_JOBS: '/training/jobs',
|
|
|
|
|
TRAINING_EVALUATION: '/training/evaluation',
|
|
|
|
|
TRAINING_DATASETS: '/training/datasets',
|
|
|
|
|
|
|
|
|
|
// Notifications
|
|
|
|
|
NOTIFICATIONS: '/notifications',
|
|
|
|
|
NOTIFICATIONS_LIST: '/notifications/list',
|
|
|
|
|
NOTIFICATIONS_TEMPLATES: '/notifications/templates',
|
|
|
|
|
NOTIFICATIONS_SETTINGS: '/notifications/settings',
|
|
|
|
|
|
|
|
|
|
// Settings
|
|
|
|
|
SETTINGS: '/settings',
|
|
|
|
|
SETTINGS_PROFILE: '/settings/profile',
|
|
|
|
|
SETTINGS_TENANT: '/settings/tenant',
|
|
|
|
|
SETTINGS_USERS: '/settings/users',
|
|
|
|
|
SETTINGS_PERMISSIONS: '/settings/permissions',
|
|
|
|
|
SETTINGS_INTEGRATIONS: '/settings/integrations',
|
|
|
|
|
SETTINGS_PREFERENCES: '/settings/preferences',
|
|
|
|
|
SETTINGS_BILLING: '/settings/billing',
|
2025-09-01 19:21:12 +02:00
|
|
|
SETTINGS_SUBSCRIPTION: '/app/settings/subscription',
|
2025-08-28 10:41:04 +02:00
|
|
|
|
|
|
|
|
// Reports
|
|
|
|
|
REPORTS: '/reports',
|
|
|
|
|
REPORTS_PRODUCTION: '/reports/production',
|
|
|
|
|
REPORTS_INVENTORY: '/reports/inventory',
|
|
|
|
|
REPORTS_SALES: '/reports/sales',
|
|
|
|
|
REPORTS_FINANCIAL: '/reports/financial',
|
|
|
|
|
REPORTS_QUALITY: '/reports/quality',
|
|
|
|
|
|
|
|
|
|
// Help & Support
|
|
|
|
|
HELP: '/help',
|
|
|
|
|
HELP_DOCUMENTATION: '/help/docs',
|
|
|
|
|
HELP_TUTORIALS: '/help/tutorials',
|
|
|
|
|
HELP_SUPPORT: '/help/support',
|
|
|
|
|
HELP_FEEDBACK: '/help/feedback',
|
|
|
|
|
|
|
|
|
|
// Error pages
|
|
|
|
|
NOT_FOUND: '/404',
|
|
|
|
|
UNAUTHORIZED: '/401',
|
|
|
|
|
FORBIDDEN: '/403',
|
|
|
|
|
SERVER_ERROR: '/500',
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
// Route configurations
|
|
|
|
|
export const routesConfig: RouteConfig[] = [
|
|
|
|
|
// Public routes
|
|
|
|
|
{
|
|
|
|
|
path: ROUTES.HOME,
|
|
|
|
|
name: 'Home',
|
|
|
|
|
component: 'HomePage',
|
|
|
|
|
title: 'Panadería IA - Gestión Inteligente',
|
|
|
|
|
requiresAuth: false,
|
|
|
|
|
showInNavigation: false,
|
|
|
|
|
meta: {
|
|
|
|
|
layout: 'minimal',
|
|
|
|
|
scrollToTop: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: ROUTES.LOGIN,
|
|
|
|
|
name: 'Login',
|
|
|
|
|
component: 'LoginPage',
|
|
|
|
|
title: 'Iniciar Sesión',
|
|
|
|
|
requiresAuth: false,
|
|
|
|
|
showInNavigation: false,
|
|
|
|
|
meta: {
|
|
|
|
|
layout: 'auth',
|
|
|
|
|
hideHeader: true,
|
|
|
|
|
hideSidebar: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: ROUTES.REGISTER,
|
|
|
|
|
name: 'Register',
|
|
|
|
|
component: 'RegisterPage',
|
|
|
|
|
title: 'Crear Cuenta',
|
|
|
|
|
requiresAuth: false,
|
|
|
|
|
showInNavigation: false,
|
|
|
|
|
meta: {
|
|
|
|
|
layout: 'auth',
|
|
|
|
|
hideHeader: true,
|
|
|
|
|
hideSidebar: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Dashboard
|
|
|
|
|
{
|
|
|
|
|
path: ROUTES.DASHBOARD,
|
|
|
|
|
name: 'Dashboard',
|
|
|
|
|
component: 'DashboardPage',
|
|
|
|
|
title: 'Panel de Control',
|
|
|
|
|
icon: 'dashboard',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
meta: {
|
|
|
|
|
headerTitle: 'Panel de Control',
|
|
|
|
|
preload: true,
|
|
|
|
|
cache: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
2025-08-28 17:15:29 +02:00
|
|
|
|
|
|
|
|
// Operations Section
|
2025-08-28 10:41:04 +02:00
|
|
|
{
|
2025-08-28 17:15:29 +02:00
|
|
|
path: '/app/operations',
|
|
|
|
|
name: 'Operations',
|
|
|
|
|
component: 'OperationsPage',
|
|
|
|
|
title: 'Operaciones',
|
|
|
|
|
icon: 'production',
|
2025-08-28 10:41:04 +02:00
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
2025-08-28 17:15:29 +02:00
|
|
|
children: [
|
|
|
|
|
{
|
|
|
|
|
path: '/app/operations/production',
|
|
|
|
|
name: 'Production',
|
|
|
|
|
component: 'ProductionPage',
|
|
|
|
|
title: 'Producción',
|
|
|
|
|
icon: 'production',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/app/operations/orders',
|
|
|
|
|
name: 'Orders',
|
|
|
|
|
component: 'OrdersPage',
|
|
|
|
|
title: 'Pedidos',
|
|
|
|
|
icon: 'orders',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/app/operations/inventory',
|
|
|
|
|
name: 'Inventory',
|
|
|
|
|
component: 'InventoryPage',
|
|
|
|
|
title: 'Inventario',
|
|
|
|
|
icon: 'inventory',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/app/operations/recipes',
|
|
|
|
|
name: 'Recipes',
|
|
|
|
|
component: 'RecipesPage',
|
|
|
|
|
title: 'Recetas',
|
|
|
|
|
icon: 'production',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/app/operations/procurement',
|
|
|
|
|
name: 'Procurement',
|
|
|
|
|
component: 'ProcurementPage',
|
|
|
|
|
title: 'Compras',
|
|
|
|
|
icon: 'procurement',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/app/operations/pos',
|
|
|
|
|
name: 'POS',
|
|
|
|
|
component: 'POSPage',
|
|
|
|
|
title: 'Punto de Venta',
|
|
|
|
|
icon: 'pos',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
],
|
2025-08-28 10:41:04 +02:00
|
|
|
},
|
2025-08-28 17:15:29 +02:00
|
|
|
|
|
|
|
|
// Analytics Section
|
2025-08-28 10:41:04 +02:00
|
|
|
{
|
2025-08-28 17:15:29 +02:00
|
|
|
path: '/app/analytics',
|
|
|
|
|
name: 'Analytics',
|
|
|
|
|
component: 'AnalyticsPage',
|
|
|
|
|
title: 'Analytics',
|
|
|
|
|
icon: 'sales',
|
2025-08-28 10:41:04 +02:00
|
|
|
requiresAuth: true,
|
2025-08-28 17:15:29 +02:00
|
|
|
requiredRoles: ['admin', 'manager'],
|
2025-08-28 10:41:04 +02:00
|
|
|
showInNavigation: true,
|
2025-08-28 17:15:29 +02:00
|
|
|
children: [
|
|
|
|
|
{
|
|
|
|
|
path: '/app/analytics/forecasting',
|
|
|
|
|
name: 'Forecasting',
|
|
|
|
|
component: 'ForecastingPage',
|
|
|
|
|
title: 'Pronósticos',
|
|
|
|
|
icon: 'forecasting',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
requiredRoles: ['admin', 'manager'],
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/app/analytics/sales',
|
|
|
|
|
name: 'SalesAnalytics',
|
|
|
|
|
component: 'SalesAnalyticsPage',
|
|
|
|
|
title: 'Análisis de Ventas',
|
|
|
|
|
icon: 'sales',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
requiredRoles: ['admin', 'manager'],
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/app/analytics/performance',
|
|
|
|
|
name: 'PerformanceAnalytics',
|
|
|
|
|
component: 'PerformanceAnalyticsPage',
|
|
|
|
|
title: 'Análisis de Rendimiento',
|
|
|
|
|
icon: 'sales',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
requiredRoles: ['admin', 'manager'],
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/app/analytics/ai-insights',
|
|
|
|
|
name: 'AIInsights',
|
|
|
|
|
component: 'AIInsightsPage',
|
|
|
|
|
title: 'Insights de IA',
|
|
|
|
|
icon: 'forecasting',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
requiredRoles: ['admin', 'manager'],
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
],
|
2025-08-28 10:41:04 +02:00
|
|
|
},
|
2025-08-28 17:15:29 +02:00
|
|
|
|
|
|
|
|
// Settings Section
|
2025-08-28 10:41:04 +02:00
|
|
|
{
|
2025-08-28 17:15:29 +02:00
|
|
|
path: '/app/settings',
|
2025-08-28 10:41:04 +02:00
|
|
|
name: 'Settings',
|
|
|
|
|
component: 'SettingsPage',
|
|
|
|
|
title: 'Configuración',
|
|
|
|
|
icon: 'settings',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
children: [
|
2025-08-28 23:40:44 +02:00
|
|
|
{
|
|
|
|
|
path: '/app/settings/profile',
|
|
|
|
|
name: 'Profile',
|
|
|
|
|
component: 'ProfilePage',
|
|
|
|
|
title: 'Mi Perfil',
|
|
|
|
|
icon: 'user',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
2025-08-28 10:41:04 +02:00
|
|
|
{
|
|
|
|
|
path: '/app/settings/bakery-config',
|
|
|
|
|
name: 'BakeryConfig',
|
|
|
|
|
component: 'BakeryConfigPage',
|
|
|
|
|
title: 'Configuración de Panadería',
|
|
|
|
|
icon: 'settings',
|
|
|
|
|
requiresAuth: true,
|
2025-08-28 17:15:29 +02:00
|
|
|
requiredRoles: ['admin'],
|
2025-08-28 10:41:04 +02:00
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
2025-08-28 17:15:29 +02:00
|
|
|
path: '/app/settings/team',
|
|
|
|
|
name: 'Team',
|
|
|
|
|
component: 'TeamPage',
|
|
|
|
|
title: 'Gestión de Equipo',
|
2025-08-28 10:41:04 +02:00
|
|
|
icon: 'settings',
|
|
|
|
|
requiresAuth: true,
|
2025-08-28 17:15:29 +02:00
|
|
|
requiredRoles: ['admin', 'manager'],
|
2025-08-28 10:41:04 +02:00
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
2025-09-01 19:21:12 +02:00
|
|
|
{
|
|
|
|
|
path: '/app/settings/subscription',
|
|
|
|
|
name: 'Subscription',
|
|
|
|
|
component: 'SubscriptionPage',
|
|
|
|
|
title: 'Suscripción y Facturación',
|
|
|
|
|
icon: 'credit-card',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
requiredRoles: ['admin', 'owner'],
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
2025-09-02 08:38:49 +02:00
|
|
|
{
|
|
|
|
|
path: '/app/settings/preferences',
|
|
|
|
|
name: 'CommunicationPreferences',
|
|
|
|
|
component: 'PreferencesPage',
|
|
|
|
|
title: 'Preferencias de Comunicación',
|
|
|
|
|
icon: 'settings',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
2025-08-28 10:41:04 +02:00
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
|
2025-09-02 08:38:49 +02:00
|
|
|
// Communications Section - Keep only for backwards compatibility
|
2025-08-28 10:41:04 +02:00
|
|
|
{
|
|
|
|
|
path: '/app/communications',
|
|
|
|
|
name: 'Communications',
|
|
|
|
|
component: 'CommunicationsPage',
|
|
|
|
|
title: 'Comunicaciones',
|
|
|
|
|
icon: 'notifications',
|
|
|
|
|
requiresAuth: true,
|
2025-09-02 08:38:49 +02:00
|
|
|
showInNavigation: false,
|
2025-08-28 10:41:04 +02:00
|
|
|
children: [
|
|
|
|
|
{
|
|
|
|
|
path: '/app/communications/preferences',
|
|
|
|
|
name: 'Preferences',
|
|
|
|
|
component: 'PreferencesPage',
|
|
|
|
|
title: 'Preferencias',
|
|
|
|
|
icon: 'settings',
|
|
|
|
|
requiresAuth: true,
|
2025-09-02 08:38:49 +02:00
|
|
|
showInNavigation: false,
|
2025-08-28 10:41:04 +02:00
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Data Management Section
|
|
|
|
|
{
|
|
|
|
|
path: '/app/data',
|
|
|
|
|
name: 'Data',
|
|
|
|
|
component: 'DataPage',
|
|
|
|
|
title: 'Gestión de Datos',
|
|
|
|
|
icon: 'data',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
children: [
|
|
|
|
|
{
|
|
|
|
|
path: '/app/data/weather',
|
|
|
|
|
name: 'Weather',
|
|
|
|
|
component: 'WeatherPage',
|
|
|
|
|
title: 'Datos Meteorológicos',
|
|
|
|
|
icon: 'data',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/app/data/traffic',
|
|
|
|
|
name: 'Traffic',
|
|
|
|
|
component: 'TrafficPage',
|
|
|
|
|
title: 'Datos de Tráfico',
|
|
|
|
|
icon: 'data',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/app/data/events',
|
|
|
|
|
name: 'Events',
|
|
|
|
|
component: 'EventsPage',
|
|
|
|
|
title: 'Eventos y Festivales',
|
|
|
|
|
icon: 'data',
|
|
|
|
|
requiresAuth: true,
|
|
|
|
|
showInNavigation: true,
|
|
|
|
|
showInBreadcrumbs: true,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
|
2025-09-03 14:06:38 +02:00
|
|
|
// Onboarding Section - Complete 9-step flow
|
2025-08-28 10:41:04 +02:00
|
|
|
{
|
|
|
|
|
path: '/app/onboarding',
|
|
|
|
|
name: 'Onboarding',
|
|
|
|
|
component: 'OnboardingPage',
|
|
|
|
|
title: 'Configuración Inicial',
|
2025-09-03 14:06:38 +02:00
|
|
|
description: 'Configuración completa en 9 pasos con IA',
|
2025-08-28 10:41:04 +02:00
|
|
|
icon: 'settings',
|
|
|
|
|
requiresAuth: true,
|
2025-09-01 08:19:54 +02:00
|
|
|
showInNavigation: false,
|
2025-09-03 14:06:38 +02:00
|
|
|
meta: {
|
|
|
|
|
hideHeader: true,
|
|
|
|
|
hideSidebar: true,
|
|
|
|
|
fullScreen: true,
|
|
|
|
|
},
|
2025-08-28 10:41:04 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Error pages
|
|
|
|
|
{
|
|
|
|
|
path: ROUTES.NOT_FOUND,
|
|
|
|
|
name: 'NotFound',
|
|
|
|
|
component: 'NotFoundPage',
|
|
|
|
|
title: 'Página no encontrada',
|
|
|
|
|
requiresAuth: false,
|
|
|
|
|
showInNavigation: false,
|
|
|
|
|
meta: {
|
|
|
|
|
layout: 'minimal',
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: ROUTES.UNAUTHORIZED,
|
|
|
|
|
name: 'Unauthorized',
|
|
|
|
|
component: 'UnauthorizedPage',
|
|
|
|
|
title: 'No autorizado',
|
|
|
|
|
requiresAuth: false,
|
|
|
|
|
showInNavigation: false,
|
|
|
|
|
meta: {
|
|
|
|
|
layout: 'minimal',
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: ROUTES.FORBIDDEN,
|
|
|
|
|
name: 'Forbidden',
|
|
|
|
|
component: 'ForbiddenPage',
|
|
|
|
|
title: 'Acceso prohibido',
|
|
|
|
|
requiresAuth: false,
|
|
|
|
|
showInNavigation: false,
|
|
|
|
|
meta: {
|
|
|
|
|
layout: 'minimal',
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Helper functions
|
|
|
|
|
export const getRouteByPath = (path: string): RouteConfig | undefined => {
|
|
|
|
|
const findRoute = (routes: RouteConfig[], targetPath: string): RouteConfig | undefined => {
|
|
|
|
|
for (const route of routes) {
|
|
|
|
|
if (route.path === targetPath) {
|
|
|
|
|
return route;
|
|
|
|
|
}
|
|
|
|
|
if (route.children) {
|
|
|
|
|
const childRoute = findRoute(route.children, targetPath);
|
|
|
|
|
if (childRoute) {
|
|
|
|
|
return childRoute;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return findRoute(routesConfig, path);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getRouteByName = (name: string): RouteConfig | undefined => {
|
|
|
|
|
const findRoute = (routes: RouteConfig[], targetName: string): RouteConfig | undefined => {
|
|
|
|
|
for (const route of routes) {
|
|
|
|
|
if (route.name === targetName) {
|
|
|
|
|
return route;
|
|
|
|
|
}
|
|
|
|
|
if (route.children) {
|
|
|
|
|
const childRoute = findRoute(route.children, targetName);
|
|
|
|
|
if (childRoute) {
|
|
|
|
|
return childRoute;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return findRoute(routesConfig, name);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getNavigationRoutes = (): RouteConfig[] => {
|
|
|
|
|
const filterNavRoutes = (routes: RouteConfig[]): RouteConfig[] => {
|
|
|
|
|
return routes
|
|
|
|
|
.filter(route => route.showInNavigation)
|
|
|
|
|
.map(route => ({
|
|
|
|
|
...route,
|
|
|
|
|
children: route.children ? filterNavRoutes(route.children) : undefined,
|
|
|
|
|
}));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return filterNavRoutes(routesConfig);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getBreadcrumbs = (path: string): RouteConfig[] => {
|
|
|
|
|
const breadcrumbs: RouteConfig[] = [];
|
|
|
|
|
const pathSegments = path.split('/').filter(segment => segment);
|
|
|
|
|
|
|
|
|
|
let currentPath = '';
|
|
|
|
|
for (const segment of pathSegments) {
|
|
|
|
|
currentPath += `/${segment}`;
|
|
|
|
|
const route = getRouteByPath(currentPath);
|
|
|
|
|
if (route && route.showInBreadcrumbs !== false) {
|
|
|
|
|
breadcrumbs.push(route);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return breadcrumbs;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const hasPermission = (route: RouteConfig, userPermissions: string[]): boolean => {
|
|
|
|
|
if (!route.requiredPermissions || route.requiredPermissions.length === 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for wildcard permission
|
|
|
|
|
if (userPermissions.includes('*')) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return route.requiredPermissions.every(permission =>
|
|
|
|
|
userPermissions.includes(permission)
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const hasRole = (route: RouteConfig, userRoles: string[]): boolean => {
|
|
|
|
|
if (!route.requiredRoles || route.requiredRoles.length === 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return route.requiredRoles.some(role =>
|
|
|
|
|
userRoles.includes(role)
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const canAccessRoute = (
|
|
|
|
|
route: RouteConfig,
|
|
|
|
|
isAuthenticated: boolean,
|
|
|
|
|
userRoles: string[] = [],
|
|
|
|
|
userPermissions: string[] = []
|
|
|
|
|
): boolean => {
|
|
|
|
|
// Check authentication requirement
|
|
|
|
|
if (route.requiresAuth && !isAuthenticated) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check role requirements
|
|
|
|
|
if (!hasRole(route, userRoles)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check permission requirements
|
|
|
|
|
if (!hasPermission(route, userPermissions)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
};
|