import { useEffect, useState, useCallback, useRef } from "react"; import { usePusherClient } from "@/lib/pusher-provider"; import type { ChannelMessage } from "@/lib/pusher-client"; interface UseChannelResult { /** Current set of humanIds present in the channel */ presence: string[]; /** Messages received on this channel (since the hook mounted) */ messages: ChannelMessage[]; /** Send a message to the channel */ sendMessage: (payload: unknown) => void; } /** * Subscribe to a pusher channel. Manages presence tracking and message delivery. * Subscribes on mount, unsubscribes on unmount. * * @param channelId - The channel to subscribe to, or null to skip. */ export function useChannel(channelId: string | null): UseChannelResult { const client = usePusherClient(); const [presence, setPresence] = useState([]); const [messages, setMessages] = useState([]); useEffect(() => { if (!client || !channelId) { setPresence([]); setMessages([]); return; } client.subscribe(channelId); const onSubscribed = (msg: { presence?: string[] }) => { setPresence(msg.presence ?? []); }; const onJoin = (msg: { humanId?: string }) => { if (msg.humanId) { setPresence((prev) => prev.includes(msg.humanId!) ? prev : [...prev, msg.humanId!], ); } }; const onLeave = (msg: { humanId?: string }) => { if (msg.humanId) { setPresence((prev) => prev.filter((id) => id !== msg.humanId)); } }; const onMessage = (msg: { humanId?: string; payload?: unknown }) => { if (msg.humanId) { setMessages((prev) => [ ...prev, { humanId: msg.humanId!, payload: msg.payload }, ]); } }; client.on(channelId, "subscribed", onSubscribed); client.on(channelId, "join", onJoin); client.on(channelId, "leave", onLeave); client.on(channelId, "message", onMessage); return () => { client.off(channelId, "subscribed", onSubscribed); client.off(channelId, "join", onJoin); client.off(channelId, "leave", onLeave); client.off(channelId, "message", onMessage); client.unsubscribe(channelId); }; }, [client, channelId]); const sendMessage = useCallback( (payload: unknown) => { if (client && channelId) { client?.sendMessage(channelId, payload); } }, [client, channelId], ); return { presence, messages, sendMessage }; }