| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- '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<ChatMessage[]>([]);
- const [systemMessages, setSystemMessages] = useState<SystemMessage[]>([]);
- const [participantCount, setParticipantCount] = useState(0);
- const [participants, setParticipants] = useState<ChatParticipant[]>([]);
- const prevConnectionRef = useRef<typeof chatConnection>(null);
- const prevChannelRef = useRef<string|null>(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
- };
- }
|