// hooks/useProximityAlerts.ts import * as React from "react"; import type { UpdateItem } from "../lib/types"; import { UPDATES_LOCAL_URL } from "../lib/constants"; export function useProximityAlerts( myLL: [number, number] | null, opts: { radiusMiles?: number; limit?: number; maxAgeHours?: number } = {} ) { const { radiusMiles = 2, limit = 5, maxAgeHours = 48 } = opts; const [nearby, setNearby] = React.useState([]); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(null); // request id to ignore stale responses const reqIdRef = React.useRef(0); const refetch = React.useCallback(async () => { if (!myLL) return; const [lat, lon] = myLL; setLoading(true); setError(null); const myId = ++reqIdRef.current; const ctrl = new AbortController(); try { const url = `${UPDATES_LOCAL_URL}?lat=${lat}&lon=${lon}&radius_miles=${radiusMiles}&limit=${limit}&max_age_hours=${maxAgeHours}`; const res = await fetch(url, { signal: ctrl.signal }); const data = await res.json(); const listRaw: any[] = Array.isArray(data) ? data : Array.isArray(data?.items) ? data.items : Array.isArray(data?.updates) ? data.updates : Array.isArray((data as any)?.results) ? (data as any).results : []; // resolve a usable rid (works even if backend forgot to surface rid at top level) const resolveRid = (u: any) => u?.rid || u?.raw?.rid || u?.raw?.id || u?.id || u?._id || u?.raw?._id || u?.raw?.uuid; if (myId !== reqIdRef.current) return; // stale // Only user reports with an id we can react to const normalized = listRaw .filter((u) => u?.kind === "report") .map((u) => { const rid = resolveRid(u); return rid ? { ...u, rid } : null; }) .filter(Boolean) as UpdateItem[]; console.log("nearby fetch URL", url); console.log("nearby raw data", data); console.log("nearby normalized", normalized); setNearby(normalized.slice(0, limit)); } catch (e: any) { if (e?.name !== "AbortError") setError(e?.message || "Failed to load nearby alerts"); } finally { if (myId === reqIdRef.current) setLoading(false); } return () => ctrl.abort(); }, [myLL, radiusMiles, limit, maxAgeHours]); React.useEffect(() => { refetch(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [refetch, myLL?.[0], myLL?.[1]]); return { nearby, loading, error, refetch, setNearby }; }