From e7070a0afa8f8e47f26c201b435d89c751c5d64b Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Mon, 5 Oct 2026 03:16:58 -0400 Subject: [PATCH] Outages review fixes: reset on new target, memoize marker icons, coverage note in popup (#184) - useOutagesIn kept the previous incident's answer while fetching the next one (IncidentPanel isn't keyed), so a newly selected incident briefly read 'none reported here'. Drop the old answer when the target changes. - OutageLayer built a fresh divIcon per marker every render; MapView re-renders on live updates, so Leaflet rebuilt every marker's DOM. Memoize. - Popup now carries the provider's coverage note (ODIN: non-reporting utilities, e.g. Con Ed/O&R, show nothing even during an outage). Co-Authored-By: Claude Opus 5.5 --- drb-frontend/components/map/OutageLayer.tsx | 8 ++++++-- drb-frontend/lib/useOutages.ts | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drb-frontend/components/map/OutageLayer.tsx b/drb-frontend/components/map/OutageLayer.tsx index 63dd7a5..31a6fed 100644 --- a/drb-frontend/components/map/OutageLayer.tsx +++ b/drb-frontend/components/map/OutageLayer.tsx @@ -91,6 +91,7 @@ function OutagePopupBody({ a, feed }: { a: OutageArea; feed?: OutageProviderFeed )}
County-level count — the marker is the county's centre, not where the outage is.
+ {feed?.coverage_note &&
{feed.coverage_note}
} @@ -163,7 +164,10 @@ export function OutageLayer({ shown }: { shown: boolean }) { const state = useMapOutages(map, shown); const areas = useMemo(() => state.data?.areas ?? [], [state.data]); const feeds = useMemo(() => new Map((state.data?.providers ?? []).map((p) => [p.id, p])), [state.data]); - const drawable = areas.filter((a) => a.lat != null && a.lon != null); + const drawable = useMemo(() => areas.filter((a) => a.lat != null && a.lon != null), [areas]); + // One icon per area per response: a fresh divIcon each render would make + // Leaflet rebuild every marker's DOM whenever MapView re-renders. + const icons = useMemo(() => new Map(drawable.map((a) => [a.id, outageIcon(a)])), [drawable]); const liveCount = areas.filter((a) => !a.stale && a.customers_out > 0).length; const staleCount = areas.filter((a) => a.stale).length; if (!shown) return null; @@ -171,7 +175,7 @@ export function OutageLayer({ shown }: { shown: boolean }) { <> {drawable.map((a) => ( - diff --git a/drb-frontend/lib/useOutages.ts b/drb-frontend/lib/useOutages.ts index 1580762..b44d1e4 100644 --- a/drb-frontend/lib/useOutages.ts +++ b/drb-frontend/lib/useOutages.ts @@ -34,7 +34,10 @@ function useOutageFetch( const seq = useRef(0); useEffect(() => { - if (!getBox) { setData(null); setError(null); setLoaded(false); return; } + // A new target (another incident, overlay re-enabled) must not be judged + // against the previous target's answer: drop it and show "checking…". + setData(null); setError(null); setLoaded(false); + if (!getBox) return; const boxFn = getBox; let last = 0; const load = async () => {