# Sistema Offline-First

Este documento describe el sistema offline-first implementado en la aplicación APR Solo.

## Características

- **Operaciones GET**: Se cachean automáticamente en IndexedDB. Si no hay conexión, se sirven desde el cache.
- **Operaciones POST/PUT/DELETE/PATCH**: Se guardan en una cola de sincronización cuando no hay conexión o cuando falla la petición.
- **Sincronización automática**: Cuando vuelve la conexión, se sincronizan automáticamente todas las operaciones pendientes.
- **Indicador visual**: Icono de sincronización en el header que muestra el estado de conexión y operaciones pendientes.

## Uso

### Usar offlineFetch en lugar de fetch

Para que las operaciones funcionen offline, reemplaza `fetch` por `offlineFetch`:

```typescript
import { offlineFetch } from "@/lib/offline-fetch";

// GET - Se cachea automáticamente
const response = await offlineFetch("/api/socios");
const data = await response.json();

// POST - Se guarda en cola si está offline
const response = await offlineFetch("/api/lecturas", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ clienteId: 1, lecturaActual: 100 }),
});
```

### Hook useOfflineSync

Para acceder al estado de sincronización en componentes:

```typescript
import { useOfflineSync } from "@/hooks/useOfflineSync";

function MyComponent() {
  const { pendingCount, syncing, online, sync, refresh } = useOfflineSync();

  return (
    <div>
      {online ? (
        <p>Conectado - {pendingCount} pendientes</p>
      ) : (
        <p>Sin conexión</p>
      )}
      <button onClick={sync} disabled={syncing}>
        Sincronizar
      </button>
    </div>
  );
}
```

### Componente SyncStatus

El componente `SyncStatus` muestra el estado de sincronización:

```typescript
import SyncStatus from "@/components/offline/SyncStatus";

// Versión compacta para headers
<SyncStatus compact />

// Versión completa
<SyncStatus />
```

## Estructura de Datos

### IndexedDB Stores

- `lecturas_pendientes`: Lecturas que no se han sincronizado
- `socios_cache`: Cache de datos de socios
- `operaciones_pendientes`: Cola de operaciones POST/PUT/DELETE/PATCH pendientes
- `cache_respuestas`: Cache de respuestas GET

### Operaciones Pendientes

Cada operación pendiente contiene:
- `method`: Método HTTP (POST, PUT, DELETE, PATCH)
- `url`: URL de la API
- `body`: Cuerpo de la petición
- `headers`: Headers de la petición
- `timestamp`: Fecha de creación
- `sincronizado`: Si ya fue sincronizada
- `intentos`: Número de intentos de sincronización
- `error`: Mensaje de error si falló

## Sincronización

La sincronización se ejecuta automáticamente cuando:
1. Vuelve la conexión a internet
2. El usuario hace clic en el botón de sincronización

La sincronización procesa:
1. Todas las lecturas pendientes
2. Todas las operaciones pendientes (POST, PUT, DELETE, PATCH)

## Migración de Código Existente

Para migrar código existente a offline-first:

1. Reemplazar `fetch` por `offlineFetch`:
   ```typescript
   // Antes
   const res = await fetch("/api/lecturas", { ... });
   
   // Después
   import { offlineFetch } from "@/lib/offline-fetch";
   const res = await offlineFetch("/api/lecturas", { ... });
   ```

2. Manejar respuestas offline:
   ```typescript
   const response = await offlineFetch("/api/lecturas", { ... });
   const data = await response.json();
   
   if (data.offline || data.pending) {
     // La operación se guardó para sincronización
     console.log("Operación guardada para sincronización");
   }
   ```

## Notas

- El cache de respuestas GET expira después de 24 horas por defecto
- Las operaciones pendientes se reintentan automáticamente cuando vuelve la conexión
- El sistema detecta automáticamente cambios en el estado de conexión
- El contador de operaciones pendientes se actualiza cada 5 segundos
