"use client"; import { commentRequest } from "./client"; import { useCallback, useEffect, useRef, useState } from "react"; import type { CommentPage } from "@/lib/comments/types"; export function useCommentFeed(endpoint: string, initial?: CommentPage) { const [page, setPage] = useState(initial ?? { items: [], nextCursor: null, viewer: null }); const [dataEndpoint, setDataEndpoint] = useState(endpoint); const [busy, setBusy] = useState(!initial); const [error, setError] = useState(""); const [revision, setRevision] = useState(0); const generation = useRef(0); const loadedPages = useRef(1); const mountedEndpoint = useRef(initial ? endpoint : ""); const active = useRef(null); const lastPayload = useRef(JSON.stringify(initial ?? { items: [], nextCursor: null, viewer: null })); const refresh = useCallback(async (options: { silent?: boolean; forceRevision?: boolean } = {}) => { active.current?.abort(); const controller = new AbortController(); active.current = controller; const sequence = ++generation.current; if (options.silent === false) setBusy(true); try { let result = await commentRequest(endpoint, { signal: controller.signal }); for (let i = 1; i < loadedPages.current && result.nextCursor; i++) { const next = await commentRequest(`${endpoint}&cursor=${encodeURIComponent(result.nextCursor)}`, { signal: controller.signal }); result = { ...next, items: [...result.items, ...next.items] }; } if (sequence === generation.current) { const payload = JSON.stringify(result); if (payload !== lastPayload.current) { lastPayload.current = payload; setPage(result); setRevision((value) => value + 1); } else if (options.forceRevision) { setRevision((value) => value + 1); } setDataEndpoint(endpoint); setError(""); } } catch (cause) { if (!controller.signal.aborted && sequence === generation.current) setError(cause instanceof Error ? cause.message : "ไม่สามารถโหลดความคิดเห็นได้"); } finally { if (sequence === generation.current) setBusy(false); } }, [endpoint]); const more = useCallback(async () => { if (!page.nextCursor || busy) return; const sequence = ++generation.current; setBusy(true); try { const next = await commentRequest(`${endpoint}&cursor=${encodeURIComponent(page.nextCursor)}`); if (sequence === generation.current) { const result = { ...next, items: [...page.items, ...next.items.filter((item) => !page.items.some((old) => old.id === item.id))] }; lastPayload.current = JSON.stringify(result); setPage(result); loadedPages.current += 1; setError(""); } } catch (cause) { if (sequence === generation.current) setError(cause instanceof Error ? cause.message : "ไม่สามารถโหลดความคิดเห็นได้"); } finally { if (sequence === generation.current) setBusy(false); } }, [endpoint, page, busy]); useEffect(() => { if (mountedEndpoint.current !== endpoint) { loadedPages.current = 1; mountedEndpoint.current = endpoint; void refresh({ silent: false }); } return () => { active.current?.abort(); }; }, [endpoint, refresh]); const visiblePage = dataEndpoint === endpoint ? page : { items: [], nextCursor: null, viewer: page.viewer }; return { page: visiblePage, busy, error, revision, refresh, more }; }