# Prompt p04 — Dashboard Gérant de Station (mobile)
*Contextes requis : ctx-global.md + ctx-mobile-expo.md + ctx-laravel-bff.md*

---

## Profil & Accès
- **Rôle** : GER (Gérant de Station)
- **Nombre d'utilisateurs** : 23 (1 par station)
- **Accès** : sa station uniquement — isolation stricte par `station_id` dans le JWT
- **Platform** : Mobile uniquement (React Native + Expo SDK 54)
- **Session** : 8h, OTP à la connexion

---

## Fichiers à créer

```
app/(mobile)/gerant/dashboard.tsx
app/(mobile)/gerant/cuves.tsx
app/(mobile)/gerant/shifts.tsx
app/(mobile)/gerant/livraisons.tsx
app/(mobile)/gerant/cloture.tsx
components/gerant/CuveBar.tsx
components/gerant/ShiftCard.tsx
components/gerant/LivraisonCard.tsx
components/gerant/AlerteBadge.tsx
components/gerant/NiveauGauge.tsx
hooks/useStationDashboard.ts
hooks/useIotCuves.ts
```

---

## Spec UX condensée

```
┌─────────────────────────┐
│ ◀  Kaloum — FlowUp  🔔2 │
│ ─────────────────────── │
│  Bonjour, Jean-Marie     │
│  Gérant · Lundi 13 mai  │
├─────────────────────────┤
│ ┌─────────────────────┐ │
│ │ NIVEAUX CUVES IOT   │ │
│ │                     │ │
│ │ Gasoil  ████████ 78%│ │
│ │ SP95    █████░░ 61% │ │
│ │ SP98    ███░░░░ 42% │ │
│ │ Pétrole ██░░░░░ 28%⚠│ │
│ │         [Actualiser]│ │
│ └─────────────────────┘ │
│ ┌─────────────────────┐ │
│ │ SHIFTS ACTIFS (3)   │ │
│ │ POM Camara  Pompe1  │ │
│ │ POM Diallo  Pompe2  │ │
│ │ POM Bah     Pompe3  │ │
│ └─────────────────────┘ │
│ ┌─────────────────────┐ │
│ │ DERNIÈRE LIVRAISON  │ │
│ │ OL-2026-0412        │ │
│ │ 12 000 L Gasoil     │ │
│ │ Il y a 2h  ✓ Conforme│ │
│ └─────────────────────┘ │
├─────────────────────────┤
│ [Cuves][Shifts][Livr.][Clôt.]│
└─────────────────────────┘
```

### Onglets
- **Cuves** : liste toutes les cuves de la station avec jauge animée (couleur : vert ≥50%, orange 20-49%, rouge <20%), historique 7j, bouton "Signaler anomalie".
- **Shifts** : liste des shifts du jour (en cours + terminés), CA par shift, nombre de ventes, bouton "Démarrer nouveau shift" (délégué au pompiste).
- **Livraisons** : historique des 10 dernières livraisons, statut, volumes, écarts de réception.
- **Clôture** : formulaire de clôture journalière (vérification caisse, signature électronique, envoi au CFO). Disponible uniquement après 17h.

### Alertes
- Badge rouge sur l'icône cloche (header) si alertes non lues
- Toast push pour alertes IoT critiques (fuite, niveau <10%)
- `AlerteBadge` affiché sur la jauge cuve concernée

---

## Endpoints BFF

```
GET /api/stations/{id}/dashboard
  Headers : Authorization: Bearer {token}
  Réponse : {
    station: { id: INT, nom: "Kaloum", statut: "ok"|"alerte"|"critique" },
    shifts_actifs: [{ id: INT, pompiste_nom: "Camara", pompe: "Pompe 1", debut: "08:00" }],
    derniere_livraison: {
      reference: "OL-2026-0412",
      volume: "12000",   // VARCHAR (litres)
      produit: "Gasoil",
      conforme: true,
      il_y_a: "2h"
    },
    alertes_non_lues: 2,
    ca_jour: "4200000"   // VARCHAR
  }

GET /api/iot/cuves?station_id={id}
  Réponse : [{
    id: INT,
    produit: "Gasoil",
    capacite: "30000",  // VARCHAR (litres)
    niveau_actuel: "23400",  // VARCHAR
    niveau_pct: "78",        // VARCHAR
    statut: "ok"|"alerte"|"critique",
    derniere_lecture: "2026-05-13T10:42:00Z"
  }]

GET /api/stations/{id}/shifts?date={YYYY-MM-DD}
  Réponse : [{ id: INT, pompiste_nom: "Camara", pompe: "Pompe 1",
               debut: "08:00", fin: null, ca: "1240000", nb_ventes: 47 }]

GET /api/stations/{id}/livraisons?limite=10
  Réponse : [{ id: INT, reference: "OL-2026-0412", produit: "Gasoil",
               volume_attendu: "12000", volume_recu: "11987",
               ecart: "13", conforme: true, date: "2026-05-13T08:30:00Z" }]

POST /api/stations/{id}/alertes
  Body : { type: "ANOMALIE_CUVE", cuve_id: INT, description: "Odeur suspecte" }
  Réponse : { id: INT, created_at: "..." }

POST /api/stations/{id}/cloture
  Body : { date: "2026-05-13", ca_especes: "...", ca_mobile_money: "...",
           ca_credit: "...", signature_base64: "..." }
  Réponse : { id: INT, statut: "SOUMIS" }
```

---

## Règles spécifiques

- **RGGER-01** : Le JWT contient `station_id` — toutes les requêtes sont filtrées par ce `station_id`. Un GER ne peut jamais voir les données d'une autre station, même en modifiant l'URL.
- **RGGER-02** : Les niveaux de cuves s'actualisent toutes les 30 secondes via polling (pas de WebSocket mobile pour économiser la batterie). Indicateur "Actualisé il y a Xs".
- **RGGER-03** : Clôture disponible uniquement après 17h00 heure locale. Avant 17h, le bouton est grisé avec message "Disponible à partir de 17h00".
- **RGGER-04** : Montants = VARCHAR — la fonction `formatGNF(str: string)` est l'unique point de formatage.
- **RGGER-05** : Mode hors-ligne partiel : les données dashboard sont cachées dans MMKV avec TTL 5 min. Bandeau orange "Mode hors-ligne — données du HH:MM" si pas de réseau.
- **RGGER-06** : IDs = `number` dans tous les types TypeScript.
- **RGGER-07** : Soft delete = `statut: 3` — ne jamais afficher les cuves/shifts avec statut 3.
- **RGGER-08** : Signature clôture via `expo-signature-canvas` — stockée en base64, envoyée dans la requête POST, jamais stockée localement après envoi réussi.

---

## Tâche Claude

Génère le code complet React Native + Expo SDK 54 TypeScript pour le Dashboard Gérant de Station FlowUp ERP.

**Contraintes techniques absolues :**
- Palette navy `#1A2157`, blue `#1E5EFF`, cyan `#00C8C0` — Inter + JetBrains Mono
- Montants = VARCHAR(255) → types TS `string`, jamais `number` pour les montants
- IDs = `number` (INT UNSIGNED)
- Navigation par onglets : `expo-router` avec `Tabs`
- MMKV pour cache offline (`react-native-mmkv`)
- Polling 30s dans `useIotCuves` avec cleanup

**Génère dans cet ordre :**
1. Types TypeScript (`types/gerant-dashboard.ts`)
2. Hook `useStationDashboard.ts` (polling 60s, MMKV cache)
3. Hook `useIotCuves.ts` (polling 30s)
4. `CuveBar.tsx` (jauge animée couleur)
5. `NiveauGauge.tsx` (affichage circulaire alternatif)
6. `ShiftCard.tsx`, `LivraisonCard.tsx`, `AlerteBadge.tsx`
7. Écrans : `dashboard.tsx`, `cuves.tsx`, `shifts.tsx`, `livraisons.tsx`, `cloture.tsx`
