Merge branch 'Bradley'

This commit is contained in:
2025-09-10 09:09:23 +01:00
37 changed files with 5347 additions and 760 deletions

View File

@@ -41,7 +41,7 @@ export function useGetOverviewSnapshot(cameraSide: string) {
queryKey: ["overviewSnapshot", cameraSide],
queryFn: () => fetchSnapshot(cameraSide),
refetchOnWindowFocus: false,
// refetchInterval: 1000,
refetchInterval: 250,
});
useEffect(() => {

View File

@@ -4,7 +4,7 @@ import { useCallback, useEffect, useRef } from "react";
async function fetchSighting() {
const response = await fetch(
// `http://100.82.205.44/api`
`http://100.116.253.81/mergedHistory/sightingSummary?mostRecentRef=-1`
`http://192.168.75.11/mergedHistory/sightingSummary?mostRecentRef=-1`
);
if (!response.ok) throw new Error("Failed to fetch sighting");
return response.json();
@@ -31,7 +31,7 @@ export function useLatestSighting() {
const { data } = useQuery({
queryKey: ["latestSighting"],
queryFn: fetchSighting,
refetchInterval: 500,
refetchInterval: 100,
});
useEffect(() => {

View File

@@ -1,86 +1,70 @@
import { useEffect, useMemo, useRef, useState } from "react";
import { useEffect, useRef, useState } from "react";
import type { SightingWidgetType } from "../types/types";
import { useQuery } from "@tanstack/react-query";
// const url = `http://100.82.205.44/SightingListFront/sightingSummary?mostRecentRef=-1`;
async function fetchSighting(url: string, ref: number, signal?: AbortSignal) {
const dynamicUrl = `${url}${ref}`;
const res = await fetch(dynamicUrl, { signal });
async function fetchSighting(url: string, ref: number): Promise<SightingWidgetType> {
const res = await fetch(`${url}${ref}`);
if (!res.ok) throw new Error(String(res.status));
return (await res.json()) as SightingWidgetType;
return await res.json();
}
export function useSightingFeed(url: string) {
const [sightings, setSightings] = useState<SightingWidgetType[]>(
() => Array(7).fill(null) as unknown as SightingWidgetType[]
);
const [noSighting, setNoSighting] = useState(false);
const [sightings, setSightings] = useState<SightingWidgetType[]>([]);
const [selectedRef, setSelectedRef] = useState<number | null>(null);
const [mostRecent, setMostRecent] = useState<SightingWidgetType | null>(null);
const mostRecentRef = useRef<number>(-1);
const lastSeenRef = useRef<number | null>(null);
const { data, isPending } = useQuery({
queryKey: ["sighting"],
queryFn: ({ signal }) => fetchSighting(url, mostRecentRef.current, signal),
refetchInterval: 2000,
refetchIntervalInBackground: true,
refetchOnWindowFocus: false,
staleTime: 0,
notifyOnChangeProps: ["data"],
});
const currentRef = useRef<number>(-1);
const pollingTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
const lastValidTimestamp = useRef<number>(Date.now());
useEffect(() => {
if (!data) return;
const poll = async () => {
try {
const data = await fetchSighting(url, currentRef.current);
if (data.ref === -1) {
setNoSighting(true);
} else {
setNoSighting(false);
}
if (data.ref === lastSeenRef.current) return; // duplicate payload → do nothing
lastSeenRef.current = data.ref;
const now = Date.now();
setSightings((prev) => {
const existing = prev.find((p) => p?.ref === data.ref);
const next = existing
? prev
: [data, ...prev.filter(Boolean)].slice(0, 7);
if (data.ref === -1) {
if (now - lastValidTimestamp.current > 60000) {
console.warn("No valid sighting in over a minute. Restarting...");
currentRef.current = -1;
lastValidTimestamp.current = now;
}
const stillHasSelection =
selectedRef != null && next.some((s) => s?.ref === selectedRef);
if (!stillHasSelection) {
setSelectedRef(data.ref);
pollingTimeout.current = setTimeout(poll, 400);
} else {
currentRef.current = data.ref;
lastValidTimestamp.current = now;
setSightings(prev => {
const updated = [data, ...prev].slice(0, 7);
return updated;
});
setMostRecent(data);
setSelectedRef(data.ref);
pollingTimeout.current = setTimeout(poll, 100);
}
} catch (err) {
console.error("Polling error:", err);
pollingTimeout.current = setTimeout(poll, 100);
}
};
return next;
});
setMostRecent(sightings[0]);
mostRecentRef.current = data.ref ?? -1;
}, [data, selectedRef, sightings]);
poll();
const selected = useMemo(
() =>
selectedRef == null
? null
: sightings.find((s) => s?.ref === selectedRef) ?? null,
[sightings, selectedRef]
);
return () => {
if (pollingTimeout.current) clearTimeout(pollingTimeout.current);
};
}, [url]);
const effectiveSelected = selected ?? mostRecent ?? null;
const selected = sightings.find(s => s?.ref === selectedRef) ?? mostRecent;
return {
sightings,
selectedRef,
setSelectedRef,
mostRecent,
effectiveSelected,
mostRecentRef,
isPending,
noSighting,
effectiveSelected: selected,
};
}