From 6fabd16d84fd3a64e392dc1678e534c2c55b16c7 Mon Sep 17 00:00:00 2001 From: manNomi Date: Sat, 14 Feb 2026 21:38:17 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=B1=84=ED=8C=85=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=A0=84=EC=86=A1=20=EC=97=94=EB=93=9C=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChatContent/_hooks/useChatListHandler.ts | 20 +++++++++++++++++ .../chat/[chatId]/_ui/ChatContent/index.tsx | 22 +++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_hooks/useChatListHandler.ts b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_hooks/useChatListHandler.ts index 4e0988ec..f2d0389e 100644 --- a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_hooks/useChatListHandler.ts +++ b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_hooks/useChatListHandler.ts @@ -87,6 +87,25 @@ const useChatListHandler = (chatId: number) => { [chatId, connectionStatus], ); // chatId와 connectionStatus가 변경될 경우에만 함수를 재생성 + const sendImageMessage = useCallback( + (imageUrls: string[]) => { + if (imageUrls.length === 0) return false; + + if (clientRef.current?.active && connectionStatus === ConnectionStatus.Connected) { + clientRef.current.publish({ + destination: `/publish/chat/${chatId}/image`, + body: JSON.stringify({ imageUrls }), + }); + + return true; + } + + console.error("WebSocket is not connected. Image message could not be sent."); + return false; + }, + [chatId, connectionStatus], + ); + // Track created object URLs for cleanup const objectUrlsRef = useRef([]); @@ -172,6 +191,7 @@ const useChatListHandler = (chatId: number) => { // Handlers sendTextMessage, + sendImageMessage, addImageMessagePreview, addFileMessagePreview, }; diff --git a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx index d13a57df..8fb606ad 100644 --- a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx +++ b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx @@ -3,9 +3,11 @@ import clsx from "clsx"; import Link from "next/link"; import { useGetPartnerInfo } from "@/apis/chat"; +import { useUploadProfileImage } from "@/apis/image-upload"; import ProfileWithBadge from "@/components/ui/ProfileWithBadge"; import useAuthStore from "@/lib/zustand/useAuthStore"; +import { toast } from "@/lib/zustand/useToastStore"; import { ConnectionStatus } from "@/types/chat"; import { UserRole } from "@/types/mentor"; import { tokenParse } from "@/utils/jwtUtils"; @@ -43,9 +45,12 @@ const ChatContent = ({ chatId }: ChatContentProps) => { // Handlers sendTextMessage, + sendImageMessage, addImageMessagePreview, } = useChatListHandler(chatId); + const uploadProfileImageMutation = useUploadProfileImage(); + const { data: partnerInfo } = useGetPartnerInfo(chatId); const { partnerId, nickname, profileUrl, university } = partnerInfo ?? {}; @@ -170,8 +175,21 @@ const ChatContent = ({ chatId }: ChatContentProps) => { onSendMessage={(data) => { sendTextMessage(data.message, userId); }} - onSendImages={(data) => { - addImageMessagePreview(data.images, userId); + onSendImages={async (data) => { + try { + const uploadedImages = await Promise.all( + data.images.map((image) => uploadProfileImageMutation.mutateAsync(image)), + ); + + const imageUrls = uploadedImages.map((image) => image.fileUrl); + const isSent = sendImageMessage(imageUrls); + + if (!isSent) { + toast.error("채팅 연결이 원활하지 않아 이미지를 전송하지 못했어요."); + } + } catch { + toast.error("이미지 전송에 실패했어요. 다시 시도해주세요."); + } }} onSendFiles={(data) => { addImageMessagePreview(data.files, userId);