v3: various improvements and fixes to real-time updates
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 40s

This commit is contained in:
khannurien
2026-06-29 07:52:56 +00:00
parent f162d23ce3
commit aab5b5bfd5
12 changed files with 227 additions and 38 deletions

View File

@@ -70,6 +70,7 @@ export function Index({ categorySlug }: { categorySlug?: string }) {
deletedDumpIds,
castVote,
removeVote,
connectionEpoch,
} = useWS();
// Resolve the scope to a real category (for its id, name, and 404 handling).
@@ -177,6 +178,36 @@ export function Index({ categorySlug }: { categorySlug?: string }) {
);
useDumpListSync(setDumpsItems);
// ── Reconnect backfill ──
// New dumps that arrived while the socket was down weren't delivered. On
// reconnect, re-fetch page 1 and merge anything not already present on top,
// preserving loaded pages and scroll position.
const backfillEpochRef = useRef(connectionEpoch);
useEffect(() => {
if (connectionEpoch === backfillEpochRef.current) return;
backfillEpochRef.current = connectionEpoch;
const controller = new AbortController();
fetch(feedUrl(1), {
signal: controller.signal,
headers: token ? { Authorization: `Bearer ${token}` } : {},
})
.then((r) => r.json())
.then((body) => {
const { items } = body.data as PaginatedData<RawDump>;
const fresh = items.map(deserializeDump);
setDumpsState((s) => {
if (s.status !== "loaded") return s;
const known = new Set(s.dumps.map((d) => d.id));
const newOnes = fresh.filter((d) => !known.has(d.id));
if (newOnes.length === 0) return s;
return { ...s, dumps: [...newOnes, ...s.dumps] };
});
})
.catch(() => {});
return () => controller.abort();
}, [connectionEpoch, feedUrl, token]);
// ── Load more ──
const loadMore = useCallback(() => {