# Spécification Dashboard ESTAIR – Widgets & Données
> Inspiré du Dashboard Analytics Vuexy · `demo-1/dashboards/analytics`

---

## Principe général

Le dashboard ESTAIR reprend la **structure en 3 colonnes** et la **hiérarchie visuelle** du dashboard Analytics Vuexy :
- Ligne 1 : Hero card large (2/3) + 2 KPI cards empilées (1/3)
- Ligne 2 : Bar chart + sous-KPIs (2/3) + Gauge tracker (1/3)
- Ligne 3 : 3 cards égales (liste agences · bilan financier · répartition BSP)
- Ligne 4 : Liste canaux (1/3) + Tableau états de vente (2/3)

La **palette** reprend les codes Vuexy : violet primaire, accents vert (hausse) / rouge (baisse), fond blanc cassé, cards blanches avec ombre légère.

---

## Vue par rôle

| Widget | admin | support | sale | finance | agency | agent |
|--------|:-----:|:-------:|:----:|:-------:|:------:|:-----:|
| Hero – Activité globale | ✅ | ✅ | ✅ | ✅ | ✅* | ✅* |
| KPI CA moyen journalier | ✅ | ✅ | ✅ | ✅ | ✅* | ✅* |
| KPI Comparatif Émissions/Remb. | ✅ | ✅ | ✅ | ✅ | ✅* | ✅* |
| Rapport d'Émissions (bar chart) | ✅ | ✅ | ✅ | ✅ | ✅* | ✅* |
| Suivi Remboursements (gauge) | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |
| Activité par Agence (liste) | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Bilan Financier (bar grouped) | ✅ | ❌ | ✅ | ✅ | ✅* | ✅* |
| Répartition BSP | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Top Compagnies (liste) | ✅ | ✅ | ✅ | ✅ | ✅* | ✅* |
| Derniers États de Vente (tableau) | ✅ | ✅ | ✅ | ✅ | ✅* | ✅* |

> `✅*` = données restreintes à l'agence connectée uniquement

---

## Détail des Widgets

---

### W1 · Hero Card – Activité de la Période
> Équivalent Vuexy : **"Website Analytics"** (carte violette avec carousel 3 slides et illustration 3D)

**Visuel :** Card large fond violet (couleur primaire ESTAIR), illustration décorative à droite (avion stylisé ou globe), carousel de 3 slides.

**Slide 1 – Vue Émissions**
| Métrique | Valeur | Source |
|---|---|---|
| Tickets émis | count | `etats-de-ventes` |
| Montant total émis | sum(montant) | `etats-de-ventes` |
| Nombre de PNR | count | `etats-de-ventes` |
| Nombre d'agences actives | count distinct | `accounts` |

**Slide 2 – Vue Financière**
| Métrique | Valeur | Source |
|---|---|---|
| CA de la période | sum(montant_ttc) | `transaction` |
| Solde moyen agences | avg(solde) | `soldes` |
| Transactions BSP | count | `bsps` |
| Montant BSP | sum | `bsp-details` |

**Slide 3 – Vue Helpdesk**
| Métrique | Valeur | Source |
|---|---|---|
| Tickets ouverts | count(statut=open) | `helpdesk` |
| Remboursements en attente | count(statut=pending) | `remboursement` |
| EMDs actifs | count | `emds` |
| Délai moyen traitement | avg(délai) | `helpdesk` |

---

### W2 · KPI – CA Moyen Journalier
> Équivalent Vuexy : **"Average Daily Sales"** (grand montant + sparkline verte)

**Visuel :** Titre + sous-titre période · Grand montant en gras · Sparkline area chart (courbe verte avec remplissage dégradé)

| Champ | Contenu |
|---|---|
| Titre | `CA Moyen Journalier` |
| Sous-titre | `Total émissions sur la période` |
| Valeur principale | `avg(montant_ttc / nb_jours)` formaté en devise |
| Sparkline | Évolution journalière du CA sur la période |
| Source | `etats-de-ventes` · `transaction` |

---

### W3 · KPI – Comparatif Émissions / Remboursements
> Équivalent Vuexy : **"Sales Overview"** (montant + % variation + barre bicolore comparative)

**Visuel :** Montant total en grand · Badge % variation vs période précédente · Toggle Émissions / Remboursements · Barre de progression bicolore (violet = émissions, cyan = remboursements)

| Champ | Contenu |
|---|---|
| Valeur principale | Montant total émissions |
| Badge variation | `+X%` vert ou `-X%` rouge vs période précédente |
| Onglet gauche | Émissions : % et montant |
| Onglet droit | Remboursements : % et montant |
| Barre comparative | Ratio visuel Émissions vs Remboursements |
| Source | `etats-de-ventes` · `remboursement` |

---

### W4 · Rapport d'Émissions (Bar Chart)
> Équivalent Vuexy : **"Earning Reports"** (bar chart hebdo + 3 sous-KPIs avec sparkline)

**Visuel :** Titre + sous-titre · Montant total période en grand + badge % · Bar chart vertical (une barre par jour, barre du jour courant en violet foncé, autres en violet clair) · 3 sous-KPIs en bas

**Bar chart :**
- Axe X : jours de la période (format court : `Lu`, `Ma`, etc.)
- Axe Y : montant émis
- Barre active (période en cours) : violet primaire
- Autres barres : violet clair (20% opacité)

**3 sous-KPIs :**
| KPI | Icône | Valeur | Couleur trait |
|---|---|---|---|
| Émissions | `$` violet | sum(montant_ttc) | Violet |
| EMDs | horloge cyan | sum(montant_emd) | Cyan |
| Remboursements | retour rouge | sum(montant_remb) | Rouge |

**Source :** `etats-de-ventes` · `emds` · `remboursement`

---

### W5 · Suivi des Remboursements (Gauge)
> Équivalent Vuexy : **"Support Tracker"** (grand nombre + liste + gauge circulaire)

**Visuel :** Grand nombre total à gauche · Liste de 3 statuts avec icône colorée · Gauge demi-cercle à droite avec % au centre

| Champ | Contenu |
|---|---|
| Grand nombre | Total demandes de remboursement |
| Sous-titre | `Demandes sur la période` |
| Ligne 1 | 🟣 Nouvelles demandes · count(statut=new) |
| Ligne 2 | 🟢 En cours de traitement · count(statut=processing) |
| Ligne 3 | 🟠 Délai moyen · avg(jours) |
| Gauge | % demandes traitées = count(statut=closed) / count(total) |
| Label gauge | `Taux de traitement` |
| Source | `remboursement` |

**Rôles :** admin, finance, support uniquement

---

### W6 · Activité par Agence (Liste)
> Équivalent Vuexy : **"Sales by Countries"** (liste avec drapeau/icône + montant + % variation)

**Visuel :** Liste scrollable · Icône agence (logo ou initiales dans un cercle coloré) · Nom agence · Montant CA · Badge % variation (↑ vert / ↓ rouge)

| Champ | Contenu |
|---|---|
| Icône | Initiales de l'agence dans avatar coloré |
| Nom | Raison sociale |
| Montant | sum(montant_ttc) sur la période |
| Variation | % vs période précédente |
| Tri | Par montant décroissant |
| Limite affichage | Top 6 agences + lien "Voir tout" |
| Source | `accounts` · `etats-de-ventes` |

**Rôles :** admin, support, sale, finance uniquement (vue globale)

---

### W7 · Bilan Financier (Bar Chart Groupé)
> Équivalent Vuexy : **"Total Earning"** (% variation + bar chart groupé + 2 lignes de résumé)

**Visuel :** % variation période en grand · Bar chart groupé (2 barres côte à côte par période : émissions vs remboursements) · 2 lignes récapitulatives en bas

**Bar chart :**
- Groupes : semaines ou mois selon la période sélectionnée
- Barre 1 : Émissions (violet)
- Barre 2 : Remboursements (gris/lavande)

**2 lignes résumé :**
| Ligne | Icône | Label | Valeur | Badge |
|---|---|---|---|---|
| 1 | 💳 | Total Émis | sum(montant_ttc) | `+X€` vert |
| 2 | ↩️ | Total Remboursé | sum(montant_remb) | `-X€` rouge |

**Source :** `etats-de-ventes` · `remboursement` · `transaction`

---

### W8 · Répartition BSP (Liste statuts)
> Équivalent Vuexy : **"Monthly Campaign State"** (liste d'indicateurs avec label + count + %)

**Visuel :** Titre + sous-titre · Liste de 6 lignes · Chaque ligne : icône colorée + label + count à droite + % coloré

| Ligne | Icône | Label | Valeur | Couleur % |
|---|---|---|---|---|
| 1 | 📄 | BSPs émis | count | Vert |
| 2 | ✅ | BSPs validés | count | Vert |
| 3 | ⏳ | BSPs en attente | count | Orange |
| 4 | ❌ | BSPs rejetés | count | Rouge |
| 5 | 💰 | Montant total BSP | sum | Vert |
| 6 | 🔄 | BSP Details en cours | count | Bleu |

**Source :** `bsps` · `bsp-details`
**Rôles :** admin, support, sale, finance uniquement

---

### W9 · Top Compagnies Aériennes (Liste canaux)
> Équivalent Vuexy : **"Source Visits"** (liste avec icône + label + count + badge variation)

**Visuel :** Liste de compagnies · Logo/code IATA dans icône ronde · Nom compagnie · Nombre de tickets · Badge % variation

| Champ | Contenu |
|---|---|
| Icône | Code IATA (ex: `AF`, `BA`, `EK`) dans avatar coloré |
| Nom | Nom compagnie aérienne |
| Count | Nombre de tickets émis sur la période |
| Badge | % variation vs période précédente |
| Tri | Par volume décroissant |
| Limite | Top 6 + lien "Voir tout" |
| Source | `compagnies` · `etats-de-ventes` |

---

### W10 · Derniers États de Vente (Tableau)
> Équivalent Vuexy : **"Project List"** (tableau avec colonnes + progress bar + actions)

**Visuel :** Barre de recherche intégrée · Tableau paginé · 5 lignes visibles · Pagination

**Colonnes :**
| Colonne | Contenu | Type |
|---|---|---|
| ☐ | Checkbox sélection | checkbox |
| Agence | Nom + logo avatar | text + avatar |
| PNR | Numéro PNR | code monospace |
| Passager | Nom passager | text |
| Compagnie | Code IATA + nom | badge |
| Montant | Montant TTC | currency |
| Statut | Émis / Annulé / Remboursé | badge coloré |
| Actions | ⋮ menu contextuel | dropdown |

**Badges statut :**
- `Émis` → vert
- `En attente` → orange
- `Annulé` → rouge
- `Remboursé` → bleu

**Source :** `etats-de-ventes` · `accounts` · `compagnies`
**Tri par défaut :** date_emission DESC
**Pagination :** 5 par page · contrôles `«` `‹` `1` `2` `…` `›` `»`

---

## Gestion de la Période (Composant global)

Le sélecteur de période est **unique et global** – il pilote tous les widgets simultanément.

**Emplacement :** En-tête du dashboard, aligné à droite

**Périodes prédéfinies :**
| Label | Valeur |
|---|---|
| Aujourd'hui | J |
| Hier | J-1 |
| 7 derniers jours | J-7 → J (défaut) |
| Ce mois | 1er du mois → J |
| Mois dernier | Mois M-1 complet |
| Personnalisé | Date picker début / fin |

---

## Contrat d'Interface Backend → Frontend

Pour chaque widget, le backend doit retourner une réponse normalisée :

```typescript
// Structure générique de réponse widget
interface WidgetResponse {
  widgetId: string           // ex: "emission-bar-chart"
  widgetType: WidgetType     // enum: KPI | BAR_CHART | GAUGE | LIST | TABLE | HERO
  title: string
  subtitle?: string
  period: { start: string; end: string }
  data: WidgetData           // typé selon widgetType
  variation?: {
    value: number            // ex: 4.2
    direction: 'up' | 'down' | 'neutral'
    vsLabel: string          // ex: "vs semaine précédente"
  }
}

// Exemple : BarChartData
interface BarChartData {
  labels: string[]           // ["Lu", "Ma", "Me", ...]
  datasets: {
    label: string
    color: string            // hex
    values: number[]
  }[]
  subKpis?: {
    label: string
    value: number | string
    color: string
    icon: string
  }[]
}

// Exemple : GaugeData
interface GaugeData {
  percentage: number         // 0-100
  centerLabel: string        // ex: "Taux de traitement"
  total: number
  totalLabel: string
  items: {
    label: string
    value: number | string
    color: string
    icon: string
  }[]
}

// Exemple : ListData (agences, compagnies)
interface ListData {
  items: {
    id: string
    avatar?: string          // initiales ou URL logo
    avatarColor?: string
    label: string
    value: string | number
    variation?: number       // % variation
    variationDirection?: 'up' | 'down'
  }[]
  hasMore: boolean
  totalCount: number
}

// Exemple : TableData
interface TableData {
  columns: {
    key: string
    label: string
    type: 'text' | 'badge' | 'currency' | 'avatar' | 'code' | 'actions'
  }[]
  rows: Record<string, unknown>[]
  pagination: {
    page: number
    pageSize: number
    total: number
  }
}
```

---

## Route API dédiée Dashboard

```
GET /api/dashboard/analytics?start=YYYY-MM-DD&end=YYYY-MM-DD&agency_id=XXX
```

Retourne tous les widgets en une seule requête (évite les waterfalls) :

```json
{
  "period": { "start": "...", "end": "..." },
  "widgets": [
    { "widgetId": "hero", "widgetType": "HERO", ... },
    { "widgetId": "avg-daily-ca", "widgetType": "KPI", ... },
    { "widgetId": "emission-vs-remb", "widgetType": "KPI", ... },
    { "widgetId": "emission-bar-chart", "widgetType": "BAR_CHART", ... },
    { "widgetId": "remboursement-gauge", "widgetType": "GAUGE", ... },
    { "widgetId": "top-agences", "widgetType": "LIST", ... },
    { "widgetId": "bilan-financier", "widgetType": "BAR_CHART", ... },
    { "widgetId": "repartition-bsp", "widgetType": "LIST", ... },
    { "widgetId": "top-compagnies", "widgetType": "LIST", ... },
    { "widgetId": "etats-de-vente", "widgetType": "TABLE", ... }
  ]
}
```

> Pour les rôles `agency` / `agent`, le backend filtre automatiquement par `agency_id` issu du token JWT Keycloak – aucune logique de filtrage côté frontend.
