Fix intraday modal races and METAR temperature fallbacks

This commit is contained in:
2569718930@qq.com
2026-04-17 18:05:52 +08:00
parent cdaea8a1f0
commit ce7a037b6d
3 changed files with 25 additions and 30 deletions
+25 -8
View File
@@ -336,6 +336,7 @@ export function DashboardStoreProvider({
const proAccessRef = useRef<ProAccessState>(getInitialProAccessState());
const mapStopMotionRef = useRef<() => void>(() => {});
const modalOpenSeqRef = useRef(0);
const hydratedSelectionRef = useRef(false);
const hydratedProCacheRef = useRef(false);
const backgroundSummaryCheckAtRef = useRef<Record<string, number>>({});
@@ -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,
-1
View File
@@ -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);
-21
View File
@@ -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<string, unknown> | 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<string, unknown> | 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<string, unknown> | null | undefined)?.obs_time || ""),
},
];
const first = candidates.find((item) => {