/** * Route configuration for the bakery management application */ import { ROLE_COMBINATIONS } from '../types/roles'; export interface RouteConfig { path: string; name: string; component: string; title: string; description?: string; icon?: string; requiresAuth: boolean; requiredRoles?: readonly string[]; requiredPermissions?: readonly string[]; requiredSubscriptionFeature?: string; requiredAnalyticsLevel?: 'basic' | 'advanced' | 'predictive'; 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: '/', FEATURES: '/features', LOGIN: '/login', REGISTER: '/register', FORGOT_PASSWORD: '/forgot-password', RESET_PASSWORD: '/reset-password', VERIFY_EMAIL: '/verify-email', // Dashboard DASHBOARD: '/app/dashboard', // Inventory Management INVENTORY: '/app/database/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', PRODUCTION_ANALYTICS: '/app/analytics/production', // 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: '/app/database/orders', ORDERS_LIST: '/orders/list', ORDERS_QUEUE: '/orders/queue', ORDERS_HISTORY: '/orders/history', ORDERS_CUSTOMERS: '/orders/customers', // Procurement PROCUREMENT: '/app/operations/procurement', PROCUREMENT_ORDERS: '/procurement/orders', PROCUREMENT_SUPPLIERS: '/procurement/suppliers', PROCUREMENT_DELIVERIES: '/procurement/deliveries', PROCUREMENT_ANALYTICS: '/app/analytics/procurement', // Distribution DISTRIBUTION: '/app/operations/distribution', // Recipes RECIPES: '/app/database/recipes', // Suppliers SUPPLIERS: '/app/database/suppliers', // Sustainability SUSTAINABILITY: '/app/database/sustainability', // Point of Sale POS: '/app/operations/pos', POS_INTEGRATION: '/pos/integration', POS_TRANSACTIONS: '/pos/transactions', POS_WEBHOOKS: '/pos/webhooks', POS_SETTINGS: '/pos/settings', // Enterprise PREMISES: '/app/enterprise/premises', // Analytics ANALYTICS_EVENTS: '/app/analytics/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: '/app/settings/profile', SETTINGS_BAKERY: '/app/settings/bakery', SETTINGS_SUBSCRIPTION: '/app/settings/subscription', SETTINGS_ORGANIZATIONS: '/app/settings/organizations', // Legacy routes (will redirect) SETTINGS_PERSONAL_INFO_OLD: '/app/settings/personal-info', SETTINGS_COMMUNICATION_OLD: '/app/settings/communication-preferences', SETTINGS_PRIVACY_OLD: '/app/settings/privacy', SETTINGS_BAKERY_INFO_OLD: '/app/database/information', SETTINGS_BAKERY_AJUSTES_OLD: '/app/database/ajustes', SETTINGS_TENANT: '/settings/tenant', SETTINGS_USERS: '/settings/users', SETTINGS_PERMISSIONS: '/settings/permissions', SETTINGS_INTEGRATIONS: '/settings/integrations', SETTINGS_BILLING: '/settings/billing', SETTINGS_TEAM: '/app/database/team', QUALITY_TEMPLATES: '/app/database/quality-templates', // Legal & Privacy Pages PRIVACY_POLICY: '/privacy', TERMS_OF_SERVICE: '/terms', COOKIE_POLICY: '/cookies', COOKIE_PREFERENCES: '/cookie-preferences', // 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', // Onboarding (Setup is now integrated into UnifiedOnboardingWizard) ONBOARDING: '/app/onboarding', // 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: 'BakeWise - 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, }, }, { path: ROUTES.FORGOT_PASSWORD, name: 'ForgotPassword', component: 'ForgotPasswordPage', title: 'Recuperar Contraseña', requiresAuth: false, showInNavigation: false, meta: { layout: 'auth', hideHeader: true, hideSidebar: true, }, }, { path: ROUTES.RESET_PASSWORD, name: 'ResetPassword', component: 'ResetPasswordPage', title: 'Restablecer Contraseña', requiresAuth: false, showInNavigation: false, meta: { layout: 'auth', hideHeader: true, hideSidebar: true, }, }, { path: ROUTES.FEATURES, name: 'Features', component: 'FeaturesPage', title: 'Funcionalidades - BakeWise', requiresAuth: false, showInNavigation: false, meta: { layout: 'minimal', scrollToTop: 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, }, }, // Enterprise Section - Multi-tenant management { path: ROUTES.PREMISES, name: 'Premises', component: 'PremisesPage', title: 'Locales', icon: 'premises', requiresAuth: true, requiredSubscriptionFeature: 'multi_tenant_management', showInNavigation: true, meta: { headerTitle: 'Locales', preload: false, }, }, // Operations Section - Business Operations Only { path: '/app/operations', name: 'Operations', component: 'OperationsPage', title: 'Operaciones', icon: 'production', requiresAuth: true, showInNavigation: true, children: [ { path: '/app/operations/procurement', name: 'Procurement', component: 'ProcurementPage', title: 'Compras', icon: 'procurement', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/operations/production', name: 'Production', component: 'ProductionPage', title: 'Producción', icon: 'production', 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, }, { path: '/app/operations/distribution', name: 'Distribution', component: 'DistributionPage', title: 'Distribución', icon: 'distribution', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, requiredSubscriptionFeature: 'distribution', }, ], }, // Analytics Section - Subscription protected { path: '/app/analytics', name: 'Analytics', component: 'AnalyticsPage', title: 'Análisis', icon: 'analytics', requiresAuth: true, requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS, requiredAnalyticsLevel: 'basic', showInNavigation: true, children: [ { path: '/app/analytics/production', name: 'ProductionAnalytics', component: 'ProductionAnalyticsPage', title: 'Dashboard de Producción', icon: 'production', requiresAuth: true, requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS, requiredAnalyticsLevel: 'advanced', showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/analytics/procurement', name: 'ProcurementAnalytics', component: 'ProcurementAnalyticsPage', title: 'Dashboard de Compras', icon: 'procurement', requiresAuth: true, requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS, requiredAnalyticsLevel: 'advanced', showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/analytics/forecasting', name: 'Forecasting', component: 'ForecastingPage', title: 'Predicciones', icon: 'forecasting', requiresAuth: true, requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS, requiredAnalyticsLevel: 'advanced', showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/analytics/sales', name: 'SalesAnalytics', component: 'SalesAnalyticsPage', title: 'Dashboard de Ventas', icon: 'sales', requiresAuth: true, requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS, requiredAnalyticsLevel: 'advanced', showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/analytics/performance', name: 'PerformanceAnalytics', component: 'PerformanceAnalyticsPage', title: 'KPIs Generales', icon: 'performance', requiresAuth: true, requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS, requiredAnalyticsLevel: 'advanced', showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/analytics/scenario-simulation', name: 'ScenarioSimulation', component: 'ScenarioSimulationPage', title: 'Análisis What-If', icon: 'simulation', requiresAuth: true, requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS, requiredAnalyticsLevel: 'advanced', showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/analytics/ai-insights', name: 'AIInsights', component: 'AIInsightsPage', title: 'Recomendaciones', icon: 'insights', requiresAuth: true, requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS, requiredAnalyticsLevel: 'advanced', // Available for Professional and Enterprise tiers showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/analytics/events', name: 'EventRegistry', component: 'EventRegistryPage', title: 'Eventos del Sistema', icon: 'events', requiresAuth: true, requiredRoles: ['admin', 'owner'], showInNavigation: true, showInBreadcrumbs: true, }, ], }, // Catalog Section - Current Bakery Status { path: '/app/database', name: 'Database', component: 'DatabasePage', title: 'Mi Panadería', icon: 'database', requiresAuth: true, showInNavigation: true, children: [ { path: '/app/settings/bakery', name: 'BakerySettings', component: 'BakerySettingsPage', title: 'Ajustes', icon: 'settings', requiresAuth: true, requiredRoles: ROLE_COMBINATIONS.ADMIN_ACCESS, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/database/suppliers', name: 'Suppliers', component: 'SuppliersPage', title: 'Proveedores', icon: 'procurement', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/database/inventory', name: 'Inventory', component: 'InventoryPage', title: 'Inventario', icon: 'inventory', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/database/recipes', name: 'Recipes', component: 'RecipesPage', title: 'Recetas', icon: 'chef-hat', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/database/orders', name: 'Orders', component: 'OrdersPage', title: 'Pedidos', icon: 'orders', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/database/maquinaria', name: 'Maquinaria', component: 'MaquinariaPage', title: 'Maquinaria', icon: 'cog', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/database/quality-templates', name: 'QualityTemplates', component: 'QualityTemplatesPage', title: 'Plantillas de Calidad', icon: 'clipboard-check', requiresAuth: true, requiredRoles: ROLE_COMBINATIONS.MANAGEMENT_ACCESS, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/database/team', name: 'Team', component: 'TeamPage', title: 'Trabajadores', icon: 'user', requiresAuth: true, requiredRoles: ROLE_COMBINATIONS.ADMIN_ACCESS, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/database/models', name: 'ModelsConfig', component: 'ModelsConfigPage', title: 'Modelos IA', icon: 'brain-circuit', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/database/sustainability', name: 'Sustainability', component: 'SustainabilityPage', title: 'Sostenibilidad', icon: 'leaf', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, } ], }, // Settings Section { path: '/app/settings', name: 'Settings', component: 'SettingsPage', title: 'Mi Perfil', icon: 'user', requiresAuth: true, showInNavigation: true, children: [ { path: '/app/settings/profile', name: 'Profile', component: 'NewProfileSettingsPage', title: 'Ajustes', icon: 'user', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/settings/subscription', name: 'Subscription', component: 'SubscriptionPage', title: 'Suscripción', icon: 'credit-card', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, }, { path: '/app/settings/organizations', name: 'Organizations', component: 'OrganizationsPage', title: 'Establecimientos', icon: 'database', requiresAuth: true, showInNavigation: true, showInBreadcrumbs: true, }, ], }, // Onboarding Section - Complete 9-step flow { path: '/app/onboarding', name: 'Onboarding', component: 'OnboardingPage', title: 'Configuración Inicial', description: 'Configuración completa en 9 pasos con IA', icon: 'settings', requiresAuth: true, showInNavigation: false, meta: { hideHeader: true, hideSidebar: true, fullScreen: true, }, }, // Setup is now integrated into UnifiedOnboardingWizard - route removed // 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; };