-
Notifications
You must be signed in to change notification settings - Fork 3
feat: 모바일 마이페이지 구현 #311
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
base: dev
Are you sure you want to change the base?
feat: 모바일 마이페이지 구현 #311
Conversation
Walkthrough이번 PR은 모바일 환경에 특화된 라우팅 로직과 UI 개선을 도입합니다. App 컴포넌트에서 모바일 기기 여부를 확인하여 MyMobilePage를 렌더링하며, 데스크탑에서는 기존의 MyPage와 하위 라우트를 유지합니다. 또한, 신규 자산 추가, 여러 컴포넌트의 타입 및 스타일 업데이트, 스토리북 예제 보강, 그리고 API 훅 함수 시그니처 개선을 포함하여 기존 코드베이스의 구조적 안전성과 유연성을 향상시켰습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant U as 사용자
participant A as App 컴포넌트
participant M as MyMobilePage
participant D as MyPage
U->>A: 페이지 요청
A->>A: isMobile 여부 확인
alt 모바일 기기
A->>M: MyMobilePage 렌더링 (/MYPAGE 경로)
else 데스크탑
A->>D: MyPage 및 하위 라우트 렌더링 (talkpick, balancegame)
end
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Tip ⚡🧪 Multi-step agentic review comment chat (experimental)
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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
🔭 Outside diff range comments (1)
src/App.tsx (1)
162-164:⚠️ Potential issue조건부 연산자 사용 오류가 있습니다.
-{isMobile ?? ( // TODO: 404페이지 생성시 조건부로 수정 +{isMobile && ( // TODO: 404페이지 생성시 조건부로 수정 <Route path={PATH.NOTIFICATION} element={<NotificationPage />} /> )}여기서는
??연산자(널 병합 연산자) 대신&&연산자(논리 AND)를 사용해야 합니다. 널 병합 연산자는 왼쪽 피연산자가 null이나 undefined일 때 오른쪽 피연산자를 반환하는데, 이 경우에는 isMobile이 true일 때만 NotificationPage를 렌더링하는 논리가 필요합니다.
🧹 Nitpick comments (8)
src/hooks/api/mypages/useMyTalkPickCommentsQuery.ts (1)
11-30: 훅 함수의 일관된 개선이 이루어졌습니다!다른 훅들과 마찬가지로
options매개변수를 추가하여 쿼리 실행의 유연성을 높였습니다. 이는 특히 모바일 환경에서 조건부 쿼리 실행에 유용할 것입니다.한 가지 제안: 이러한 옵션의 사용 목적과 가능한 값들에 대한 간단한 문서화(JSDoc 등)를 추가하면 미래의 개발자들이 이 훅을 더 쉽게 이해하고 활용할 수 있을 것입니다.
src/hooks/api/mypages/useMyGameWrittensQuery.ts (1)
12-37: 모든 마이페이지 훅에 일관된 개선이 완료되었습니다!다른 훅들과 마찬가지로
options매개변수를 추가하여 무한 스크롤 기능의 유연성을 높였습니다. 이러한 일관된 변경은 PR 목표인 "마이페이지를 위한 무한 스크롤 기능 재설계"를 효과적으로 지원합니다.추가 제안: 이러한 옵션 처리가 올바르게 작동하는지 확인하는 단위 테스트를 추가하면 좋을 것 같습니다. 특히
enabled옵션이 모바일 환경에서 조건부 쿼리 실행에 어떻게 영향을 미치는지 테스트하면 유용할 것입니다.src/components/mobile/organisms/BalanceGameSection/BalanceGameSection.tsx (4)
13-13: 경로 표기 오류가 발견되었습니다.-import Button from '@/components/mobile//atoms/Button/Button'; +import Button from '@/components/mobile/atoms/Button/Button';이중 슬래시('//')가 경로에 있습니다. 경로 표기법을 일관되게 유지하려면 수정이 필요합니다.
14-14: 경로 표기 오류가 발견되었습니다.-import IconButton from '@/components/mobile//atoms/IconButton/IconButton'; +import IconButton from '@/components/mobile/atoms/IconButton/IconButton';이중 슬래시('//')가 경로에 있습니다. 경로 표기법을 일관되게 유지하려면 수정이 필요합니다.
15-16: 경로 표기 오류가 발견되었습니다.-import GameTag from '@/components/mobile//atoms/GameTag/GameTag'; -import GameTagChip from '@/components/mobile//atoms/GameTagChip/GameTagChip'; +import GameTag from '@/components/mobile/atoms/GameTag/GameTag'; +import GameTagChip from '@/components/mobile/atoms/GameTagChip/GameTagChip';이중 슬래시('//')가 경로에 있습니다. 경로 표기법을 일관되게 유지하려면 수정이 필요합니다.
17-17: 경로 표기 오류가 발견되었습니다.-import GameStageLabel from '@/components/mobile//atoms/GameStageLabel/GameStageLabel'; +import GameStageLabel from '@/components/mobile/atoms/GameStageLabel/GameStageLabel';이중 슬래시('//')가 경로에 있습니다. 경로 표기법을 일관되게 유지하려면 수정이 필요합니다.
src/components/mobile/organisms/DateGroupedCard/DateGroupedCard.style.ts (1)
5-11: containerStyle 정의가 적절합니다.컨테이너 스타일이 명확하게 정의되어 있습니다. 다만, 고정 너비(333px)를 사용하고 있어 다양한 모바일 화면 크기에 대응하기 어려울 수 있습니다. 반응형 디자인을 위해 상대적인 단위(%, rem 등)나 min/max-width 속성을 고려해 보세요.
export const containerStyle = css({ display: 'flex', flexDirection: 'column', - width: '333px', + width: '100%', + maxWidth: '333px', border: 'none', backgroundColor: color.WT, });src/components/mobile/organisms/DateGroupedCard/DateGroupedCard.stories.tsx (1)
68-115: All 스토리 구성 및 다양한 상황 테스트All 스토리에서는 여러 날짜와 콘텐츠 항목을 가진 DateGroupedCard 컴포넌트들을 렌더링하여 다양한 상황을 테스트할 수 있도록 구성되어 있습니다. 각 항목의 onClick 이벤트 핸들러가 console.log를 사용하여 디버깅하기 쉽게 설정되어 있습니다.
다만, 실제 앱에서는 console.log 대신 적절한 이벤트 핸들링 로직으로 대체해야 합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
src/assets/images/my-card-sample-first.pngis excluded by!**/*.pngsrc/assets/images/my-card-sample-second.pngis excluded by!**/*.pngsrc/assets/svg/smile-emoji.svgis excluded by!**/*.svg
📒 Files selected for processing (33)
src/App.tsx(2 hunks)src/assets/index.ts(1 hunks)src/components/atoms/MenuTap/MenuTap.style.ts(1 hunks)src/components/atoms/MenuTap/MenuTap.tsx(1 hunks)src/components/mobile/molecules/ProfileListItem/ProfileListItem.stories.tsx(3 hunks)src/components/mobile/molecules/ProfileListItem/ProfileListItem.tsx(1 hunks)src/components/mobile/organisms/BalanceGameSection/BalanceGameSection.tsx(1 hunks)src/components/mobile/organisms/DateGroupedCard/DateGroupedCard.stories.tsx(1 hunks)src/components/mobile/organisms/DateGroupedCard/DateGroupedCard.style.ts(1 hunks)src/components/mobile/organisms/DateGroupedCard/DateGroupedCard.tsx(1 hunks)src/components/mobile/organisms/DateGroupedList/DateGroupedList.tsx(2 hunks)src/components/mobile/organisms/IconButtonArea/IconButtonArea.tsx(2 hunks)src/components/mobile/organisms/ProfileInfoCard/ProfileInfoCard.stories.tsx(3 hunks)src/components/mobile/organisms/ProfileInfoCard/ProfileInfoCard.tsx(2 hunks)src/components/mobile/organisms/TalkPickSection/TalkPickSection.tsx(1 hunks)src/components/molecules/CommentItem/CommentItem.tsx(2 hunks)src/components/molecules/ContentsButton/ContentsButton.tsx(1 hunks)src/components/molecules/ReplyItem/ReplyItem.tsx(1 hunks)src/components/organisms/BalanceGameSection/BalanceGameSection.tsx(1 hunks)src/components/organisms/TalkPickSection/TalkPickSection.tsx(1 hunks)src/hooks/api/mypages/useInfiniteScroll.ts(1 hunks)src/hooks/api/mypages/useMyGameBookmarksQuery.ts(1 hunks)src/hooks/api/mypages/useMyGameVotesQuery.ts(1 hunks)src/hooks/api/mypages/useMyGameWrittensQuery.ts(1 hunks)src/hooks/api/mypages/useMyTalkPickBookmarksQuery.ts(1 hunks)src/hooks/api/mypages/useMyTalkPickCommentsQuery.ts(1 hunks)src/hooks/api/mypages/useMyTalkPickVotesQuery.ts(1 hunks)src/hooks/api/mypages/useMyTalkPickWrittensQuery.ts(1 hunks)src/layout/layout.tsx(1 hunks)src/pages/mobile/MyMobilePage/MyMobilePage.style.ts(1 hunks)src/pages/mobile/MyMobilePage/MyMobilePage.tsx(1 hunks)src/stories/atoms/MenuTap.stories.tsx(1 hunks)src/types/mypages.ts(4 hunks)
🔇 Additional comments (73)
src/hooks/api/mypages/useMyGameBookmarksQuery.ts (1)
12-37: 훅 함수의 유연성이 향상되었습니다!
options매개변수를 추가함으로써 모바일 환경에서의 조건부 쿼리 실행이 가능해졌습니다.useInfiniteScroll의 옵션을 직접 전달할 수 있어 재사용성과 확장성이 크게 향상되었습니다. 특히 TypeScript의Parameters유틸리티 타입을 활용하여 타입 안전성을 유지한 점이 좋습니다.src/hooks/api/mypages/useMyTalkPickBookmarksQuery.ts (1)
11-33: 일관된 패턴으로 훅 함수가 개선되었습니다!이전 파일과 동일한 패턴으로
options매개변수를 추가하여 모바일 환경에서의 유연한 쿼리 실행이 가능해졌습니다. 모든 마이페이지 관련 훅에 일관된 패턴을 적용함으로써 코드 베이스의 일관성과 예측 가능성이 향상되었습니다. 직접 반환 방식으로 코드가 더 간결해진 점도 좋은 개선사항입니다.src/hooks/api/mypages/useMyTalkPickVotesQuery.ts (1)
11-32: 유연성 향상을 위한 훅 수정 👍이 변경은
useMyTalkPickVotesQuery훅에 옵션 매개변수를 추가하여 호출 시 더 많은 유연성을 제공합니다. 타입 안전성도 적절히 유지하면서 모바일 페이지에 필요한 조건부 쿼리 실행을 가능하게 해줍니다.아래와 같은 장점이 있습니다:
enabled같은 옵션을 전달할 수 있어 모바일 특화 로직 구현이 가능해졌습니다- 코드 구조 간소화로 가독성이 향상되었습니다
- 명시적 타입 정의로 타입 안전성이 강화되었습니다
PR 목표에 맞게 잘 구현되었습니다.
src/hooks/api/mypages/useMyGameVotesQuery.ts (1)
11-33: 유연한 옵션 처리를 위한 훅 개선 👍
useMyGameVotesQuery함수에 옵션 매개변수를 추가하여 모바일 마이페이지에서 필요한 조건부 쿼리 기능을 지원하도록 개선되었습니다.개선된 부분:
as const어서션을 사용하여 쿼리 키의 타입 안전성 향상- 간결해진 코드 구조로 가독성 향상
- 유연한 옵션 처리로 모바일 환경에서의 쿼리 활성화 조건 지정 가능
이러한 변경사항은 PR 목표인 "모바일 환경을 위한 쿼리 구조 수정"에 잘 부합합니다.
src/hooks/api/mypages/useMyTalkPickWrittensQuery.ts (1)
11-32: 훅 인터페이스 개선 및 유연성 향상 👍
useMyTalkPickWrittensQuery함수가 옵션 매개변수를 받도록 수정되어 모바일 마이페이지 구현에 필요한 유연성을 제공합니다.개선된 점:
- 조건부 쿼리 실행을 위한
enabled옵션 등을 전달할 수 있는 유연한 인터페이스- 타입 안전성 유지
- 일관된 코드 패턴으로 유지보수성 향상
이 변경사항은 PR 목표인 "모바일 마이페이지를 위한 커스텀 훅 조정 및 무한 스크롤 재설계"에 잘 부합합니다.
src/hooks/api/mypages/useInfiniteScroll.ts (5)
1-6: 필요한 의존성만 가져오도록 import 구문 개선 👍필요한 타입과 함수들을 명시적으로 import하도록 변경되었습니다. 이는 코드의 의도를 명확히 하고 번들 크기 최적화에도 도움이 됩니다.
14-21: 유연한 옵션 처리를 위한 타입 정의 추가 👍
MyInfiniteUserOptions타입 정의를 통해 커스텀 옵션 처리가 가능해졌습니다.Omit을 사용하여 내부에서 이미 설정하는 필드들을 제외함으로써 충돌을 방지한 것이 좋습니다.이 타입 정의는 모바일 마이페이지의 조건부 쿼리 실행에 필요한
enabled속성을 전달할 수 있는 기반을 마련합니다.
23-29: 명확한 문서화 👍함수의 매개변수와 반환 값에 대한 자세한 설명을 추가한 것이 좋습니다. 특히 새로 추가된
options매개변수의 역할과 사용법을 명확히 설명하여 다른 개발자들이 이 함수를 사용할 때 도움이 될 것입니다.
34-38: 함수 매개변수 개선 👍주요 개선 사항:
queryKey를readonly string[]로 변경하여 불변성 보장queryFn의 매개변수 타입을 더 명확하게 정의- 새로운
options매개변수 추가로 유연성 향상- 반환 타입을 명시적으로 선언하여 타입 안전성 강화
이러한 변경사항은 코드의 안정성과 유연성을 함께 향상시킵니다.
39-51: 구현 로직 개선 👍함수 구현이 다음과 같이 개선되었습니다:
useInfiniteQuery에 객체 매개변수 패턴 사용pageParam타입 체크 로직 추가로 타입 안전성 강화- 사용자 정의 옵션을 스프레드 연산자로 전달하여 유연성 제공
이러한 변경사항은 모바일 마이페이지에서 필요한 조건부 쿼리 실행을 지원하며, PR 목표인 "무한 스크롤 재설계"에 잘 부합합니다.
src/components/molecules/ContentsButton/ContentsButton.tsx (1)
20-20: 속성 변경이 적절하게 처리되었습니다.
images속성을 선택적으로 변경한 것은 좋은 개선입니다. 컴포넌트가 이미지 없이도 사용할 수 있게 되었고, 이미 58-63번 라인에서images가 없거나 비어있을 때memoizedRandomPair로 대체하는 로직이 있어 문제없이 작동할 것입니다.src/layout/layout.tsx (1)
63-65: 모바일 레이아웃 개선이 잘 적용되었습니다.모바일 화면(430px 이하)에서 상단 패딩을 55px로 설정하는 미디어 쿼리가 추가되었습니다. 이는
Layout과LayoutNoSearch컴포넌트에 이미 적용된 것과 일관성을 유지하며, 모바일 기기에서의 사용자 경험을 향상시킵니다.src/components/molecules/CommentItem/CommentItem.tsx (2)
104-119: 메뉴 아이템에 고유 ID 추가 적용이 잘 되었습니다.각 메뉴 아이템에
id속성을 추가한 것은 컴포넌트의 안정성을 높이는 좋은 변경입니다. 이는 React의 렌더링 최적화와 키 관리에 도움이 되며, MenuTap 컴포넌트와의 일관성을 유지합니다.
121-129: reportComment 배열의 메뉴 아이템에도 ID 추가가 잘 적용되었습니다.신고 메뉴 아이템에도 동일하게
id속성이 추가되어 일관성 있게 적용되었습니다. 이는 MenuTap 컴포넌트의 요구사항에 맞게 수정된 것으로 보입니다.src/components/atoms/MenuTap/MenuTap.style.ts (1)
17-28: 메뉴 스타일링 개선이 잘 이루어졌습니다.메뉴의 너비를 고정값 대신
max-content로 변경하고 최소 너비(minWidth)를 설정한 것은 유연성을 높이는 좋은 개선입니다. 이제 메뉴 항목의 텍스트 길이에 따라 너비가 자동으로 조정되면서도 최소한의 너비를 유지할 수 있게 되었습니다. 이는 특히 다국어 지원이나 다양한 길이의 텍스트를 표시해야 할 때 유용합니다.src/components/molecules/ReplyItem/ReplyItem.tsx (2)
75-90: MenuTap 구조 개선을 위한 id 속성 추가가 잘 되었습니다.각 메뉴 아이템에 고유한 id 값을 추가하여 컴포넌트 구조가 더 일관되고 명확해졌습니다. 이는 React 렌더링 최적화에도 도움이 됩니다.
92-100: 신고 메뉴 아이템에도 id 속성이 잘 추가되었습니다.신고 관련 메뉴 아이템에도 id 속성이 추가되어 일관된 구조를 유지하고 있습니다.
src/assets/index.ts (1)
156-158: 모바일 마이페이지에 필요한 에셋들이 잘 추가되었습니다.
MobileCardSampleFirst,MobileCardSampleSecond,SmileEmoji등 모바일 마이페이지 구현에 필요한 에셋들이 적절하게 추가되었습니다. 에셋 이름이 용도를 명확하게 나타내고 있어 좋습니다.src/components/mobile/organisms/DateGroupedCard/DateGroupedCard.tsx (3)
1-6: 적절한 임포트 구성입니다.필요한 컴포넌트와 스타일을 깔끔하게 임포트하고 있습니다.
7-10: 명확한 인터페이스 정의가 잘 되었습니다.DateGroupedCardProps 인터페이스가 간결하고 명확하게 정의되어 있습니다.
date와items속성의 타입이 적절하게 정의되어 있습니다.
12-23: 간결하고 효율적인 컴포넌트 구현입니다.화살표 함수와 암시적 반환을 활용하여 코드가 간결하며, 컴포넌트 내부에서 items를 map을 사용해 효율적으로 렌더링하고 있습니다. key 값으로 id를 사용한 것도 적절합니다.
src/components/mobile/organisms/ProfileInfoCard/ProfileInfoCard.stories.tsx (2)
38-51: Default 스토리에 id 속성이 잘 추가되었습니다.메뉴 아이템에 id 속성을 추가하여 MenuTap 컴포넌트의 변경사항에 맞게 적절히 수정되었습니다.
64-87: All 스토리의 메뉴 아이템에도 id 속성이 잘 추가되었습니다.여러 ProfileInfoCard 컴포넌트의 메뉴 아이템에 고유한 id 값(0, 1)을 부여하여 구조적으로 일관성을 유지하고 있습니다.
src/components/mobile/organisms/ProfileInfoCard/ProfileInfoCard.tsx (1)
1-1: MenuTap 컴포넌트와의 일관성을 유지하기 위한 타입 변경을 확인했습니다.MenuData 타입에 id 속성을 추가하고 label을 ReactNode로 변경한 것은 모바일 마이페이지에서 더 유연한 메뉴 아이템 표현을 가능하게 합니다.
Also applies to: 13-13
src/components/organisms/BalanceGameSection/BalanceGameSection.tsx (1)
134-140: 메뉴 아이템에 id 속성이 추가되었습니다.MenuTap 컴포넌트와 일관성을 유지하기 위해 myGameItem 및 otherGameItem에 id 속성을 적절히 추가했습니다. 이는 메뉴 아이템을 구별하는 데 도움이 되며, 컴포넌트 렌더링 시 키(key) 속성으로 활용할 수 있습니다.
src/components/mobile/organisms/BalanceGameSection/BalanceGameSection.tsx (1)
133-157: 모바일용 BalanceGameSection에 메뉴 아이템 id 속성이 적용되었습니다.마찬가지로 모바일 버전의 MenuItem 배열에도 id 속성이 추가되었습니다. 각 메뉴 아이템에 고유 식별자를 추가하여 컴포넌트의 유지보수성과 일관성이 향상되었습니다.
src/App.tsx (1)
22-22: 모바일 환경에 맞춘 라우팅 처리가 적절히 구현되었습니다.isMobile 상태에 따라 MyMobilePage와 MyPage 컴포넌트를 조건부로 렌더링하는 구조는 모바일 사용자 경험을 최적화하는 좋은 접근법입니다. 각 환경에 맞는 UI를 제공하면서도 기존 로직을 유지하고 있습니다.
Also applies to: 123-140
src/components/mobile/molecules/ProfileListItem/ProfileListItem.tsx (3)
14-28: 랜덤 이미지 구현이 잘 되었습니다.프로필 이미지가 없을 때 랜덤 이미지를 표시하는 기능이 잘 구현되었습니다.
useMemo를 활용하여 불필요한 재계산을 방지한 점이 좋습니다.
30-35: 인터페이스 수정이 적절하게 이루어졌습니다.
imgUrl을 선택적으로 변경하고to속성을 추가한 것은 컴포넌트의 유연성을 향상시키는 좋은 변경사항입니다. 라우팅 기능을 위한 준비가 잘 되어있습니다.
37-54: Link 컴포넌트 활용이 적절합니다.기존 div에서 Link 컴포넌트로 변경하여 라우팅 기능을 추가한 것은 좋은 접근법입니다. 랜덤 이미지 기능과 함께 사용자 경험을 개선하는 데 도움이 됩니다.
src/components/atoms/MenuTap/MenuTap.tsx (2)
10-14: MenuItem 타입 개선이 적절합니다.
id속성을 필수로 추가하고label을 ReactNode 타입으로 변경한 것은 좋은 개선점입니다. 이렇게 하면 메뉴 아이템에 더 다양한 컨텐츠를 표시할 수 있고, 고유한 식별자를 통해 안정적인 렌더링이 가능해집니다.
44-53: key 속성 사용이 개선되었습니다.메뉴 아이템의 key로
label대신id를 사용하는 것은 React의 권장 사항에 맞는 좋은 변경입니다. 고유한 ID를 사용함으로써 리렌더링 시 성능과 안정성이 향상됩니다.src/components/mobile/organisms/DateGroupedList/DateGroupedList.tsx (2)
5-9: imgUrl 속성을 선택적으로 변경한 것이 적절합니다.
DateGroupedListItem인터페이스에서imgUrl을 선택적 속성으로 변경한 것은ProfileListItem컴포넌트의 변경사항과 일관성을 유지하는 좋은 접근법입니다.
22-26: ProfileListItem에 to 속성 추가가 적절합니다.
ProfileListItem컴포넌트에to속성을 추가하여 item의 id를 기반으로 TalkPick 페이지로 이동하는 기능을 구현한 것은 좋은 UX 개선입니다.src/components/mobile/organisms/DateGroupedCard/DateGroupedCard.style.ts (2)
18-25: listStyle의 그리드 레이아웃이 적절합니다.그리드 레이아웃을 사용하여 항목을 2열로 표시하는 것은 모바일 UI에 적합한 접근법입니다.
27-27: 빈 listItemStyle에 대한 검토가 필요합니다.
listItemStyle이 정의되어 있지만 내용이 비어있습니다. 향후 사용을 위한 것인지, 아니면 불필요한 코드인지 확인해 보세요. 불필요하다면 제거하는 것이 좋습니다.src/types/mypages.ts (3)
90-90: 새로운TabType정의에 대한 의견
TabType이'talkPick' | 'balanceGame'형태로 직관적으로 잘 정의되었습니다. 가독성과 유지보수성 측면에서 적절하며, 추후 탭이 늘어나는 경우에도 확장하기 용이합니다.
92-92:ButtonType정의에 대한 칭찬
'saved' | 'voted' | 'commented' | 'created'처럼 구체적인 문자열 리터럴 유니온을 사용하여, 상태를 명확하게 표현하였습니다. 상태별 처리가 명확해져서 코드의 의미 전달이 분명합니다.
94-101:AllQueryData유니온 타입 설계다수의 인터페이스를 하나의 유니온 타입으로 통합하여, 확장 가능한 구조를 잘 확보하였습니다. 이후 같은 케이스가 추가되거나 제거될 때, 단일 지점(
AllQueryData)에서 관리할 수 있어 유지보수에 유리합니다.src/pages/mobile/MyMobilePage/MyMobilePage.style.ts (6)
1-3: Emotion, 컬러/타이포 임포트 구성Emotion과 공용 스타일 코드를 임포트하여 모듈화된 형태로 활용하고 있습니다. 프로젝트 전반적으로 색상과 타이포를 통일성 있게 쓰는 것은 매우 바람직합니다.
5-12:pageStyle의 컬럼 레이아웃 설정컬럼 방향 정렬 및
padding등을 통해 모바일 환경 레이아웃을 깔끔하게 구성하고 있습니다.width: '100%'로 가로 폭을 화면에 맞춤 처리한 점도 적절합니다.
14-20:selectGroupWrapper의 센터 정렬
alignItems와justifyContent모두'center'로 설정하여, 선택 그룹 요소가 수평·수직으로 중앙에 배치됩니다. 모바일 UI 측면에서 사용자가 집중하기 좋게 배치하는 것으로 보이며, 의도에 충실합니다.
22-30:contentWrapper사용내부 컨텐츠를 모두 세로 배열로 정렬하고,
gap으로 간격을 부여하였습니다. 여러 컴포넌트가 배치될 때 가독성을 높이는 데 도움이 됩니다.
32-37:menuDataBox스타일링
flex와gap으로 내부 아이콘이나 텍스트 배열을 유연하게 처리한 점이 좋습니다. 색상과 폰트 스타일을 상수로 관리하여 전체 프로젝트에서 일관성을 유지하고 있습니다.
39-42:observerWrapper의 기능적 배치
marginTop을 두어 무한 스크롤용 옵저버를 화면 하단과 약간 띄워 배치하는 구조로 보입니다. 유저가 추가 데이터를 자연스럽게 로드하도록 유도하는 방식으로 무난합니다.src/pages/mobile/MyMobilePage/MyMobilePage.tsx (8)
1-36: 다양한 타입 및 훅 임포트다양한 API 훅, 타입을 명확히 분리·임포트하여, 파일 내에서 가독성을 높였습니다.
TabType,ButtonType등으로 뷰 로직을 분기하는 부분도 일관성을 유지해주어 좋습니다.
37-43:InfiniteQueryOrNull타입 정의
UseInfiniteQueryResult를 옵셔널로 처리해, 실제로 활성화되지 않은 쿼리 호출을 구분할 수 있도록 설계하셨습니다. 코드 가독성과 안전성을 높이는 좋은 방법입니다.
105-113: 무한 스크롤 데이터 결합 로직
data.pages.flatMap(...).content방식으로 여러 페이지를 깔끔하게 합치고 있어, 무한 스크롤 구현 시 중복 데이터를 줄이는 데 효과적입니다.
191-199: 버튼 클릭 핸들러
handleButtonClick을 통해activeButton을 갱신하는 흐름이 단순명료합니다. 뷰 로직을 따로 분리해 유지보수하기 수월해 보입니다.
201-205:currentQuery널 체크 로직쿼리가 준비되지 않은 경우 빠르게
return하는 구조로 방어 코드를 배치한 점이 좋습니다. 사용자가 의도치 않게 빈 화면을 보는 상황을 최소화할 수 있습니다.
207-211: 에디트 메뉴 라벨으로 ReactNode 활용
editMenuLabel을<span>으로 감싸고, 내부에 이모지를 함께 렌더링하여 유연하게 표현해주었습니다.ReactNode를 라벨로 사용하는 패턴이 잘 드러납니다.
214-266: 최종 렌더링
- 프로필 정보 카드, 탭/버튼 UI, 데이터 그룹 컴포넌트 배치를 통해 모바일용 마이페이지를 간결하게 구성했습니다.
- 옵저버
ref를 별도의<div>에 연결해, 스크롤 이벤트를 구조화하고 있어 무한 스크롤 처리로도 적합합니다.
44-100:❓ Verification inconclusive
쿼리 맵핑 및 상태 관리
activeTab,activeButton에 따라 다른 쿼리를 활성화하여, 불필요한 데이터 요청을 방지하는 구조가 합리적입니다.queryMap을 객체로 만들어 버튼/탭 별 쿼리를 한 곳에서 관리하므로 가독성을 높였습니다.member!.id사용 시, 멤버 값이undefined가 아닌지 확인할 안전장치가 필요할 수 있습니다.실제로
member가 아직 로딩 중이 아닐 때member!.id접근이 일어날 여지는 없는지 확인해주세요.
🏁 Script executed:
#!/bin/bash # 파일 내에서 member 사용 시점들을 확인하고, 'undefined' 방어 로직이 있는지 grep으로 확인합니다. rg --context 5 'member\!'Length of output: 108
Member 데이터 접근 관련 안전성 추가 검증 요청
현재 코드는 탭과 버튼에 따라 쿼리를 활성화해 불필요한 데이터 요청을 방지하는 구조로 잘 작성되었습니다. 다만,
member!.id를 직접 사용하고 있어,member가 아직 로딩 중이거나undefined일 경우 발생할 수 있는 잠재적 오류에 대한 안전 체크가 부족해 보입니다.useMyGameVotesQuery(member!.id, {...})호출 시, member 값이 확실히 존재하는지 다시 한 번 검토하고, 필요하다면 로딩 상태나 존재 여부를 명시적으로 확인하는 로직을 추가하시길 권장합니다.추가 검증이 필요한 부분이므로, 관련 사항에 대해 수동 점검 후 안전 장치가 확실히 마련되었는지 확인해주시기 바랍니다.
src/components/mobile/organisms/TalkPickSection/TalkPickSection.tsx (2)
82-97: MenuItem 배열에 id 속성이 추가되었습니다.각 메뉴 아이템에 고유 식별자(id)를 추가한 것은 좋은 변경입니다. 이는 React에서 리스트 렌더링 시 key 값으로 사용되어 DOM 업데이트 효율성을 향상시킵니다.
99-107: otherTalkPickItem에도 id 속성이 추가되었습니다.마찬가지로 otherTalkPickItem 배열에도 id 속성을 추가하여 일관성 있게 구현되었습니다.
src/components/mobile/organisms/IconButtonArea/IconButtonArea.tsx (5)
13-13: 타입 안전성 개선을 위한 새로운 타입 임포트문자열 타입 대신 명확하게 정의된 TabType과 ButtonType을 사용함으로써 타입 안전성이 향상되었습니다.
16-22: IconButtonConfig 인터페이스 추가버튼 구성을 위한 명확한 인터페이스를 만들어 코드의 가독성과 유지보수성이 향상되었습니다.
24-28: IconButtonAreaProps 인터페이스 업데이트기존 string 타입 대신 더 구체적인 TabType과 ButtonType을 사용하여 타입 안전성이 향상되었습니다.
30-59: 버튼 구성을 컴포넌트 외부로 이동allButtons 배열을 컴포넌트 외부로 이동시켜 컴포넌트의 재렌더링 시에도 이 배열이 재생성되지 않도록 최적화되었습니다. 이는 성능 개선에 도움이 됩니다.
72-84: map 함수 내 isActive 변수 추가로 가독성 개선isActive 상수를 추가하여 코드 가독성이 향상되었습니다. 이전에는 조건식이 직접 JSX 내에 있었을 것으로 추정됩니다.
src/components/mobile/molecules/ProfileListItem/ProfileListItem.stories.tsx (4)
5-5: 라우팅 기능을 위한 MemoryRouter 임포트ProfileListItem 컴포넌트에 라우팅 기능을 추가하기 위해 MemoryRouter를 임포트했습니다. 이는 스토리북 환경에서 라우팅을 시뮬레이션하기 위한 좋은 접근 방식입니다.
25-29: to 속성 추가ProfileListItem에 이동할 경로를 지정하는 to 속성이 추가되었습니다. 이는 사용자가 컴포넌트를 클릭했을 때 이동할 경로를 지정할 수 있어 유용합니다.
40-46: Default 스토리에 to 속성 및 MemoryRouter 추가Default 스토리에 to 속성을 추가하고 MemoryRouter로 컴포넌트를 감싸서 라우팅 기능을 활성화했습니다. 이제 스토리북에서도 라우팅 기능을 테스트할 수 있게 되었습니다.
51-80: All 스토리에 MemoryRouter 및 to 속성 추가All 스토리에서도 모든 ProfileListItem 컴포넌트에 고유한 to 속성을 추가하고 MemoryRouter로 감싸서 일관된 라우팅 기능을 제공합니다.
src/components/mobile/organisms/DateGroupedCard/DateGroupedCard.stories.tsx (3)
1-34: DateGroupedCard 스토리북 파일 생성 및 샘플 데이터 구성새로운 DateGroupedCard 컴포넌트를 위한 스토리북 파일이 잘 구성되었습니다. 테스트를 위한 sampleItems 데이터가 적절하게 정의되어 있습니다.
36-56: 메타 데이터 구성스토리북 메타 데이터가 잘 구성되어 있으며, argTypes에 date와 items에 대한 설명이 명확하게 작성되어 있습니다.
61-66: Default 스토리 구성기본 스토리가 적절하게 구성되어 있습니다. 기본 date와 items 값이 잘 설정되어 있습니다.
src/components/organisms/TalkPickSection/TalkPickSection.tsx (2)
92-107: MenuItem 객체에 id 속성 추가 적용이 잘 되었습니다.각 MenuItem 객체에 고유 id를 추가하여 React 렌더링에서 고유 키로 사용할 수 있도록 개선했습니다. 이는 React의 리스트 렌더링 성능과 안정성을 향상시키는 좋은 변경사항입니다.
108-116: otherTalkPickItem에도 id 속성이 잘 구현되었습니다.otherTalkPickItem도 myTalkPickItem과 동일한 패턴으로 id 속성을 추가하여 일관성 있게 수정했습니다.
src/stories/atoms/MenuTap.stories.tsx (4)
7-11: 메뉴 데이터 구조에 id 속성 추가가 잘 되었습니다.모든 MenuItem 객체에 일관되게 고유한 id 값을 추가했습니다. 이는 MenuItem 타입 변경에 맞게 스토리북 예제도 적절히 업데이트된 것입니다.
13-21: reportMenu에도 id 속성이 잘 적용되었습니다.reportMenu 데이터에도 id 값이 추가되어 일관된 MenuItem 인터페이스를 유지하고 있습니다.
23-38: myCommentMenu의 MenuItem 객체들에 id 속성이 잘 구현되었습니다.여러 항목이 있는 myCommentMenu에 각각 고유한 id 값(0, 1)을 부여하여 적절하게 구현했습니다.
40-55: otherCommentMenu에도 id 속성이 일관되게 적용되었습니다.otherCommentMenu의 각 MenuItem 객체에도 고유 id 값을 추가하여 MenuTap 컴포넌트의 요구사항에 맞게 잘 수정되었습니다.
| commentCount: number; | ||
| editedAt: string; | ||
| bookmarked: boolean; | ||
| imgUrls?: string; |
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.
imgUrls 타입 불일치 문제
현재 imgUrls가 string 혹은 undefined로 선언되어 있지만, 실제 사용되는 코드(MyMobilePage.tsx 등)에서 item.imgUrls[0]와 같이 배열 형태로 접근하고 있습니다. 이는 타입 선언과 실제 사용 방식이 어긋나서 런타임 에러를 유발할 수 있습니다.
아래와 같이 string[]로 변경하여, 코드 전체가 일관되도록 맞추기를 권장드립니다:
- imgUrls?: string;
+ imgUrls?: string[];Also applies to: 21-21, 32-32
| useEffect(() => { | ||
| setActiveButton('saved'); | ||
| }, [activeTab]); | ||
|
|
||
| useEffect(() => { | ||
| if (!mergedData || !mergedData.content) { | ||
| setDateGroupedData([]); | ||
| return; | ||
| } | ||
|
|
||
| if (activeTab === 'talkPick') { | ||
| const talkPickItems = mergedData.content as ( | ||
| | BookmarkInfoItemResponse | ||
| | CommentInfoItemResponse | ||
| | VoteInfoItemResponse | ||
| | WrittenInfoItemResponse | ||
| )[]; | ||
| const groups: { [date: string]: DateGroupedListItem[] } = {}; | ||
|
|
||
| talkPickItems.forEach((item) => { | ||
| const dateStr = item.editedAt || '날짜없음'; | ||
| const transformedItem: DateGroupedListItem = { | ||
| id: item.id, | ||
| title: item.title, | ||
| imgUrl: | ||
| item.imgUrls && item.imgUrls.length > 0 ? item.imgUrls[0] : '', | ||
| }; | ||
|
|
||
| if (groups[dateStr]) { | ||
| groups[dateStr].push(transformedItem); | ||
| } else { | ||
| groups[dateStr] = [transformedItem]; | ||
| } | ||
| }); | ||
|
|
||
| const groupedData = Object.keys(groups) | ||
| .sort((a, b) => (a < b ? 1 : -1)) | ||
| .map((date) => ({ date, items: groups[date] })); | ||
|
|
||
| setDateGroupedData(groupedData); | ||
| } else if (activeTab === 'balanceGame') { | ||
| const balanceGameItems = mergedData.content as MyBalanceGameItem[]; | ||
| const newArr: { date: string; items: ContentsButtonProps[] }[] = []; | ||
|
|
||
| balanceGameItems.forEach((item) => { | ||
| const dateStr = item.editedAt || '날짜없음'; | ||
|
|
||
| const transformed: ContentsButtonProps = { | ||
| id: String(item.gameId), | ||
| title: item.title, | ||
| images: | ||
| item.optionAImg && item.optionBImg | ||
| ? [item.optionAImg, item.optionBImg] | ||
| : [], | ||
| mainTag: item.mainTagName || '', | ||
| subTag: item.subTag || '', | ||
| onClick: () => navigate(`/balancegame/${item.gameId}`), | ||
| onBookmarkClick: () => { | ||
| handleBookmarkClick(item); | ||
| }, | ||
| bookmarked: item.bookmarked ?? false, | ||
| showBookmark: activeButton === 'saved' || activeButton === 'voted', | ||
| size: 'extraSmall', | ||
| }; | ||
|
|
||
| const existingGroup = newArr.find((group) => group.date === dateStr); | ||
| if (existingGroup) { | ||
| existingGroup.items.push(transformed); | ||
| } else { | ||
| newArr.push({ date: dateStr, items: [transformed] }); | ||
| } | ||
| }); | ||
| setDateGroupedData(newArr); | ||
| } | ||
| }, [mergedData, activeTab, activeButton, navigate, handleBookmarkClick]); |
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
데이터 그룹화 로직 주의점
imgUrls?: string;로 선언된 프로퍼티를 배열처럼 사용하는 부분(item.imgUrls[0])이 있어 타입 불일치로 인한 에러 가능성이 큽니다.- 임시로
'날짜없음'을 사용해 날짜를 표시하는 부분은 괜찮지만, 국제화(i18n)를 고려한다면 별도 상수 혹은 번역 키로 뽑아 관리하는 것을 권장합니다.
이미 인터페이스가 배열 형태로 바뀌어야 할 것으로 보이니, 기존에 코멘트한 대로 imgUrls?: string[];로 수정하여 안전하게 처리해주세요.
|
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: 0
🧹 Nitpick comments (2)
src/pages/mobile/MyMobilePage/MyMobilePage.tsx (2)
203-207: 더 나은 로딩/오류 화면 처리 제안현재
isMemberLoading나!currentQuery시 단순<div />만 리턴하고 있습니다. 사용자가 로딩 중임을 인지할 수 있는 피드백(스피너, 플레이스홀더, 에러 메시지 등)을 제공하면 UX 개선에 도움이 됩니다.
261-265: 데이터가 없을 때 사용자에게 명확한 안내 필요
dateGroupedData가 비어 있을 경우 아무것도 표시하지 않거나<p />만 렌더링하고 있습니다. 사용자에게 “저장된 데이터가 없습니다.”와 같은 구체적인 안내 문구나 UI 요소를 제공하면 상황을 더 명확히 전달할 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/mobile/molecules/ProfileListItem/ProfileListItem.tsx(1 hunks)src/pages/mobile/MyMobilePage/MyMobilePage.tsx(1 hunks)
🔇 Additional comments (8)
src/components/mobile/molecules/ProfileListItem/ProfileListItem.tsx (6)
3-11: 새로운 에셋 및 리액트 라우터 링크 임포트가 추가되었습니다.여러 랜덤 프레임 이미지를 임포트하고
Link컴포넌트를 추가하여 네비게이션 기능을 확장했습니다. 이로써 컴포넌트의 사용성이 향상되었습니다.
14-21: 랜덤 이미지 배열 정의가 잘 되었습니다.다양한 프레임 이미지를 배열로 정의하여 랜덤 이미지 선택을 위한 기반을 만들었습니다. 코드 가독성이 좋고 확장성도 고려되었습니다.
23-28: useRandomImage 훅이 효율적으로 구현되었습니다.
useMemo를 활용하여 랜덤 이미지 선택을 최적화한 점이 좋습니다. 빈 의존성 배열을 사용하여 컴포넌트가 마운트될 때만 이미지를 선택하도록 한 점도 적절합니다.
30-35: 인터페이스 변경이 적절히 이루어졌습니다.
ProfileListItemProps인터페이스에서:
imgUrl을 선택적 속성으로 변경하여 유연성을 높였습니다.- 라우팅을 위한
to속성을 추가하여 네비게이션 기능을 강화했습니다.div대신a태그의 속성을 확장하도록 변경하여 링크 기능에 맞게 조정했습니다.이러한 변경은 컴포넌트의 용도와 잘 부합합니다.
37-44: 랜덤 이미지 폴백 로직이 효과적으로 구현되었습니다.
imgUrl이 제공되지 않을 경우 랜덤 이미지를 사용하는 폴백 메커니즘이 잘 구현되었습니다. 널 병합 연산자(??)를 사용하여 간결하게 처리한 점이 좋습니다.
45-54: Link 컴포넌트로의 전환이 잘 이루어졌습니다.
div에서Link컴포넌트로 변경하여 네비게이션 기능을 추가한 것은 좋은 개선입니다. 기존 스타일과 속성을 유지하면서도 새로운 기능을 자연스럽게 통합했습니다.src/pages/mobile/MyMobilePage/MyMobilePage.tsx (2)
135-143: '날짜없음' 문자열의 i18n 적용 검토이미 과거 리뷰에서 언급된 부분과 동일합니다.
'날짜없음'대신 국제화(i18n) 처리를 통해 다국어 환경에 대비하거나 상수 파일로 분리하여 재사용성을 높이는 방법을 고려해 보세요.
48-58:❓ Verification inconclusive
멤버 데이터가 아직 로딩되지 않은 상태에서
member!사용 주의
member!를 통해 non-null 단언을 사용하고 있으나, 이 로직은member가undefined일 경우 런타임 오류로 이어질 수 있습니다.isMemberLoading만으로 충분히 방어할 수 있는지 확인하고, 필요하다면member존재 여부를 추가로 체크하는 로직을 고려해주세요.아래 스크립트를 통해
member!가 다른 곳에서도 무방비하게 사용되는지 확인해 볼 수 있습니다:
🏁 Script executed:
#!/bin/bash # repository 전체에서 member! 사용 위치를 검색 rg -A 2 'member!'Length of output: 291
주의: member! 사용에 대한 추가 확인 필요
- 코드 상
src/pages/mobile/MyMobilePage/MyMobilePage.tsx파일에서member!는useMyGameVotesQuery(member!.id, { … })호출 시에만 사용되고 있음이 확인되었습니다.useMemberQuery에서 반환하는isMemberLoading이 member 값의 안정성을 충분히 보장하는지 재검토해주시기 바랍니다.- 만약 로딩 중인 상태에서
member!를 사용하게 되면 런타임 오류가 발생할 수 있으므로, 추가적인 null 체크 또는 조건부 처리가 필요해 보입니다.
areumH
left a 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.
모바일 마이페이지 구현 너무 고생하셨습니다 🤩🙌
코멘트 간단히 남겼습니다!! 확인 부탁드려요
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.
해당 컴포넌트 스토리북 오류로 확인이 안됩니다 수정 부탁드려요!!
| {isMobile ? ( | ||
| <Route index element={<MyMobilePage />} /> | ||
| ) : ( | ||
| <Route element={<MyPage />}> |
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.
현재 구현된 방식도 괜찮은 것 같습니다!! 👍
|
|
||
| const MenuTap = ({ menuData }: MenuTapProps) => { |
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.
스토리북으로 확인해보니 글자 수가 같아도 메뉴가 1개일 때와 2개일 때의 width 길이가 차이가 나는 것 같아요!! 스타일 확인 부탁드립니닷
|
|
||
| export const listItemStyle = css({}); |
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.
사용되지 않는 스타일은 삭제 부탁드려요!!
| ) : ( | ||
| <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.
위 코드는 dateGroupedData가 빈 요소일 때 빈 값을 보여주기 위한 코드인가요??
맞다면 삼항연산자 대신 &&를 사용하는건 어떨까요!??



💡 작업 내용
💡 자세한 설명
작업한 내용들이 git 오류로 인해..... push가 안되어서 해결하다가 그냥 새로 클론을 받고 수동 커밋을 해버린 슬픈 사연이 있습니다.... 이것만 며칠을 트라이했네요 ㅠ(force push 는 위험성이 너무 크다고 판단하여 새롭게 클론 후 구현)
✅ 모바일에서의 쿼리 호출
와 같이 enabled 속성을 넣어서 특정 조건(state)이 만족되어야 쿼리가 실행되도록 설정하였습니다. 이는 모바일의 경우 웹과 다르게 Outlet을 이용한 구조가 아닌, 단일 페이지이기 때문에 처리한 부분입니다.
(실제 영상)
default.mp4
default.mp4
✅ 마이페이지 전체 쿼리 수정
✅ MenuTap props 수정
✅ 기타
📗 참고 자료 (선택)
📢 리뷰 요구 사항 (선택)
🚩 후속 작업 (선택)
✅ 셀프 체크리스트
closes #273
Summary by CodeRabbit
New Features
Style Updates
Asset Enhancements