diff --git a/src/components/chat/Chat.tsx b/src/components/chat/Chat.tsx index 3746eff..0ac4cd9 100644 --- a/src/components/chat/Chat.tsx +++ b/src/components/chat/Chat.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import ChatButton from '@/components/chat/ChatButton'; import ChatDetail from '@/components/chat/ChatDetail'; @@ -41,10 +41,11 @@ const Chat = ({ isUser, shopImageUrl, }: ChatProps) => { + // TODO: 커스텀 훅으로 빼기. const seller: SellerInfo = { sellerId: sellerId, shopName: sellerName }; const product: ProductInfo = { productId: productId, productName: productName }; const [user, setUser] = useState({ userId: userId, userName: userName }); - const [isCustomRoomId, setIsCustomRoomId] = useState(true); + const [isNowChatRoom, setIsNowChatRoom] = useState(false); const isSeller = isUser; const role = isSeller ? 'seller' : 'user'; @@ -65,45 +66,43 @@ const Chat = ({ return customRoomId; } - /** clickPrevButton() : 채팅방에서 뒤로가기 버튼 누르면 - * 1. 분기처리를 위해 customRoomId값을 빈 스트링을 넣는다. */ + /** clickPrevButton() : 채팅방에서 뒤로가기 버튼 */ const clickPrevButton = () => { - setCustomRoomId(''); + setIsNowChatRoom((prev) => !prev); }; /** clickListBox() : 채팅list에서 해당 채팅방으로 들어가기 위해 - * 1. isCustomRoomId를 false, + * 1. isNowChatRoom로 분기처리, * 2. ChatBody.tsx에서 custumroomId를 받아와서 ChatList.tsx로 넘겨줌. * 3. seller일때 현재 디테일에서 넘어오는 userId, userName값은 판매자의 정보여서 ChatList.tsx에서 문의한 구매자의 userId값, userName값을 가져옴. */ const clickListBox = (customRoomId: string, userId: number, userName: string) => { - setIsCustomRoomId((prev) => !prev); + setIsNowChatRoom((prev) => !prev); setCustomRoomId(customRoomId); setUser({ ...user, userId, userName }); }; const handleOpen = () => { setIsModalOpen((prev) => !prev); + setIsNowChatRoom(false); }; - useEffect(() => { - if (customRoomId.length === 0) { - setIsCustomRoomId((prev) => !prev); - } - }, [customRoomId]); + console.log('isNowChatRoom', isNowChatRoom); return ( <> {isModalOpen && isSeller && ( - {isCustomRoomId ? ( + {!isNowChatRoom ? ( ) : ( @@ -122,12 +121,14 @@ const Chat = ({ )} {isModalOpen && !isSeller && ( - {!isCustomRoomId ? ( + {isNowChatRoom ? ( ) : ( diff --git a/src/components/chat/ChatList.tsx b/src/components/chat/ChatList.tsx index c3b857c..dc097da 100644 --- a/src/components/chat/ChatList.tsx +++ b/src/components/chat/ChatList.tsx @@ -3,7 +3,8 @@ import { useEffect, useState } from 'react'; import { sellerChatList, userChatList } from '@/apis/chat'; import ChatBody from '@/components/chat/chatList/ChatBody'; import ChatHeader from '@/components/chat/chatList/ChatHeader'; -import { Message } from '@/models/chat'; +import { useSSE } from '@/hooks/useSSE'; +import { Message, UserInfo } from '@/models/chat'; export type Chat = { [timestamp: string]: Message; @@ -23,30 +24,42 @@ export type List = { lastChat: Message; }; -type chatProps = { +type ChatProps = { clickListBox: (customRoomId: string, userId: number, userName: string) => void; handleOpen: () => void; seller: { sellerId: number; shopName: string; }; + user: UserInfo; product: { productId: number; productName: string; }; isSeller: boolean; + role: string; }; -const ChatList = ({ handleOpen, clickListBox, seller, isSeller, product }: chatProps) => { +const ChatList = ({ + handleOpen, + clickListBox, + seller, + user, + isSeller, + product, + role, +}: ChatProps) => { const [list, setList] = useState([]); - const [shopImg, setShopImg] = useState(''); + const message = useSSE(role, seller.sellerId, user.userId); + + //TODO: 리액트쿼리로 변경하기 const loadUserChatList: () => Promise = async () => { - const sellerId = seller.sellerId; - userChatList(sellerId) + userChatList(seller.sellerId) .then((resData) => { const data = resData.chatList; + console.log('list', data); const img = resData.shopImage; setList([...data]); setShopImg(img); @@ -62,6 +75,7 @@ const ChatList = ({ handleOpen, clickListBox, seller, isSeller, product }: chatP sellerChatList(sellerId, productId) .then((resData) => { const data = resData.chatList; + console.log('list', data); const img = resData.shopImage; setList([...data]); setShopImg(img); @@ -77,10 +91,10 @@ const ChatList = ({ handleOpen, clickListBox, seller, isSeller, product }: chatP }, [isSeller]); return ( -
+ <> - -
+ + ); }; diff --git a/src/components/chat/chatList/ChatBody.tsx b/src/components/chat/chatList/ChatBody.tsx index afe0aea..e75beed 100644 --- a/src/components/chat/chatList/ChatBody.tsx +++ b/src/components/chat/chatList/ChatBody.tsx @@ -1,13 +1,15 @@ import { List } from '@/components/chat/ChatList'; import ChatBox from '@/components/chat/chatList/ChatBox'; +import { ChatAlarm } from '@/hooks/useSSE'; import * as S from '../Chat.styles'; type ChatBodyProps = { chatList: List[]; clickListBox: (customRoomId: string, userId: number, userName: string) => void; + newMessage?: ChatAlarm; }; -const ChatBody = ({ chatList, clickListBox }: ChatBodyProps) => { +const ChatBody = ({ chatList, clickListBox, newMessage }: ChatBodyProps) => { return ( {chatList?.map((item, idx) => { @@ -17,7 +19,11 @@ const ChatBody = ({ chatList, clickListBox }: ChatBodyProps) => { key={idx} > { + const [message, setMessage] = useState(); + + const isUser = + role === 'user' + ? `${import.meta.env.VITE_API_SSE_URL}/chat-alarm/${role}/${sellerId}/${userId}` + : `${import.meta.env.VITE_API_SSE_URL}/chat-alarm/${role}/${sellerId}`; + + const [eventSource] = useState(() => new EventSource(isUser)); + + useEffect(() => { + console.log('되나', eventSource); + eventSource.addEventListener('sse', function (event) { + const message = JSON.parse(event.data); + console.log('새로운 채팅 알람: ', message); + setMessage({ ...message }); + }); + + eventSource.onerror = function (error) { + console.error('EventSource failed:', error); + eventSource.close(); + }; + + window.addEventListener('unload', function () { + if (eventSource) { + eventSource.close(); + console.log('EventSource closed'); + } + }); + }, []); + + return message; +};