feat : comment feature
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
/** One stream per board/thread; open replies refresh through the board revision. */
|
||||
export function useCommentEvents(scope: { target: string } | { admin: true }, refresh: (changed: boolean) => Promise<unknown>) {
|
||||
const refreshRef = useRef(refresh);
|
||||
useEffect(() => { refreshRef.current = refresh; }, [refresh]);
|
||||
const query = "target" in scope ? `target=${encodeURIComponent(scope.target)}` : "scope=admin";
|
||||
useEffect(() => {
|
||||
let source: EventSource | null = null;
|
||||
let timer: ReturnType<typeof setTimeout> | undefined;
|
||||
let refreshing = false;
|
||||
let dirty = false;
|
||||
let pendingChange = false;
|
||||
let connectedBefore = false;
|
||||
let disposed = false;
|
||||
async function flush() {
|
||||
timer = undefined;
|
||||
if (disposed) return;
|
||||
if (refreshing) { dirty = true; return; }
|
||||
refreshing = true;
|
||||
const changed = pendingChange;
|
||||
pendingChange = false;
|
||||
try { await refreshRef.current(changed); }
|
||||
finally {
|
||||
refreshing = false;
|
||||
if (dirty && !disposed) { dirty = false; schedule(); }
|
||||
}
|
||||
}
|
||||
function schedule(changed = false) {
|
||||
pendingChange ||= changed;
|
||||
if (!timer && !disposed) timer = setTimeout(() => { void flush(); }, 250);
|
||||
}
|
||||
function connect() {
|
||||
source?.close(); source = null;
|
||||
if (document.visibilityState !== "visible") return;
|
||||
source = new EventSource(`/api/comments/events?${query}`);
|
||||
source.addEventListener("changed", () => schedule(true));
|
||||
// Catch updates between the initial page response and stream subscription,
|
||||
// and updates missed while disconnected. EventSource handles reconnects.
|
||||
source.addEventListener("open", () => {
|
||||
// A reconnect can have missed reply edits even if the root is unchanged.
|
||||
schedule(connectedBefore);
|
||||
connectedBefore = true;
|
||||
});
|
||||
}
|
||||
connect();
|
||||
document.addEventListener("visibilitychange", connect);
|
||||
return () => {
|
||||
disposed = true; source?.close();
|
||||
if (timer) clearTimeout(timer);
|
||||
document.removeEventListener("visibilitychange", connect);
|
||||
};
|
||||
}, [query]);
|
||||
}
|
||||
Reference in New Issue
Block a user