From ce7a037b6d3818f292461d38ea93e869fc45cadc Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Fri, 17 Apr 2026 18:05:52 +0800 Subject: [PATCH] Fix intraday modal races and METAR temperature fallbacks --- frontend/hooks/useDashboardStore.tsx | 33 +++++++++++++++++++++------- frontend/hooks/useLeafletMap.ts | 1 - frontend/lib/dashboard-utils.ts | 21 ------------------ 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/frontend/hooks/useDashboardStore.tsx b/frontend/hooks/useDashboardStore.tsx index ee74b9f4..8edd5375 100644 --- a/frontend/hooks/useDashboardStore.tsx +++ b/frontend/hooks/useDashboardStore.tsx @@ -336,6 +336,7 @@ export function DashboardStoreProvider({ const proAccessRef = useRef(getInitialProAccessState()); const mapStopMotionRef = useRef<() => void>(() => {}); + const modalOpenSeqRef = useRef(0); const hydratedSelectionRef = useRef(false); const hydratedProCacheRef = useRef(false); const backgroundSummaryCheckAtRef = useRef>({}); @@ -1003,7 +1004,10 @@ export function DashboardStoreProvider({ cities, cityDetailsByName, citySummariesByName, - closeFutureModal: () => setFutureModalDate(null), + closeFutureModal: () => { + modalOpenSeqRef.current += 1; + setFutureModalDate(null); + }, closeHistory: () => setHistoryState((current) => ({ ...current, isOpen: false })), closePanel: () => { @@ -1020,17 +1024,22 @@ export function DashboardStoreProvider({ mapStopMotionRef.current(); if (!selectedCity || !proAccess.subscriptionActive) return; const cityName = selectedCity; + const modalSeq = (modalOpenSeqRef.current += 1); + const isLatestModalRequest = () => + modalOpenSeqRef.current === modalSeq && + selectedCityRef.current === cityName; let cachedDetail = cityDetailsByName[selectedCity]; if (!cachedDetail) { setLoadingState((current) => ({ ...current, cityDetail: true })); try { cachedDetail = await ensureCityDetail(cityName, false, "panel"); } finally { - if (selectedCityRef.current === cityName) { + if (isLatestModalRequest()) { setLoadingState((current) => ({ ...current, cityDetail: false })); } } } + if (!isLatestModalRequest()) return; const hasFullCachedDetail = detailSatisfiesDepth(cachedDetail, "full") && !hasSparseDetailCoverage(cachedDetail, dateStr); @@ -1040,6 +1049,7 @@ export function DashboardStoreProvider({ dateStr, ); + setSelectedForecastDate(dateStr); setFutureModalDate(dateStr); if (!hasMarketCachedDetail || forceRefresh) { void ensureCityDetail(cityName, forceRefresh, "market").catch(() => {}); @@ -1052,7 +1062,7 @@ export function DashboardStoreProvider({ void ensureCityDetail(cityName, true, "full") .catch(() => {}) .finally(() => { - if (selectedCityRef.current !== cityName) return; + if (!isLatestModalRequest()) return; setLoadingState((current) => ({ ...current, futureDeep: false, @@ -1068,17 +1078,22 @@ export function DashboardStoreProvider({ mapStopMotionRef.current(); const cityName = selectedCity; + const modalSeq = (modalOpenSeqRef.current += 1); + const isLatestModalRequest = () => + modalOpenSeqRef.current === modalSeq && + selectedCityRef.current === cityName; let cachedDetail = cityDetailsByName[cityName]; if (!cachedDetail) { setLoadingState((current) => ({ ...current, cityDetail: true })); try { cachedDetail = await ensureCityDetail(cityName, false, "panel"); } finally { - if (selectedCityRef.current === cityName) { + if (isLatestModalRequest()) { setLoadingState((current) => ({ ...current, cityDetail: false })); } } } + if (!isLatestModalRequest()) return; const hasFullCachedDetail = detailSatisfiesDepth(cachedDetail, "full") && !hasSparseDetailCoverage(cachedDetail, cachedDetail?.local_date); @@ -1088,7 +1103,9 @@ export function DashboardStoreProvider({ cachedDetail?.local_date, ); const targetDate = - cachedDetail?.local_date || selectedForecastDate || null; + cachedDetail?.local_date || + cachedDetail?.forecast?.daily?.[0]?.date || + null; if (targetDate) { setSelectedForecastDate(targetDate); setFutureModalDate(targetDate); @@ -1116,19 +1133,19 @@ export function DashboardStoreProvider({ "full", ) .then((detail) => { - if (selectedCityRef.current !== cityName) return; + if (!isLatestModalRequest()) return; setSelectedForecastDate(detail.local_date); setFutureModalDate(detail.local_date); }) .catch(() => { - if (selectedCityRef.current !== cityName) return; + if (!isLatestModalRequest()) return; if (cachedDetail?.local_date) { setSelectedForecastDate(cachedDetail.local_date); setFutureModalDate(cachedDetail.local_date); } }) .finally(() => { - if (selectedCityRef.current !== cityName) return; + if (!isLatestModalRequest()) return; setLoadingState((current) => ({ ...current, futureDeep: false, diff --git a/frontend/hooks/useLeafletMap.ts b/frontend/hooks/useLeafletMap.ts index da6b11af..add1cd15 100644 --- a/frontend/hooks/useLeafletMap.ts +++ b/frontend/hooks/useLeafletMap.ts @@ -77,7 +77,6 @@ function pickMarkerTemperature( currentTemp, detail.airport_current?.temp, isNmcStation(detail.airport_primary) ? null : detail.airport_primary?.temp, - detail.mgm_nearby?.[0]?.temp, ]; for (const value of candidates) { const numeric = Number(value); diff --git a/frontend/lib/dashboard-utils.ts b/frontend/lib/dashboard-utils.ts index e8b0f45e..11bb63c0 100644 --- a/frontend/lib/dashboard-utils.ts +++ b/frontend/lib/dashboard-utils.ts @@ -410,27 +410,6 @@ function buildCurrentObservationFallback( temp: detail.airport_current?.temp, time: detail.airport_current?.obs_time || detail.airport_current?.report_time, }, - { - sourceLabel: - detail.center_station_candidate?.source_label || - detail.center_station_candidate?.source_code, - temp: detail.center_station_candidate?.temp, - time: String((detail.center_station_candidate as Record | null | undefined)?.obs_time || ""), - }, - { - sourceLabel: - detail.official_nearby?.[0]?.source_label || - detail.official_nearby?.[0]?.source_code, - temp: detail.official_nearby?.[0]?.temp, - time: String((detail.official_nearby?.[0] as Record | null | undefined)?.obs_time || ""), - }, - { - sourceLabel: - detail.mgm_nearby?.[0]?.source_label || - detail.mgm_nearby?.[0]?.source_code, - temp: detail.mgm_nearby?.[0]?.temp, - time: String((detail.mgm_nearby?.[0] as Record | null | undefined)?.obs_time || ""), - }, ]; const first = candidates.find((item) => {