Fix today analysis modal routing
This commit is contained in:
@@ -287,12 +287,18 @@ function getTrendMetricVisual(metric: {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DailyTemperatureChart({ dateStr }: { dateStr: string }) {
|
function DailyTemperatureChart({
|
||||||
|
dateStr,
|
||||||
|
forceToday = false,
|
||||||
|
}: {
|
||||||
|
dateStr: string;
|
||||||
|
forceToday?: boolean;
|
||||||
|
}) {
|
||||||
const store = useDashboardStore();
|
const store = useDashboardStore();
|
||||||
const { locale, t } = useI18n();
|
const { locale, t } = useI18n();
|
||||||
const detail = store.selectedDetail;
|
const detail = store.selectedDetail;
|
||||||
const view = detail ? getFutureModalView(detail, dateStr, locale) : null;
|
const view = detail ? getFutureModalView(detail, dateStr, locale) : null;
|
||||||
const isToday = detail ? dateStr === detail.local_date : false;
|
const isToday = forceToday || (detail ? dateStr === detail.local_date : false);
|
||||||
const todayChartData = useMemo(
|
const todayChartData = useMemo(
|
||||||
() => (detail && isToday ? getTemperatureChartData(detail, locale) : null),
|
() => (detail && isToday ? getTemperatureChartData(detail, locale) : null),
|
||||||
[detail, isToday, locale],
|
[detail, isToday, locale],
|
||||||
@@ -711,7 +717,9 @@ export function FutureForecastModal() {
|
|||||||
};
|
};
|
||||||
}, [dateStr, detail]);
|
}, [dateStr, detail]);
|
||||||
|
|
||||||
const isToday = dateStr === detail.local_date;
|
const isToday =
|
||||||
|
store.forecastModalMode === "today" ||
|
||||||
|
(store.forecastModalMode == null && dateStr === detail.local_date);
|
||||||
const detailDepth = detail.detail_depth || "full";
|
const detailDepth = detail.detail_depth || "full";
|
||||||
const isFullDetailReady = detailDepth === "full";
|
const isFullDetailReady = detailDepth === "full";
|
||||||
const isStructureSyncing = store.loadingState.futureDeep || !isFullDetailReady;
|
const isStructureSyncing = store.loadingState.futureDeep || !isFullDetailReady;
|
||||||
@@ -1713,7 +1721,7 @@ export function FutureForecastModal() {
|
|||||||
: "今日气温路径(锚点观测 + 模型)"}
|
: "今日气温路径(锚点观测 + 模型)"}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<DailyTemperatureChart dateStr={dateStr} />
|
<DailyTemperatureChart dateStr={dateStr} forceToday={isToday} />
|
||||||
<div className="future-v2-chart-thresholds">
|
<div className="future-v2-chart-thresholds">
|
||||||
<span>{locale === "en-US" ? "Base" : "基准"} · {baseCaseBucket || "--"}</span>
|
<span>{locale === "en-US" ? "Base" : "基准"} · {baseCaseBucket || "--"}</span>
|
||||||
<span>{locale === "en-US" ? "Upside" : "上修"} · {intradayMeteorology.upside_bucket || "--"}</span>
|
<span>{locale === "en-US" ? "Upside" : "上修"} · {intradayMeteorology.upside_bucket || "--"}</span>
|
||||||
@@ -1891,7 +1899,7 @@ export function FutureForecastModal() {
|
|||||||
|
|
||||||
<section className="future-modal-section">
|
<section className="future-modal-section">
|
||||||
<h3>{t("future.targetTempTrend")}</h3>
|
<h3>{t("future.targetTempTrend")}</h3>
|
||||||
<DailyTemperatureChart dateStr={dateStr} />
|
<DailyTemperatureChart dateStr={dateStr} forceToday={isToday} />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div className="future-modal-grid">
|
<div className="future-modal-grid">
|
||||||
|
|||||||
@@ -1020,7 +1020,11 @@ export function ForecastTable() {
|
|||||||
daily.map((day, index) => {
|
daily.map((day, index) => {
|
||||||
const isToday = day.date === data.local_date || index === 0;
|
const isToday = day.date === data.local_date || index === 0;
|
||||||
const isSelected =
|
const isSelected =
|
||||||
store.futureModalDate === day.date ||
|
(isToday &&
|
||||||
|
store.forecastModalMode === "today" &&
|
||||||
|
Boolean(store.futureModalDate)) ||
|
||||||
|
(store.forecastModalMode !== "today" &&
|
||||||
|
store.futureModalDate === day.date) ||
|
||||||
store.selectedForecastDate === day.date;
|
store.selectedForecastDate === day.date;
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
@@ -1033,6 +1037,10 @@ export function ForecastTable() {
|
|||||||
)}
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
|
if (isToday) {
|
||||||
|
store.openTodayModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
store.openFutureModal(day.date);
|
store.openFutureModal(day.date);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
CityListItem,
|
CityListItem,
|
||||||
CitySummary,
|
CitySummary,
|
||||||
DashboardState,
|
DashboardState,
|
||||||
|
ForecastModalMode,
|
||||||
HistoryPoint,
|
HistoryPoint,
|
||||||
HistoryPayload,
|
HistoryPayload,
|
||||||
HistoryPayloadMeta,
|
HistoryPayloadMeta,
|
||||||
@@ -40,6 +41,7 @@ interface DashboardStoreValue extends DashboardState {
|
|||||||
force?: boolean,
|
force?: boolean,
|
||||||
depth?: "panel" | "nearby" | "full",
|
depth?: "panel" | "nearby" | "full",
|
||||||
) => Promise<CityDetail>;
|
) => Promise<CityDetail>;
|
||||||
|
forecastModalMode: ForecastModalMode | null;
|
||||||
futureModalDate: string | null;
|
futureModalDate: string | null;
|
||||||
loadCities: () => Promise<void>;
|
loadCities: () => Promise<void>;
|
||||||
openFutureModal: (dateStr: string, forceRefresh?: boolean) => Promise<void>;
|
openFutureModal: (dateStr: string, forceRefresh?: boolean) => Promise<void>;
|
||||||
@@ -323,6 +325,8 @@ export function DashboardStoreProvider({
|
|||||||
string | null
|
string | null
|
||||||
>(null);
|
>(null);
|
||||||
const [futureModalDate, setFutureModalDate] = useState<string | null>(null);
|
const [futureModalDate, setFutureModalDate] = useState<string | null>(null);
|
||||||
|
const [forecastModalMode, setForecastModalMode] =
|
||||||
|
useState<ForecastModalMode | null>(null);
|
||||||
const [isMapInteracting, setIsMapInteracting] = useState(false);
|
const [isMapInteracting, setIsMapInteracting] = useState(false);
|
||||||
const [loadingState, setLoadingState] = useState<LoadingState>(
|
const [loadingState, setLoadingState] = useState<LoadingState>(
|
||||||
getInitialLoadingState,
|
getInitialLoadingState,
|
||||||
@@ -761,6 +765,7 @@ export function DashboardStoreProvider({
|
|||||||
setIsPanelOpen(true);
|
setIsPanelOpen(true);
|
||||||
setSelectedForecastDate(null);
|
setSelectedForecastDate(null);
|
||||||
setFutureModalDate(null);
|
setFutureModalDate(null);
|
||||||
|
setForecastModalMode(null);
|
||||||
|
|
||||||
const summaryPromise = !citySummariesRef.current[cityName]
|
const summaryPromise = !citySummariesRef.current[cityName]
|
||||||
? ensureCitySummary(cityName).catch(() => null)
|
? ensureCitySummary(cityName).catch(() => null)
|
||||||
@@ -1007,6 +1012,7 @@ export function DashboardStoreProvider({
|
|||||||
closeFutureModal: () => {
|
closeFutureModal: () => {
|
||||||
modalOpenSeqRef.current += 1;
|
modalOpenSeqRef.current += 1;
|
||||||
setFutureModalDate(null);
|
setFutureModalDate(null);
|
||||||
|
setForecastModalMode(null);
|
||||||
},
|
},
|
||||||
closeHistory: () =>
|
closeHistory: () =>
|
||||||
setHistoryState((current) => ({ ...current, isOpen: false })),
|
setHistoryState((current) => ({ ...current, isOpen: false })),
|
||||||
@@ -1014,6 +1020,7 @@ export function DashboardStoreProvider({
|
|||||||
setIsPanelOpen(false);
|
setIsPanelOpen(false);
|
||||||
},
|
},
|
||||||
ensureCityDetail,
|
ensureCityDetail,
|
||||||
|
forecastModalMode,
|
||||||
futureModalDate,
|
futureModalDate,
|
||||||
historyState,
|
historyState,
|
||||||
isPanelOpen,
|
isPanelOpen,
|
||||||
@@ -1048,9 +1055,16 @@ export function DashboardStoreProvider({
|
|||||||
"market",
|
"market",
|
||||||
dateStr,
|
dateStr,
|
||||||
);
|
);
|
||||||
|
const todayDate =
|
||||||
|
cachedDetail?.local_date ||
|
||||||
|
cachedDetail?.forecast?.daily?.[0]?.date ||
|
||||||
|
null;
|
||||||
|
const modalMode: ForecastModalMode =
|
||||||
|
todayDate && dateStr === todayDate ? "today" : "future";
|
||||||
|
|
||||||
setSelectedForecastDate(dateStr);
|
setSelectedForecastDate(dateStr);
|
||||||
setFutureModalDate(dateStr);
|
setFutureModalDate(dateStr);
|
||||||
|
setForecastModalMode(modalMode);
|
||||||
if (!hasMarketCachedDetail || forceRefresh) {
|
if (!hasMarketCachedDetail || forceRefresh) {
|
||||||
void ensureCityDetail(cityName, forceRefresh, "market").catch(() => {});
|
void ensureCityDetail(cityName, forceRefresh, "market").catch(() => {});
|
||||||
}
|
}
|
||||||
@@ -1109,6 +1123,7 @@ export function DashboardStoreProvider({
|
|||||||
if (targetDate) {
|
if (targetDate) {
|
||||||
setSelectedForecastDate(targetDate);
|
setSelectedForecastDate(targetDate);
|
||||||
setFutureModalDate(targetDate);
|
setFutureModalDate(targetDate);
|
||||||
|
setForecastModalMode("today");
|
||||||
}
|
}
|
||||||
if (!proAccess.subscriptionActive) return;
|
if (!proAccess.subscriptionActive) return;
|
||||||
const needsDetailRefresh =
|
const needsDetailRefresh =
|
||||||
@@ -1136,12 +1151,14 @@ export function DashboardStoreProvider({
|
|||||||
if (!isLatestModalRequest()) return;
|
if (!isLatestModalRequest()) return;
|
||||||
setSelectedForecastDate(detail.local_date);
|
setSelectedForecastDate(detail.local_date);
|
||||||
setFutureModalDate(detail.local_date);
|
setFutureModalDate(detail.local_date);
|
||||||
|
setForecastModalMode("today");
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
if (!isLatestModalRequest()) return;
|
if (!isLatestModalRequest()) return;
|
||||||
if (cachedDetail?.local_date) {
|
if (cachedDetail?.local_date) {
|
||||||
setSelectedForecastDate(cachedDetail.local_date);
|
setSelectedForecastDate(cachedDetail.local_date);
|
||||||
setFutureModalDate(cachedDetail.local_date);
|
setFutureModalDate(cachedDetail.local_date);
|
||||||
|
setForecastModalMode("today");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
@@ -1170,6 +1187,7 @@ export function DashboardStoreProvider({
|
|||||||
cities,
|
cities,
|
||||||
cityDetailsByName,
|
cityDetailsByName,
|
||||||
citySummariesByName,
|
citySummariesByName,
|
||||||
|
forecastModalMode,
|
||||||
futureModalDate,
|
futureModalDate,
|
||||||
historyState,
|
historyState,
|
||||||
isPanelOpen,
|
isPanelOpen,
|
||||||
|
|||||||
@@ -606,6 +606,8 @@ export interface ProAccessState {
|
|||||||
error: string | null;
|
error: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ForecastModalMode = "today" | "future";
|
||||||
|
|
||||||
export interface DashboardState {
|
export interface DashboardState {
|
||||||
cities: CityListItem[];
|
cities: CityListItem[];
|
||||||
cityDetailsByName: Record<string, CityDetail>;
|
cityDetailsByName: Record<string, CityDetail>;
|
||||||
@@ -613,6 +615,7 @@ export interface DashboardState {
|
|||||||
selectedCity: string | null;
|
selectedCity: string | null;
|
||||||
isPanelOpen: boolean;
|
isPanelOpen: boolean;
|
||||||
selectedForecastDate: string | null;
|
selectedForecastDate: string | null;
|
||||||
|
forecastModalMode: ForecastModalMode | null;
|
||||||
loadingState: LoadingState;
|
loadingState: LoadingState;
|
||||||
historyState: HistoryState;
|
historyState: HistoryState;
|
||||||
proAccess: ProAccessState;
|
proAccess: ProAccessState;
|
||||||
|
|||||||
Reference in New Issue
Block a user