From c170bbca7da801be72b9fa32e6086fb33f3e8d8b Mon Sep 17 00:00:00 2001 From: Florian Date: Mon, 1 Jun 2026 16:56:04 +0200 Subject: [PATCH] =?UTF-8?q?fix(dept):=20vert=20=E2=89=A0=20vigilance,=20co?= =?UTF-8?q?nseils=20sur=20chaque=20alerte=20active?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le flux Météo France renvoie parfois des phénomènes explicitement au vert (colorId 1) : ils étaient traités comme des alertes, d'où un « Que faire maintenant ? » affiché sur un phénomène vert et un dropdown limité aux phénomènes absents du flux. - "Active" = vigilance jaune ou plus (colorId >= 2) ; le vert n'est jamais une alerte - Tout au vert → un seul encadré « Aucune vigilance active » - Dropdown regroupe désormais tous les phénomènes au vert (présents au vert dans le flux + absents) - Une vigilance présente → bloc complet « Que faire maintenant ? » sur chacune des alertes actives (au lieu de la première seulement) - Tableau Aujourd'hui vs Demain et suite : inchangés Au passage, fix typage FranceMap : Map par défaut typée pour ne pas perdre VigilanceAlert (5 erreurs astro check), imports inutilisés retirés. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/components/FranceMap.astro | 6 +- src/pages/departement/[code].astro | 116 +++++++++++++---------------- 2 files changed, 55 insertions(+), 67 deletions(-) diff --git a/src/components/FranceMap.astro b/src/components/FranceMap.astro index def4185..b038c37 100644 --- a/src/components/FranceMap.astro +++ b/src/components/FranceMap.astro @@ -1,7 +1,7 @@ --- import franceMap from '../data/france-map.json'; -import { COLORS, COLOR_LABEL, PHENOMENA } from '../lib/phenomena'; -import type { ColorId, PhenomenonId } from '../lib/phenomena'; +import { COLORS, PHENOMENA } from '../lib/phenomena'; +import type { ColorId } from '../lib/phenomena'; import type { VigilanceAlert } from '../lib/vigilance'; import { getDepartement } from '../lib/departements'; @@ -10,7 +10,7 @@ interface Props { alertsByDept?: Map; } -const { colorsByDept, alertsByDept = new Map() } = Astro.props; +const { colorsByDept, alertsByDept = new Map() } = Astro.props; const entries = Object.entries(franceMap.paths) as [string, { d: string; name: string }][]; // Construire un objet { code: { name, color, alerts: [{phenLabel, colorName, colorId}] } } diff --git a/src/pages/departement/[code].astro b/src/pages/departement/[code].astro index 1d8fecf..aed4731 100644 --- a/src/pages/departement/[code].astro +++ b/src/pages/departement/[code].astro @@ -147,16 +147,20 @@ const j1Available = snapshot ? (ech === 'J' && hasJ1Period(snapshot)) : false; const today = snapshot ? alertsForDepartement(snapshot, dept.code, ech) : []; const tomorrow = j1Available ? alertsForDepartement(snapshot!, dept.code, 'J1') : []; -// Sort by severity desc, pick top alert for the hero block +// Sort by severity desc. "Active" = vigilance jaune ou plus (colorId >= 2). +// Le flux MF renvoie parfois des phénomènes explicitement au vert (colorId 1) — +// ce ne sont PAS des alertes : ils rejoignent le dropdown "tous au vert", au même +// titre que les phénomènes absents du flux. topAlert = la plus sévère des actives +// (sert aux numéros d'urgence + carte "Kit" en bas de page). const sortedToday = [...today].sort((a, b) => b.colorId - a.colorId); -const topAlert = sortedToday[0] ?? null; -const otherAlerts = sortedToday.slice(1); +const activeToday = sortedToday.filter((a) => a.colorId >= 2); +const topAlert = activeToday[0] ?? null; -const adviceFor = topAlert ? ADVICE[topAlert.phenomenonId] : null; -// First 3 action items as quick bullets inside the hero block -const quickActions = adviceFor - ? adviceFor.blocks.flatMap((b) => b.items).slice(0, 3) - : []; +// First 3 action items, par phénomène, pour le bloc "Que faire maintenant ?" +function quickActionsFor(phenId: PhenomenonId): string[] { + const advice = ADVICE[phenId]; + return advice ? advice.blocks.flatMap((b) => b.items).slice(0, 3) : []; +} // Per-phenomenon color maps for the comparison table const PHENOM_IDS: PhenomenonId[] = [1, 2, 3, 5, 6, 8, 9]; @@ -179,9 +183,10 @@ const comparisonRows = PHENOM_IDS.map((id) => ({ changed: j1Available && (todayByPhenom.get(id) ?? 1) !== (tomorrowByPhenom.get(id) ?? 1), })); -// Phenomena with no active alert today (green) -const activePhenomIds = new Set(today.map((a) => a.phenomenonId)); -const inactivePhenomIds = PHENOM_IDS.filter((id) => !activePhenomIds.has(id)); +// Phénomènes au vert aujourd'hui = ceux sans alerte active (jaune+). Inclut aussi +// les phénomènes absents du flux MF (réputés verts). Tous regroupés dans le dropdown. +const activePhenomIds = new Set(activeToday.map((a) => a.phenomenonId)); +const greenPhenomIds = PHENOM_IDS.filter((id) => !activePhenomIds.has(id)); const productDate = snapshot?.productDatetime ? new Date(snapshot.productDatetime).toLocaleString('fr-FR', { @@ -204,10 +209,6 @@ const tomorrowLabel = tomorrow[0] ? labelDate(tomorrow[0].beginTime) : ''; // Glyphs matching the pill levels const GLYPHS: Record = { 1: '●', 2: '▲', 3: '◆', 4: '■' }; - -// Pre-computed display values for the hero alert block -const topColorName = topAlert ? COLORS[topAlert.colorId].name : null; -const topPhen = topAlert ? PHENOMENA[topAlert.phenomenonId] : null; --- - {/* All-green state */} - {sortedToday.length === 0 && ( + {/* All-green state — aucune vigilance active (jaune+) */} + {activeToday.length === 0 && (

● Aucune vigilance active {todayLabel ? `pour ${todayLabel}` : "aujourd'hui"}

- Tous les phénomènes sont au vert pour {dept.name}. Restez attentif aux mises à jour Météo France. + Tous les phénomènes sont au vert pour {dept.name} — rien de particulier à signaler. + Restez attentif aux mises à jour Météo France.

)} - {/* Hero — top alert */} - {topAlert && topColorName && topPhen && ( -
-
- -

- {GLYPHS[topAlert.colorId]} {topPhen.label} — {COLOR_LABEL[topAlert.colorId]} -

-
- - {adviceFor && ( -
- Que faire maintenant ? -
    - {quickActions.map((a) =>
  • {a}
  • )} -
- - Voir le kit complet {topPhen.label} → - -
- )} - -

- Valide du {fmtTime(topAlert.beginTime)} au {fmtTime(topAlert.endTime)} — heure de Paris. -

-
- )} - - {/* Other active alerts */} - {otherAlerts.map((a) => { + {/* Active alerts (jaune+) — bloc complet "Que faire maintenant ?" sur chacune */} + {activeToday.map((a) => { const colorName = COLORS[a.colorId].name; const phen = PHENOMENA[a.phenomenonId]; + const advice = ADVICE[a.phenomenonId]; + const quickActions = quickActionsFor(a.phenomenonId); return ( -
-
-
- - {phen.label} -
- +
+
+ +

+ {GLYPHS[a.colorId]} {phen.label} — {COLOR_LABEL[a.colorId]} +

-

- Du {fmtTime(a.beginTime)} au {fmtTime(a.endTime)} + + {advice && ( +

+ Que faire maintenant ? +
    + {quickActions.map((item) =>
  • {item}
  • )} +
+ + Voir le kit complet {phen.label} → + +
+ )} + +

+ Valide du {fmtTime(a.beginTime)} au {fmtTime(a.endTime)} — heure de Paris.

); })} - {/* Collapsible: inactive phenomena (all green) */} - {inactivePhenomIds.length > 0 && ( + {/* Collapsible: phénomènes au vert (sans vigilance) */} + {greenPhenomIds.length > 0 && (
- {inactivePhenomIds.length} phénomène{inactivePhenomIds.length > 1 ? 's' : ''} — tous au vert + {greenPhenomIds.length} phénomène{greenPhenomIds.length > 1 ? 's' : ''} au vert — aucune vigilance
- {inactivePhenomIds.map((id) => ( + {greenPhenomIds.map((id) => (
{PHENOMENA[id].label}