feat: add useAiCityForecast hook to manage streamed AI city weather forecasting logic
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { scanTerminalClient } from "@/components/dashboard/scan-terminal/scan-terminal-client";
|
import { scanTerminalClient } from "@/components/dashboard/scan-terminal/scan-terminal-client";
|
||||||
import type { AiCityForecastState } from "@/components/dashboard/scan-terminal/types";
|
import type { AiCityForecastState } from "@/components/dashboard/scan-terminal/types";
|
||||||
import type { CityDetail } from "@/lib/dashboard-types";
|
import type { CityDetail } from "@/lib/dashboard-types";
|
||||||
@@ -33,6 +33,12 @@ export function useAiCityForecast({
|
|||||||
report: string;
|
report: string;
|
||||||
}) {
|
}) {
|
||||||
const [aiRefreshToken, setAiRefreshToken] = useState(0);
|
const [aiRefreshToken, setAiRefreshToken] = useState(0);
|
||||||
|
// Keep refs to the latest detail/report so the effect closure always reads
|
||||||
|
// current values without needing to list unstable object refs as deps.
|
||||||
|
const detailRef = useRef<CityDetail | null>(detail);
|
||||||
|
const reportRef = useRef<string>(report);
|
||||||
|
detailRef.current = detail;
|
||||||
|
reportRef.current = report;
|
||||||
const aiForecastKey = useMemo(
|
const aiForecastKey = useMemo(
|
||||||
() => buildAiCityForecastKey({ detail, detailCityName, locale, report }),
|
() => buildAiCityForecastKey({ detail, detailCityName, locale, report }),
|
||||||
[detail, detailCityName, locale, report],
|
[detail, detailCityName, locale, report],
|
||||||
@@ -67,19 +73,19 @@ export function useAiCityForecast({
|
|||||||
|
|
||||||
const loadingState = buildAiCityLoadingForecastState({
|
const loadingState = buildAiCityLoadingForecastState({
|
||||||
cacheKey,
|
cacheKey,
|
||||||
detail,
|
detail: detailRef.current,
|
||||||
isEn,
|
isEn,
|
||||||
report,
|
report: reportRef.current,
|
||||||
});
|
});
|
||||||
setAiForecast(loadingState);
|
setAiForecast(loadingState);
|
||||||
const softTimeoutId = window.setTimeout(() => {
|
const softTimeoutId = window.setTimeout(() => {
|
||||||
if (cancelled || resolved) return;
|
if (cancelled || resolved) return;
|
||||||
const fallbackState = buildAiCityErrorForecastState({
|
const fallbackState = buildAiCityErrorForecastState({
|
||||||
cacheKey,
|
cacheKey,
|
||||||
detail,
|
detail: detailRef.current,
|
||||||
error: "ai_soft_timeout_fallback",
|
error: "ai_soft_timeout_fallback",
|
||||||
isEn,
|
isEn,
|
||||||
report,
|
report: reportRef.current,
|
||||||
});
|
});
|
||||||
setAiForecast(fallbackState);
|
setAiForecast(fallbackState);
|
||||||
}, AI_CITY_READ_SOFT_TIMEOUT_MS);
|
}, AI_CITY_READ_SOFT_TIMEOUT_MS);
|
||||||
@@ -106,10 +112,10 @@ export function useAiCityForecast({
|
|||||||
window.clearTimeout(softTimeoutId);
|
window.clearTimeout(softTimeoutId);
|
||||||
const readyState = buildAiCityReadyForecastState({
|
const readyState = buildAiCityReadyForecastState({
|
||||||
cacheKey,
|
cacheKey,
|
||||||
detail,
|
detail: detailRef.current,
|
||||||
isEn,
|
isEn,
|
||||||
payload,
|
payload,
|
||||||
report,
|
report: reportRef.current,
|
||||||
});
|
});
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
setAiForecast(readyState);
|
setAiForecast(readyState);
|
||||||
@@ -120,10 +126,10 @@ export function useAiCityForecast({
|
|||||||
window.clearTimeout(softTimeoutId);
|
window.clearTimeout(softTimeoutId);
|
||||||
const errorState = buildAiCityErrorForecastState({
|
const errorState = buildAiCityErrorForecastState({
|
||||||
cacheKey,
|
cacheKey,
|
||||||
detail,
|
detail: detailRef.current,
|
||||||
error,
|
error,
|
||||||
isEn,
|
isEn,
|
||||||
report,
|
report: reportRef.current,
|
||||||
});
|
});
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
setAiForecast(errorState);
|
setAiForecast(errorState);
|
||||||
@@ -136,12 +142,10 @@ export function useAiCityForecast({
|
|||||||
}, [
|
}, [
|
||||||
aiForecastKey,
|
aiForecastKey,
|
||||||
aiRefreshToken,
|
aiRefreshToken,
|
||||||
detail,
|
|
||||||
detailCityName,
|
detailCityName,
|
||||||
enabled,
|
enabled,
|
||||||
isEn,
|
isEn,
|
||||||
locale,
|
locale,
|
||||||
report,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const refreshAiForecast = useCallback(() => {
|
const refreshAiForecast = useCallback(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user