-
Notifications
You must be signed in to change notification settings - Fork 1
[feat] 채팅 전송시 스크롤 자동이동 , 채팅 보낸 유저 이름 추가 #130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughNextConfig의 최상위 Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User as 사용자
participant ChatRoom as ChatRoom 컴포넌트
participant EffectInit as useEffect(roomId, initMessages)
participant EffectRT as useEffect(realTimeMessages)
participant DOM as 하단 앵커 div(endRef)
User->>ChatRoom: 채팅 화면 진입 또는 방 전환
ChatRoom->>EffectInit: roomId/initMessages 변경 감지
EffectInit->>DOM: endRef.scrollIntoView({ behavior: "instant" })
Note over DOM,ChatRoom: 초기 진입/방 전환 시 즉시 스크롤
User->>ChatRoom: 실시간 메시지 수신
ChatRoom->>EffectRT: realTimeMessages 변경 감지
EffectRT->>DOM: endRef.scrollIntoView({ behavior: "smooth" })
Note over DOM,ChatRoom: 새 메시지 도착 시 부드럽게 스크롤
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
next.config.ts(1 hunks)src/app/globals.css(1 hunks)src/features/chat/ui/chatMessage/ChatMessage.tsx(1 hunks)src/features/chat/ui/chatRoom/index.tsx(4 hunks)
🔇 Additional comments (2)
src/app/globals.css (1)
16-16: 새 토큰--color-gray500추가 OK — Tailwind 빌드에서text-gray500생성 여부 확인 필요
- 사용처: src/features/chat/ui/chatMessage/ChatMessage.tsx:19 —
text-gray500사용 확인됨.- package.json에서 tailwindcss 버전이 출력되지 않았습니다. tailwind.config.{js,cjs,ts}에서 theme.colors에
gray500: 'var(--color-gray500)'매핑 또는 CSS 변수→색상 매핑 플러그인(또는 Tailwind v4 토큰 체계)이 적용되어 있는지 확인해 주세요.next.config.ts (1)
6-14: 확인 완료 — images.remotePatterns 설정 유효 (Next.js 15.3.3)package.json에서 next가 15.3.3으로 확인되었습니다. images.remotePatterns는 공식 설정이며(v15.3.0에서 new URL() 배열 지원 추가) 현재 구성(단일 호스트 + '/**')은 과도하지 않아 안전합니다. (en.nextjs.im)
승인합니다.
| import ChatMessage from '../chatMessage/ChatMessage'; | ||
| import ChatRoomHeader from './ChatRoomHeader'; | ||
| import { useMyInfoQuery } from '@/entities/mypage/model/query'; | ||
| import { useEffect, useRef } from 'react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick
자동 스크롤 기본 동작은 충족. 다만 사용자가 위로 스크롤 중일 때 강제 하단 점프를 막아주세요.
현재는 새 메시지/초기 메시지 로딩마다 무조건 하단으로 스크롤됩니다. 사용자가 과거 메시지를 읽는 중에도 끌어내리는 UX 문제가 있습니다. 스크롤이 바닥에 근접한 경우에만 자동 스크롤하도록 가드하세요.
다음과 같이 변경을 제안합니다.
@@
- const endRef = useRef<HTMLDivElement>(null);
+ const endRef = useRef<HTMLDivElement>(null);
+ const scrollContainerRef = useRef<HTMLDivElement>(null);
+ const isAtBottomRef = useRef(true);
@@
- useEffect(() => {
- if (endRef.current) {
- endRef.current.scrollIntoView({ behavior: 'smooth' });
- }
- }, [realTimeMessages, initMessages]);
+ useEffect(() => {
+ if (!endRef.current) return;
+ if (isAtBottomRef.current) {
+ endRef.current.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'nearest' });
+ }
+ }, [realTimeMessages, initMessages]);추가로 적용해야 하는 변경(선택적 별도 패치):
// 컴포넌트 상단에 핸들러 추가
const handleScroll = () => {
const el = scrollContainerRef.current;
if (!el) return;
const threshold = 80; // px
const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight <= threshold;
isAtBottomRef.current = atBottom;
};- <div className="flex-1 p-4 flex flex-col gap-4 overflow-y-scroll">
+ <div
+ ref={scrollContainerRef}
+ onScroll={handleScroll}
+ className="flex-1 p-4 flex flex-col gap-4 overflow-y-scroll"
+ >Also applies to: 19-19, 28-33, 57-57
🤖 Prompt for AI Agents
In src/features/chat/ui/chatRoom/index.tsx around lines 9, 19, 28-33 and 57, the
component currently forces scroll-to-bottom on every new/initial message which
interrupts users reading older messages; add an isAtBottomRef and a scroll
handler that computes atBottom using a threshold (e.g. 80px) by comparing
el.scrollHeight - el.scrollTop - el.clientHeight, update isAtBottomRef in the
onScroll handler attached to the scroll container, and guard all auto-scroll
calls (initial load and on new messages) to only perform scroll-to-bottom when
isAtBottomRef.current is true; ensure the handler is created near the top of the
component, uses the existing scrollContainerRef, and that refs are kept stable
(useRef) so auto-scroll logic references the latest isAtBottom state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/features/chat/ui/chatMessage/ChatMessage.tsx(1 hunks)
🔇 Additional comments (2)
src/features/chat/ui/chatMessage/ChatMessage.tsx (2)
10-12: 발신자 닉네임 렌더링 수정 — LGTM
msg.name사용으로 이전 리뷰의 문제(내 닉네임 표기)가 해결되었습니다. 정렬 처리도isOwn과 일관적입니다.
17-19: 접근성: 작은 텍스트(text-xs) 대비 검증 필요text-gray500(중간 회색)은 text-xs 크기에서 WCAG AA(대비비 4.5:1)를 충족하지 못할 가능성이 큽니다.
파일: src/features/chat/ui/chatMessage/ChatMessage.tsx (라인 17–19)
- 권장: Tailwind 'text-gray-600' 이상 사용하거나 글자 크기/굵기 조정. 또는 사용 중인 색상 토큰(HEX 또는 토큰 매핑)을 제공하면 대비비를 계산해 권장 색상을 제안하겠습니다.
| className={`max-w-[70%] w-fit px-4 py-2 rounded-[14px] ${isOwn ? ' bg-primary' : ' bg-secondary-background'}`} | ||
| > | ||
| <p className="whitespace-pre-wrap break-words">{msg.message}</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick
동적 클래스 문자열의 불필요한 공백 제거
템플릿 내 ' bg-primary', ' bg-secondary-background' 앞 공백은 불필요합니다. 다음처럼 정리하세요.
- className={`max-w-[70%] w-fit px-4 py-2 rounded-[14px] ${isOwn ? ' bg-primary' : ' bg-secondary-background'}`}
+ className={`max-w-[70%] w-fit px-4 py-2 rounded-[14px] ${isOwn ? 'bg-primary' : 'bg-secondary-background'}`}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| className={`max-w-[70%] w-fit px-4 py-2 rounded-[14px] ${isOwn ? ' bg-primary' : ' bg-secondary-background'}`} | |
| > | |
| <p className="whitespace-pre-wrap break-words">{msg.message}</p> | |
| className={`max-w-[70%] w-fit px-4 py-2 rounded-[14px] ${isOwn ? 'bg-primary' : 'bg-secondary-background'}`} | |
| > | |
| <p className="whitespace-pre-wrap break-words">{msg.message}</p> |
🤖 Prompt for AI Agents
In src/features/chat/ui/chatMessage/ChatMessage.tsx around lines 13 to 15, the
conditional class strings include unnecessary leading spaces (' bg-primary' and
' bg-secondary-background'); remove the leading spaces so the template builds
classes without embedded leading spaces (e.g., use isOwn ? 'bg-primary' :
'bg-secondary-background') and ensure a single separating space is present in
the surrounding string/template so final className still has proper spacing
between tokens.
🧩 Analysis chain
색상 토큰 존재 여부 확인 필요: bg-primary / bg-secondary-background
Tailwind 설정(theme.extend.colors) 혹은 전역 CSS에 해당 토큰이 실제로 매핑되어 있는지 확인 바랍니다. 미정의 시 배경색이 적용되지 않습니다.
🏁 Script executed:
#!/bin/bash
# 토큰 정의 위치 탐색
fd -HI "tailwind.config.*" | xargs -I{} rg -n --no-heading -C2 "colors\s*:|primary|secondary-background|gray500" {}
# 전역 CSS에서 커스텀 클래스/변수 확인
rg -n --type=css -S "\.bg-secondary-background|\.bg-primary|--color-gray500" -C2Length of output: 197
색상 토큰 미정의: bg-primary / bg-secondary-background 확인 필요
검증 결과: src/app/globals.css에서 --color-gray700, --color-gray500, --color-active 등 CSS 변수는 존재하나 'bg-primary' / 'bg-secondary-background' 클래스 또는 tailwind.config.*(theme.extend.colors) 정의는 검색되지 않음 (예: src/app/globals.css:16 — --color-gray500: #888).
조치: tailwind.config.js의 theme.extend.colors에 primary / secondary-background 추가하거나 globals.css에 .bg-primary/.bg-secondary-background 유틸(또는 기존 CSS 변수에 대한 매핑)을 추가하거나 컴포넌트에서 --color-* 변수를 사용하도록 변경.
🤖 Prompt for AI Agents
src/features/chat/ui/chatMessage/ChatMessage.tsx lines 13-15: The component uses
non-existent utility classes 'bg-primary' and 'bg-secondary-background', so add
definitions for these tokens; either add primary and secondary-background color
entries under theme.extend.colors in tailwind.config.js, or create CSS utility
classes in src/app/globals.css that map .bg-primary/.bg-secondary-background to
the appropriate --color-* variables (or change the component to use the existing
CSS variables directly), then rebuild Tailwind to ensure the classes are
generated.
| <p className={`text-xs text-gray500 mt-1 ${isOwn ? 'text-right' : 'text-left'}`}> | ||
| {formattedDate} | ||
| </p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
비표준 클래스 text-gray500: Tailwind에서 생성되지 않을 수 있음
Tailwind 기본 클래스는 text-gray-500 형태입니다. 커스텀 색을 CSS 변수로 쓰는 목적이라면, 클래스 생성 없이도 다음처럼 임의 값 표기를 쓰는 편이 안전합니다.
- <p className={`text-xs text-gray500 mt-1 ${isOwn ? 'text-right' : 'text-left'}`}>
+ <p className={`text-xs mt-1 ${isOwn ? 'text-right' : 'text-left'} text-[var(--color-gray500)]`}>대안: Tailwind 설정에 colors: { gray500: 'var(--color-gray500)' }를 추가해 text-gray500을 실제로 생성.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <p className={`text-xs text-gray500 mt-1 ${isOwn ? 'text-right' : 'text-left'}`}> | |
| {formattedDate} | |
| </p> | |
| <p className={`text-xs mt-1 ${isOwn ? 'text-right' : 'text-left'} text-[var(--color-gray500)]`}> | |
| {formattedDate} | |
| </p> |
🤖 Prompt for AI Agents
In src/features/chat/ui/chatMessage/ChatMessage.tsx around lines 17 to 19, the
class name uses a nonstandard Tailwind token "text-gray500" which may not be
generated; replace it with a valid Tailwind utility (e.g., "text-gray-500") or
use an arbitrary value that references the CSS variable (e.g., the
bracket/inline arbitrary color syntax) to ensure the style is applied, or
alternatively add the custom color mapping to tailwind.config.js under
theme.colors (e.g., gray500: 'var(--color-gray500)') so "text-gray500" will be
emitted.
🧹 Nitpick
타임스탬프는 <time> 태그 사용 권장
시맨틱/접근성 및 i18n에 유리합니다.
- <p className={`text-xs mt-1 ${isOwn ? 'text-right' : 'text-left'} text-[var(--color-gray500)]`}>
- {formattedDate}
- </p>
+ <time
+ className={`text-xs mt-1 ${isOwn ? 'text-right' : 'text-left'} text-[var(--color-gray500)]`}
+ dateTime={new Date(msg.time).toISOString()}
+ >
+ {formattedDate}
+ </time>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <p className={`text-xs text-gray500 mt-1 ${isOwn ? 'text-right' : 'text-left'}`}> | |
| {formattedDate} | |
| </p> | |
| <time | |
| className={`text-xs mt-1 ${isOwn ? 'text-right' : 'text-left'} text-[var(--color-gray500)]`} | |
| dateTime={new Date(msg.time).toISOString()} | |
| > | |
| {formattedDate} | |
| </time> |
🤖 Prompt for AI Agents
In src/features/chat/ui/chatMessage/ChatMessage.tsx around lines 17 to 19, the
timestamp is rendered with a <p> tag; replace it with a <time> element to
improve semantics/accessibility and i18n support, keep the existing className
including the conditional alignment (isOwn ? 'text-right' : 'text-left'), render
the same formattedDate as the element content, and add a dateTime attribute with
the ISO/UTC timestamp (e.g. timestamp.toISOString() or the original raw
timestamp string) so assistive tech and browsers can parse the time.
🔎 작업 사항
❗️ 전달 사항
e.g. ) npm i 하세요 ...
➕ 관련 이슈
Summary by CodeRabbit
신규 기능
스타일
정리/관리