From 06d611318e859bb6ec0aded59de582c69c8d3b6e Mon Sep 17 00:00:00 2001 From: fraxle Date: Tue, 2 Jun 2026 23:53:25 +0100 Subject: [PATCH] 2.5.1 Slow down API calls to every 15mins on non-pro --- assets/js/hooks/useAppState.js | 24 ++++++++++++++---------- assets/js/hooks/useForecast.js | 17 +++++++++++------ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/assets/js/hooks/useAppState.js b/assets/js/hooks/useAppState.js index 0ce3c44..bd0e0b9 100644 --- a/assets/js/hooks/useAppState.js +++ b/assets/js/hooks/useAppState.js @@ -52,7 +52,19 @@ export function useAppState() { setLocation(loc); }; - const { forecast, airQuality, loading, error, now, fetchedAt } = useForecast(location); + // Pro tier flag is read early so useForecast can pick its refresh cadence + // (Pro: 5 min, free: 15 min). Full setup notes in the PRO TIER section below. + const [isPro, setIsPro] = useState(() => { + const params = new URLSearchParams(window.location.search); + if (params.get('pro') === '1') { + localStorage.setItem('sunscope_pro', '1'); + window.history.replaceState({}, '', window.location.pathname); + return true; + } + return localStorage.getItem('sunscope_pro') === '1'; + }); + + const { forecast, airQuality, loading, error, now, fetchedAt } = useForecast(location, isPro); const [searchQuery, setSearchQuery] = useState(''); const [searchResults, setSearchResults] = useState([]); @@ -109,15 +121,7 @@ export function useAppState() { }; // ── 3. PRO TIER ────────────────────────────────────────────────────── - const [isPro, setIsPro] = useState(() => { - const params = new URLSearchParams(window.location.search); - if (params.get('pro') === '1') { - localStorage.setItem('sunscope_pro', '1'); - window.history.replaceState({}, '', window.location.pathname); - return true; - } - return localStorage.getItem('sunscope_pro') === '1'; - }); + // (isPro is declared near the top so useForecast can read it; see above.) // ── 4. PROFILE + COLUMN VISIBILITY ─────────────────────────────────── const [activeProfile, setActiveProfile] = useState(() => { diff --git a/assets/js/hooks/useForecast.js b/assets/js/hooks/useForecast.js index d346e7c..bbd55ab 100644 --- a/assets/js/hooks/useForecast.js +++ b/assets/js/hooks/useForecast.js @@ -12,13 +12,15 @@ // c. Stale soil cache — used if ICON fetch fails. // 3. Fetch /v1/air-quality on location change, with a 6-hour // localStorage cache (AQI / pollen update slowly). -// 4. Auto-refresh forecast every 15 minutes (matches Open-Meteo -// update cadence). Air quality only refetches if cache is stale. +// 4. Auto-refresh forecast every 5 minutes for Pro, 15 minutes for +// free (Open-Meteo updates ~every 15 min). Air quality only +// refetches if cache is stale. // 5. Tick `now` every 2 minutes to keep the current-row highlight // accurate without any API cost. // // Inputs: // location - { lat, lon, name, country } +// isPro - boolean; true tightens auto-refresh to 5 min // // Outputs: // forecast - raw /v1/forecast response, or null @@ -119,7 +121,7 @@ function mergeSoil(forecastData, soilHourly) { return { ...forecastData, hourly: h }; } -export function useForecast(location) { +export function useForecast(location, isPro = false) { const [forecast, setForecast] = useState(null); const [airQuality, setAirQuality] = useState(null); const [loading, setLoading] = useState(false); @@ -235,8 +237,11 @@ export function useForecast(location) { return () => clearInterval(id); }, []); - // ─── 15-MINUTE REFRESH (matches Open-Meteo update cadence) ──────── + // ─── AUTO REFRESH (Pro: 5 min, free: 15 min) ───────────────────── + // Open-Meteo updates roughly every 15 min; Pro users get a tighter + // poll so the current-conditions row stays fresher. useEffect(() => { + const refreshMs = isPro ? FIVE_MIN_MS : FIFTEEN_MIN_MS; const id = setInterval(() => { async function refresh() { const key = forecastCacheKey(location); @@ -254,9 +259,9 @@ export function useForecast(location) { loadAirQuality(location); } refresh(); - }, FIFTEEN_MIN_MS); + }, refreshMs); return () => clearInterval(id); - }, [location]); + }, [location, isPro]); return { forecast, airQuality, loading, error, now, fetchedAt }; } \ No newline at end of file