1"use client";
2
3
21import { useEffect, useRef } from "react";
22import { toast, useUiStore } from "@/stores/ui-store";
23import { useBlockPatchStore } from "@/stores/block-patch-store";
24import type { Presence } from "@/lib/types";
25
26const EMPTY_PRESENCE: Record<string, Presence> = {};
27
28export function usePresenceToasts(pageId: string | null, selfUserId?: string | null): void {
29 const enabled = useUiStore((s) => s.presenceToastsEnabled);
30 const prevRef = useRef<Map<string, string> | null>(null);
31
32 useEffect(() => {
33 if (pageId === null || !enabled) {
34 prevRef.current = null;
35 return;
36 }
37 const feed = (state: { presence: Record<string, Record<string, Presence>> }): void => {
38 const roster = Object.values(state.presence[pageId] ?? EMPTY_PRESENCE);
39 const now = new Map<string, string>();
40 for (const p of roster) if (p.userId !== selfUserId) now.set(p.userId, p.name);
41 const prev = prevRef.current;
42 if (prev !== null) {
43 for (const [userId, name] of now) {
44 if (!prev.has(userId)) toast("info", `${name} joined`);
45 }
46 for (const [userId, name] of prev) {
47 if (!now.has(userId)) toast("info", `${name} left`);
48 }
49 }
50 prevRef.current = now;
51 };
52 feed(useBlockPatchStore.getState());
53 const off = useBlockPatchStore.subscribe(feed);
54 return () => {
55 off();
56 prevRef.current = null;
57 };
58 }, [pageId, enabled, selfUserId]);
59}
60