# Vue tableau du planning — Spécification de design

## Contexte

Eolem Planning permet de créer des formations dans Google Calendar. Il manque une vue de consultation pour voir l'ensemble des formations de l'année sous forme de tableau, directement dans l'application web.

## Fonctionnalité

Page de consultation en lecture seule affichant toutes les formations de l'année en cours dans un tableau filtrable.

## Architecture

- **Approche** : rendu côté serveur, filtrage côté client en JavaScript pur
- **Nouvelle page** : `public/planning.php` (contrôleur) + `templates/planning.php` (template)
- **Pas de nouveau service PHP** — appel direct à `GoogleCalendarService::listEvents()` existant
- **Navigation** : lien "Planning" ajouté dans `templates/layout.php` entre "Nouvelle formation" et "Formations"

## Flux de données

1. `public/planning.php` appelle `bootstrap.php` (session, auth, services)
2. Calcule les dates de l'année en cours : `YYYY-01-01` → `YYYY-12-31`
3. Appelle `$gcal->listEvents($dateStart, $dateEnd)`
4. Parse chaque événement pour extraire formation, client, lieu depuis le `summary`
5. Trie par date de début croissante
6. Rend `templates/planning.php` dans le layout commun

## Tableau — Colonnes

| Colonne | Source | Détail |
|---------|--------|--------|
| Statut | `colorId` | Pastille colorée + texte (Option/Confirmée/Commandée) |
| Formation | `summary` parsé | 1ère partie avant le premier " - " |
| Client | `summary` parsé | 2ème partie |
| Lieu | `location` | Champ location de l'événement Google Calendar |
| Dates | `start` / `end` | "15 avr." si 1 jour, "15 → 17 avr. 2026" si plusieurs jours |
| Horaires | `description` | Première ligne de la description (ex: "09:00 - 17:00") |

### Parsing du summary

Le titre des événements suit le format **"Formation - Client - Lieu"** (séparateur ` - ` avec espaces).

- `explode(' - ', $summary, 3)` pour extraire les 3 parties
- Si le format ne correspond pas (événement manuel), le summary complet va dans Formation, Client et Lieu restent vides

### Date de fin exclusive

Google Calendar retourne une date de fin exclusive (+1 jour). À l'affichage, on soustrait 1 jour pour montrer la vraie date de fin.

### Mapping colorId → statut

Réutilisation de la correspondance existante (inverse de `GoogleCalendarService::COLOR_MAP`) :

| colorId | Statut | Couleur pastille |
|---------|--------|-----------------|
| 5 | Option | Jaune (Banana) `rgb(246, 191, 38)` |
| 1 | Confirmée | Lavande `rgb(121, 134, 203)` |
| 11 | Commandée | Rouge (Tomato) `rgb(213, 0, 0)` |

Les événements avec un `colorId` non reconnu affichent un statut vide (pas de pastille).

## Filtres

Trois `<select>` natifs affichés sur une même ligne au-dessus du tableau :

| Filtre | Options |
|--------|---------|
| Statut | Tous / Option / Confirmée / Commandée |
| Client | Tous + liste dédupliquée des clients du tableau, triée alphabétiquement |
| Formation | Tous + liste dédupliquée des formations du tableau, triée alphabétiquement |

### Comportement des filtres

- Filtrage instantané en JavaScript pur (pas de bibliothèque)
- Masquage des `<tr>` avec `display: none` selon les 3 filtres combinés (AND)
- Attributs `data-statut`, `data-client`, `data-formation` sur chaque `<tr>` pour le filtrage
- Compteur sous les filtres : "X formation(s) affichée(s)", mis à jour à chaque changement

## Style

- Tailwind CSS, cohérent avec le reste de l'application
- Conteneur `max-w-6xl` (plus large que le `max-w-4xl` des autres pages pour accueillir plus de colonnes)
- Lignes alternées pour la lisibilité
- Pastille de statut : `<span>` avec `border-radius: 50%` et couleur de fond selon le statut

## Gestion des erreurs & cas limites

- **Google Calendar non authentifié** : message d'avertissement invitant à se reconnecter via le flux OAuth
- **Aucun événement** : message "Aucune formation trouvée pour l'année XXXX" à la place du tableau
- **Summary mal formaté** : summary complet dans la colonne Formation, Client et Lieu vides
- **colorId inconnu** : statut affiché vide, pas de pastille

## Fichiers impactés

| Fichier | Action |
|---------|--------|
| `public/planning.php` | Créer — contrôleur de la page |
| `templates/planning.php` | Créer — template du tableau avec filtres et JS |
| `templates/layout.php` | Modifier — ajouter le lien "Planning" dans la navigation |

## Hors périmètre

- Pas d'actions (modifier, supprimer) depuis le tableau
- Pas de pagination (volume faible pour un planning annuel individuel)
- Pas de sélecteur d'année (année en cours uniquement)
- Pas de tests unitaires (page de consultation sans logique métier nouvelle)
