# Arquitectura del Frontend — Smart POS

> Documentación técnica detallada del frontend (`pos-ventas`). Para editores AI.

---

## Índice

1. [Stack y dependencias](#1-stack-y-dependencias)
2. [Estructura de directorios](#2-estructura-de-directorios)
3. [Punto de entrada y bootstrap](#3-punto-de-entrada-y-bootstrap)
4. [Sistema de rutas](#4-sistema-de-rutas)
5. [Autenticación y permisos](#5-autenticación-y-permisos)
6. [State management (Zustand)](#6-state-management-zustand)
7. [Server state (TanStack Query)](#7-server-state-tanstack-query)
8. [Capa API (Axios)](#8-capa-api-axios)
9. [Layout y Sidebar](#9-layout-y-sidebar)
10. [Módulo POS](#10-módulo-pos)
11. [Sistema Offline-First](#11-sistema-offline-first)
12. [PWA y Service Worker](#12-pwa-y-service-worker)
13. [Módulo de Suscripciones](#13-módulo-de-suscripciones)
14. [Módulo de Listas de Precios](#14-módulo-de-listas-de-precios)
15. [Estilos y temas](#15-estilos-y-temas)
16. [Patrones y convenciones](#16-patrones-y-convenciones)

---

## 1. Stack y dependencias

| Tecnología | Versión | Uso |
|---|---|---|
| React | 18.2 | Framework UI |
| Vite | 5.1 | Build tool + dev server |
| Zustand | 4.5 | State management (stores) |
| TanStack Query | 5.22 | Server state + caching |
| MUI (Material UI) | 7.3 | Componentes UI principales |
| styled-components | 6.1 | Estilos CSS-in-JS (algunos componentes) |
| Axios | 1.13 | HTTP client |
| React Router | 6.22 | Routing |
| Dexie.js | 4.3 | IndexedDB wrapper (offline) |
| vite-plugin-pwa | 1.2 | PWA + Service Worker |
| Sonner | 1.4 | Toast notifications |
| Recharts | 2.14 | Gráficos en dashboard |
| pdfmake | 0.2 | Generación de PDF (tickets, reportes) |
| react-hook-form | 7.50 | Formularios |
| Ant Design | 5.22 | Algunos componentes (DatePicker, Table) |
| @iconify/react | 4.1 | Iconos (Lucide, MDI, etc.) |
| date-fns / dayjs | 4.1 / 1.11 | Manipulación de fechas |
| SweetAlert2 | 11.10 | Diálogos de confirmación |

### Archivo: `package.json`

```
pos-ventas/package.json
```

Scripts disponibles:
```bash
npm run dev      # Dev server (Vite) → http://localhost:5173
npm run build    # Build producción → dist/
npm run preview  # Preview del build
npm run lint     # ESLint
```

---

## 2. Estructura de directorios

```
pos-ventas/
├── public/
│   └── logo_simple.png         # Icono PWA 512x512
├── index.html                  # HTML base + meta PWA
├── vite.config.js              # Vite + PWA + Workbox config
├── package.json
└── src/
    ├── main.jsx                # ReactDOM.createRoot → App
    ├── App.jsx                 # Providers (Auth, Empresa, Theme) + Router
    ├── index.js                # Re-exports de componentes principales
    │
    ├── api/                    # 32 archivos — servicios API (axios calls)
    │   ├── api.config.js       # Axios instance + JWT interceptors + refresh
    │   ├── auth.service.js     # login, register, logout, refresh, getMe
    │   ├── sync.service.js     # syncFull, syncDelta, pushVentasOffline
    │   ├── facturas.service.js # CRUD facturas
    │   ├── productos.service.js# CRUD + búsqueda productos
    │   ├── clientes.service.js # CRUD clientes
    │   ├── cobros.service.js   # Gestión de cobros
    │   ├── listas-precios.service.js  # Listas de precios
    │   ├── ofertas.service.js  # Ofertas y promociones
    │   ├── suscripciones.service.js   # Suscripciones SaaS
    │   ├── vendedores-cobradores.service.js
    │   └── index.js            # Re-exports de funciones principales
    │
    ├── store/                  # 31 archivos — Zustand stores
    │   ├── AuthStore.jsx       # Login, permisos, hasModule, hasPermission
    │   ├── SyncStore.jsx       # Sincronización offline (11KB)
    │   ├── ThemeStore.jsx      # Tema claro/oscuro, colores
    │   ├── ProductosStore.jsx  # Estado productos
    │   ├── VentasStore.jsx     # Estado ventas
    │   ├── CartVentasStoreTemporal.jsx  # Carrito de ventas temporal
    │   ├── ListasPreciosStore.jsx       # Listas de precios (12KB)
    │   ├── CierreCajaStore.jsx # Estado cierre de caja
    │   └── ... (23 stores más)
    │
    ├── tanstack/               # 28 archivos — TanStack Query hooks
    │   ├── PosConfigStack.js   # usePosConfigQuery (config POS por sucursal)
    │   └── ... (queries para cada módulo)
    │
    ├── hooks/                  # Custom hooks
    │   ├── Layout.jsx          # Layout con sidebar (Grid MUI)
    │   ├── ProtectedRoute.jsx  # Guard de rutas con permisos
    │   ├── useOfflinePOS.js    # Fallbacks API → IndexedDB
    │   ├── useOfertasCarrito.js# Cálculo ofertas en carrito
    │   ├── useBuscarProductos.js
    │   ├── usePermission.js
    │   └── useValidarPermisosOperativos.jsx
    │
    ├── offline/
    │   └── db.js               # Dexie.js: schema, helpers CRUD, búsqueda local
    │
    ├── components/
    │   ├── templates/          # 26 templates (páginas principales)
    │   │   ├── POSRetailTemplate.jsx     # 141KB — POS Retail completo
    │   │   ├── POSAdminTemplate.jsx      # 56KB — POS Admin completo
    │   │   ├── DashboardTemplateV2.jsx   # Dashboard
    │   │   ├── CobrosTemplateV2.jsx      # 101KB — Cobros
    │   │   ├── LoginTemplate.jsx
    │   │   ├── RegisterTemplate.jsx
    │   │   └── ...
    │   ├── organismos/         # Componentes complejos (multi-componente)
    │   │   ├── sidebar/
    │   │   │   └── Sidebar.jsx # Sidebar con links filtrados por permisos
    │   │   ├── POSDesign/      # Componentes del POS
    │   │   ├── suscripciones/  # Tabs de suscripciones
    │   │   └── EmpresaConfigDesign/  # Config empresa
    │   └── ui/                 # Componentes UI reutilizables
    │       └── SyncStatusBar.jsx  # Indicador de conexión/sync
    │
    ├── pages/                  # 32 páginas (wrappers de templates)
    │   ├── POSAdmin.jsx        # Switch retail/admin según config
    │   ├── POS.jsx             # Lógica de apertura de caja
    │   ├── Ventas.jsx
    │   ├── Dashboard.jsx
    │   └── ...
    │
    ├── routers/
    │   └── routes.jsx          # Todas las rutas con ProtectedRoute + Layout
    │
    ├── context/
    │   ├── AuthContent.jsx     # AuthContextProvider
    │   └── EmpresaContext.jsx  # EmpresaProvider (empresa activa)
    │
    ├── utils/
    │   ├── dataEstatica.jsx    # Links sidebar, datos estáticos, módulos config
    │   ├── Conversiones.jsx    # FormatearNumeroDinero, conversiones
    │   ├── invoiceCalculations.js  # Cálculos de factura
    │   └── ...
    │
    ├── reports/                # Generación de reportes PDF
    ├── supabase/               # 22 archivos — integración Supabase (legacy?)
    ├── constants/              # Constantes
    ├── assets/                 # Imágenes estáticas
    └── styles/
        └── variables.js        # Variables de tema + iconos de React Icons
```

---

## 3. Punto de entrada y bootstrap

### `main.jsx`

```jsx
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
```

### `App.jsx`

```jsx
function App() {
  return (
    <ThemeProvider theme={theme}>
      <AuthContextProvider>
        <EmpresaProvider>
          <MyRoutes />
        </EmpresaProvider>
      </AuthContextProvider>
    </ThemeProvider>
  );
}
```

**Orden de providers:**
1. `ThemeProvider` — Tema MUI + styled-components
2. `AuthContextProvider` — React Context para auth (wrapper de Zustand)
3. `EmpresaProvider` — Empresa activa
4. `MyRoutes` — React Router

### `index.js`

Re-exporta componentes principales para imports limpios:
```javascript
export { Layout } from "./hooks/Layout";
export { ProtectedRoute } from "./hooks/ProtectedRoute";
export { Login } from "./pages/Login";
// ... etc
```

---

## 4. Sistema de rutas

### Archivo: `src/routers/routes.jsx`

Todas las rutas de la aplicación están en un solo archivo. Patrones:

**Ruta con sidebar (mayoría):**
```jsx
<Route path="/ventas" element={
  <Layout>
    <ProtectedRoute accessBy="authenticated" modulo="FACTURACION">
      <Ventas />
    </ProtectedRoute>
  </Layout>
} />
```

**Ruta sin sidebar (POS fullscreen):**
```jsx
<Route path="/pos" element={
  <ProtectedRoute accessBy="authenticated" modulo="POS_ADMIN">
    <POSAdmin />
  </ProtectedRoute>
} />
```

**Ruta con sidebar para POS admin:**
```jsx
<Route path="/pos-admin" element={
  <Layout>
    <ProtectedRoute accessBy="authenticated" modulo="POS_ADMIN">
      <POSAdmin />
    </ProtectedRoute>
  </Layout>
} />
```

**Rutas de autenticación (sin auth):**
```jsx
<Route path="/login" element={
  <ProtectedRoute accessBy="non-authenticated">
    <Login />
  </ProtectedRoute>
} />
```

### ProtectedRoute (`src/hooks/ProtectedRoute.jsx`)

```jsx
export function ProtectedRoute({ children, accessBy, modulo }) {
  const { isAuthenticated, hasModule } = useAuthStore();
  
  if (accessBy === "authenticated") {
    if (!isAuthenticated) return <Navigate to="/login" />;
    if (modulo && !hasModule(modulo)) return <Navigate to="/access-denied" />;
    return children;
  }
  
  if (accessBy === "non-authenticated") {
    if (isAuthenticated) return <Navigate to="/" />;
    return children;
  }
}
```

---

## 5. Autenticación y permisos

### AuthStore (`src/store/AuthStore.jsx`)

Estado principal:
```javascript
{
  user: { id, nombre, email, empresa_id, is_superadmin, empresa: {...} },
  empresa: { id, razon_social, ruc, ... },
  suscripcion: { plan, estado, ... },
  modulos: ["DASHBOARD", "POS_ADMIN", "FACTURACION", ...],   // string[]
  modulosDetalle: [{ codigo, descripcion, tipo }],            // detalle
  permisos: { PRODUCTOS: ["LEER", "CREAR", "EDITAR", "ELIMINAR"], ... },
  isSuperAdmin: false,
  isAuthenticated: true,
}
```

Acciones principales:
- **`login(credentials)`** → API login + fetchMe → guarda tokens + contexto completo
- **`cerrarSesion()`** → API logout + clearTokens + limpiar estado
- **`fetchMe()`** → `GET /auth/me` → actualiza modulos, permisos, empresa
- **`hasModule(codigo)`** → `true` si superadmin o si `modulos.includes(codigo)`
- **`hasPermission(modulo, privilegio)`** → verifica `permisos[modulo].includes(privilegio)`

### Persistencia

- Tokens en `localStorage`: `access_token`, `refresh_token`, `user`
- Contexto completo en `localStorage`: `user_context` (JSON con empresa, módulos, permisos)
- Al recargar la app: `checkAuth()` rehidrata desde localStorage
- `fetchMe()` actualiza desde el servidor

---

## 6. State management (Zustand)

Cada store es un archivo en `src/store/`. Patrón:

```javascript
import { create } from "zustand";

export const useProductosStore = create((set, get) => ({
  productos: [],
  isLoading: false,
  
  fetchProductos: async () => {
    set({ isLoading: true });
    const data = await apiGetProductos();
    set({ productos: data, isLoading: false });
  },
}));
```

### Stores principales

| Store | Archivo | Propósito |
|---|---|---|
| `useAuthStore` | `AuthStore.jsx` | Auth, permisos, user, empresa |
| `useSyncStore` | `SyncStore.jsx` | Sync offline, conexión, auto-sync |
| `useThemeStore` | `ThemeStore.jsx` | Tema claro/oscuro, colores primarios |
| `useProductosStore` | `ProductosStore.jsx` | CRUD productos |
| `useVentasStore` | `VentasStore.jsx` | Estado ventas/facturas |
| `useCartVentasStore` | `CartVentasStoreTemporal.jsx` | Carrito temporal |
| `useListasPreciosStore` | `ListasPreciosStore.jsx` | Listas de precios |
| `useCierreCajaStore` | `CierreCajaStore.jsx` | Cierre de caja |
| `useCategoriasStore` | `CategoriasStore.jsx` | Categorías |
| `useClientesProveedoresStore` | `ClientesProveedoresStore.jsx` | Clientes y proveedores |
| `useImpresorasStore` | `ImpresorasStore.jsx` | Impresoras configuradas |
| `useSerializacionStore` | `SerializacionStore.jsx` | Numeraciones de comprobantes |
| `useMovCajaStore` | `MovCajaStore.jsx` | Movimientos de caja |
| `useStockStore` | `StockStore.jsx` | Stock por almacén |
| `usePermisosStore` | `PermisosStore.jsx` | Permisos detallados |
| `useEmpresaStore` | `EmpresaStore.jsx` | Datos empresa activa |
| `useGlobalStore` | `GlobalStore.jsx` | Estado global UI |

---

## 7. Server state (TanStack Query)

Directorio: `src/tanstack/` (28 archivos)

Cada archivo exporta hooks de TanStack Query para un recurso. Ejemplo de patrón:

```javascript
// src/tanstack/PosConfigStack.js
import { useQuery } from "@tanstack/react-query";
import { getPosConfig } from "../api/posConfig.service";

export function usePosConfigQuery(sucursalId) {
  return useQuery({
    queryKey: ["posConfig", sucursalId],
    queryFn: () => getPosConfig(sucursalId),
    enabled: !!sucursalId,
    staleTime: 5 * 60 * 1000,
  });
}
```

TanStack Query se usa para:
- **Caching automático** de datos del servidor
- **Refetch** automático al volver a la pestaña
- **Invalidación** de queries al mutar datos
- **Loading/error states** automáticos

---

## 8. Capa API (Axios)

### Archivo: `src/api/api.config.js`

Configura una instancia de Axios con:

1. **Base URL**: `VITE_API_BASE_URL` (env) o `http://localhost:3000/api/v1`
2. **Headers**: `Content-Type: application/json`, `x-app-key: <APP_KEY>`
3. **Request interceptor**: agrega `Authorization: Bearer <token>` automáticamente
4. **Response interceptor**: maneja refresh de token transparente

### Flujo de refresh token

```
Request falla con 401
  → ¿Ya está refreshing? → Encolar request
  → Obtener refresh_token de localStorage
  → POST /auth/refresh
  → Si OK → guardar nuevos tokens → reintentar request original
  → Si falla → clearTokens() → redirect a /login
```

El interceptor usa un **failedQueue** para manejar múltiples requests que fallan simultáneamente con 401.

### Servicios API

Cada servicio en `src/api/` sigue el patrón:

```javascript
import api from "./api.config";

export const getProductos = async (page, limit) => {
  const { data } = await api.get(`/productos?page=${page}&limit=${limit}`);
  return data;
};

export const createProducto = async (body) => {
  const { data } = await api.post("/productos", body);
  return data;
};
```

---

## 9. Layout y Sidebar

### Layout (`src/hooks/Layout.jsx`)

Grid MUI de 2 columnas:
```
┌──────┬─────────────────────────────────┐
│      │                                 │
│ Side │        Main Content             │
│ bar  │                                 │
│      │                                 │
│(280px│        (flex: 1)                │
│ max) │                                 │
└──────┴─────────────────────────────────┘
```

- **Desktop**: Sidebar + Content
- **Mobile**: Sidebar oculto (hamburguesa para abrir)
- El POS Retail **NO** usa Layout (fullscreen)

### Sidebar (`src/components/organismos/sidebar/Sidebar.jsx`)

- Links definidos en `src/utils/dataEstatica.jsx` → `LinksArray` y `SecondarylinksArray`
- Cada link tiene `modulo` (string). El sidebar filtra con `hasModule(link.modulo)`
- Iconos: `@iconify/react` con prefijo `lucide:`
- Hover/active states con styled-components
- Logo de la empresa en la parte superior
- Datos de usuario + dropdown (Mi perfil, Config, Cerrar sesión) en la parte inferior

---

## 10. Módulo POS

### Arquitectura de decisión

```
/pos (ruta) → POSAdmin.jsx
  │
  ├── Carga config: usePosConfigQuery(sucursal_id)
  │
  ├── ¿Caja abierta? (sesionCaja)
  │   ├── No → PantallaAperturaCaja
  │   └── Sí → Continuar
  │
  ├── tipo_pos === "retail"?
  │   ├── Sí → POSRetailTemplate (fullscreen, sin sidebar)
  │   └── No → POSAdminTemplate
  │       └── Si ruta es /pos → wrappear con <Layout> dinámicamente
  │
  └── /pos-admin (ruta) → POSAdmin con <Layout> siempre
```

### POSRetailTemplate (`src/components/templates/POSRetailTemplate.jsx`)

**El componente más grande del proyecto (141KB, ~3800 líneas)**

Estructura visual:
```
┌─────────────────────────────────────────────────────────────┐
│ ☰ │ Sync │ Búsqueda productos        │ Cliente │ Info caja  │ ← TopInfoBar
├───┴──────┴────────────────────────┬───┴─────────┴────────────┤
│                                   │                          │
│     Grilla de productos           │    Carrito de compras    │
│     (categorías + tiles)          │    (items + totales)     │
│                                   │                          │
│                                   │                          │
├───────────────────────────────────┤    ┌──────────────────┐  │
│     Categorías (tabs/chips)       │    │  Numpad           │  │
│                                   │    │  (teclado numérico│  │
│                                   │    │   para cantidad)  │  │
│                                   │    └──────────────────┘  │
│                                   ├──────────────────────────┤
│                                   │  Botones: Pagar, Limpiar │
└───────────────────────────────────┴──────────────────────────┘
```

Features implementadas:
- **Grilla de productos** con tiles configurables (tamaño, columnas, imagen, precio, stock)
- **Búsqueda** con detección de lector de código de barras vs escritura manual
- **Carrito** con cantidades editables, descuentos, eliminación
- **Selección de cliente** con búsqueda
- **Múltiples medios de pago** (efectivo, tarjeta, transferencia, etc.)
- **Cálculo de vuelto** automático
- **Numpad** para entrada rápida de cantidades
- **Menú hamburguesa** (☰) con acceso a admin, config, cierre caja, logout
- **SyncStatusBar** compacto (indicador de conexión + sync)
- **Integración offline**: usa `useOfflinePOS` para fallbacks

### Detección de código de barras

Constantes:
```javascript
const BARCODE_SCAN_THRESHOLD_MS = 80;  // Umbral entre teclas
```

Lógica:
```
Input recibe caracteres
  → Registrar timestamps entre cada keystroke
  → Al presionar Enter:
      → Calcular promedio de intervalos
      → Si promedio < 80ms → es lector de códigos
          → Buscar producto por código exacto
          → Si 1 resultado → auto-add al carrito + toast
          → Si múltiples → mostrar dropdown
      → Si promedio >= 80ms → es escritura manual
          → Mostrar dropdown de resultados
```

Configurable con `barcode_auto_add: true` en `DEFAULT_CONFIG`.

### POSAdminTemplate (`src/components/templates/POSAdminTemplate.jsx`)

**56KB** — Formulario completo de facturación con todos los campos:
- Selección de cliente con creación inline
- Tabla de items editable
- Condición de operación (contado, crédito)
- Medios de pago múltiples
- Numeración de documento
- Cálculos de IVA detallados
- Integración con SIFEN

### POSAdmin.jsx (`src/pages/POSAdmin.jsx`)

Page component que:
1. Carga la configuración POS de la sucursal
2. Verifica si hay caja abierta
3. Renderiza el template correcto según `tipo_pos`
4. Si `tipo_pos === "admin"` y la ruta es `/pos`, wrappea con `<Layout>`

---

## 11. Sistema Offline-First

> Documentación completa en `docs/OFFLINE_SYNC.md`

### Resumen de componentes

| Componente | Archivo | Descripción |
|---|---|---|
| **Dexie DB** | `src/offline/db.js` | Schema IndexedDB, helpers CRUD, búsqueda local |
| **SyncStore** | `src/store/SyncStore.jsx` | Estado sync, auto-sync 5min, push ventas, ping 30s |
| **useOfflinePOS** | `src/hooks/useOfflinePOS.js` | Hook con fallbacks API → IndexedDB |
| **sync.service** | `src/api/sync.service.js` | Cliente API para endpoints de sync |
| **SyncStatusBar** | `src/components/ui/SyncStatusBar.jsx` | UI: indicador conexión + sync |

### SyncStore — Detalles de implementación

**Inicialización (`init()`):**
1. Guard contra múltiples llamadas (`_initialized`)
2. Solicita `navigator.storage.persist()` para proteger IndexedDB
3. Carga `lastSyncAt` desde IndexedDB
4. Cuenta ventas pendientes
5. Verifica conectividad real con `GET /sync/ping` (timeout 5s)
6. Registra event listeners `online`/`offline` (limpia previos)
7. Inicia ping periódico cada 30s
8. Inicia auto-sync cada 5min

**Sync Manual (`syncManual()`):**
1. Push ventas pendientes
2. `GET /sync/full` → descarga todo
3. `bulkPutItems()` en IndexedDB para cada tabla
4. Guarda `lastSyncAt`
5. Limpia ventas sincronizadas

**Sync Auto (`syncAuto()`):**
1. Si nunca se sincronizó → redirige a `syncManual()`
2. Push ventas pendientes
3. `GET /sync/delta?since=lastSyncAt` → solo cambios
4. `bulkPutItems()` upsert de cambios
5. Para medios_pago, numeraciones, condiciones_pago → clear + replace
6. Actualiza `lastSyncAt`

**Push Ventas (`_pushPendingVentas()`):**
1. Lee ventas `status: "pending"` de IndexedDB
2. Marca como `"syncing"` (lock para evitar duplicados)
3. `POST /sync/push/ventas` al servidor
4. Si OK → marca como `"synced"` o `"failed"` según respuesta
5. Si falla el POST → revierte a `"pending"` para reintentar

**Conectividad:**
- `checkRealConnectivity()` — ping al backend cada 30s (no confía solo en `navigator.onLine`)
- Al detectar reconexión → ejecuta `syncAuto()` inmediatamente

### useOfflinePOS — Patrón de fallback

Cada función sigue el mismo patrón:
```javascript
async function fallback(args, apiFn) {
  if (isOnline && apiFn) {
    try { return await apiFn(args); }     // Intenta API
    catch { return localFn(args); }        // Fallback a Dexie
  }
  return localFn(args);                    // Offline directo
}
```

Caso especial — `createFacturaFallback`:
- Si online → envía a API normalmente
- Si la API falla por error de red → encola en IndexedDB + toast
- Si offline → encola directamente en IndexedDB
- Distingue errores de red vs errores de validación (4xx)

---

## 12. PWA y Service Worker

### Configuración (`vite.config.js`)

```javascript
VitePWA({
  registerType: "autoUpdate",
  manifest: {
    name: "Smart POS",
    short_name: "Smart POS",
    theme_color: "#f88533",
    display: "standalone",
  },
  workbox: {
    maximumFileSizeToCacheInBytes: 15 * 1024 * 1024,  // 15MB
    runtimeCaching: [
      // Google Fonts → CacheFirst
      // /api/v1/sync/* → NetworkFirst (10s timeout)
      // Imágenes → CacheFirst (30 días)
    ],
  },
})
```

- **App shell** precacheado (JS, CSS, HTML) → funciona sin internet
- **Auto-update** del Service Worker silencioso
- Instalable como app en Android/iOS

---

## 13. Módulo de Suscripciones

### Arquitectura

La página de suscripciones (`src/pages/Suscripciones.jsx`) muestra tabs dinámicas según el tipo de usuario:

| User Type | Tabs visibles |
|---|---|
| **holding** | Mi Suscripción, Red Empresarial, Métricas, Comisiones |
| **reseller** | Mi Suscripción, Mis Comisiones, Mis Subsidiarios |
| **subsidiario** | Mi Suscripción |

### Componentes

```
src/components/organismos/suscripciones/
├── MiSuscripcion.jsx       # Info plan actual, uso, renovación
├── RedEmpresarial.jsx      # Jerarquía empresarial (holding)
├── Resellers.jsx           # Dashboard comisiones reseller
├── ResellersContent.jsx    # Placeholder
├── ComisionesContent.jsx   # Placeholder
├── MetricasContent.jsx     # Placeholder
├── MisSubsidiariosContent.jsx  # Placeholder
└── MetricasResellerContent.jsx # Placeholder
```

### API: `src/api/suscripciones.service.js` (16KB)

Funciones para comisiones, jerarquía, métricas de holding y reseller.

---

## 14. Módulo de Listas de Precios

### Estilo

Usa **styled-components** (no MUI) con variables de tema:
```javascript
p.theme.body, p.theme.primary, p.theme.text, p.theme.border, p.theme.background
```

### Componentes clave

```
src/components/templates/listas-precios/
├── WizardCrearLista.jsx        # Wizard de creación de lista
├── AsignacionesListaDialog.jsx # Asignar lista a clientes
├── ProductosListaDialog.jsx    # Asignar precios por producto
└── TablaGestionListas.jsx      # Tabla CRUD de listas
```

### Patrón UI

- **Overlay/Container** para diálogos (position:fixed)
- **SectionHeader**: icono + título + subtítulo
- **FormGrid**: grid-template-columns
- Iconos: `@iconify/react` con prefijo `mdi:`
- Notificaciones: `sonner` toast
- Data fetching: TanStack Query

---

## 15. Estilos y temas

### Doble sistema de estilos

1. **MUI (Material UI)** — mayoría de componentes
2. **styled-components** — algunos componentes custom (listas precios, sidebar, login)

### ThemeStore (`src/store/ThemeStore.jsx`)

Maneja tema claro/oscuro + colores personalizables:
```javascript
{
  theme: "light" | "dark",
  primaryColor: "#f88533",  // Naranja Automia
  // ... colores derivados
}
```

### Variables (`src/styles/variables.js`)

Exporta:
- Iconos de React Icons (v, iconoUser, iconoSettings, etc.)
- Breakpoints
- Colores base

### Convenciones de estilo

- Templates grandes usan **inline styles** + **MUI sx prop** + **className CSS**
- Componentes de listas de precios usan **styled-components**
- Sidebar usa **styled-components**
- Los templates de POS combinan ambos estilos (CSS inline para layout + MUI para componentes)

---

## 16. Patrones y convenciones

### Estructura de una página

```
Page (src/pages/Xxx.jsx)
  └── Template (src/components/templates/XxxTemplate.jsx)
        ├── Estado local (useState, useRef)
        ├── Zustand stores (useXxxStore)
        ├── TanStack queries
        └── JSX con MUI components
```

### Convenciones de archivos

- **Stores**: `src/store/XxxStore.jsx` — Zustand con `create()`
- **API services**: `src/api/xxx.service.js` — funciones async con Axios
- **TanStack hooks**: `src/tanstack/XxxStack.js` — `useQuery`, `useMutation`
- **Custom hooks**: `src/hooks/useXxx.js`
- **Páginas**: `src/pages/Xxx.jsx` — wrapper ligero
- **Templates**: `src/components/templates/XxxTemplate.jsx` — toda la lógica
- **Extensiones**: `.jsx` para todo (incluyendo stores y hooks)

### Notificaciones

- **Sonner** (`toast()`): para mensajes rápidos (éxito, info)
- **SweetAlert2** (`Swal.fire()`): para confirmaciones y diálogos
- **MUI Snackbar**: usado en algunos componentes legacy

### Formularios

- **react-hook-form** en formularios complejos (registro, config)
- **useState** directo en formularios simples (POS, búsquedas)

### Formateo de moneda

```javascript
// src/utils/Conversiones.jsx
FormatearNumeroDinero(numero, currency, iso)
// Ejemplo: FormatearNumeroDinero(50000, "PYG", "PY") → "Gs. 50.000"
// ⚠️ Crashea si 'numero' es undefined — siempre usar fallback: (precio || 0)
```

---

*Documento generado: Febrero 2026*
