From b7200540be164a4c65ea066dc03893bbd51a9fd0 Mon Sep 17 00:00:00 2001 From: manNomi Date: Fri, 19 Jun 2026 16:43:07 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=A9=98=ED=86=A0=20=EC=B1=84=ED=8C=85?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChatContent/_hooks/useChatListHandler.ts | 37 +++++++++++++++---- .../ChatContent/_ui/ChatMessageBox/index.tsx | 4 +- .../chat/[chatId]/_ui/ChatContent/index.tsx | 1 + 3 files changed, 34 insertions(+), 8 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 7d9e1684..c6b97a6a 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 @@ -10,6 +10,7 @@ import useInfinityScroll from "@/utils/useInfinityScroll"; const BOTTOM_PROXIMITY_THRESHOLD = 80; const OUTBOUND_TEXT_SCROLL_CONFIRM_TIMEOUT_MS = 5000; +const INITIAL_SCROLL_SETTLE_DELAYS_MS = [100, 350, 800]; interface PendingOutboundTextScroll { id: string; @@ -210,20 +211,42 @@ const useChatListHandler = (chatId: number) => { shouldForceScrollToBottomRef.current = false; }, [chatId, clearPendingOutboundTextScrolls]); - // 초기 히스토리 로딩 완료 후, 최초 1회만 하단으로 이동합니다. + // 초기 메시지가 렌더링되면 최초 1회만 하단으로 이동합니다. useEffect(() => { - if (isLoading || isFetchingNextPage || submittedMessages.length === 0 || hasInitialAutoScrolledRef.current) { + if (isLoading || submittedMessages.length === 0 || hasInitialAutoScrolledRef.current) { return; } - const rafId = requestAnimationFrame(() => { + const rafIds: number[] = []; + const timeoutIds: ReturnType[] = []; + + const scheduleScrollToBottom = () => { + const rafId = requestAnimationFrame(() => { + scrollToBottom(); + }); + rafIds.push(rafId); + }; + + scheduleScrollToBottom(); + const doubleRafId = requestAnimationFrame(() => { scrollToBottom(); - hasInitialAutoScrolledRef.current = true; - prevMessageCountRef.current = submittedMessages.length; + scheduleScrollToBottom(); }); + rafIds.push(doubleRafId); - return () => cancelAnimationFrame(rafId); - }, [isLoading, isFetchingNextPage, scrollToBottom, submittedMessages.length]); + INITIAL_SCROLL_SETTLE_DELAYS_MS.forEach((delayMs) => { + const timeoutId = setTimeout(scrollToBottom, delayMs); + timeoutIds.push(timeoutId); + }); + + hasInitialAutoScrolledRef.current = true; + prevMessageCountRef.current = submittedMessages.length; + + return () => { + rafIds.forEach((rafId) => cancelAnimationFrame(rafId)); + timeoutIds.forEach((timeoutId) => clearTimeout(timeoutId)); + }; + }, [isLoading, scrollToBottom, submittedMessages.length]); // 신규 메시지 도착 시 하단 근처라면 유지하고, 내가 보낸 메시지는 현재 위치와 무관하게 하단으로 이동합니다. useEffect(() => { diff --git a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/index.tsx b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/index.tsx index e749e580..d90961fc 100644 --- a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/index.tsx +++ b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/_ui/ChatMessageBox/index.tsx @@ -17,6 +17,7 @@ interface ChatMessageBoxProps { message: ChatMessage; currentUserId?: number; // 현재 사용자 ID partnerNickname?: string; // 상대방 닉네임 + partnerProfileUrl?: string | null; isPartnerMentor?: boolean; } @@ -135,6 +136,7 @@ const ChatMessageBox = ({ message, currentUserId = 1, partnerNickname = "상대방", + partnerProfileUrl = null, isPartnerMentor = false, }: ChatMessageBoxProps) => { const isMine = message.senderId === Number(currentUserId); @@ -198,7 +200,7 @@ const ChatMessageBox = ({ ) : (
- +
{partnerNickname}
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 50353ca0..9293a700 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 @@ -165,6 +165,7 @@ const ChatContent = ({ chatId }: ChatContentProps) => { message={message} currentUserId={userId} partnerNickname={nickname} + partnerProfileUrl={profileUrl} isPartnerMentor={isPartnerMentor} />