"use client"; import { useCallback, useEffect, useMemo, useState } from "react"; import { buildApiUrl } from "@/lib/api/url"; import { parseRatesResponse, RatesResponse } from "@/lib/rates"; const REFRESH_INTERVAL_MS = 60_000; export function useMarketRates() { const [data, setData] = useState(null); const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(true); const fetchRates = useCallback(async () => { try { const response = await fetch(buildApiUrl("/api/rates")); if (!response.ok) { const payload = (await response.json().catch(() => null)) as { message?: string; } | null; throw new Error( payload?.message ?? "Unable to fetch latest market rates", ); } const payload = await response.json(); const parsed = parseRatesResponse(payload); const isFallback = response.headers.get("X-Cache-Fallback") === "stale-on-error"; const fallbackError = response.headers.get("X-Cache-Fallback-Error"); setData(parsed); setError(isFallback ? (fallbackError ?? "Upstream provider error") : null); } catch (err) { const message = err instanceof Error ? err.message : "Unknown error"; setError(message); } finally { setIsLoading(false); } }, []); useEffect(() => { void fetchRates(); const tick = () => { if (document.visibilityState === "visible") { void fetchRates(); } }; const id = window.setInterval(() => { tick(); }, REFRESH_INTERVAL_MS); const handleVisibilityChange = () => { if (document.visibilityState === "visible") { void fetchRates(); } }; document.addEventListener("visibilitychange", handleVisibilityChange); return () => { window.clearInterval(id); document.removeEventListener("visibilitychange", handleVisibilityChange); }; }, [fetchRates]); const state = useMemo( () => ({ data, error, isLoading, refresh: fetchRates, }), [data, error, isLoading, fetchRates], ); return state; }