GastosApp es una aplicación de escritorio construida con Electron 42, React 19 y Vite 8. El proceso de desarrollo distingue dos modos: uno puramente web (útil para iterar sobre la UI con hot-reload rápido) y otro completo con Electron donde el proceso principal y el renderer corren en paralelo. Esta guía cubre las convenciones y patrones que rigen la base de código para que cualquier colaborador pueda incorporarse sin fricciones.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Davidmallega/Gastos-App/llms.txt
Use this file to discover all available pages before exploring further.
Iniciar el entorno
npm run dev no instancia el proceso principal de Electron (electron/main.js), por lo que window.electronAPI no estará disponible. Para las operaciones de control de ventana (minimizar, maximizar, cerrar) es necesario usar npm run electron:dev.
Estructura del proyecto
Componentes UI reutilizables
Todos los primitivos de interfaz se exportan desdesrc/components/ui/index.jsx. Usarlos garantiza consistencia visual y respeta las variables CSS del sistema de diseño (temas claro/oscuro).
| Componente | Props principales | Descripción |
|---|---|---|
PageHeader | title, subtitle, actions | Cabecera de página con título h1, subtítulo opcional y área de acciones (botones) a la derecha |
Card | children, style, className | Contenedor con fondo var(--bg-card), borde y borderRadius: 12 |
StatCard | label, value, sub, pre, color, icon | Tarjeta KPI con etiqueta, valor principal, sub-texto y valor tachado opcional (pre) |
Btn | variant, size, onClick, disabled | Botón con 5 variantes: primary, secondary, danger, ghost, success; 3 tamaños: sm, md, lg |
Badge | label, color | Chip de estado con 5 colores: blue, green, red, yellow, gray |
Input | label, value, onChange, type, required, placeholder | Input estilizado con label, foco en acento y soporte para datalist |
InputMonto | label, value, onChange, required | Input numérico para montos CLP: muestra formato con puntos al perder el foco, solo dígitos al editar |
Select | label, value, onChange, options, required | Select estilizado que acepta array de strings o de { value, label } |
Modal | open, onClose, title, width | Modal de formulario con overlay, cierre por Escape, montado en document.body vía createPortal |
Dialog | open, onClose, title, message, onConfirm, variant | Diálogo de confirmación con 3 variantes: danger, warning, info; montado vía createPortal |
Table | headers, sortKey, sortDir, onSort | Tabla con cabeceras ordenables; headers acepta strings o { label, align, key } |
TR y TD. TD acepta los props mono (fuente tabular), right (alineación) y muted (color secundario).
Patrones de código
Navegación mediante Custom Events
GastosApp no usa React Router. La navegación entre páginas se implementa con eventos del DOM para evitar prop drilling y sin instalar dependencias adicionales:Modal y Dialog con createPortal
Los componentesModal y Dialog usan createPortal(content, document.body) para montarse directamente en <body>, fuera del árbol del Sidebar. Esto es necesario porque el Sidebar tiene overflow: hidden, que en Chromium/Electron recorta cualquier position: fixed anidado dentro de ese contexto:
Fechas como string 'YYYY-MM-DD'
Todos los campos de fecha en el store se almacenan como string 'YYYY-MM-DD', nunca como objetos Date ni como ISO strings UTC. Esto evita por completo los desfases de zona horaria en Electron. Para convertir entre formatos se usan exclusivamente las funciones de utils/format.js (parseLocalDate, formatDate, addDays).
Soft delete con papelera
Ningún registro se elimina físicamente del store. Al borrar cualquier documento desde un módulo, el ítem se mueve astate.papelera[] con los campos deletedAt (ISO string) y deletedFrom (nombre del módulo de origen). Al arrancar la app se ejecuta una auto-purga silenciosa que descarta los ítems con más de 30 días en papelera.
ESLint
La configuracióneslint.config.js usa el formato plano (flat config) de ESLint 10 con tres extensiones:
@eslint/js— reglas base recomendadas de JavaScripteslint-plugin-react-hooks— valida las reglas de hooks (exhaustive-deps,rules-of-hooks)eslint-plugin-react-refresh— asegura que los módulos sean compatibles con el HMR de Vite
dist/ queda excluida globalmente mediante globalIgnores.