/* Trascend CRM · Shell: login (con 2FA), sidebar por permisos, router */ const ACL = window.TrascendACL; /* ------------------------------------------------ carga diferida de módulos Los módulos de negocio (modules/*.jsx) NO se cargan al abrir la página: se piden recién DESPUÉS del login. En producción se sirven por api/asset.php, que exige sesión → su código no se puede descargar sin estar autenticado. En modo demo (sin PHP) se cargan directo. */ const BUSINESS_MODULES = [ 'onboarding', 'dashboard', 'clientes', 'leads', 'pipeline', 'diagnostico', 'flows', 'qa', 'monitoreo', 'documentos', 'age-billing', 'automatizacion', 'integraciones', 'informes', 'social', 'calendario', 'inbox', 'finanzas', 'paquetes', 'analitica', 'age', 'comercial', 'ajustes-roles', 'ajustes-conexiones', 'ajustes-seguridad', 'ajustes', ]; let __modulesPromise = null; function loadBusinessModules() { if (window.__modulesLoaded) return Promise.resolve(); if (__modulesPromise) return __modulesPromise; __modulesPromise = (async () => { const V = '20260819p'; let mode = 'local'; try { mode = await TrascendAPI.mode(); } catch (e) {} for (let i = 0; i < BUSINESS_MODULES.length; i++) { const name = BUSINESS_MODULES[i]; const url = (mode === 'mysql') ? ('api/asset.php?f=modules/' + name + '.jsx&v=' + V) : ('modules/' + name + '.jsx?v=' + V); const res = await fetch(url, { credentials: 'same-origin' }); if (!res.ok) throw new Error('No se pudo cargar el módulo «' + name + '» (HTTP ' + res.status + '). Volvé a iniciar sesión.'); const srcCode = await res.text(); let out; try { out = Babel.transform(srcCode, { presets: ['react'], filename: name + '.jsx' }).code; } catch (e) { throw new Error('Error al compilar «' + name + '»: ' + ((e && e.message) || e)); } const s = document.createElement('script'); s.setAttribute('data-module', name); s.textContent = out; // se ejecuta en ámbito global, igual que un