Spaces:
Sleeping
Sleeping
File size: 2,671 Bytes
71c1c9d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | // 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<UpdateItem[]>([]);
const [loading, setLoading] = React.useState(false);
const [error, setError] = React.useState<string | null>(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 };
}
|