feat : comment feature
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
"use client";
|
||||
|
||||
import { createContext, useCallback, useContext, useEffect, useRef, useState, type ReactNode } from "react";
|
||||
import Link from "next/link";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { commentRequest } from "./client";
|
||||
import { useCommentEvents } from "./use-comment-events";
|
||||
|
||||
type Counts = { counts: Record<string, number>; total: number };
|
||||
const UnreadContext = createContext<Counts & { markRead: (target: string) => Promise<void> }>({ counts: {}, total: 0, markRead: async () => {} });
|
||||
export function AdminUnreadCommentsProvider({ children }: { children: ReactNode }) {
|
||||
const [counts, setCounts] = useState<Counts>({ counts: {}, total: 0 });
|
||||
const generation = useRef(0);
|
||||
const refresh = useCallback(async () => {
|
||||
try { const sequence = ++generation.current; const result = await commentRequest<Counts>("/api/admin/comments/unread"); if (sequence === generation.current) setCounts(result); } catch { /* Protected routes handle expired admin sessions. */ }
|
||||
}, []);
|
||||
const markRead = useCallback(async (target: string) => {
|
||||
try {
|
||||
await commentRequest("/api/admin/comments/unread", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ target }) });
|
||||
await refresh();
|
||||
} catch { /* Reading stays available when the counter cannot be saved. */ }
|
||||
}, [refresh]);
|
||||
useEffect(() => { void Promise.resolve().then(refresh); }, [refresh]);
|
||||
useCommentEvents({ admin: true }, refresh);
|
||||
return <UnreadContext value={{ ...counts, markRead }}>{children}</UnreadContext>;
|
||||
}
|
||||
export function useMarkCommentsRead() { return useContext(UnreadContext).markRead; }
|
||||
export function AdminUnreadCount({ target }: { target?: string }) {
|
||||
const state = useContext(UnreadContext);
|
||||
const count = target ? state.counts[target] ?? 0 : state.total;
|
||||
return count > 0 ? <Badge variant="destructive" className="min-w-5 justify-center rounded-full px-1.5" aria-label={`ความคิดเห็นใหม่ ${count} รายการ`}>{count > 99 ? "99+" : count}</Badge> : null;
|
||||
}
|
||||
export function AdminUnreadBadge({ target }: { target: string }) {
|
||||
const state = useContext(UnreadContext);
|
||||
if (!(state.counts[target] > 0)) return null;
|
||||
return <Link href={`/admin/comments?target=${encodeURIComponent(target)}`} prefetch={false} className="relative z-20 self-end" aria-label="ดูความคิดเห็นใหม่"><AdminUnreadCount target={target} /></Link>;
|
||||
}
|
||||
Reference in New Issue
Block a user