'use client'; import { useState, useEffect, useCallback, useRef } from 'react'; import { useSignalRContext } from '@/contexts/signalrProvider'; import type { ChatMessage } from '@/types/chat'; type SystemMessage = { id: number; content: string; receivedAt: string; }; type ChatParticipant = { memberName: string; isGuest: boolean; }; let systemMsgId = 0; export default function useChat(channelSID?: string) { const { chatConnection, chatConnected } = useSignalRContext(); const [messages, setMessages] = useState([]); const [systemMessages, setSystemMessages] = useState([]); const [participantCount, setParticipantCount] = useState(0); const [participants, setParticipants] = useState([]); const prevConnectionRef = useRef(null); const prevChannelRef = useRef(null); useEffect(() => { if (!chatConnection || !chatConnected) { return; } // 동일 connection + 동일 channel 이면 중복 등록 방지 if (prevConnectionRef.current === chatConnection && prevChannelRef.current === channelSID) { return; } prevConnectionRef.current = chatConnection; prevChannelRef.current = channelSID ?? null; chatConnection.on('ReceiveHistory', (history: ChatMessage[]) => { setMessages(history); }); chatConnection.on('ReceiveMessage', (message: ChatMessage) => { setMessages((prev) => [...prev, message]); }); chatConnection.on('ReceiveSystemMessage', (content: string) => { setSystemMessages((prev) => [ ...prev, { id: ++systemMsgId, content, receivedAt: new Date().toISOString() } ]); }); chatConnection.on('ReceiveParticipantCount', (count: number) => { setParticipantCount(count); }); chatConnection.on('ReceiveParticipants', (list: ChatParticipant[]) => { setParticipants(list); }); // 채널 참가 (channelSID 필수) if (channelSID) { chatConnection.invoke('JoinChannel', channelSID).catch((err) => { console.error('채팅 채널 참가 실패:', err); }); } return () => { chatConnection.off('ReceiveHistory'); chatConnection.off('ReceiveMessage'); chatConnection.off('ReceiveSystemMessage'); chatConnection.off('ReceiveParticipantCount'); chatConnection.off('ReceiveParticipants'); // 채널 퇴장 if (channelSID && chatConnection.state === 'Connected') { chatConnection.invoke('LeaveChannel').catch(() => {}); } prevConnectionRef.current = null; prevChannelRef.current = null; }; }, [chatConnection, chatConnected, channelSID]); const sendMessage = useCallback(async (content: string) => { if (!chatConnection || !chatConnected) { return; } const trimmed = content.trim(); if (!trimmed || trimmed.length > 500) { return; } try { await chatConnection.invoke('SendMessage', trimmed); } catch (error) { console.error('메시지 전송 실패:', error); } }, [chatConnection, chatConnected]); const clearMessages = useCallback(() => { setMessages([]); setSystemMessages([]); }, []); const refreshChat = useCallback(async () => { if (!chatConnection || !chatConnected) { return; } setMessages([]); setSystemMessages([]); try { await chatConnection.invoke('RequestHistory'); await chatConnection.invoke('RequestParticipantCount'); } catch { // ignore } }, [chatConnection, chatConnected]); const requestParticipants = useCallback(async () => { if (!chatConnection || !chatConnected) { return; } try { await chatConnection.invoke('RequestParticipants'); } catch { // ignore } }, [chatConnection, chatConnected]); return { messages, systemMessages, participantCount, participants, sendMessage, clearMessages, refreshChat, requestParticipants, chatConnected }; }