"use client"; import { useCallback, useEffect, useRef, useState } from "react"; import { scanTerminalQueryPolicy, scanTerminalClient, shouldRunAutoTerminalRefresh, shouldSkipManualTerminalRefresh, } from "@/components/dashboard/scan-terminal/scan-terminal-client"; import { useRemoteDataQuery } from "@/components/dashboard/scan-terminal/use-remote-data-query"; import type { ScanTerminalResponse } from "@/lib/dashboard-types"; const SCAN_CACHE_KEY = "polyweather_scan_v1"; const SCAN_CACHE_TTL_MS = 2 * 60 * 1000; // 2 min — cities list instant on revisit function readScanCache(): ScanTerminalResponse | null { try { const raw = localStorage.getItem(SCAN_CACHE_KEY); if (!raw) return null; const cached = JSON.parse(raw); if (cached.ts && Date.now() - cached.ts < SCAN_CACHE_TTL_MS && cached.data?.rows) { return cached.data; } } catch { /* ignore */ } return null; } function writeScanCache(data: ScanTerminalResponse) { try { localStorage.setItem(SCAN_CACHE_KEY, JSON.stringify({ ts: Date.now(), data })); } catch { /* ignore */ } } export function useScanTerminalQuery({ isPro, proAccessLoading, timezoneOffsetSeconds, tradingRegion, }: { isPro: boolean; proAccessLoading: boolean; timezoneOffsetSeconds?: number | null; tradingRegion?: string; }) { const { data: terminalData, error: scanError, isLoading, loading: scanLoading, remote: scanRemote, reset, run, } = useRemoteDataQuery(); const lastForcedScanRefreshAtRef = useRef(0); const [cachedRows, setCachedRows] = useState(() => { if (typeof window !== "undefined") return readScanCache(); return null; }); const fetchScanTerminal = useCallback( async ({ forceRefresh = false, showLoading = false, }: { forceRefresh?: boolean; showLoading?: boolean; } = {}) => { if (proAccessLoading || !isPro) return; if (typeof fetch !== "function" || typeof AbortController === "undefined") { return; } if (forceRefresh) { lastForcedScanRefreshAtRef.current = Date.now(); } await run({ request: (signal) => scanTerminalClient.getTerminal({ forceRefresh, signal, timezoneOffsetSeconds, tradingRegion, }), showLoading, onSuccess: (data) => { writeScanCache(data); setCachedRows(data); }, }); }, [isPro, proAccessLoading, run, timezoneOffsetSeconds, tradingRegion], ); useEffect(() => { if (proAccessLoading) return; if (!isPro) { reset(); return; } void fetchScanTerminal({ forceRefresh: false, showLoading: true }); }, [fetchScanTerminal, isPro, proAccessLoading, reset, timezoneOffsetSeconds, tradingRegion]); const effectiveData = terminalData || cachedRows; const refreshScanTerminalManually = useCallback(() => { if ( shouldSkipManualTerminalRefresh({ hasCurrentData: Boolean(terminalData), lastForcedRefreshAt: lastForcedScanRefreshAtRef.current, }) ) { return; } void fetchScanTerminal({ forceRefresh: true, showLoading: true }); }, [fetchScanTerminal, terminalData]); useEffect(() => { if (proAccessLoading || !isPro) return; if ( typeof window === "undefined" || typeof window.setInterval !== "function" || typeof window.clearInterval !== "function" ) { return; } const intervalId = window.setInterval(() => { if ( !shouldRunAutoTerminalRefresh({ documentHidden: document.hidden, isLoading: isLoading(), }) ) { return; } void fetchScanTerminal({ forceRefresh: false, showLoading: false }); }, scanTerminalQueryPolicy.autoRefreshMs); return () => window.clearInterval(intervalId); }, [fetchScanTerminal, isLoading, isPro, proAccessLoading]); return { refreshScanTerminalManually, scanError, scanLoading, scanRemote, terminalData: effectiveData, }; }