Skip to content

Conversation

@alwubin
Copy link
Collaborator

@alwubin alwubin commented Feb 19, 2025

💡 작업 내용

  • 댓글 UI 구현
  • 댓글 작성 CommentInput 컴포넌트 구현
  • 댓글 관련 api 연동 (이 부분에 대해서는 현재 db가 없는건지 서버 작동이 안되는건지 호출 오류가 있어 테스트 해보진 못했습니다.)

💡 자세한 설명

✅ MobileCommentItem, MobileCommentSection

  • 기존에 있는 컴포넌트에서 미디어 쿼리를 사용할 수 있는 부분은 최대한 사용하려고 했습니다.
  • 모바일 댓글 UI에는 페이지네이션이 따로 구현되지 않아서 하단 페이지네이션은 제거하였습니다.
  • 아직 답글 페이지가 구현되지 않았기 때문에 기존 코드에서 사용될 가능성 있는 부분은 주석 처리하였습니다.
  • 구현 화면 : 댓글 1개일 때 및 답글 없을 때 | 댓글 1개일 때 | 댓글이 없을 때 | 작성자일 때

✅ CommentInput

  • TalkPickMobilePage에서 관리되는 모바일 댓글 Input 컴포넌트이고, input이 아닌 textarea로 받아 최대 3줄까지 컴포넌트가 늘어날 수 있도록 구현하였습니다.
  • 스토리북도 작성해두었지만 position: fixed로 인해 세가지 상태가 모두 보이지 않아 하단에 사진을 첨부하겠습니다.
  • 구현 화면 : 스토리북에 구현된 세가지 상태 | 실제 페이지에 적용된 상태
스크린샷 2025-02-18 오후 10 32 28

📗 참고 자료 (선택)

📢 리뷰 요구 사항 (선택)

🚩 후속 작업 (선택)

✅ 셀프 체크리스트

  • PR 제목을 형식에 맞게 작성했나요?
  • 브랜치 전략에 맞는 브랜치에 PR을 올리고 있나요? (master/main이 아닙니다.)
  • 이슈는 close 했나요?
  • Reviewers, Labels, Projects를 등록했나요?
  • 작업 도중 문서 수정이 필요한 경우 잘 수정했나요?
  • 테스트는 잘 통과했나요?
  • 불필요한 코드는 제거했나요?

closes #300

Summary by CodeRabbit

  • New Features
    • 모바일 사용자를 위해 TalkPick 페이지가 모바일 전용 버전으로 제공됩니다.
    • 댓글 입력 필드, 모바일 댓글 아이템 및 댓글 섹션 등 새로운 모바일 컴포넌트가 추가되었습니다.
    • 모바일 전용 좋아요 버튼과 아이콘 업데이트로 인터랙션이 개선되었습니다.
    • 새로운 상수 COMMENT가 추가되어 댓글 관련 메시지가 향상되었습니다.
    • 보고를 위한 새로운 모달 컴포넌트가 추가되어 사용자 경험이 향상되었습니다.
  • Style
    • 다양한 컴포넌트에 반응형 디자인을 적용하여 작은 화면에서도 최적화된 레이아웃과 스타일을 제공합니다.
    • 새로운 색상 팔레트와 모바일 아이콘이 추가되어 전체 UI가 더욱 깔끔해졌습니다.
  • Refactor
    • 스타일 정의 방식을 객체 기반으로 통일하여 코드 일관성을 높였습니다.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2025

Walkthrough

이번 PR은 애플리케이션의 모바일 환경 대응을 강화하기 위해 여러 컴포넌트와 스타일을 수정 및 추가하였습니다. 주요 변경 사항으로는 App.tsx에서 모바일 전용 페이지 컴포넌트를 조건부 렌더링하도록 라우팅 로직이 업데이트되었으며, 관련 SVG 자산과 댓글, 좋아요 등 모바일 UI 전용 컴포넌트 및 스타일이 추가되었습니다. 또한 여러 CSS-in-JS 스타일 정의가 템플릿 리터럴에서 객체 문법으로 전환되어 반응형 처리와 유지보수성이 개선되었습니다.

Changes

File(s) 변경 요약
src/App.tsx PATH.TALKPICK 경로에 대해 isMobile 상태에 따라 TalkPickMobilePage 또는 TalkPickPage를 조건부 렌더링하도록 수정
src/assets/index.ts 모바일 전용 SVG 아이콘 (MobileComment, CryEmoji, MobileLikeButtonDF, MobileLikeButtonPR, MobileArrowUp, MobileArrowDown) 6개 추가
src/components/atoms/CategoryBarChip/* extraSmall 사이즈 옵션 추가 및 CategoryBarChipProps 인터페이스 확장 (large, small, extraSmall)
src/components/atoms/CommentProfile/CommentProfile.style.ts,
src/components/atoms/LikeButton/LikeButton.style.ts,
src/components/molecules/CommentItem/CommentItem.style.ts,
src/components/organisms/CommentsSection/CommentsSection.style.ts
템플릿 리터럴을 객체 문법으로 전환하고 미디어 쿼리 적용으로 반응형 스타일 업데이트
src/components/atoms/ToastModal/ToastModal.style.ts typo 속성 확산 및 430px 이하 미디어 쿼리 추가로 스타일 업데이트
src/components/atoms/MenuTap/MenuTap.style.ts 모바일 반응형 디자인을 위한 미디어 쿼리 및 typography 스타일 수정
src/components/mobile/atoms/CommentInput/* 댓글 입력 컴포넌트 및 관련 스타일 신규 추가
src/components/mobile/molecules/MobileCommentItem/* 모바일 댓글 항목 및 관련 스타일 신규 추가
src/components/mobile/organisms/MobileCommentsSection/* 댓글 섹션 컴포넌트 및 관련 스타일 신규 추가
src/pages/mobile/TalkPickMobilePage/* 모바일 전용 TalkPick 페이지 컴포넌트와 스타일 추가
src/stories/mobile/atoms/CommentInput.stories.tsx CommentInput 컴포넌트의 Storybook 스토리 추가
src/constants/message.ts 댓글 관련 메시지 상수 COMMENT (아직 댓글 없음, 첫 댓글 제안, 최대 길이 500) 추가
src/styles/color.ts 회색 계열 색상에 새로운 항목 (#97A0A9, #555555) 추가
src/components/atoms/MoreButton/* MoreButton 컴포넌트의 아이콘 옵션 및 스타일 수정

Suggested labels

✨feature, 🎨 markup, ✔︎pull requests

Suggested reviewers

  • areumH
  • WonJuneKim

Poem

나는 깡충깡충 달리는 작은 토끼,
코드 숲 속의 변화들을 반기네.
모바일 화면에 새풍 불어와,
스타일과 컴포넌트가 춤을 추네.
🐇 행복한 코드, 모두에게 전하리라!

(깡총깡총! 아주 신나는 하루!)


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e29ff66 and c8fe332.

📒 Files selected for processing (2)
  • src/assets/index.ts (1 hunks)
  • src/constants/message.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/constants/message.ts
  • src/assets/index.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build

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.
    • Generate unit testing code for this file.
    • 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. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai 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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • 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.

Copy link
Contributor

@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: 6

🧹 Nitpick comments (22)
src/components/atoms/CategoryBarChip/CategoryBarChip.style.ts (1)

34-38: 미디어 쿼리 브레이크포인트 표준화가 필요합니다.

430px와 같은 매직 넘버를 상수로 분리하여 재사용하는 것이 좋습니다.

다음과 같이 브레이크포인트를 상수화하는 것을 추천드립니다:

+// src/styles/breakpoints.ts
+export const BREAKPOINTS = {
+  MOBILE: '430px',
+} as const;

// CategoryBarChip.style.ts
export const categoryBarChipStyling = css({
  ...typo.Comment.SemiBold,
  display: 'flex',
  justifyContent: 'center',
  alignItems: 'center',
  backgroundColor: color.MAIN,
  color: color.WT,
-  '@media (max-width: 430px)': {
+  [`@media (max-width: ${BREAKPOINTS.MOBILE})`]: {
    ...typo.Mobile.Text.SemiBold_10,
    backgroundColor: color.WT_VIOLET,
    color: color.MAIN,
  },
});
src/components/atoms/CommentProfile/CommentProfile.style.ts (1)

36-39: 모바일 스타일의 수치 표준화가 필요합니다.

24.5px와 같은 구체적인 픽셀값은 유지보수를 어렵게 만들 수 있습니다.

다음과 같이 상수화하거나 상대적인 단위를 사용하는 것을 추천드립니다:

+// src/styles/sizes.ts
+export const PROFILE_SIZES = {
+  DESKTOP: '45px',
+  MOBILE: '24.5px',
+} as const;

export const profileWrapper = css({
-  width: '45px',
-  height: '45px',
+  width: PROFILE_SIZES.DESKTOP,
+  height: PROFILE_SIZES.DESKTOP,
  borderRadius: '50%',
  overflow: 'hidden',
  backgroundSize: 'cover',
  backgroundPosition: 'center',
  cursor: 'pointer',
  '@media (max-width: 430px)': {
-    width: '24.5px',
-    height: '24.5px',
+    width: PROFILE_SIZES.MOBILE,
+    height: PROFILE_SIZES.MOBILE,
  },
});
src/components/atoms/ToastModal/ToastModal.style.ts (1)

33-36:

Details

❓ Verification inconclusive

모바일 브레이크포인트 일관성 검토 필요

모바일 미디어 쿼리에서 사용된 430px 브레이크포인트가 다른 컴포넌트들과 일관성이 있는지 확인이 필요합니다. 브레이크포인트를 상수로 분리하여 재사용하는 것을 고려해보세요.

다음 스크립트로 프로젝트 내의 브레이크포인트 사용을 확인할 수 있습니다:


🏁 Script executed:

#!/bin/bash
# 프로젝트 내의 미디어 쿼리 브레이크포인트 사용 현황 확인
rg -g '*.ts' -g '*.tsx' '@media.*\d+px'

Length of output: 7065


모바일 브레이크포인트 일관성 확인 필요

현재 ToastModal 컴포넌트에서는 430px 브레이크포인트가 사용되고 있습니다. 프로젝트 전체를 검색한 결과, 대다수의 컴포넌트에서는 430px를 사용하고 있으나 일부 컴포넌트(예: CategoryButton, CategoryBox)에서는 320px가 사용되고 있음을 확인했습니다.

  • 해당 컴포넌트들의 디자인 의도와 breakpoint 값이 명확한지 재검토해 주세요.
  • 가능하다면, breakpoint 값을 상수로 분리하여 재사용하도록 리팩토링하는 방안을 고려해 보시기 바랍니다.
src/stories/mobile/atoms/CommentInput.stories.tsx (2)

28-29: 핸들러 구현 개선 필요

빈 화살표 함수 대신 Storybook의 action을 활용하여 핸들러의 동작을 모니터링하는 것이 좋습니다.

다음과 같이 수정해보세요:

-          onCommentChange={() => {}}
-          onCommentSubmit={() => {}}
+          onCommentChange={meta.argTypes.onCommentChange.action}
+          onCommentSubmit={meta.argTypes.onCommentSubmit.action}

Also applies to: 33-34, 38-39


22-44: 테스트 케이스 보완 제안

현재 빈 문자열, 긴 문자열, 최대 길이 초과 케이스를 테스트하고 있습니다. 다음 케이스들도 추가하면 좋을 것 같습니다:

  • 특수 문자 포함
  • 이모지 포함
  • 줄바꿈 문자 포함
src/components/atoms/LikeButton/LikeButton.tsx (2)

28-44: switch 문 최적화 제안

현재 switch 문이 다소 복잡합니다. 조건부 할당을 사용하여 더 간단하게 구현할 수 있습니다.

다음과 같이 수정해보세요:

-  switch (true) {
-    case likeState && isMobile:
-      Icon = MobileLikeButtonPR;
-      break;
-    case likeState && !isMobile:
-      Icon = LikeButtonPR;
-      break;
-    case !likeState && isMobile:
-      Icon = MobileLikeButtonDF;
-      break;
-    case !likeState && !isMobile:
-      Icon = LikeButtonDF;
-      break;
-    default:
-      Icon = LikeButtonDF;
-      break;
-  }
+  Icon = isMobile
+    ? likeState
+      ? MobileLikeButtonPR
+      : MobileLikeButtonDF
+    : likeState
+      ? LikeButtonPR
+      : LikeButtonDF;

50-50: 좋아요 텍스트 상수화 권장

하드코딩된 '좋아요' 문자열을 상수로 분리하는 것이 좋습니다.

constants 폴더에 관련 상수를 추가하고 import하여 사용하세요.

src/components/atoms/LikeButton/LikeButton.style.ts (2)

13-16: 미디어 쿼리 중단점 표준화 필요

미디어 쿼리 중단점(430px)이 임의적으로 보입니다. 일관성을 위해 공통 상수나 테마 설정에서 중단점을 관리하는 것이 좋습니다.

+ // src/styles/breakpoints.ts 파일 생성
+ export const BREAKPOINTS = {
+   MOBILE: '430px',
+   TABLET: '768px',
+   DESKTOP: '1024px',
+ } as const;

29-63: 중복 스타일 코드 리팩토링 제안

defaultLabelpressedLabel에 중복된 스타일이 많이 있습니다. 공통 스타일을 분리하여 재사용하면 유지보수가 더 쉬워질 것 같습니다.

+ const baseLabel = css({
+   ...typo.Number.Medium_18,
+   display: 'flex',
+   flexDirection: 'column',
+   justifyContent: 'center',
+   alignItems: 'center',
+   width: '22px',
+   height: '29px',
+   padding: 0,
+   margin: 0,
+   '@media (max-width: 430px)': {
+     ...typo.Mobile.Main.Regular_12,
+     width: '15px',
+     height: '15px',
+   },
+ });

export const defaultLabel = css({
+   ...baseLabel,
-   ...typo.Number.Medium_18,
-   display: 'flex',
-   flexDirection: 'column',
-   justifyContent: 'center',
-   alignItems: 'center',
-   width: '22px',
-   height: '29px',
    color: color.GY[1],
-   padding: 0,
-   margin: 0,
-   '@media (max-width: 430px)': {
-     ...typo.Mobile.Main.Regular_12,
-     width: '15px',
-     height: '15px',
-   },
});

export const pressedLabel = css({
+   ...baseLabel,
-   ...typo.Number.Medium_18,
-   display: 'flex',
-   flexDirection: 'column',
-   justifyContent: 'center',
-   alignItems: 'center',
-   width: '22px',
-   height: '29px',
    color: color.MAIN,
-   padding: 0,
-   margin: 0,
-   '@media (max-width: 430px)': {
-     ...typo.Mobile.Main.Regular_12,
-     width: '15px',
-     height: '15px',
-   },
});
src/styles/color.ts (2)

25-25: TODO 주석 처리 필요

이전 색상 타입 정리에 대한 TODO 주석이 있습니다. 색상 시스템의 일관성을 위해 이 작업을 진행하는 것이 좋을 것 같습니다.

색상 타입 정리 작업을 도와드릴까요? 새로운 이슈를 생성하여 추적할 수 있습니다.


4-12: 색상 네이밍 컨벤션 개선 제안

GY.1, GY.2와 같은 숫자 기반의 네이밍은 의미를 파악하기 어렵습니다. 색상의 용도나 의미를 반영하는 네이밍으로 변경하면 좋을 것 같습니다.

 const color = {
   MAIN: '#7782FF',
   BK: '#181818',
   GY: {
-    1: '#8C8C8C',
-    2: '#D9D9D9',
-    3: '#F1F1F1',
-    4: '#E6E9EF',
-    5: '#F6F7F9',
-    6: '#97A0A9',
-    7: '#555555',
+    text: '#8C8C8C',
+    border: '#D9D9D9',
+    background: '#F1F1F1',
+    divider: '#E6E9EF',
+    hover: '#F6F7F9',
+    icon: '#97A0A9',
+    label: '#555555',
   },
src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.style.ts (1)

5-8: MainContainer 네이밍 개선 제안

MainContainer라는 이름은 너무 일반적입니다. 컴포넌트의 특정 목적을 더 잘 반영하는 이름을 사용하면 좋을 것 같습니다.

-export const MainContainer = css({
+export const CommentItemContainer = css({
   display: 'flex',
   flexDirection: 'column',
 });
src/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection.style.ts (1)

9-9: 주석 처리된 코드 정리 필요

주석 처리된 paddingBottom 속성이 있습니다. 이 코드가 필요하지 않다면 제거하고, 필요하다면 주석 대신 실제 코드로 변경하는 것이 좋습니다.

src/components/mobile/atoms/CommentInput/CommentInput.style.ts (1)

19-41: 반응형 디자인 개선 제안

현재 고정된 픽셀 값으로 너비가 지정되어 있어 다양한 모바일 화면 크기에서 문제가 발생할 수 있습니다.

다음과 같이 상대적인 단위를 사용하는 것을 제안드립니다:

export const inputBoxWrapper = (length: number) =>
  css({
    backgroundColor: color.GY[5],
    padding: '3px 4px 3px 18px',
-   width: '335px',
+   width: '100%',
+   maxWidth: '335px',
    height: 'auto',
    borderRadius: length < 20 ? '30px' : '17px',
    display: 'flex',
  });

export const inputStyling = css(typo.Text.Regular, {
  flex: 1,
  border: 'none',
  outline: 'none',
-  width: '213px',
+  width: '100%',
  resize: 'none',
  overflowY: 'auto',
  maxHeight: '66px',
  height: 'auto',
  '&::placeholder': {
    color: color.GY[6],
  },
});
src/components/mobile/atoms/CommentInput/CommentInput.tsx (1)

43-46: 접근성 개선 필요

현재 textarea에 aria-label이 누락되어 있습니다.

<textarea
  ref={textareaRef}
  css={S.inputStyling}
  placeholder="댓글을 입력해주세요"
+ aria-label="댓글 입력창"
  value={comment}
  onChange={(e) => {
    onCommentChange(e.target.value);
    handleInput();
  }}
  maxLength={COMMENT.MAX_LENGTH}
  rows={1}
  {...attributes}
/>
src/components/molecules/CommentItem/CommentItem.style.ts (2)

5-9: 반응형 디자인 및 일관성 개선 필요

MainContainer의 고정 너비는 모바일 환경에서 문제가 될 수 있습니다.

export const MainContainer = css({
  display: 'flex',
  flexDirection: 'column',
- width: '1175px',
+ width: '100%',
+ maxWidth: '1175px',
});

50-54: 색상 상수 사용의 일관성 개선 필요

일부 색상값이 직접 hex 코드로 하드코딩되어 있습니다. 색상 상수를 사용하여 일관성을 유지해야 합니다.

export const createdTime = css({
  ...typo.Comment.SemiBold,
- color: '#67727E',
+ color: color.GY[1],
  marginLeft: '10px',
});

export const commentTextWrapper = css({
  display: 'flex',
  width: '100%',
  paddingRight: '20px',
  ...typo.Comment.Regular,
- color: '#505050',
+ color: color.GY[2],
});

Also applies to: 61-67

src/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection.tsx (2)

1-1: eslint 규칙 비활성화 제거 필요

@typescript-eslint/no-unused-vars 규칙을 비활성화하는 대신 사용하지 않는 변수를 제거하는 것이 좋습니다.

-/* eslint-disable @typescript-eslint/no-unused-vars */

70-77: 주석 처리된 페이지네이션 코드 처리 필요

페이지네이션 기능이 구현되지 않아 주석 처리된 상태입니다. 향후 구현 계획이 있다면 TODO 주석을 추가하고, 그렇지 않다면 코드를 제거하는 것이 좋습니다.

-      {/* <div css={S.paginationWrapper}>
-        <Pagination
-          pages={pages}
-          selected={selectedPage}
-          maxPage={totalPages}
-          onChangeNavigate={handlePageChange}
-        />
-      </div> */}
src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.tsx (2)

1-1: eslint 규칙 비활성화 제거 필요

@typescript-eslint/no-unused-vars 규칙을 비활성화하는 대신 사용하지 않는 변수를 제거하는 것이 좋습니다.

-/* eslint-disable @typescript-eslint/no-unused-vars */

98-101: 주석 처리된 함수들의 처리 필요

여러 기능이 주석 처리되어 있습니다. 각 기능의 구현 계획에 따라 TODO 주석을 추가하거나 코드를 제거하는 것이 좋습니다.

-  //   const handleDeleteCommentButton = () => {
-  //     onCloseModal();
-  //     handleDelete();
-  //   };

-  //   const handleReportCommentButton = (reason: string) => {
-  //     handleReport(reason);
-  //     onCloseModal();
-  //   };

-  //   const handleMoreButton = () => {
-  //     setVisibleReply((reply) => reply + 10);
-  //   };

Also applies to: 127-130, 132-134

src/assets/index.ts (1)

160-160:

Details

❓ Verification inconclusive

TODO 주석 정리가 필요합니다.

"이전 SVG" 관련 TODO 주석이 있습니다. 이전 SVG 에셋들의 사용 여부를 확인하고, 불필요한 경우 정리가 필요해 보입니다.

다음 스크립트를 실행하여 이전 SVG 에셋들의 사용 여부를 확인해보세요:


🏁 Script executed:

#!/bin/bash
# Description: Check usage of old SVG assets

# List of old SVG assets to check
OLD_ASSETS=("Email" "Profile" "Report" "Like" "Star" "Hearts" "Home" "Key" "LeftButton" "RightButton" "Person" "Rank" "Winner" "Fight" "Vote" "Edit" "Delete" "DisabledHeart" "Closed" "RightArrow")

for asset in "${OLD_ASSETS[@]}"; do
  echo "Checking usage of $asset..."
  rg -l "\b${asset}\b" --type ts --type tsx
done

Length of output: 3590


[검증 필요] 이전 SVG TODO 정리 및 스크립트 수정 요청

현재 src/assets/index.ts의 160번째 줄에 남아있는 "이전 SVG" 관련 TODO 주석이 있습니다. 이 주석은 이전 SVG 에셋들의 사용 여부를 확인한 후 불필요하다면 정리할 필요가 있음을 의미합니다.

실행된 스크립트에서 ripgrep이 --type tsx 옵션을 인식하지 못해 "unrecognized file type: tsx" 오류가 발생하였습니다. 이에 따라 아래와 같이 조치해 주시기 바랍니다:

  • 검증 조치:

    • TS 및 TSX 파일 모두에서 에셋 사용 여부를 확인할 수 있도록 스크립트를 수정하거나, 수동으로 코드베이스 내에서 해당 에셋(예: "Email", "Profile", "Report" 등)의 사용 여부를 재검증해 주세요.
    • ripgrep이 TSX 파일을 인식할 수 있도록 --type-add 옵션 등의 수정 방안을 적용해 볼 수 있습니다.
  • 주석 정리:

    • 에셋이 사용 중이지 않다면, 해당 TODO 주석을 제거해 주세요.
    • 사용 중인 것이 확인된다면, 관련 코멘트를 최신 상태에 맞게 업데이트하거나 필요에 따라 주석 내용을 보완해 주세요.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f17e265 and 4d20217.

⛔ Files ignored due to path filters (5)
  • src/assets/svg/cry-emoji.svg is excluded by !**/*.svg
  • src/assets/svg/mobile-arrow-up.svg is excluded by !**/*.svg
  • src/assets/svg/mobile-comment.svg is excluded by !**/*.svg
  • src/assets/svg/mobile-like-button-df.svg is excluded by !**/*.svg
  • src/assets/svg/mobile-like-button-pr.svg is excluded by !**/*.svg
📒 Files selected for processing (22)
  • src/App.tsx (2 hunks)
  • src/assets/index.ts (1 hunks)
  • src/components/atoms/CategoryBarChip/CategoryBarChip.style.ts (1 hunks)
  • src/components/atoms/CategoryBarChip/CategoryBarChip.tsx (1 hunks)
  • src/components/atoms/CommentProfile/CommentProfile.style.ts (2 hunks)
  • src/components/atoms/LikeButton/LikeButton.style.ts (1 hunks)
  • src/components/atoms/LikeButton/LikeButton.tsx (1 hunks)
  • src/components/atoms/MenuTap/MenuTap.style.ts (2 hunks)
  • src/components/atoms/ToastModal/ToastModal.style.ts (2 hunks)
  • src/components/mobile/atoms/CommentInput/CommentInput.style.ts (1 hunks)
  • src/components/mobile/atoms/CommentInput/CommentInput.tsx (1 hunks)
  • src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.style.ts (1 hunks)
  • src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.tsx (1 hunks)
  • src/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection.style.ts (1 hunks)
  • src/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection.tsx (1 hunks)
  • src/components/molecules/CommentItem/CommentItem.style.ts (2 hunks)
  • src/components/organisms/CommentsSection/CommentsSection.style.ts (1 hunks)
  • src/constants/message.ts (1 hunks)
  • src/pages/mobile/TalkPickMobilePage/TalkPickMobilePage.style.ts (1 hunks)
  • src/pages/mobile/TalkPickMobilePage/TalkPickMobilePage.tsx (1 hunks)
  • src/stories/mobile/atoms/CommentInput.stories.tsx (1 hunks)
  • src/styles/color.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/components/organisms/CommentsSection/CommentsSection.style.ts
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: storybook
🔇 Additional comments (11)
src/pages/mobile/TalkPickMobilePage/TalkPickMobilePage.style.ts (1)

4-8: 스타일 구현이 깔끔합니다!

플렉스 컨테이너를 사용하여 콘텐츠를 세로 방향으로 정렬하는 구현이 적절합니다.

src/components/atoms/CategoryBarChip/CategoryBarChip.tsx (1)

5-5: 사이즈 옵션 추가가 잘 구현되었습니다!

'extraSmall' 사이즈 옵션을 추가한 것이 모바일 환경에 적합해 보입니다.

src/components/atoms/CategoryBarChip/CategoryBarChip.style.ts (1)

18-21: extraSmall 스타일링이 잘 구현되었습니다!

작은 크기의 카테고리 칩에 적합한 스타일링입니다.

src/components/atoms/CommentProfile/CommentProfile.style.ts (1)

4-14: 컨테이너 스타일 구현이 개선되었습니다!

객체 문법을 사용한 스타일 정의가 가독성과 유지보수성을 향상시켰습니다.

src/components/atoms/MenuTap/MenuTap.style.ts (1)

45-50:

Details

❓ Verification inconclusive

모바일 텍스트 색상 대비 검토 필요

모바일 뷰에서 사용되는 color.GY[1]과 배경색의 대비가 접근성 기준을 충족하는지 확인이 필요합니다.

다음 Python 스크립트로 색상 대비를 확인할 수 있습니다:


🏁 Script executed:

#!/bin/bash
# 색상 대비 검사
python3 << END
from wcag_contrast_ratio import rgb
import json

# styles/color.ts 파일에서 색상값 추출
with open('src/styles/color.ts', 'r') as f:
    content = f.read()
    
# GY[1]과 WT 색상의 대비 계산
background = rgb(255, 255, 255)  # WT color
text = None  # GY[1] color will be extracted

# Calculate and print contrast ratio
if text:
    ratio = text.contrast_ratio(background)
    print(f"Contrast ratio: {ratio}")
    print(f"Meets WCAG AA for large text: {ratio >= 3}")
    print(f"Meets WCAG AA for small text: {ratio >= 4.5}")
END

Length of output: 141


모바일 텍스트 색상 대비 수동 검증 필요

모바일 뷰에 적용된 color.GY[1] 텍스트와 예상 배경색(흰색) 간의 대비가 WCAG 접근성 기준(작은 텍스트: 최소 4.5, 큰 텍스트: 최소 3)을 충족하는지 확인해야 합니다.
현재 실행한 Python 스크립트에서 wcag_contrast_ratio 모듈이 존재하지 않아 대비 결과를 얻지 못했습니다. 이에 따라 아래 사항을 참고하여 수동 검증 또는 대체 도구를 통한 검토를 부탁드립니다:

  • 파일: src/components/atoms/MenuTap/MenuTap.style.ts (45-50 라인)
  • 검토 항목: 모바일 뷰에서 사용되는 텍스트 색상(color.GY[1])과 흰색 배경 간의 색상 대비
  • 필요 시 wcag_contrast_ratio 모듈 설치 또는 외부 도구를 이용해 정확한 색상 대비 값을 확인해주세요.
src/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection.style.ts (1)

40-52: 성능 최적화 고려 필요

backdropFilter: 'blur'는 모바일 기기에서 성능 저하를 일으킬 수 있습니다. 대체 방안을 고려하거나 성능 테스트를 진행하는 것이 좋을 것 같습니다.

더 가벼운 대안으로 반투명 배경만 사용하는 것을 고려해보세요:

 export const loggedOutBackground = css({
   width: '100%',
   height: '100%',
-  backgroundColor: 'rgba(255, 255, 255, 0.01)',
-  backdropFilter: 'blur(11px)',
+  backgroundColor: 'rgba(255, 255, 255, 0.9)',
   position: 'absolute',
   top: 0,
   left: 0,
   zIndex: 1,
   display: 'flex',
   flexDirection: 'column',
   gap: '29px',
 });
src/components/mobile/atoms/CommentInput/CommentInput.style.ts (1)

6-17:

Details

❓ Verification inconclusive

모바일 키보드 동작 시 입력창 위치 검토 필요

fixed 포지션을 사용한 입력창이 모바일 가상 키보드와 함께 사용될 때 문제가 발생할 수 있습니다. 키보드가 올라올 때 입력창이 가려질 수 있으며, iOS Safari에서 특히 주의가 필요합니다.


🌐 Web query:

How to handle fixed positioning with mobile virtual keyboards?

💡 Result:

Handling fixed positioning elements when mobile virtual keyboards appear requires addressing viewport resizing and element repositioning. Here are key approaches based on current best practices:

Modern Solution: VirtualKeyboard API

For browsers supporting the new standard (Chrome 94+):

.fixed-element {
  position: fixed;
  bottom: calc(20px + env(keyboard-inset-height, 0px));
}
// Enable API behavior
if ("virtualKeyboard" in navigator) {
  navigator.virtualKeyboard.overlaysContent = true;
}

This API provides real keyboard height through CSS environment variables (keyboard-inset-*), allowing precise positioning[1].

Fallback Techniques

1. Viewport Resize Detection

const vv = window.visualViewport;
vv.addEventListener('resize', () => {
  const keyboardHeight = window.innerHeight - vv.height;
  document.documentElement.style.setProperty(
    '--keyboard-height', 
    `${keyboardHeight}px`
  );
});
.fixed-element {
  position: fixed;
  bottom: calc(20px + var(--keyboard-height, 0px));
}

Uses Visual Viewport API to track keyboard height changes[4].

2. Position Switching (Legacy iOS)

/* Default state */
.fixed-element {
  position: fixed;
  bottom: 0;
}

/* Keyboard active state */
.keyboard-active .fixed-element {
  position: absolute;
  bottom: var(--keyboard-height);
}
document.addEventListener('focusin', () => {
  document.body.classList.add('keyboard-active');
});

document.addEventListener('focusout', () => {
  document.body.classList.remove('keyboard-active');
});

Switches between fixed/absolute positioning during input interactions[2][6].

Layout Strategies

CSS Grid Approach

body {
  display: grid;
  height: 100dvh;
  grid-template-rows: 
    1fr 
    auto 
    env(keyboard-inset-height, 0px);
}

Reserves dedicated space for keyboard using modern viewport units[1].

Technique Pros Cons
VirtualKeyboard API Native solution, precise control Limited browser support
Visual Viewport Wider support Requires JS calculations
Position Switching Works on older iOS Layout shifts

For most implementations today, a combination of Visual Viewport detection with CSS custom properties provides the best cross-browser coverage while waiting for VirtualKeyboard API adoption[4][1]. When supporting legacy iOS versions (15+), position switching remains necessary for critical fixed elements like chat inputs[2][6].

Citations:


모바일 키보드 대응: 입력창 위치 조정 검토 필요

현재 inputContainerfixed 포지션으로 설정되어 있는데, 모바일 기기에서 가상 키보드가 활성화될 경우 입력창이 키보드에 가려질 수 있는 위험이 있습니다. 특히 iOS Safari에서 이러한 문제가 두드러지므로, 아래와 같은 대안 기법들을 검토해보시기 바랍니다.

  • VirtualKeyboard API 활용: 최신 브라우저(Chrome 94+ 등)에서는 CSS의 env(keyboard-inset-height)와 함께 VirtualKeyboard API를 사용할 수 있습니다.
  • Visual Viewport API 활용: JS로 뷰포트 리사이징 이벤트를 감지하여 키보드 높이를 계산하고, CSS 커스텀 프로퍼티를 적용하는 방법.
  • 포지션 전환 기법: iOS와 같은 환경에서는 조건에 따라 fixedabsolute 포지션을 전환하는 방식.

특히 iOS Safari에서의 동작 여부를 충분히 테스트한 후, 필요에 따라 위 대안들을 적용하여 입력창이 항상 올바르게 표시되도록 개선해 주세요.

src/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection.tsx (1)

13-19: Props 인터페이스가 잘 정의되어 있습니다.

필요한 모든 props가 명확하게 타입이 지정되어 있으며, 선택적 props도 적절하게 처리되어 있습니다.

src/constants/message.ts (1)

221-225: 댓글 관련 메시지가 적절하게 정의되어 있습니다.

사용자 친화적인 메시지가 잘 구성되어 있으며, 댓글 길이 제한도 적절하게 설정되어 있습니다.

src/App.tsx (1)

96-99: 모바일 대응이 적절하게 구현되어 있습니다.

isMobile 상태에 따라 적절한 컴포넌트를 렌더링하도록 구현되어 있습니다. 모바일과 데스크톱 사용자 모두에게 최적화된 경험을 제공할 수 있습니다.

src/assets/index.ts (1)

154-158: 모바일 UI 관련 에셋 추가가 적절합니다.

모바일 댓글 UI 구현을 위한 새로운 SVG 에셋들이 잘 추가되었습니다. 각 에셋의 이름이 용도를 명확하게 나타내고 있어 좋습니다.

Comment on lines 10 to 14
export const commentsWrapStyle = css({
marginTop: '444px',
borderTop: `10px solid ${color.GY[5]}`,
width: '100%',
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

고정된 상단 여백 사용에 대한 검토가 필요합니다.

marginTop: '444px'와 같은 고정된 값은 다양한 화면 크기에서 레이아웃 문제를 일으킬 수 있습니다.

다음과 같이 상대적인 값을 사용하는 것을 고려해보세요:

export const commentsWrapStyle = css({
-  marginTop: '444px',
+  marginTop: 'clamp(20px, 30vh, 444px)',
  borderTop: `10px solid ${color.GY[5]}`,
  width: '100%',
});
📝 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.

Suggested change
export const commentsWrapStyle = css({
marginTop: '444px',
borderTop: `10px solid ${color.GY[5]}`,
width: '100%',
});
export const commentsWrapStyle = css({
marginTop: 'clamp(20px, 30vh, 444px)',
borderTop: `10px solid ${color.GY[5]}`,
width: '100%',
});

Comment on lines 1 to 11
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useState } from 'react';
import { useLocation, useParams } from 'react-router-dom';
import MobileCommentsSection from '@/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection';
// import { useMemberQuery } from '@/hooks/api/member/useMemberQuery';
import { useTalkPickDetailQuery } from '@/hooks/api/talk-pick/useTalkPickDetailQuery';
// import { ToggleGroupItem } from '@/types/toggle';
import { useCommentsQuery } from '@/hooks/api/comment/useCommentsQuery';
import CommentInput from '@/components/mobile/atoms/CommentInput/CommentInput';
import { useCreateCommentMutation } from '@/hooks/api/comment/useCreateCommentMutation';
import * as S from './TalkPickMobilePage.style';
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

미사용 코드 정리 및 에러 처리 개선 필요

  1. 미사용 코드 주석 제거
  2. API 호출에 대한 에러 처리 추가 필요
-/* eslint-disable @typescript-eslint/no-unused-vars */
 import React, { useState } from 'react';
 import { useLocation, useParams } from 'react-router-dom';
 import MobileCommentsSection from '@/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection';
-// import { useMemberQuery } from '@/hooks/api/member/useMemberQuery';
 import { useTalkPickDetailQuery } from '@/hooks/api/talk-pick/useTalkPickDetailQuery';
-// import { ToggleGroupItem } from '@/types/toggle';
 import { useCommentsQuery } from '@/hooks/api/comment/useCommentsQuery';
📝 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.

Suggested change
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useState } from 'react';
import { useLocation, useParams } from 'react-router-dom';
import MobileCommentsSection from '@/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection';
// import { useMemberQuery } from '@/hooks/api/member/useMemberQuery';
import { useTalkPickDetailQuery } from '@/hooks/api/talk-pick/useTalkPickDetailQuery';
// import { ToggleGroupItem } from '@/types/toggle';
import { useCommentsQuery } from '@/hooks/api/comment/useCommentsQuery';
import CommentInput from '@/components/mobile/atoms/CommentInput/CommentInput';
import { useCreateCommentMutation } from '@/hooks/api/comment/useCreateCommentMutation';
import * as S from './TalkPickMobilePage.style';
import React, { useState } from 'react';
import { useLocation, useParams } from 'react-router-dom';
import MobileCommentsSection from '@/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection';
import { useTalkPickDetailQuery } from '@/hooks/api/talk-pick/useTalkPickDetailQuery';
import { useCommentsQuery } from '@/hooks/api/comment/useCommentsQuery';
import CommentInput from '@/components/mobile/atoms/CommentInput/CommentInput';
import { useCreateCommentMutation } from '@/hooks/api/comment/useCreateCommentMutation';
import * as S from './TalkPickMobilePage.style';

Copy link
Contributor

@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

🧹 Nitpick comments (7)
src/constants/message.ts (1)

221-226: 잘 구현된 댓글 관련 상수 정의입니다!

상수의 구조와 네이밍이 일관성 있게 잘 정의되어 있으며, 사용자 친화적인 메시지를 포함하고 있습니다.

문서화 제안

MAX_LENGTH와 MAX_SHORTEN_LENGTH의 용도를 주석으로 명확히 설명하면 좋을 것 같습니다.

다음과 같이 주석을 추가하는 것을 제안드립니다:

 export const COMMENT = {
   NO_COMMENTS_YET: '아직 댓글이 없어요',
   FIRST_COMMENT_SUGGESTION: '첫 댓글을 달아보는건 어때요?',
+  // 댓글의 최대 길이 제한
   MAX_LENGTH: 500,
+  // 모바일 화면에서 표시되는 댓글 미리보기의 최대 길이
   MAX_SHORTEN_LENGTH: 90,
 };
src/components/atoms/MoreButton/MoreButton.style.ts (1)

14-24: 모바일 반응형 스타일링 구현이 적절합니다.

미디어 쿼리를 통한 모바일 환경 대응이 잘 구현되어 있습니다. 'arrow' 아이콘과 기본 아이콘에 대해 각각 다른 타이포그래피와 간격을 적용한 것이 좋은 접근입니다.

다만, 다음 사항들을 고려해보시면 좋을 것 같습니다:

  • 매직 넘버인 430px을 상수로 분리하여 재사용성을 높이는 것을 고려해보세요.
  • 반복되는 color.GY[1] 스타일을 상위 스타일로 이동하는 것을 검토해보세요.
+const MOBILE_BREAKPOINT = '430px';
+
 export const moreButtonStyling = (icon: Required<MoreButtonProps>['icon']) =>
   css({
     ...typo.Main.Medium,
     display: 'flex',
     alignItems: 'center',
     gap: '7px',
     color: icon === 'plus' ? color.GY[1] : color.MAIN,
     cursor: 'pointer',
-    '@media (max-width: 430px)':
+    '@media (max-width: ${MOBILE_BREAKPOINT})': {
+      color: color.GY[1],
       icon === 'arrow'
         ? {
             ...typo.Mobile.Text.Medium_12,
-            color: color.GY[1],
             gap: '3px',
           }
         : {
             ...typo.Mobile.Text.SemiBold_14,
-            color: color.GY[1],
           },
+    }
   });
src/components/atoms/MoreButton/MoreButton.tsx (1)

15-22: 모바일 아이콘 분기 처리가 명확합니다.

size와 icon prop에 따른 조건부 렌더링이 잘 구현되어 있습니다. switch 문을 사용한 분기 처리가 가독성이 좋습니다.

다만, 다음과 같은 개선을 고려해보시면 좋을 것 같습니다:

  • 아이콘 매핑을 객체로 분리하여 switch 문을 제거하는 것을 고려해보세요.
+const SMALL_ICONS = {
+  arrow: MobileArrowDown,
+  plus: MoreSmall,
+} as const;
+
 const getIcon = () => {
   if (size === 'small') {
-    switch (icon) {
-      case 'arrow':
-        return <MobileArrowDown />;
-      default:
-        return <MoreSmall />;
-    }
+    const Icon = SMALL_ICONS[icon] || MoreSmall;
+    return <Icon />;
   }
   return icon === 'plus' ? <More /> : <MoreReply />;
 };
src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.style.ts (4)

10-12: 스타일 네이밍 컨벤션 개선 제안

myCommentColor는 배경색만 정의하고 있으므로, 더 명확한 의미를 전달하기 위해 myCommentBackgroundhighlightedCommentBackground와 같은 이름으로 변경하는 것이 좋을 것 같습니다.


25-41: 간격 값의 일관성 개선 필요

현재 gap 값이 8px3.5px로 일관성이 없습니다. 디자인 시스템의 일관성을 위해 간격 값을 표준화하는 것이 좋습니다. 가능하다면 4px의 배수를 사용하는 것을 추천드립니다.

 export const commentInfoWrapper = css({
   display: 'flex',
   flexDirection: 'column',
   width: '100%',
-  gap: '3.5px',
+  gap: '4px',
 });

54-62: 크로스 브라우저 호환성 고려 필요

텍스트 말줄임(...) 처리를 위해 webkit 전용 속성만 사용하고 있습니다. Firefox나 다른 브라우저에서의 호환성을 위해 대체 스타일을 추가하는 것이 좋습니다.

 export const commentTextWrapper = css({
   ...typo.Mobile.Text.Regular_14,
   display: '-webkit-box',
+  display: 'flex',
   width: '100%',
   '-webkit-line-clamp': 3,
   '-webkit-box-orient': 'vertical',
   overflow: 'hidden',
+  textOverflow: 'ellipsis',
   color: color.BK,
 });

64-66: 현대적인 레이아웃 방식 사용 제안

float 속성 대신 Flexbox나 Grid를 사용하여 더 안정적이고 현대적인 레이아웃을 구현하는 것을 추천드립니다.

 export const moreButtonWrapper = css({
-  float: 'right',
+  marginLeft: 'auto',
+  display: 'flex',
+  alignItems: 'center',
 });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d20217 and 622f2b4.

⛔ Files ignored due to path filters (1)
  • src/assets/svg/mobile-arrow-down.svg is excluded by !**/*.svg
📒 Files selected for processing (7)
  • src/assets/index.ts (1 hunks)
  • src/components/atoms/MoreButton/MoreButton.style.ts (1 hunks)
  • src/components/atoms/MoreButton/MoreButton.tsx (2 hunks)
  • src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.style.ts (1 hunks)
  • src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.tsx (1 hunks)
  • src/constants/message.ts (1 hunks)
  • src/pages/mobile/TalkPickMobilePage/TalkPickMobilePage.style.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/pages/mobile/TalkPickMobilePage/TalkPickMobilePage.style.ts
  • src/assets/index.ts
  • src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.tsx
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: storybook
  • GitHub Check: build
🔇 Additional comments (2)
src/components/atoms/MoreButton/MoreButton.tsx (1)

2-2: 아이콘 import 구문이 깔끔하게 정리되었습니다.

모든 아이콘을 한 줄로 import하여 코드가 간결해졌습니다.

src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.style.ts (1)

54-62: 데스크톱용 타이포그래피를 모바일용으로 변경 필요

이전 리뷰에서도 지적된 사항으로, 모바일 컴포넌트에서 데스크톱용 타이포그래피를 사용하고 있습니다.

 export const commentTextWrapper = css({
-  ...typo.Text.Regular,
+  ...typo.Mobile.Text.Regular_14,
   display: '-webkit-box',
   width: '100%',
   '-webkit-line-clamp': 3,
   '-webkit-box-orient': 'vertical',
   overflow: 'hidden',
   color: color.BK,
 });

Comment on lines +224 to +225
MAX_LENGTH: 500,
MAX_SHORTEN_LENGTH: 90,
Copy link
Collaborator

Choose a reason for hiding this comment

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

매직 넘버까지 constants에 표현한 점 좋습니다! 주로 텍스트 부분만 해당 디렉토리에 처리를 해왔었는데, 이 부분은 약간의 규칙성이 필요할 수도 있을 거 같아요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

약간 애매하긴합니다... 둘다 최대 길이이긴 해서 최대한 구분할 수 있도록 생각한건데... 좋은 상수명 있으신가요...

Copy link
Collaborator

Choose a reason for hiding this comment

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

아하 네이밍에 대한 코멘트가 아니라, 매직 넘버와 상수 데이터 에 대한 코멘트 였어요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

아...! 문장을 잘못 이해하고 있었네요ㅎ 매직 넘버도 상수처리하는게 좋을거 같긴한데 원준님 말씀대로 한두번쓰이는 숫자도 모두 상수에 포함해야할 지 아니면 비즈니스 로직과 직접적으로 연결된 것, 혹은 반복 사용 숫자만 상수화 하는 등의 규칙이 필요할 거 같긴하네요!

Copy link
Contributor

@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: 1

🧹 Nitpick comments (4)
src/hooks/comment/useCommentActions.ts (2)

9-10: 매개변수 타입 변경에 따른 안전한 속성 접근 구현

null 처리를 위해 옵셔널 체이닝과 널 병합 연산자를 사용한 것은 좋습니다. 하지만 타입 안전성을 더욱 강화할 수 있습니다.

-const id = commentData?.id ?? 0;
-const talkPickId = commentData?.talkPickId ?? 0;
-const content = commentData?.content ?? '';
-const myLike = commentData?.myLike ?? false;
+const { id = 0, talkPickId = 0, content = '', myLike = false } = commentData ?? {};

Also applies to: 17-20


60-68: 빈 함수 반환 시 타입 안전성 개선 필요

빈 함수를 반환할 때 타입 안전성을 보장하기 위해 반환 타입을 명시적으로 정의하는 것이 좋습니다.

+type CommentActions = {
+  handleEditSubmit: () => void;
+  handleDelete: () => void;
+  handleLikeToggle: () => void;
+  handleReport: () => void;
+};

if (!commentData) {
-  return {
+  return <CommentActions>{
    handleEditSubmit: () => {},
    handleDelete: () => {},
    handleLikeToggle: () => {},
    handleReport: () => {},
  };
}
src/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection.tsx (1)

59-69: 성능 최적화 필요

댓글 목록을 렌더링할 때 불필요한 리렌더링이 발생할 수 있습니다.

+const MemoizedMobileCommentItem = React.memo(MobileCommentItem);

{commentList?.content.map((commentData, idx) => (
- <MobileCommentItem
+ <MemoizedMobileCommentItem
    idx={idx}
    totalElements={commentList.totalElements}
    key={commentData.id}
    comment={commentData}
    selectedPage={selectedPage}
    talkPickWriter={talkPickWriter}
    onEditComment={onEditComment}
  />
))}
src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.tsx (1)

98-120: 메뉴 아이템 상수화 필요

메뉴 아이템 배열을 컴포넌트 외부로 분리하여 상수화하는 것이 좋습니다.

+const MY_COMMENT_MENU_ITEMS = [
+  {
+    label: '수정',
+    action: 'edit',
+  },
+  {
+    label: '삭제',
+    action: 'delete',
+  },
+] as const;
+
+const REPORT_MENU_ITEMS = [
+  {
+    label: '신고',
+    action: 'report',
+  },
+] as const;

-const myComment: MenuItem[] = [...]
-const reportComment: MenuItem[] = [...]
+const myComment = MY_COMMENT_MENU_ITEMS.map(item => ({
+  label: item.label,
+  onClick: () => {
+    if (item.action === 'edit') {
+      onEditComment(comment.id, comment.content);
+    } else if (item.action === 'delete') {
+      setActiveModal('deleteText');
+    }
+  },
+}));
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 622f2b4 and 0010410.

📒 Files selected for processing (7)
  • src/components/mobile/atoms/CommentInput/CommentInput.tsx (1 hunks)
  • src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.style.ts (1 hunks)
  • src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.tsx (1 hunks)
  • src/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection.style.ts (1 hunks)
  • src/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection.tsx (1 hunks)
  • src/hooks/comment/useCommentActions.ts (4 hunks)
  • src/pages/mobile/TalkPickMobilePage/TalkPickMobilePage.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/components/mobile/organisms/MobileCommentsSection/MobileCommentsSection.style.ts
  • src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.style.ts
  • src/pages/mobile/TalkPickMobilePage/TalkPickMobilePage.tsx
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: storybook
🔇 Additional comments (2)
src/components/mobile/atoms/CommentInput/CommentInput.tsx (1)

41-45: 입력값 유효성 검사 누락

공백 문자만 입력하는 경우나 최소 길이에 대한 검증이 필요합니다.

onChange={(e) => {
+ const value = e.target.value.trim();
+ if (!value) {
+   return;
+ }
- onCommentChange(e.target.value);
+ onCommentChange(value);
  handleInput();
}}
src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.tsx (1)

74-83: 답글 생성 에러 처리 누락

답글 생성 시 에러 처리가 되어있지 않습니다.

const { mutate: createReply } = useCreateReplyMutation(
  comment.talkPickId,
  comment.id,
  selectedPage,
+ {
+   onError: (error) => {
+     showToastModal('답글 작성에 실패했습니다.');
+     console.error('Reply creation failed:', error);
+   }
+ }
);

Copy link
Collaborator

@WonJuneKim WonJuneKim left a comment

Choose a reason for hiding this comment

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

수정된 부분까지 확인 완료했습니다! sonarcloud 이슈들만 해결되면 approve 드릴게요!

Copy link
Collaborator

@areumH areumH left a comment

Choose a reason for hiding this comment

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

댓글 관련 구현 수고 많으셨어요!!! api 연동 테스트 진행 후 머지하면 좋을 것 같아요~~
플로우 관련으로 질문 몇 개 남겼습니다!! 😊

Comment on lines +35 to +39
const { comments } = useCommentsQuery(
id,
{ page: currentPage - 1, size: 7 },
'comments',
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

페이지네이션이 사용되지 않는다고 했는데 사이즈를 7로 넘겨주는 이유가 있나요!??

Copy link
Collaborator

Choose a reason for hiding this comment

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

이 파일에 handleCommentPageChange 등 페이지네이션 관련 코드가 많은데 어떻게 사용되고 있는건지 궁금합니다!!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

먼저 늦은 답변 죄송합니다🥲 이 부분은 웹 페이지의 코드를 그대로 가져온거라... size에 대한 수정은 하지 않았습니다..! 그리고 모바일에서는 페이지네이션이 따로 없어서 api 호출 시 pageable 부분인 page와 size를 필수로 넣어서 호출해야하는지 궁금합니다 (스웨거에는 required라고 표시되어 있어서요)

Copy link
Collaborator

Choose a reason for hiding this comment

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

한번에 모든 데이터 배열을 받아올 수 있는지 백엔드에 질문이 필요할 듯 합니다..🥹
아님 다른 페이지처럼 무한 스크롤 처리를 하는 방식도 있겠네요..!!

Comment on lines 65 to 83
const [visibleReply, setVisibleReply] = useState<number>(10);
const [showReply, setShowReply] = useState(false);
const [replyValue, setReplyValue] = useState('');

const handleReplyToggle = () => {
setShowReply(!showReply);
setVisibleReply(10);
};

const { mutate: createReply } = useCreateReplyMutation(
comment.talkPickId,
comment.id,
selectedPage,
);

const handleReplyButton = () => {
createReply({ content: replyValue });
setReplyValue('');
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

위 답글 관련 기능은 해당 컴포넌트에서 사용되는 건가요??? 답글 쓰기에 답글이 보여지는 함수가 연결된 것 같아요..!!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

아뇨 추후에 사용될거 같아서 추가해둔건데 수정하였습니다!

Comment on lines +64 to +67
const handleEditComment = (commentId: number, content: string) => {
setEditCommentId(commentId);
setEditCommentText(content);
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

댓글 수정도 생성과 같은 input 컴포넌트를 사용하는 것 같은데 한번 댓글 수정을 눌렀을 땐 댓글 수정을 완료하기 전까진 댓글 생성 플로우로 돌아갈 수 없는 건가요?!??

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

넵 애초에 모바일에서 하단에 답글 수정 및 생성 관련 input 바가 고정으로 존재하는 거라 수정과 생성 모두 같은 컴포넌트에서 진행됩니다!

Copy link
Collaborator

Choose a reason for hiding this comment

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

피그마 확인해보니 댓글 수정 중일 때 텍스트 필드 외의 영역을 클릭하면 수정 모드가 해제된다고 되어있던데 이 부분도 구현된 상태인건지 궁금합니다,!! 안된 상태라면 useOutsideClick 훅을 사용하여 구현하면 편하고 좋을 것 같아요!!!

Comment on lines 106 to 109
label: '삭제',
onClick: () => {
setActiveModal('deleteText');
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

댓글 삭제 플로우 누락인걸까요!?? 😶

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

알고보니 MobileReportModal이 디자인이 생성되었더라구요..!! 그래서 추가 구현 완료하였습니다! 3d054b5

Copy link
Contributor

@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: 3

♻️ Duplicate comments (1)
src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.tsx (1)

86-89: 🛠️ Refactor suggestion

댓글 삭제 확인 과정 누락

댓글 삭제 시 사용자 확인 과정이 없습니다. 중요한 작업인 삭제는 실수로 클릭했을 때를 대비해 확인 과정이 필요합니다.

    {
      label: '삭제',
-     onClick: () => handleDelete(),
+     onClick: () => {
+       if (window.confirm('댓글을 삭제하시겠습니까?')) {
+         handleDelete();
+       }
+     },
    },
🧹 Nitpick comments (6)
src/components/mobile/molecules/MobileReportModal/MobileReportModal.tsx (2)

1-77: 신고 모달 기능이 잘 구현되었으나 접근성 개선이 필요합니다.

신고 사유 선택 및 제출 기능이 잘 구현되었습니다. 하지만 접근성 측면에서 개선이 필요합니다:

  1. 버튼에 aria 속성이 없어 스크린 리더 사용자를 위한 접근성이 부족합니다.
  2. 사유 선택 버튼들이 라디오 버튼 그룹으로 구현되면 더 의미론적으로 올바를 것 같습니다.

다음과 같이 수정하는 것을 권장합니다:

-        <div css={S.getButtonContainer(reportReason === '기타')}>
-          {reportOptions.map((option) => (
-            <button
-              type="button"
-              key={option.value}
-              css={S.reasonButton}
-              value={option.value}
-              onClick={handleReportReason}
-            >
-              {option.label}
-            </button>
-          ))}
-        </div>
+        <fieldset css={S.getButtonContainer(reportReason === '기타')}>
+          <legend css={S.srOnly}>신고 사유 선택</legend>
+          {reportOptions.map((option) => (
+            <button
+              type="button"
+              key={option.value}
+              css={[S.reasonButton, reportReason === option.value && S.selectedButton]}
+              value={option.value}
+              onClick={handleReportReason}
+              aria-pressed={reportReason === option.value}
+            >
+              {option.label}
+            </button>
+          ))}
+        </fieldset>

또한 '기타' 입력 필드에 레이블을 추가하는 것이 좋습니다:

        {reportReason === '기타' && (
+         <label htmlFor="otherReasonInput" css={S.srOnly}>
+           기타 신고 사유
+         </label>
          <input
+           id="otherReasonInput"
            css={S.reportInputStyling}
            placeholder="신고사유를 입력해주세요."
            onChange={handleOtherReportReason}
+           aria-required="true"
          />
        )}

스타일 파일에 시각적으로만 숨겨진 sr-only 클래스도 추가해야 합니다.


31-34: handleConfirm에 사용자 피드백 추가 필요

사용자가 신고를 제출했을 때 피드백이 부족합니다. 신고가 성공적으로 제출되었다는 알림이나 피드백이 있으면 좋을 것 같습니다.

  const handleConfirm = () => {
    if (!finalReportReason.trim()) return;
    onConfirm?.(finalReportReason);
+   // 신고가 성공적으로 제출되었다는 알림 표시
+   // 예: showToastModal('신고가 성공적으로 제출되었습니다.');
  };
src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.tsx (2)

74-77: 신고 처리 후 사용자 피드백 부족

신고 처리 후 사용자에게 피드백을 주는 로직이 부족합니다. 신고가 성공적으로 처리되었다는 정보를 사용자에게 제공하는 것이 좋습니다.

  const handleReportCommentButton = (reason: string) => {
    handleReport(reason);
    closeReportModal();
+   showToastModal('신고가 접수되었습니다.');
  };

52-54: isTalkPickWriter의 초기값 설정 필요

isTalkPickWriter 계산 시 talkPickWriter가 undefined일 경우 예기치 않은 동작이 발생할 수 있습니다. 안전한 접근을 위해 초기값 처리가 필요합니다.

  const isTalkPickWriter = useMemo(() => {
-   return comment?.nickname === talkPickWriter;
+   return !!comment?.nickname && !!talkPickWriter && comment.nickname === talkPickWriter;
  }, [comment?.nickname, talkPickWriter]);
src/components/mobile/molecules/MobileReportModal/MobileReportModal.style.ts (2)

20-20: 불필요한 빈 객체가 있습니다.

타이포그래피 스타일을 적용할 때 빈 객체 {}를 추가로 전달하는 것은 불필요합니다.

다음과 같이 간소화할 수 있습니다:

-export const titleStyle = css(typo.Main.SemiBold, {});
+export const titleStyle = css(typo.Main.SemiBold);

57-68: 제출 버튼의 고정 패딩 값이 반응형에 제한을 줄 수 있습니다.

padding: '9px 118.5px'와 같은 고정 값은 다양한 화면 크기에서 일관된 모습을 보장하지 못할 수 있습니다.

좀 더 반응형 접근 방식을 고려해보세요:

-  padding: '9px 118.5px',
+  padding: '9px 0',
+  height: '44px', /* 필요한 경우 고정 높이 지정 */

너비가 이미 100%로 설정되어 있으므로, 좌우 패딩 대신 텍스트를 중앙에 배치하는 것이 더 유연한 레이아웃에 도움이 됩니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d34d2e2 and 3d054b5.

⛔ Files ignored due to path filters (1)
  • src/assets/svg/mobile-report.svg is excluded by !**/*.svg
📒 Files selected for processing (8)
  • src/assets/index.ts (1 hunks)
  • src/components/mobile/atoms/Modal/Modal.style.ts (1 hunks)
  • src/components/mobile/atoms/Modal/Modal.tsx (1 hunks)
  • src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.style.ts (1 hunks)
  • src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.tsx (1 hunks)
  • src/components/mobile/molecules/MobileReportModal/MobileReportModal.style.ts (1 hunks)
  • src/components/mobile/molecules/MobileReportModal/MobileReportModal.tsx (1 hunks)
  • src/stories/mobile/molecules/MobileReportModal.stories.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/stories/mobile/molecules/MobileReportModal.stories.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/assets/index.ts
  • src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.style.ts
🔇 Additional comments (11)
src/components/mobile/atoms/Modal/Modal.style.ts (1)

30-32: 새로운 report 모달 스타일 적절하게 추가되었습니다.

코드 구조에 맞게 report 액션에 대한 스타일이 잘 추가되었습니다. 패딩 값이 다른 모달 스타일과 일관성 있게 적용되었습니다.

src/components/mobile/atoms/Modal/Modal.tsx (1)

8-8: Modal 컴포넌트 action 속성에 report 옵션 추가 확인.

ModalProps 인터페이스에 'report' 옵션이 추가되어 이전 파일에서 추가된 스타일과 일치하는 것을 확인했습니다.

src/components/mobile/molecules/MobileCommentItem/MobileCommentItem.tsx (3)

7-8: 미사용 코드(주석 처리된 임포트) 검토 필요

현재 주석 처리된 답글 관련 기능 임포트가 있습니다. 이는 아직 개발되지 않은 기능을 위한 것으로 보입니다. PR이 완료되면 이러한 주석 처리된 코드에 대한 계획을 명확히 하는 것이 좋습니다.

향후 릴리스에서 답글 기능을 구현할 계획이 있는지 확인해주세요. 계획이 없다면 이 주석 처리된 코드를 제거하는 것이 코드 가독성을 높일 수 있습니다.


48-50: 메모이제이션 로직이 적절합니다.

사용자 정보를 기반으로 한 isMyComment 계산에 useMemo를 사용한 것은 좋은 최적화입니다. 의존성 배열도 적절하게 설정되어 있습니다.


144-157: 미완성 답글 기능 UI 이슈

해당 PR 설명에 따르면 답글 기능은 아직 개발되지 않았다고 했는데, 현재 코드에서는 답글 버튼이 활성화되어 있고 handleReplyToggle 함수와 연결되어 있습니다. 하지만 상태 변경 후 실제로 보여지는 UI 요소가 없어 사용자에게 혼란을 줄 수 있습니다.

-              <button
-                type="button"
-                css={S.replyButton}
-                onClick={handleReplyToggle}
-              >
-                {comment.replyCount === 0 ? (
-                  '답글쓰기'
-                ) : (
-                  <>
-                    <MobileComment />
-                    <span>{comment.replyCount}</span>
-                  </>
-                )}
-              </button>
+              {/* TODO: 답글 기능 구현 시 활성화 */}
+              <div css={S.replyButtonPlaceholder}>
+                {comment.replyCount > 0 && (
+                  <>
+                    <MobileComment />
+                    <span>{comment.replyCount}</span>
+                  </>
+                )}
+              </div>

또는 아예 댓글 수만 표시하고 클릭 기능을 제거하는 방법도 고려해볼 수 있습니다.

src/components/mobile/molecules/MobileReportModal/MobileReportModal.style.ts (6)

1-4: 필요한 의존성이 적절히 임포트되어 있습니다.

임포트된 모듈들이 명확하게 구성되어 있으며, 스타일링에 필요한 필수 요소들이 포함되어 있습니다.


5-10: 모달의 기본 레이아웃이 적절히 설정되었습니다.

플렉스 레이아웃을 사용하여 모바일 화면에 적합한 세로 방향 및 중앙 정렬을 구현했습니다.


12-18: 타이틀 컨테이너 스타일이 잘 구성되어 있습니다.

플렉스 레이아웃을 사용한 중앙 정렬과 적절한 간격 설정이 되어 있습니다.


22-28: 동적 스타일링이 잘 구현되어 있습니다.

입력 필드의 가시성에 따라 마진이 달라지는 조건부 스타일링이 적절히 구현되어 있습니다.


46-55: 입력 필드 스타일이 명확하게 정의되어 있습니다.

너비, 패딩, 테두리 등의 스타일과 함께 플레이스홀더 색상도 적절히 설정되어 있습니다.


30-44:

Details

❓ Verification inconclusive

버튼 스타일이 상호작용에 따라 적절히 변경됩니다.

호버 시 배경색, 테두리, 텍스트 색상이 변경되는 효과가 잘 구현되어 있습니다.

다만, 색상 대비가 접근성 기준을 충족하는지 확인하는 것이 좋습니다.


🌐 Web query:

웹 접근성 WCAG 2.1 AA 레벨에서 요구하는 텍스트 색상 대비 기준은 무엇인가요?

💡 Result:

웹 접근성 지침인 WCAG 2.1 AA 레벨에서 요구하는 텍스트 색상 대비 기준은 다음과 같이 명시되어 있습니다.

일반 텍스트 기준

일반 텍스트(18pt 미만 또는 14pt 미만 굵은 글씨)의 경우 최소 4.5:1 명암비가 요구됩니다. 이는 시력이 약한 사용자나 색각 이상자가 콘텐츠를 명확히 인식할 수 있도록 보장하기 위한 최소 기준입니다[1][2][6].

예를 들어 흰색 배경(#FFFFFF)에 회색 계열 텍스트를 사용할 경우, AA 기준을 충족하려면 Gray-600 이상 색상이 필요합니다[1][5].

큰 텍스트 기준

다음 조건을 충족하는 텍스트는 최소 3:1 명암비를 적용할 수 있습니다:

  • 18pt 이상 크기의 일반 텍스트
  • 14pt 이상 굵은(Bold) 텍스트[3][4][6]

이 기준은 텍스트가 클수록 가독성이 높아지기 때문에 완화된 수치를 적용한 것으로, Material Design 등 주요 디자인 시스템에서도 동일한 원칙을 사용합니다[1][3].

예외 사항

  • 로고 타입: 브랜드 로고의 텍스트는 대비 기준 적용에서 제외됩니다[9].
  • 비활성 텍스트(Gray-500 등): 플레이스홀더나 비활성화된 텍스트는 4.5:1 미만 대비 사용이 허용되지만, 기능적 비활성 상태를 명확히 표시해야 합니다[1][5].

검증 도구

명암비 검증을 위해 Coolors Contrast CheckerAccessibleWeb Color Contrast Checker 같은 도구를 활용할 수 있으며, 이들 도구는 WCAG AA/AAA 기준에 대한 Pass/Fail 결과를 즉시 확인할 수 있게 해줍니다[1][2].

이 기준들은 20/40 시력을 가진 사용자의 인식 능력을 보상하기 위해 수학적 계산(L*=0.2126R + 0.7152G + 0.0722*B)으로 도출되었으며, 전 세계 2억 2천만 명 이상의 시각 장애인이 웹 콘텐츠에 접근할 수 있도록 지원합니다[2][6].

Citations:


버튼 호버 효과 및 접근성 대비 검토 요청

현재 버튼의 호버 상태에서 배경색, 테두리, 텍스트 색상이 의도대로 변경되어 인터랙션 효과가 잘 구현되어 있습니다.
다만, 사용 중인 색상들이 웹 접근성 WCAG 2.1 AA 기준을 충족하는지 확인해 주시기 바랍니다.
구체적으로, 일반 텍스트의 경우 최소 명암비는 4.5:1, 큰 텍스트나 굵은 텍스트(18pt 미만 또는 14pt 미만 굵은)의 경우 3:1 이상의 명암비가 요구됩니다.
해당 기준에 맞게 색상 대비를 한 번 더 점검해 주시면 감사하겠습니다.

Comment on lines +119 to +121
{idx === 0 && totalElements === 1 && (
<CategoryBarChip size="extraSmall">첫댓글</CategoryBarChip>
)}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

첫 댓글 확인 로직 개선 필요

현재 첫 댓글 체크 로직은 idx === 0 && totalElements === 1로 되어 있어, 댓글이 딱 하나만 있을 때만 첫 댓글로 표시됩니다. 댓글 수와 상관없이 첫 번째 댓글임을 표시하려면 idx === 0만 확인하는 것이 맞습니다.

-               {idx === 0 && totalElements === 1 && (
+               {idx === 0 && (
                  <CategoryBarChip size="extraSmall">첫댓글</CategoryBarChip>
                )}
📝 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.

Suggested change
{idx === 0 && totalElements === 1 && (
<CategoryBarChip size="extraSmall">첫댓글</CategoryBarChip>
)}
{idx === 0 && (
<CategoryBarChip size="extraSmall">첫댓글</CategoryBarChip>
)}

Comment on lines +65 to +68
const isLongText = comment?.content.length > COMMENT.MAX_SHORTEN_LENGTH;
const shortenContent = isExpanded
? comment?.content
: `${comment?.content.slice(0, COMMENT.MAX_SHORTEN_LENGTH)}...`;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

텍스트 처리에 안전성 개선 필요

comment.content가 null이거나 undefined일 경우 런타임 오류가 발생할 수 있습니다. 안전한 접근을 위해 옵셔널 체이닝과 기본값 처리가 필요합니다.

-  const isLongText = comment?.content.length > COMMENT.MAX_SHORTEN_LENGTH;
-  const shortenContent = isExpanded
-    ? comment?.content
-    : `${comment?.content.slice(0, COMMENT.MAX_SHORTEN_LENGTH)}...`;
+  const contentText = comment?.content || '';
+  const isLongText = contentText.length > COMMENT.MAX_SHORTEN_LENGTH;
+  const shortenContent = isExpanded
+    ? contentText
+    : isLongText ? `${contentText.slice(0, COMMENT.MAX_SHORTEN_LENGTH)}...` : contentText;
📝 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.

Suggested change
const isLongText = comment?.content.length > COMMENT.MAX_SHORTEN_LENGTH;
const shortenContent = isExpanded
? comment?.content
: `${comment?.content.slice(0, COMMENT.MAX_SHORTEN_LENGTH)}...`;
const contentText = comment?.content || '';
const isLongText = contentText.length > COMMENT.MAX_SHORTEN_LENGTH;
const shortenContent = isExpanded
? contentText
: isLongText ? `${contentText.slice(0, COMMENT.MAX_SHORTEN_LENGTH)}...` : contentText;

Comment on lines +40 to +46
const { handleDelete, handleLikeToggle, handleReport } = useCommentActions(
comment,
comment.content,
selectedPage,
() => {},
showToastModal,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

useCommentActions 콜백 함수 개선 필요

useCommentActions 훅에 빈 콜백 함수(() => {})를 전달하고 있습니다. 이는 좋은 패턴이 아니며, 명확한 목적을 가진 함수를 전달하거나 필요한 경우 인터페이스를 수정하는 것이 좋습니다.

  const { handleDelete, handleLikeToggle, handleReport } = useCommentActions(
    comment,
    comment.content,
    selectedPage,
-   () => {},
+   // 이 콜백의 목적에 맞는 함수를 구현하거나
+   // 필요 없다면 useCommentActions 훅을 수정하여 옵셔널하게 만드는 것이 좋습니다
    showToastModal,
  );

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Contributor

@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: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d054b5 and e29ff66.

⛔ Files ignored due to path filters (1)
  • src/assets/svg/mobile-report.svg is excluded by !**/*.svg
📒 Files selected for processing (3)
  • src/App.tsx (2 hunks)
  • src/assets/index.ts (1 hunks)
  • src/constants/message.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/App.tsx
  • src/constants/message.ts
🧰 Additional context used
🪛 ESLint
src/assets/index.ts

[error] 160-160: Multiple exports of name 'MobileReport'.

(import/export)

🪛 GitHub Actions: build
src/assets/index.ts

[error] 161-161: Module parse failed: Duplicate export 'MobileReport'.

🔇 Additional comments (1)
src/assets/index.ts (1)

154-159: 모바일 UI 구현을 위한 새로운 아이콘 추가가 잘 되었습니다.

PR 목표와 일치하는 모바일 댓글 UI 구현을 위한 필요한 아이콘들이 적절하게 추가되었습니다. 특히 MobileComment, MobileLikeButtonDF, MobileLikeButtonPR 등은 모바일 환경에서 사용자 상호작용 개선에 도움이 될 것입니다.

Comment on lines 160 to 161
export { default as MobileReport } from './svg/mobile-report.svg';
export { default as MobileReport } from './svg/mobile-report.svg';
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

중복된 MobileReport 익스포트를 수정해야 합니다.

동일한 이름의 MobileReport 익스포트가 두 번 선언되었습니다. 이로 인해 빌드 파이프라인 오류가 발생하고 있습니다.

다음과 같이 중복된 익스포트를 제거해주세요:

export { default as MobileReport } from './svg/mobile-report.svg';
-export { default as MobileReport } from './svg/mobile-report.svg';
📝 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.

Suggested change
export { default as MobileReport } from './svg/mobile-report.svg';
export { default as MobileReport } from './svg/mobile-report.svg';
export { default as MobileReport } from './svg/mobile-report.svg';
🧰 Tools
🪛 ESLint

[error] 160-160: Multiple exports of name 'MobileReport'.

(import/export)


[error] 161-161: Multiple exports of name 'MobileReport'.

(import/export)

🪛 GitHub Actions: build

[error] 161-161: Module parse failed: Duplicate export 'MobileReport'.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 5, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
9 New issues

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

모바일 톡픽 상세 조회 페이지 댓글 UI 및 기능 구현

4 participants