Créneaux à la main + grille des besoins en axe des temps (30 min)

Un poste ne génère plus de créneaux à sa création : la coordination crée
elle-même ceux dont elle a besoin, avec ses propres horaires de début et
de fin (ConfigGrid.tsx). La génération depuis les créneaux types reste
disponible en option (bouton « Générer les créneaux »).

La grille des besoins devient un vrai axe des temps : une colonne = 30 min,
bornée par jour à la plage réellement utilisée, avec les cases fusionnées
pour correspondre aux horaires de chaque créneau (buildTimeGrid /
placeInTimeGrid). La « Vue bénévoles » garde son ancien modèle (une colonne
par créneau distinct), plus adapté à son tableau bénévole × créneau.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
AdamThomas
2026-09-22 18:44:20 +02:00
co-authored by Claude Sonnet 5
parent f1d88302a4
commit 15109acfe5
9 changed files with 474 additions and 179 deletions
+27 -11
View File
@@ -118,10 +118,17 @@ les tables sauf les tables d'association.
(`VolunteerHomeView`) plutôt qu'un écran référent vide.
- **`Shift`** : `position_id`, `day_part_id` (nullable ; le créneau type dont
il est issu, `SET NULL` si le type est supprimé), `starts_at`, `ends_at`
(peut finir le lendemain), `min_staff`, `ideal_staff`. À la création d'un
`Position`, un `Shift` à 0/0 est généré par jour de l'édition et par
`DayPart` ; `POST /editions/{id}/positions/{pid}/generate-shifts` recrée les
manquants (après ajout d'un créneau type ou extension des dates).
(peut finir le lendemain), `min_staff`, `ideal_staff`. **Aucun créneau
n'est généré automatiquement à la création d'un `Position`** : la
coordination crée elle-même ceux dont elle a besoin, à l'horaire de son
choix (`POST /editions/{id}/shifts`, sans lien à un `DayPart`,
`day_part_id: null`) — écran « Postes & créneaux » (`ConfigGrid.tsx`), un
formulaire heure de début / heure de fin par jour. Repartir des créneaux
types reste possible en option, à la demande :
`POST /editions/{id}/positions/{pid}/generate-shifts` génère un `Shift` à
0/0 par jour de l'édition et par `DayPart` manquant (bouton « Générer les
créneaux », idempotent — n'écrase jamais un créneau déjà généré, même
modifié depuis).
- **`Availability`** : `volunteer_id`, `date`, `start_time`, `end_time`
(`end_time <= start_time` ⇒ la fenêtre se termine le lendemain). Fenêtre
horaire **libre** ; plusieurs par (`volunteer`, `date`). Unique
@@ -425,13 +432,21 @@ effectivement tourné (`POST .../solver/suggestions`), ses bénévoles retenus
passent malgré tout en tête (ce sont eux le résultat d'une vraie optimisation
jointe, pas juste un score local).
**Colonnes de la grille des besoins** — une colonne représente un **créneau**
distinct (`starts_at` + `ends_at`), pas seulement une heure de début : deux
créneaux qui démarrent en même temps mais durent différemment ont chacun leur
colonne (`buildLattice` / `LatticeColumn` dans `frontend/src/lib/planning.ts`).
Largeur adaptative par jour (`columnWidthPx`) : peu de créneaux dans une
journée ⇒ colonnes larges, beaucoup de créneaux ⇒ largeur compacte avec
défilement horizontal — jamais de colonnes étroites par défaut.
**Colonnes de la grille des besoins** (`GrillePage.tsx`) — un vrai axe des
temps : une colonne = 30 min, bornée par jour à la plage réellement utilisée
(du créneau le plus matinal au plus tardif, arrondi à la demi-heure
englobante — pas les 24 h complètes). Les créneaux gardent des horaires
libres (`ShiftCreate`, § 2) ; ils sont replacés dans cette grille fixe en
fusionnant les cases qu'ils couvrent (`gridColumn: span N`), arrondis à la
tranche englobante s'ils ne tombent pas pile sur un multiple de 30 min
(`buildTimeGrid` / `placeInTimeGrid` dans `frontend/src/lib/planning.ts`).
Largeur adaptative par jour (`columnWidthPx`, en fonction du nombre de
tranches) : peu de tranches ⇒ colonnes larges, beaucoup ⇒ largeur compacte
avec défilement horizontal — jamais de colonnes étroites par défaut.
La « Vue bénévoles » (`VolunteerViewPage.tsx`) reste sur l'ancien modèle,
distinct : une colonne par **créneau** (signature `starts_at`/`ends_at`)
plutôt qu'un axe temporel continu (`buildLattice` / `LatticeColumn`), plus
adapté à son tableau bénévole × créneau.
---
@@ -618,6 +633,7 @@ Aucune dépendance locale requise hors Docker.
| 20 | Planches de badges bénévoles (PDF) : recto personnalisable (fond + champs nom/poste(s)/catégorie/rôle, éditeur glisser-déposer), verso fixe (même image pour tous), écran « Badges » dédié (`/badges`, COORDINATION) | à valider |
| 21 | Formulaire public d'inscription (`/inscription`, sans authentification) : champs activables par la coordination (email, téléphone, vœux de poste — max 2, vœux d'artiste — un par soir, vœu de compagnon en texte libre, disponibilité/cotisation déclaratives, photo, commentaire), captcha hCaptcha, ouverture/fermeture, lien à partager, écran de configuration dédié (`/inscriptions`, COORDINATION) — les bénévoles créés rejoignent directement la liste | à valider |
| 22 | Feuilles de poste (PDF, complément des badges) : une page par poste et par jour avec le référent, les créneaux, les bénévoles affectés et leur téléphone — bouton depuis la grille des besoins (COORDINATION) ; photo du bénévole affichée sur son écran et sur l'écran référent (en face du nom de chaque membre de l'équipe) | à valider |
| 23 | Créneaux : plus de génération automatique à la création d'un poste — création manuelle à horaire libre (`ConfigGrid.tsx`), génération depuis les créneaux types conservée en option (« Générer les créneaux ») ; grille des besoins redessinée en vrai axe des temps (une colonne = 30 min, bornée à la plage utilisée par jour, cases fusionnées pour chaque créneau — `buildTimeGrid`/`placeInTimeGrid`) | à valider |
**Reste hors périmètre** (modèle prêt à les accueillir) : SMS, constructeur
de formulaire, pointage sur site, IA. Frontend : squelette + 6 écrans +