From 3ae29ba8244ecbce486bb679e2d14c7744bb34f2 Mon Sep 17 00:00:00 2001 From: wooktori Date: Wed, 31 Dec 2025 23:00:28 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9D=BD=EC=9D=8C=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=20API=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/service/chat-service/index.ts | 7 ++++++ src/app/chat/[roomId]/ChatRoomPage.tsx | 23 +++++++++++++------ src/components/pages/chat/chat-list/index.tsx | 12 +++++++++- src/hooks/use-chat/use-chat-messages/index.ts | 1 + src/hooks/use-chat/use-chat-read/index.ts | 19 +++++++++++++++ src/hooks/use-chat/use-chat-socket/index.ts | 2 +- src/types/service/chat.ts | 10 ++++++++ 7 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 src/hooks/use-chat/use-chat-read/index.ts diff --git a/src/api/service/chat-service/index.ts b/src/api/service/chat-service/index.ts index 3bdeea6d..a6e01732 100644 --- a/src/api/service/chat-service/index.ts +++ b/src/api/service/chat-service/index.ts @@ -5,6 +5,8 @@ import { GetChatMessagesParams, GetChatMessagesResponse, GetChatRoomsResponse, + ReadMessagesParams, + ReadMessagesResponse, } from '@/types/service/chat'; export const chatServiceRemote = () => ({ @@ -27,4 +29,9 @@ export const chatServiceRemote = () => ({ }, }); }, + + // 메세지 읽음 처리 + readMessages: async ({ roomId }: ReadMessagesParams) => { + return apiV1.put(`/chat/rooms/${roomId}/read`); + }, }); diff --git a/src/app/chat/[roomId]/ChatRoomPage.tsx b/src/app/chat/[roomId]/ChatRoomPage.tsx index b204bce6..193e3ba1 100644 --- a/src/app/chat/[roomId]/ChatRoomPage.tsx +++ b/src/app/chat/[roomId]/ChatRoomPage.tsx @@ -6,6 +6,7 @@ import { DEFAULT_PROFILE_IMAGE } from 'constants/default-images'; import { ChatHeader, ChatInput, MyChat, OtherChat } from '@/components/pages/chat'; import { UserList } from '@/components/pages/chat/chat-user-list'; import { useGetChatMessages } from '@/hooks/use-chat'; +import { useReadMessages } from '@/hooks/use-chat/use-chat-read'; import { useChatSocket } from '@/hooks/use-chat/use-chat-socket'; import { ChatMessage } from '@/types/service/chat'; @@ -82,14 +83,9 @@ interface IProps { const ChatRoomPage = ({ accessToken, roomId, userId }: IProps) => { const [isUserListOpen, setIsUserListOpen] = useState(false); const [chatMessages, setChatMessages] = useState([]); - const { data: previousMessages } = useGetChatMessages(roomId); - - useEffect(() => { - if (!previousMessages) return; - // eslint-disable-next-line react-hooks/set-state-in-effect - setChatMessages([...previousMessages.messages].reverse()); - }, [previousMessages]); + const { data: previousMessages } = useGetChatMessages(roomId); + const { mutate: readMessages } = useReadMessages(roomId, userId); const { messages: newMessages, sendMessage, @@ -103,6 +99,19 @@ const ChatRoomPage = ({ accessToken, roomId, userId }: IProps) => { setChatMessages((prev) => [...prev, message]); }, }); + + useEffect(() => { + if (!isConnected) return; + + readMessages(); + }, [isConnected, readMessages, newMessages]); + + useEffect(() => { + if (!previousMessages) return; + // eslint-disable-next-line react-hooks/set-state-in-effect + setChatMessages([...previousMessages.messages].reverse()); + }, [previousMessages]); + console.log(newMessages); const handleSubmit = (text: string) => { diff --git a/src/components/pages/chat/chat-list/index.tsx b/src/components/pages/chat/chat-list/index.tsx index 47807382..e91df52e 100644 --- a/src/components/pages/chat/chat-list/index.tsx +++ b/src/components/pages/chat/chat-list/index.tsx @@ -2,6 +2,9 @@ import Image from 'next/image'; import { useRouter } from 'next/navigation'; +import { useEffect } from 'react'; + +import { useQueryClient } from '@tanstack/react-query'; import { DEFAULT_PROFILE_IMAGE } from 'constants/default-images'; import { useGetChatList } from '@/hooks/use-chat/use-chat-list'; @@ -13,13 +16,20 @@ interface IProps { export const ChatList = ({ userId }: IProps) => { const router = useRouter(); - + const queryClient = useQueryClient(); const handleClick = (chatId: number) => { router.push(`/chat/${chatId}`); }; const { data: chatList } = useGetChatList({ userId }); + console.log(chatList); + // 현재 방식은 tanstack query를 이용해서 단지 목록 조회 + // but, 소켓 통신을 하고 있는 상황이므로 목록 역시 소켓을 열어서 페이지에 머물러 있을 때도 실시간으로 확인 가능하도록 + useEffect(() => { + queryClient.invalidateQueries({ queryKey: ['chatList', userId] }); + }, [chatList, userId]); + return (
    {chatList?.chatRooms?.map((chat) => ( diff --git a/src/hooks/use-chat/use-chat-messages/index.ts b/src/hooks/use-chat/use-chat-messages/index.ts index 8cc7a9c8..890f7a43 100644 --- a/src/hooks/use-chat/use-chat-messages/index.ts +++ b/src/hooks/use-chat/use-chat-messages/index.ts @@ -6,6 +6,7 @@ export const useGetChatMessages = (roomId: number, cursor?: number, size?: numbe const query = useQuery({ queryKey: ['chatMessages', roomId], queryFn: () => API.chatService.getChatMessages({ roomId, cursor, size }), + staleTime: 0, }); return query; }; diff --git a/src/hooks/use-chat/use-chat-read/index.ts b/src/hooks/use-chat/use-chat-read/index.ts new file mode 100644 index 00000000..cc883ff4 --- /dev/null +++ b/src/hooks/use-chat/use-chat-read/index.ts @@ -0,0 +1,19 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { API } from '@/api'; + +export const useReadMessages = (roomId: number, userId: number) => { + const queryClient = useQueryClient(); + + const query = useMutation({ + mutationKey: ['chatMessages', roomId], + mutationFn: () => API.chatService.readMessages({ roomId }), + onSuccess: () => { + console.log('메세지를 읽었어요!'); + queryClient.invalidateQueries({ + queryKey: ['chatList', userId], + }); + }, + }); + return query; +}; diff --git a/src/hooks/use-chat/use-chat-socket/index.ts b/src/hooks/use-chat/use-chat-socket/index.ts index 7d07d0ee..9314be0d 100644 --- a/src/hooks/use-chat/use-chat-socket/index.ts +++ b/src/hooks/use-chat/use-chat-socket/index.ts @@ -49,7 +49,7 @@ export const useChatSocket = ({ Authorization: `Bearer ${accessToken}`, }, debug: (str) => console.log(str), - reconnectDelay: 60000, + reconnectDelay: 6000, heartbeatIncoming: 4000, heartbeatOutgoing: 4000, }); diff --git a/src/types/service/chat.ts b/src/types/service/chat.ts index 24b9453e..756b06b3 100644 --- a/src/types/service/chat.ts +++ b/src/types/service/chat.ts @@ -52,3 +52,13 @@ export interface GetChatMessagesResponse { nextCursor: number | null; hasNext: boolean; } + +export interface ReadMessagesParams { + roomId: number; +} + +export interface ReadMessagesResponse { + chatRoomId: number; + lastReadMessageId: number; + unreadCount: number; +}