From cb070a17e3960d394af5b3b4ff504175e20a6c49 Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Wed, 12 Aug 2026 08:56:55 +0000 Subject: [PATCH] Refresh forecast tiles periodically, not just once on mount Dashboard's week/month tiles were only computed on initial load; the 5-minute timer refreshed the AI insight but not the tiles, so an installed PWA left open would keep showing stale forecast numbers indefinitely. Monthly's forecast had no refresh at all. Both now recompute every 5 minutes while viewing the current month. --- frontend/src/pages/Dashboard.tsx | 4 +++- frontend/src/pages/Monthly.tsx | 10 +++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 6a7a3fe..c3c9b6f 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -227,7 +227,9 @@ export default function Dashboard() { useEffect(() => { load() loadStats() - const id = setInterval(load, REFRESH_MS) + // Both on the same timer — an installed PWA left open for a while previously left the + // week/month tiles frozen at whatever they were on first load (only the AI insight refreshed). + const id = setInterval(() => { load(); loadStats() }, REFRESH_MS) return () => clearInterval(id) }, [load, loadStats]) diff --git a/frontend/src/pages/Monthly.tsx b/frontend/src/pages/Monthly.tsx index 8e586bf..50874d6 100644 --- a/frontend/src/pages/Monthly.tsx +++ b/frontend/src/pages/Monthly.tsx @@ -23,6 +23,7 @@ function budgetColour(pct: number): string { return pct <= 100 ? 'var(--app-primary)' : pct <= 110 ? '#b45309' : '#dc2626' } const DEPT_COLORS = ['#065f46','#059669','#0891b2','#7c3aed','#c2410c','#b45309','#0f766e','#4338ca','#be185d','#15803d'] +const REFRESH_MS = 5 * 60_000 export default function Monthly() { const today = new Date() @@ -144,7 +145,14 @@ export default function Monthly() { } }, [fromStr, toStr, actualsFromStr, pyFromStr, pyToStr, pmFromStr, pmToStr, isCurrentMonth, yesterdayStr, year, month, pyDim]) - useEffect(() => { load() }, [load]) + useEffect(() => { + load() + // Only worth polling while viewing the in-progress month — the forecast is the only + // thing that moves; past months are static once loaded. + if (!isCurrentMonth) return + const id = setInterval(load, REFRESH_MS) + return () => clearInterval(id) + }, [load, isCurrentMonth]) useEffect(() => { if (!modal) { setModalEmps(null); return }