Plataforma técnica · Sevastopol
Ingresos View Island
Ingresos Islands Sevastopol
Propósito
Section titled “Propósito”IngresosViewIsland es una island dispatcher: no consulta datos ni guarda estado de negocio. Renderiza una barra de pestañas con dos opciones — Operaciones (vista de ventas/boletas) y PPM anual (actualización por corrección monetaria) — y decide cuál de los dos componentes hijos mostrar. La pestaña inicial puede provenir de otra island vía sessionStorage.
Ubicación
Section titled “Ubicación”Directorysevastopol/src/components/islands/contabilidad/
- IngresosViewIsland.tsx — componente único, ~40 líneas
Directorysevastopol/src/components/islands/accounting/
- OperationsViewIsland.tsx — pestaña Operaciones
Directorysevastopol/src/components/islands/contabilidad/
- PpmActualizacionAnualIsland.tsx — pestaña PPM
Composición
Section titled “Composición”type IngresosTab = "operaciones" | "ppm";const [tab, setTab] = createSignal<IngresosTab>("operaciones");Una única signal local — tab — controla qué componente hijo se monta. El switch usa <Show> con fallback:
<Show when={tab() === "operaciones"} fallback={<PpmActualizacionAnualIsland />}> <OperacionesIngresosIsland /></Show>| Pestaña | Componente | Endpoint base |
|---|---|---|
operaciones | OperacionesIngresosIsland (alias de IngresosViewIsland exportado desde OperationsViewIsland.tsx) | /api/operaciones |
ppm | PpmActualizacionAnualIsland | /api/reportes/ppm-actualizacion-anual |
Deep-link desde otras islands
Section titled “Deep-link desde otras islands”onMount lee sessionStorage.ingresos.activeTab para permitir abrir directamente una pestaña específica desde un origen externo:
onMount(() => { const requestedTab = window.sessionStorage.getItem("ingresos.activeTab"); if (requestedTab === "operaciones" || requestedTab === "ppm") { setTab(requestedTab); window.sessionStorage.removeItem("ingresos.activeTab"); }});Tres detalles:
- Valida la clave — solo acepta
"operaciones"o"ppm"; cualquier otra cosa la ignora. - Borra la clave después de leerla — si no se borrara, navegar a Ingresos por el sidebar después de un deep-link forzaría la misma pestaña accidentalmente.
- Se ejecuta una sola vez en mount — cambiar de pestaña posteriormente con el sidebar global no escribe la clave.
Quién emite el evento
Section titled “Quién emite el evento”| Origen | Acción | Código |
|---|---|---|
CicloContableIsland paso ppm | Botón Abrir PPM anual | sessionStorage.setItem("ingresos.activeTab", "ppm") + CustomEvent("sidebar:navigate", { detail: "IngresosView" }) |
Cualquier island futura puede usar el mismo mecanismo para llevar al operador a una pestaña específica.
Estilos del tab bar
Section titled “Estilos del tab bar”Los botones usan clases inline derivadas de tab():
const tabClass = (value: IngresosTab) => `px-3 py-1 text-xs font-semibold rounded-md transition-colors ${ tab() === value ? "bg-white dark:bg-zinc-700 shadow text-black dark:text-white" : "text-zinc-500 hover:text-black dark:hover:text-white" }`;No usa WorkspaceTabBar (el componente compartido de finanzas) porque la island está en contabilidad/ y predates ese token visual. Mantenerlo inline también deja la island liviana — sin imports adicionales del workspace.
Reglas de UI
Section titled “Reglas de UI”| Regla | Motivo |
|---|---|
| Sin fetch en el dispatcher | El contenedor no debe acoplarse al ciclo de datos de las hijas; cada pestaña gestiona su propio fetch y caché. |
Validar la clave de sessionStorage antes de aplicar | Una clave corrupta o legacy no debería forzar un crash al hacer setTab("foo"). |
| Borrar la clave después de leer | Evita que una navegación posterior herede la pestaña forzada. |
| Dos pestañas explícitas (sin opción “ambos”) | Operaciones es mensual; PPM es anual. Mezclarlas confunde al operador. |
<Show fallback> en vez de <Switch> con dos <Match> | Hay solo dos opciones; el Show con fallback es más compacto. |
| Sin persistir la pestaña activa | Cambiar de pestaña no se guarda — al volver a la island, siempre arranca en Operaciones (el caso más común). |