1"use client";
2
3
18import { useEffect, useRef, useState } from "react";
19import { PresenceAnnouncer } from "@/lib/presence-announcer";
20import { useBlockPatchStore } from "@/stores/block-patch-store";
21import type { Presence } from "@/lib/types";
22
23const EMPTY_PRESENCE: Record<string, Presence> = {};
24const FLUSH_INTERVAL_MS = 1000;
25
26export function usePresenceAnnouncer(pageId: string | null, selfUserId?: string | null): string {
27 const [text, setText] = useState("");
28 const announcerRef = useRef<PresenceAnnouncer | null>(null);
29
30 useEffect(() => {
31 if (pageId === null) return;
32 const announcer = new PresenceAnnouncer();
33 announcerRef.current = announcer;
34
35 const emit = (a: { text: string } | null): void => {
36 if (a !== null) setText(a.text);
37 };
38
39 const feed = (state: { presence: Record<string, Record<string, Presence>> }): void => {
40 const roster = Object.values(state.presence[pageId] ?? EMPTY_PRESENCE);
41 emit(announcer.update(selfUserId ? roster.filter((p) => p.userId !== selfUserId) : roster));
42 };
43 feed(useBlockPatchStore.getState());
44 const off = useBlockPatchStore.subscribe(feed);
45
46
47
48 const id = window.setInterval(() => emit(announcer.flush()), FLUSH_INTERVAL_MS);
49 return () => {
50 off();
51 window.clearInterval(id);
52 announcerRef.current = null;
53 announcer.reset();
54 setText("");
55 };
56 }, [pageId, selfUserId]);
57
58 return text;
59}
60