Appearance
Componente Navbar - Documentación Técnica
Componente: ts/core/components/layout/Navbar.tsxTipo: Layout Component (Core) Estado: Implementado
Descripción General
Navbar es la barra de navegación superior del layout AdminLTE. Se renderiza dentro de Layout y consume ConfigContext de forma opcional para leer permisos del usuario.
Características principales:
- Lectura de
ConfigContextconuseContextdirecto (compatible con React Compiler) - Renderizado condicional de
SchemaSelectorssegún permisoCONFIG_CAMBIO-SUCURSAL - Soporte de prop fallback para entornos sin
ConfigProvider(modo heredado) - Renderizado de nombre de usuario y período de ejercicio opcionales
Arquitectura Dual: Navbar Legacy vs. React Navbar
El sistema mantiene dos barras de navegación coexistentes:
| Aspecto | Legacy (PHP SSR) | React Navbar |
|---|---|---|
| Archivo | php/components/ (views PHP) | ts/core/components/layout/Navbar.tsx |
| Renderizado | Servidor (PHP) | Cliente (React) |
| Contexto | Variables PHP globales | ConfigContext |
| Estado | Solo mantenimiento | Activo / en uso |
| Uso | Módulos legacy sin migrar | Apps React Full Module |
La React Navbar solo aparece en apps que usan el componente Layout (ver sección de consumidores).
Patrón useContext(ConfigContext) — Optional Provider Consumption
Decisión de diseño
Navbar usa useContext(ConfigContext) directamente en lugar de useConfig().
| Aspecto | useConfig() | useContext(ConfigContext) |
|---|---|---|
| Comportamiento sin Provider | Lanza Error | Retorna undefined |
| Hooks en try/catch | Requería el anti-patrón | No aplica |
| React Compiler | Violación (hooks-in-try) | Compatible |
| Uso correcto | Componentes que requieren config | Componentes con config opcional |
useConfig() sigue siendo la opción correcta para componentes donde ConfigProvider es obligatorio (formularios, vistas de módulos).
useContext(ConfigContext) es la opción correcta cuando el componente puede funcionar sin ConfigProvider (modo fallback por props).
Fuentes de datos en Navbar
Nombre de usuario: config?.usuario.usuario ?? props.userName
Permiso sucursal: config?.usuario.permisos.includes('CONFIG_CAMBIO-SUCURSAL') ?? falseSi ConfigProvider está ausente, config es undefined y se usan los valores fallback (props.userName, sin selectores de esquema).
SchemaSelectors — Renderizado Condicional
SchemaSelectors se renderiza dentro de Navbar como <li> implícito via React.Fragment.
Condición de visibilidad:
- El usuario tiene el permiso
CONFIG_CAMBIO-SUCURSALenAppConfiguration.usuario.permisos - Y hay más de una sucursal o más de una caja disponible (lógica interna de
SchemaSelectors)
Ubicación del componente: ts/config/components/SchemaSelectors.tsx
Corrección HTML: Fragment en lugar de div
SchemaSelectors usa React.Fragment como wrapper raíz (no <div>).
Motivo: Navbar renderiza sus hijos dentro de <ul className="navbar-nav">. Un <div> como hijo directo de <ul> produce HTML inválido. React.Fragment permite que SucursalSelect y CajaSelect se rendericen como <li> directos de la <ul>.
Jerarquía de Componentes
Layout
└── Navbar
├── MaintenanceBanner
└── SchemaSelectors [condicional: CONFIG_CAMBIO-SUCURSAL]
├── SucursalSelect [condicional: múltiples sucursales o cajas]
└── CajaSelect [condicional: sucursal seleccionada + múltiples cajas]Estructura de Archivos
ts/
├── core/
│ ├── components/layout/
│ │ └── Navbar.tsx # Componente principal
│ ├── context/
│ │ └── ConfigContext.tsx # ConfigContext + ConfigProvider + useConfig
│ └── types/
│ └── layout.types.ts # NavbarProps
└── config/
└── components/
├── SchemaSelectors.tsx # Contenedor de selectores (usa React.Fragment)
├── SucursalSelect.tsx # Selector de sucursal
└── CajaSelect.tsx # Selector de caja (depende de sucursal)Props
NavbarProps (todas opcionales):
| Prop | Tipo | Descripción |
|---|---|---|
userName | string | Nombre de usuario fallback cuando ConfigProvider está ausente |
showExercisePeriod | boolean | Mostrar el período de ejercicio. Default: false |
exercisePeriod | string | Texto del período de ejercicio |
Layout construye NavbarProps desde sus propios props y los pasa a Navbar.
Gestión de Estado
No hay estado local en Navbar. El estado de los selectores de esquema es encapsulado en SchemaSelectors.
SchemaSelectors maneja internamente:
currentSucursal: sucursal activa seleccionada por el usuarioshouldShowSelectors: booleano derivado de la cantidad de sucursales/cajassucursalData: array con datos de sucursales y conteo de cajasloading: estado de carga inicial
Integración con API (SchemaSelectors)
SchemaSelectors consume dos endpoints vía api.get:
GET /config/sucursales— Lista de sucursales disponiblesGET /config/sucursales/{sucursal}/cajas— Cajas de una sucursal
Ambas respuestas se cachean en localStorage via sucursalStorage utils. No usan TanStack Query (inicialización de estado estructural, no datos reactivos).
Aplicaciones Consumidoras
Cualquier app que use Layout obtiene Navbar (y SchemaSelectors) automáticamente.
Apps actualmente en producción:
| App | Archivo | Incluye ConfigProvider |
|---|---|---|
MembershipsApp | ts/mod-membresias/MembershipsApp.tsx | Sí — SchemaSelectors activo |
CRMApp | ts/crm/CRMApp.tsx | Sí — SchemaSelectors activo |
Patrón esperado para nuevas apps:
StrictMode
└── ConfigProvider ← habilita SchemaSelectors en Navbar
└── HashRouter
└── Layout ← incluye Navbar con SchemaSelectors condicional
└── AppRouterApps que omitan ConfigProvider seguirán funcionando (Navbar acepta ausencia de contexto), pero no mostrarán SchemaSelectors.
Accesibilidad
- La
<nav>usa clases AdminLTE con rol semántico correcto <a data-widget="pushmenu">mantienerole="button"para accesibilidadSchemaSelectorsse renderiza comoReact.Fragmentgarantizando HTML válido dentro de<ul>
Notas Adicionales
useConfig()NO debe usarse enNavbar— lanza error siConfigProviderestá ausente- El permiso
CONFIG_CAMBIO-SUCURSALes el único gate para mostrar selectores de esquema; la visibilidad interna (múltiples sucursales/cajas) la controlaSchemaSelectorspor su cuenta MaintenanceBannertambién se renderiza enNavbarcon lógica de visibilidad propia, independiente deConfigContext