Skip to content

[fix] 1차 QA 반영#93

Merged
maylh merged 6 commits intodevelopfrom
fix/#90/qa-1
Aug 30, 2025
Merged

[fix] 1차 QA 반영#93
maylh merged 6 commits intodevelopfrom
fix/#90/qa-1

Conversation

@maylh
Copy link
Collaborator

@maylh maylh commented Aug 30, 2025

🛰️ 관련 이슈


✨ 주요 변경 사항

  • 홈페이지 캐러셀 컨텐츠 클릭 시 다음 컨텐츠의 노래가 재생되는 이슈
  • 댓글 삭제 시 채팅 히스토리 갱신 안 되는 이슈 해결
  • 메인페이지 캐러셀 버튼 폰트 굵기 확인
  • 공유하기 캐러셀, 플리 상세 페이지 cd 이미지 반영

🔍 테스트 방법 / 체크리스트

  • 없음

🗯️ PR 포인트


🚀 알게된 점


📖 참고 자료 (선택)

Summary by CodeRabbit

  • New Features
    • 채팅 메시지 삭제 시 화면에서 즉시 제거되어 대화가 실시간으로 정리됩니다.
    • 공유 UI가 스티커를 지원하도록 확장되어 재생목록 헤더·액션바·공유 시트에서 스티커 사용이 가능합니다.
  • Refactor
    • 디스커버 초기 재생목록 설정을 데이터 준비 완료 후로 지연해 안정성 향상.
    • 재생 확정 및 조회수 갱신 주기를 5초로 단축해 반응 속도 개선.
  • Style
    • 첫 슬라이드 버튼의 글꼴 두께를 500으로 조정.

@maylh maylh requested a review from hansololiviakim as a code owner August 30, 2025 00:34
@gemini-code-assist
Copy link

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai
Copy link

coderabbitai bot commented Aug 30, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

채팅 메시지 삭제 흐름에 removeMessage 콜백을 도입하고 훅/소켓/컴포넌트에 연결했습니다. 공유 UI에 stickers 데이터를 전달하는 props를 추가·전파했습니다. Discover 페이지는 초기화 가드와 타이밍(폴링/확인)을 조정했고, 홈 캐러셀 버튼의 폰트 굵기 스타일을 보강했습니다.

Changes

Cohort / File(s) Summary
Chat: 삭제 콜백 도입 및 연결
src/entities/comment/ui/Comment.tsx, src/features/chat/model/useChat.ts, src/features/chat/model/sendMessage.ts, src/widgets/chat/ChatBottomSheet.tsx
Comment에 removeMessage prop 추가 및 전달. useDeleteChatMessage(roomId, removeMessage) 호출로 시그니처 확장. useChatSocketremoveMessage를 반환하도록 변경해 BottomSheet → Comment로 전달.
Share/Playlist: stickers 전파
src/features/share/ui/ShareButton.tsx, src/widgets/playlist/ActionBar.tsx, src/widgets/playlist/PlaylistLayout.tsx, src/pages/discover/playlist/index.tsx
stickers?: CdCustomData[] prop 추가 및 상위에서 하위(Cd)로 전달하여 공유/플레이리스트 뷰에 스티커 데이터 적용.
Discover: 초기화 가드/타이밍 조정
src/pages/discover/index.tsx
isReady 플래그 도입으로 초기화 조건 강화. confirmPlaylist 딜레이 15000→5000ms, view refetch 10000→5000ms로 단축. 불필요 로그/주석 제거.
홈 캐러셀 스타일
src/pages/home/ui/LoopCarousel.tsx
FirstContent 내 버튼에 font-weight: 500 적용하는 중첩 스타일 추가(프레젠테이션 변경).

Sequence Diagram(s)

sequenceDiagram
  actor User as User
  participant UI as Comment Component
  participant Hook as useDeleteChatMessage
  participant API as Chat API
  participant Socket as useChatSocket (removeMessage)

  User->>UI: 삭제 버튼 클릭
  UI->>Hook: mutate(messageId)
  Hook->>API: DELETE /messages/:id
  API-->>Hook: 200 OK
  Hook->>Hook: invalidate chat-history
  Hook-->>Socket: removeMessage(messageId)
  Socket->>Socket: messages 상태에서 id 제거
  UI-->>User: 삭제 반영
Loading
sequenceDiagram
  participant Layout as PlaylistLayout
  participant ActionBar as ActionBar
  participant Share as ShareButton
  participant Cd as Cd (variant="share")

  Layout->>ActionBar: stickers = data?.cdItems ?? onlyCdResponse?.cdItems ?? []
  ActionBar->>Share: stickers 전달
  Share->>Cd: stickers 전달하여 렌더
  Cd-->>Share: 스티커 포함 뷰 렌더
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Assessment against linked issues

Objective Addressed Explanation
댓글 invalidate queries [#90]
메인페이지 캐러셀 버튼 폰트 굵기 확인 [#90]
공유하기 캐러셀, 플리 상세 페이지 cd 이미지 반영 [#90]
홈페이지 캐러셀 컨텐츠 클릭 시 다음 컨텐츠의 노래 재생되는 이슈 [#90] 해당 PR에서 관련 플레이리스트/캐러셀 클릭 재생 로직 변경(핵심 재생 순서/클릭 처리 수정)은 포함되어 있지 않음.

Out-of-scope changes

Code Change Explanation
Discover 초기화 및 타이머 조정 (src/pages/discover/index.tsx) linked issue 작업 목록에 명시된 항목이 아닌 타이머/초기화 지연 변경으로, QA 목록의 '홈페이지 캐러셀 클릭 재생'과 직접적 연관이 불분명합니다.

Possibly related PRs

Suggested labels

HIGH

Suggested reviewers

  • hansololiviakim

Poem

"토끼가 톡! 메시지를 훅— 지워요,
스티커 반짝 CD 위에 내려앉고,
디스커버는 성급히 준비를 재확인하네,
캐러셀 버튼은 한 획 굵게 당당히,
깡총—코드는 깔끔히, 배포는 가볍게! 🐇✨"


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between db10dd1 and 4eae8be.

📒 Files selected for processing (1)
  • src/pages/discover/playlist/index.tsx (2 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/#90/qa-1

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link

github-actions bot commented Aug 30, 2025

🎵 Storybook Link 🎵
🔗 https://689dbb45f8d09aea7832eeb1-imeaczwixz.chromatic.com/

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/features/chat/model/sendMessage.ts (1)

24-26: roomId 변경/cleanup 시 재연결 누락 및 연결 상태 불일치 가능성

clientRef.current?.active 가드로 인해 roomId 변경 타이밍에 새 연결이 생략될 수 있고, cleanup에서 connected를 false로 되돌리지 않습니다. onDisconnect 핸들러와 함께 가드를 제거하고 cleanup 시 ref를 null로 초기화하는 편이 안전합니다.

   useEffect(() => {
     if (!roomId) return
-    if (clientRef.current?.active) return // 이미 활성화된 연결 방지
@@
-    return () => {
-      client.deactivate()
-    }
+    client.onDisconnect = () => {
+      setConnected(false)
+    }
+    client.onStompError = () => {
+      setConnected(false)
+    }
+
+    return () => {
+      setConnected(false)
+      client.deactivate()
+      clientRef.current = null
+    }

Also applies to: 51-54

src/widgets/chat/ChatBottomSheet.tsx (2)

69-74: 버그: 소유자(role) 판별 로직이 반대로 작동

현재는 “내가 방장일 때” 내 메시지가 아닌 모든 메시지가 owner로 표시됩니다. 메시지의 발신자가 creatorId인 경우에만 owner가 되어야 합니다.

-            if (msg.senderId === userData?.userId) {
-              role = 'mine'
-            } else if (userData?.userId === creatorId) {
-              role = 'owner'
-            }
+            if (msg.senderId === userData?.userId) {
+              role = 'mine'
+            } else if (msg.senderId === creatorId) {
+              role = 'owner'
+            }

39-41: 중복 메시지 제거 및 sentAt 미존재 대비 정렬 가드

히스토리와 소켓 병합 시 중복이 생길 수 있고, sentAt! 단언은 빈값일 때 NaN을 유발합니다. messageId 기준 dedupe + 안전한 정렬을 권장합니다.

-  const allMessages = [...historyMessages, ...socketMessages].sort(
-    (a, b) => new Date(a.sentAt!).getTime() - new Date(b.sentAt!).getTime()
-  )
+  const merged = [...historyMessages, ...socketMessages]
+  const allMessages = Array.from(new Map(merged.map((m) => [m.messageId, m])).values()).sort(
+    (a, b) => (new Date(a.sentAt ?? 0).getTime()) - (new Date(b.sentAt ?? 0).getTime())
+  )
🧹 Nitpick comments (14)
src/pages/home/ui/LoopCarousel.tsx (1)

183-186: 후속 개선: 타입 셀렉터 대신 컴포넌트 래핑으로 명시적 오버라이드

후손 셀렉터(button)는 디자인 시스템(Button)의 타이포 설정과 충돌하거나 렌더 태그 변경 시(예: a/div) 무력화될 수 있습니다. Button을 래핑한 styled 컴포넌트로 명시적으로 오버라이드하는 방식을 권장합니다. 가능하면 테마 토큰(예: theme.FONT_WEIGHT.medium)이 있으면 그 값을 사용해 매직 넘버를 제거하세요.

아래와 같이 현재 범위에서는 후손 셀렉터를 제거하세요:

-  button {
-    font-weight: 500;
-  }

그리고 파일 바깥 변경(참고용) — Button 래핑 및 사용 교체:

// 1) styled 정의
const FirstSlideButton = styled(Button)`
  font-weight: 500;
`

// 2) JSX 교체
// <Button ...>{...}</Button>
<FirstSlideButton
  size="S"
  state="primary"
  onClick={() => (isLogin ? navigate('/mypage/customize') : navigate('/login'))}
>
  {isLogin ? BUTTON_TEXT.MEMBER : BUTTON_TEXT.GUEST}
</FirstSlideButton>
src/pages/discover/playlist/index.tsx (1)

46-46: null 병합 연산자로 안전하게 기본값 처리 권장

빈 배열도 falsy로 처리되는 || 대신 ??를 사용해 의도치 않은 덮어쓰기를 방지하는 편이 안전합니다.

-          stickers={playlistData?.onlyCdResponse?.cdItems || []}
+          stickers={playlistData?.onlyCdResponse?.cdItems ?? []}
src/widgets/playlist/PlaylistLayout.tsx (1)

110-111: ActionBar로 전달하는 stickers의 참조 안정화

렌더마다 새로운 배열 리터럴이 생성되어 하위 컴포넌트가 불필요하게 리렌더될 수 있습니다. 상단에서 useMemo로 안정화해 전달하세요.

@@
-        <ActionBar
+        <ActionBar
           playlistId={data.playlistId}
           isFollowing={!!isFollowing}
           userName={data.creator.creatorNickname}
           showFollow={type !== 'My'}
           creatorId={data.creator.creatorId}
-          stickers={data?.cdItems ?? data?.onlyCdResponse?.cdItems ?? []}
+          stickers={stickers}
         />

컴포넌트 상단(반환부 위)에 다음을 추가:

+  const stickers = useMemo(
+    () => data?.cdItems ?? data?.onlyCdResponse?.cdItems ?? [],
+    [data]
+  )
src/widgets/playlist/ActionBar.tsx (1)

20-31: 옵셔널 stickers의 기본값 지정으로 분기 제거

ShareButton까지 동일한 기본값([])을 유지하면 분기 최소화와 타입 일관성에 도움이 됩니다.

 interface ActionBarProps {
@@
-  stickers?: CdCustomData[]
+  stickers?: CdCustomData[]
 }
@@
-  stickers,
+  stickers = [],
 }: ActionBarProps) => {
src/pages/discover/index.tsx (2)

97-106: 초기화 가드(isReady)로 초기 진입 지연 가능성 — 부분 완화 제안

shuffleData가 늦게 도착하면 상세가 준비돼도 초기 재생이 지연됩니다. 상세만 준비되면 우선 초기화하고, 이후 셔플 데이터를 합치는 흐름을 권장합니다.

-  const isReady = !!playlistAsInfo && shuffleData !== undefined
+  const isReady = !!playlistAsInfo
@@
-  if (!currentPlaylist && playlistsData.length > 0 && isReady) {
+  if (!currentPlaylist && isReady && playlistsData.length > 0) {

또는 isReady를 deps에 포함시켜 의도 명확성 확보:

-}, [playlistsData, currentPlaylist, playlistId, setPlaylist])
+}, [playlistsData, currentPlaylist, playlistId, setPlaylist, isReady])

128-133: 뷰 카운트 5초 폴링 — 가시성/백그라운드 제어 권장

탭 비활성화 시 불필요한 호출을 줄이기 위해 document.visibilityState 기반 정지/재개를 권장합니다.

-    const viewCountTimer = setInterval(() => {
-      if (isPlaying) {
-        refetchViewCounts()
-      }
-    }, 5000)
+    const tick = () => {
+      if (document.visibilityState === 'visible' && isPlaying) {
+        refetchViewCounts()
+      }
+    }
+    const viewCountTimer = setInterval(tick, 5000)
src/features/share/ui/ShareButton.tsx (3)

10-21: stickers 기본값 지정 및 prop 안정성 강화

stickers에 기본값을 지정하면 Cd에 항상 배열이 전달되어 방어 코드가 단순해집니다.

-export interface ShareButtonProps {
+export interface ShareButtonProps {
   playlistId: number
   stickers?: CdCustomData[]
 }
 
-const ShareButton = ({ playlistId, stickers }: ShareButtonProps) => {
+const ShareButton = ({ playlistId, stickers = [] }: ShareButtonProps) => {

26-37: html-to-image 사용 시 CORS/캐시 문제 대응 옵션 추가 제안

외부 이미지가 포함된 스티커는 캔버스 오염으로 실패할 수 있습니다. cacheBust: true 등 옵션 적용을 고려하세요.

-      const dataUrl = await toPng(currentRef)
+      const dataUrl = await toPng(currentRef, { cacheBust: true, pixelRatio: 2 })

26-37: slides 메모이제이션(경미한 최적화)

slides는 렌더마다 새로 생성됩니다. 빈번한 리렌더를 줄이기 위해 useMemo 적용을 고려할 수 있습니다. 영향이 미미하다면 현 상태도 무방합니다.

-  const slides = [
+  const slides = useMemo(() => ([
     { id: 'cd', content: <Cd variant="share" bgColor="none" stickers={stickers} /> },
     {
       id: 'member',
       content: <img src={MemberCharacter} alt="Member Character" width={220} height={220} />,
     },
     {
       id: 'guest',
       content: <img src={GuestCharacter} alt="Guest Character" width={220} height={220} />,
     },
-  ]
+  ]), [stickers])
src/features/chat/model/sendMessage.ts (1)

28-30: 하드코딩된 WS URL을 환경변수로 분리

배포 환경별 엔드포인트를 .env로 관리하세요. Vite 기준 예시:

-      webSocketFactory: () => new SockJS('https://api.deulak.com/chat/ws') as unknown as WebSocket,
+      webSocketFactory: () =>
+        new SockJS(import.meta.env.VITE_CHAT_WS_URL) as unknown as WebSocket,
src/features/chat/model/useChat.ts (1)

31-37: 히스토리 캐시도 낙관적 삭제하여 깜빡임/지연 최소화

현재는 무효화만 하므로 재요청 전까지 히스토리 영역에 항목이 남아 있을 수 있습니다. onMutate로 낙관적 제거 후 에러 시 롤백하는 패턴을 권장합니다.

   return useMutation({
     mutationFn: (messageId: string) => deleteChatMessage(roomId, messageId),
-    onSuccess: (_, messageId) => {
-      queryClient.invalidateQueries({ queryKey: ['chat-history', roomId] })
-      removeMessage(messageId) //  소켓 state 업데이트
-    },
+    onMutate: async (messageId: string) => {
+      await queryClient.cancelQueries({ queryKey: ['chat-history', roomId] })
+      const prev = queryClient.getQueryData<InfiniteData<ChatHistoryResponse>>([
+        'chat-history',
+        roomId,
+      ])
+      // 히스토리 캐시에서 낙관적 제거
+      queryClient.setQueryData<InfiniteData<ChatHistoryResponse>>(
+        ['chat-history', roomId],
+        (data) =>
+          data && {
+            pageParams: data.pageParams,
+            pages: data.pages.map((p) => ({
+              ...p,
+              messages: p.messages.filter((m) => m.messageId !== messageId),
+            })),
+          }
+      )
+      // 소켓 로컬 상태도 즉시 제거
+      removeMessage(messageId)
+      return { prev }
+    },
+    onError: (_err, _messageId, ctx) => {
+      if (ctx?.prev) {
+        queryClient.setQueryData(['chat-history', roomId], ctx.prev)
+      }
+    },
+    onSettled: () => {
+      queryClient.invalidateQueries({ queryKey: ['chat-history', roomId] })
+    },
   })
src/widgets/chat/ChatBottomSheet.tsx (2)

53-55: 스크롤 최상단 판별 엄격도 완화

부동소수/서브픽셀 영향으로 === 0 비교가 불안정할 수 있습니다. <= 0 또는 임계값(e.g. <= 2) 비교를 권장합니다.

-    if (scrollRef.current.scrollTop === 0 && hasNextPage && !isFetchingNextPage) {
+    if (scrollRef.current.scrollTop <= 0 && hasNextPage && !isFetchingNextPage) {

58-58: 디버그 로그 제거

불필요한 콘솔 로그는 제거해주세요.

-  console.log(allMessages)
+  // console.log(allMessages)
src/entities/comment/ui/Comment.tsx (1)

46-49: 삭제 실패 피드백 추가 권장

에러 시 사용자 피드백이 없습니다. onError 토스트를 추가하세요.

-      deleteMessage(messageId, {
-        onSuccess: () => toast('COMMENT'),
-      })
+      deleteMessage(messageId, {
+        onSuccess: () => toast('COMMENT'),
+        onError: () => toast('ERROR'),
+      })
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c6f0c80 and db10dd1.

📒 Files selected for processing (10)
  • src/entities/comment/ui/Comment.tsx (2 hunks)
  • src/features/chat/model/sendMessage.ts (1 hunks)
  • src/features/chat/model/useChat.ts (1 hunks)
  • src/features/share/ui/ShareButton.tsx (1 hunks)
  • src/pages/discover/index.tsx (2 hunks)
  • src/pages/discover/playlist/index.tsx (1 hunks)
  • src/pages/home/ui/LoopCarousel.tsx (1 hunks)
  • src/widgets/chat/ChatBottomSheet.tsx (2 hunks)
  • src/widgets/playlist/ActionBar.tsx (4 hunks)
  • src/widgets/playlist/PlaylistLayout.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

**/*.{ts,tsx,js,jsx}: ## 1. 일반적인 코딩 컨벤션

포맷팅

  • .prettierrc 설정에 따라 포맷팅 확인
  • 들여쓰기: 2칸 스페이스
  • 최대 줄 길이: 100자
  • 세미콜론 사용 안함
  • 따옴표: 작은따옴표 사용
  • 괄호 안 공백: 있음
  • 화살표 함수 괄호: 항상 사용
  • 줄바꿈: LF 사용

네이밍 컨벤션

  • 컴포넌트: PascalCase (예: UserProfile)
  • 유틸리티/훅/변수: camelCase (예: getUserData, useUserInfo)
  • 상수: UPPER_SNAKE_CASE (예: API_BASE_URL)
  • 이미지 파일: kebab-case (예: user-profile-icon.png)

주석 사용

  • 복잡한 로직에만 주석 추가
  • 불필요한 주석 지양 (코드로 설명 가능한 것)
  • TODO/FIXME 형식: // TODO: 설명 - 작성자

가독성

  • 매직 넘버 지양, 의미있는 상수 사용
  • 함수는 하나의 책임만 가지도록 작성 (최대 20줄 권장)
  • 중첩 깊이 최소화 (3단계 이하 권장)

2. React 모범 사례

컴포넌트 작성

  • 최신 React hooks 사용 권장
  • 컴포넌트는 단일 책임 원칙 준수
  • Presentational/Container 컴포넌트 분리
  • 성능 최적화: memo, useCallback, useMemo 적절히 사용
  • 대용량 리스트는 가상화 라이브러리 사용 고려

상태 관리

  • Zustand와 Tanstack Query를 일관되게 사용
  • 상태 구조는 정규화된 형태로 관리
  • 에러 처리: Error Boundary와 try-catch 또는 onError 콜백 활용

3. 스타일링

Styled Components

  • Styled Components 일관되게 사용
  • 스타일드 컴포넌트명은 의미있게 작성
  • 동적 스타일링은 props나 CSS 변수 활용
  • 테마 시스템 활용하여 글로벌 스타일 관리
  • 재사용 가능한 스타일은 mixin이나 확장으로 관리
  • CSS 포맷팅 가독성 유지
  • 사용하지 않는 스타일이나 중복 스타일 제거

4. Vite 및 빌드 최적화

  • 모듈 import 최적화 (tree-shaking 고려)
  • 환경변수는 .env 파일로 관리
  • vite.config.ts에서 빌드 성능 튜닝 (sourcemap 설정, 플러그인 최적화 등)

5. 아키텍처 및 개발 환경

폴더 구조

  • Feature-Sliced Design (FSD) 구조 준수
  • 레이어별 참조 규칙 엄격히 적용

타입스크립트

  • strict 모드 사용
  • 타입 명시적으로 작성 (any 사용 지양)
  • path alias (@/_) 절대 경로 import 사용

Git 훅

  • Husky 설정으로 pre-commit, commit-msg 린팅 확인

6. 기타 가이드라인

  • 충분한 근거와 함께 리뷰 제공
  • 정보 검증 후 답변
  • 간결하고 명확한 응답
  • 필요시 추가 컨텍스트 요청
  • 검증되지 않은 주장 지양
  • 가능한 경우 출처 명시
  • 별도 언급 없으면 JavaScript 기준
  • 한국어로 응답
  • 대부분 브라우저에서 지원하는 ES6+ 기능 활용
  • 코드 리뷰를 통한 유지보수성 향상에 적극 활용

Files:

  • src/pages/discover/playlist/index.tsx
  • src/features/chat/model/sendMessage.ts
  • src/features/chat/model/useChat.ts
  • src/pages/home/ui/LoopCarousel.tsx
  • src/widgets/playlist/ActionBar.tsx
  • src/pages/discover/index.tsx
  • src/widgets/playlist/PlaylistLayout.tsx
  • src/features/share/ui/ShareButton.tsx
  • src/widgets/chat/ChatBottomSheet.tsx
  • src/entities/comment/ui/Comment.tsx
🧬 Code graph analysis (5)
src/features/chat/model/useChat.ts (1)
src/features/chat/api/chat.ts (1)
  • deleteChatMessage (10-12)
src/widgets/playlist/ActionBar.tsx (1)
src/entities/playlist/types/playlist.ts (1)
  • CdCustomData (23-34)
src/features/share/ui/ShareButton.tsx (1)
src/entities/playlist/types/playlist.ts (1)
  • CdCustomData (23-34)
src/widgets/chat/ChatBottomSheet.tsx (1)
src/features/chat/model/sendMessage.ts (1)
  • useChatSocket (17-80)
src/entities/comment/ui/Comment.tsx (1)
src/features/chat/model/useChat.ts (1)
  • useDeleteChatMessage (28-38)
🔇 Additional comments (10)
src/pages/home/ui/LoopCarousel.tsx (1)

183-186: LGTM — 버튼 폰트 굵기 보정 목표 충족

FirstContent 하위의 버튼 폰트 굵기를 500으로 고정하는 목적에 부합합니다. 다만 이 선택자는 실제 Button 컴포넌트가 HTML button 요소로 렌더링될 때만 적용됩니다. 확인 부탁드립니다.

src/widgets/playlist/PlaylistLayout.tsx (1)

105-111: creatorId 타입 일치 여부 확인 및 문자열 강제 변환 고려

ActionBarcreatorId가 string으로 정의되어 있을 가능성이 높습니다. data.creator.creatorId가 number라면 런타임 불일치가 생길 수 있으니 명시적 변환 또는 Prop 타입 조정을 검토하세요.

-          creatorId={data.creator.creatorId}
+          creatorId={String(data.creator.creatorId)}
src/widgets/playlist/ActionBar.tsx (2)

6-6: 타입 import 경로 확인

@/entities/playlistCdCustomData를 재export하지 않으면 빌드가 실패합니다. 실제 export 경로(@/entities/playlist/types/playlist)를 확인해 주세요.


52-53: ShareButton으로의 데이터 전달 LGTM

공유 이미지에 필요한 CD 스티커 데이터가 적절히 전달됩니다.

src/pages/discover/index.tsx (1)

123-126: confirm 타이밍 5초로 단축 — 서버 규칙과 일치 여부 확인

뷰 처리·중복 집계 정책과 맞는지 확인이 필요합니다. 너무 짧으면 의도치 않은 confirm 남발이 될 수 있습니다.

src/features/chat/model/sendMessage.ts (1)

75-77: LGTM: 로컬 소켓 상태에서 메시지 제거 콜백 추가로 삭제 UX 개선

정확히 messageId 기준으로 필터링하고, useCallback의 함수형 업데이트 사용도 적절합니다.

src/features/chat/model/useChat.ts (1)

28-28: LGTM: 삭제 훅 시그니처 확장 및 성공 시 소켓 상태 싱크

onSuccess에서 variables로 넘어온 messageId를 사용해 소켓 측 상태를 정리하는 흐름이 명확합니다.

Also applies to: 33-36

src/widgets/chat/ChatBottomSheet.tsx (1)

27-27: LGTM: 삭제 콜백 전달 경로 연결 완료

useChatSocket에서 받은 removeMessageComment에 프롭으로 전달하는 연결이 일관됩니다.

Also applies to: 86-87

src/entities/comment/ui/Comment.tsx (2)

18-19: LGTM: 삭제 흐름 프롭 추가 및 훅 시그니처 반영

removeMessage 프롭 추가와 useDeleteChatMessage(roomId, removeMessage) 적용이 정상적으로 연결되었습니다.

Also applies to: 42-43


120-122: 디자인 확인 요청: 삭제/신고 색상 매핑

현재 'delete'는 회색, 'report'는 에러 색입니다. 통상 삭제가 파괴적 액션으로 강조색(에러)을 씁니다. 의도된 디자인인지 확인 부탁드립니다.

@maylh maylh changed the title Fix/#90/qa 1 [fix] 1차 QA 반영 Aug 30, 2025
@maylh maylh merged commit ad06a47 into develop Aug 30, 2025
3 of 4 checks passed
@maylh maylh deleted the fix/#90/qa-1 branch August 30, 2025 02:29
@hansololiviakim hansololiviakim added the HIGH 빠르게 처리해야 하는 높은 우선순위 label Aug 30, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

HIGH 빠르게 처리해야 하는 높은 우선순위

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[fix] 1차 QA 반영

2 participants