import { useEffect, useMemo, useRef, useState } from "react"; import type { SightingWidgetType } from "../types/types"; export function useSightingFeed( baseUrl: string, { limit = 7, pollMs = 800, autoSelectLatest = true, }: { limit?: number; pollMs?: number; autoSelectLatest?: boolean; } = {} ) { const [items, setItems] = useState( () => Array(limit).fill(null) as unknown as SightingWidgetType[] ); const [selectedRef, setSelectedRef] = useState(null); const [mostRecent, setMostRecent] = useState(null); const mostRecentRef = useRef(-1); // effective selected (fallback to most recent) const selected = useMemo( () => selectedRef == null ? null : items.find((x) => x?.ref === selectedRef) ?? null, [items, selectedRef] ); const effectiveSelected = selected ?? mostRecent ?? null; useEffect(() => { let delay = pollMs; let dead = false; const controller = new AbortController(); async function tick() { try { // Pause when tab hidden to save CPU/network if (document.hidden) { setTimeout(tick, Math.max(delay, 2000)); return; } const url = `http://100.116.253.81/mergedHistory/sightingSummary?mostRecentRef=${mostRecentRef.current}`; const res = await fetch(url, { signal: controller.signal }); if (!res.ok) throw new Error(String(res.status)); const obj: SightingWidgetType = await res.json(); if (obj && typeof obj.ref === "number" && obj.ref > -1) { setItems((prev) => { const next = [obj, ...prev].slice(0, limit); // maintain selection if still present; otherwise select newest if allowed const stillExists = selectedRef != null && next.some((x) => x?.ref === selectedRef); if (autoSelectLatest && !stillExists) { setSelectedRef(obj.ref); } return next; }); setMostRecent(obj); mostRecentRef.current = obj.ref; delay = pollMs; // reset backoff on success } } catch { // exponential backoff (max 10s) delay = Math.min(delay * 2, 10000); } finally { if (!dead) setTimeout(tick, delay); } } const t = setTimeout(tick, pollMs); return () => { dead = true; controller.abort(); clearTimeout(t); }; }, [baseUrl, limit, pollMs, autoSelectLatest, selectedRef]); return { items, selectedRef, setSelectedRef, mostRecent, effectiveSelected, mostRecentRef, }; }