Skip to content
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

refactor: 변경된 밸런스게임 조회 api 파라미터 수정 #264

Open
wants to merge 43 commits into
base: dev
Choose a base branch
from

Conversation

alwubin
Copy link
Collaborator

@alwubin alwubin commented Dec 16, 2024

💡 작업 내용

  • activeTab 상태 속 tag명 수정
  • getBestGames / getLatestGames 파라미터 수정

💡 자세한 설명

✅ getBestGames, getLatestGames

  • '인기' 태그의 경우 태그로 들어가는 것이 아닌 인기순으로 밸런스게임을 조회하는 것이기 때문에 '' 조회시 tagName이 들어가지 않도록 api가 수정되어 이에 맞춰 수정하였습니다.
  • page,size는 고정 파라미터로 넣어준 뒤 tagName이 빈값이 아닐 시에만 tagName 파라미터가 추가되도록 리팩토링하였습니다!

📗 참고 자료 (선택)

📢 리뷰 요구 사항 (선택)

🚩 후속 작업 (선택)

✅ 셀프 체크리스트

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

closes #263

Summary by CodeRabbit

  • 신규 기능

    • 모바일 뷰포트 설정을 위한 @storybook/addon-viewport 추가.
    • 다양한 SVG 및 이미지 자산 추가로 UI 다양성 향상.
    • FloatingButton, DraftSaveButton, MobileSideMenu, MobileToggleGroup와 같은 새로운 모바일 컴포넌트 추가.
  • 스타일 변경

    • 여러 컴포넌트의 반응형 디자인 조정, 특히 430px 이하의 화면 크기에 맞춘 스타일 수정.
    • LandingPageTodayTalkPickBanner와 같은 컴포넌트의 모바일 반응형 스타일 수정.
  • 문서화

    • Storybook에서 Bookmark, CategoryButton, MobileSideMenu, FloatingButton의 스토리 업데이트, 모바일 뷰에 대한 새로운 스토리 추가.

alwubin and others added 30 commits December 8, 2024 02:42
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@alwubin alwubin added 👩🏻‍💻 frontend 프론트엔드 작업 🪄refactor 리팩토링 labels Dec 16, 2024
@alwubin alwubin requested review from areumH and WonJuneKim December 16, 2024 11:19
@alwubin alwubin self-assigned this Dec 16, 2024
Copy link

coderabbitai bot commented Dec 16, 2024

개요

Walkthrough

이번 풀 리퀘스트는 애플리케이션의 모바일 반응형 디자인을 강화하고, 다양한 컴포넌트의 스타일과 기능을 개선하는 광범위한 변경 사항을 포함하고 있습니다. 주요 초점은 모바일 뷰포트에 최적화된 레이아웃, 새로운 모바일 컴포넌트 추가, 그리고 기존 컴포넌트의 반응형 스타일링입니다.

Changes

파일 변경 요약
.storybook/main.ts Storybook viewport 애드온 추가
.storybook/preview.ts 커스텀 뷰포트 설정 추가
package.json @storybook/addon-viewport 의존성 추가
public/index.html 뷰포트 메타 태그 추가
src/api/game.ts getBestGames/getLatestGames 함수의 파라미터 객체화
src/assets/index.ts 여러 SVG 및 이미지 자산 추가
src/components/mobile/* 새로운 모바일 전용 컴포넌트 다수 추가
src/styles/typo.ts 모바일 전용 타이포그래피 스타일 추가

시퀀스 다이어그램

sequenceDiagram
    participant User
    participant App
    participant MobileHook
    participant Components

    User->>App: 페이지 로드
    App->>MobileHook: useIsMobile() 호출
    MobileHook-->>App: 모바일 여부 반환
    App->>Components: 모바일/데스크톱 렌더링 결정
    Components->>User: 적절한 UI 렌더링
Loading

연결된 이슈에 대한 평가

목표 해결 여부 설명
activeTab 상태 속 tag명 수정 [#263] 빈 문자열로 초기화되도록 변경됨
getBestGames/getLatestGames 파라미터 수정 [#263] params 객체를 사용하여 파라미터 구성 방식 개선

시 (Poem)

🐰 모바일의 세계로 홉!
반응형 디자인 깡총깡총
작은 화면에 맞춰 춤추는 UI
사용자의 손끝에서 반짝이는 기쁨
코드는 토끼처럼 민첩하게! 🌈

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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. (Beta)
  • @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

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

🧹 Nitpick comments (40)
src/components/molecules/CategoryBox/CategoryBox.tsx (1)

11-24: 코드 중복을 줄일 수 있는 여지가 있습니다.

CategoryButtonisMobile prop을 전달하는 부분에서 중복이 발생합니다. 다음과 같은 개선을 고려해보세요:

- <CategoryButton isMobile imageType="PickVote" label="톡&픽 플레이스" />
+ <CategoryButton
+   {...(isMobile && { isMobile })}
+   imageType="PickVote"
+   label="톡&픽 플레이스"
+ />

또는 모바일 버전용 버튼들을 별도의 컴포넌트로 추출하는 것도 고려해볼 수 있습니다:

const MobileCategoryButtons = ({ handleService }: { handleService: () => void }) => (
  <>
    <Link to="/talkpickplace">
      <CategoryButton isMobile imageType="PickVote" label="톡&픽 플레이스" />
    </Link>
    <CategoryButton
      isMobile
      imageType="RandomGame"
      label="랜덤 밸런스 게임"
      onClick={handleService}
    />
  </>
);
src/components/molecules/SearchTagBar/SearchTagBar.tsx (1)

23-29: 조건부 렌더링 로직을 개선할 수 있습니다.

현재 구현은 작동하지만, 다음과 같은 개선사항을 제안드립니다:

  1. SearchBar 컴포넌트로 전달되는 isMobile prop의 영향이 명확하지 않습니다. 주석이나 문서화가 필요해 보입니다.
  2. 조건부 렌더링 로직을 더 간단하게 만들 수 있습니다.

다음과 같이 개선해 보시는 것은 어떨까요?:

- return isMobile ? (
-   <SearchBar
-     isMobile
-     onInputChange={handleInputChange}
-     onSearchClick={handleSearchClick}
-     value={inputValue}
-   />
- ) : (
+ const commonSearchBarProps = {
+   onInputChange: handleInputChange,
+   onSearchClick: handleSearchClick,
+   value: inputValue,
+ };
+
+ return (
    <div css={S.searchBarContainerStyling}>
-     <SearchBar
-       onInputChange={handleInputChange}
-       onSearchClick={handleSearchClick}
-       value={inputValue}
-     />
+     <SearchBar {...commonSearchBarProps} isMobile={isMobile} />
+     {!isMobile && (
      <div css={S.btnWrapperStyling}>
        {KEYWORD_TAG.map((keyWord) => (
          <Button key={keyWord} size="large" variant="outlinePrimary">
            #{keyWord}
          </Button>
        ))}
      </div>
+     )}
    </div>
  );
src/components/mobile/atoms/DraftSaveButton/DraftSaveButton.tsx (1)

8-14: 접근성 개선을 위한 제안사항이 있습니다.

버튼 컴포넌트의 기본 구현은 잘 되어있으나, 다음과 같은 접근성 속성들을 추가하면 좋을 것 같습니다:

 <button 
   css={S.buttonStyle} 
   type="button" 
   onClick={onClick}
+  aria-label="임시저장"
+  role="button"
 >
   임시저장
 </button>
src/components/atoms/Bookmark/Bookmark.style.ts (1)

14-17: CSS 변수 사용을 통한 유지보수성 개선을 제안드립니다.

현재 하드코딩된 픽셀값들을 CSS 변수로 관리하면 일관성 있는 유지보수가 가능할 것 같습니다.

+const styles = {
+  bookmark: {
+    desktop: {
+      size: '30px',
+    },
+    mobile: {
+      size: '19px',
+    },
+  },
+} as const;

 export const bookmarkButton = css`
   display: flex;
   align-items: center;
   justify-content: center;
-  width: 30px;
-  height: 30px;
+  width: ${styles.bookmark.desktop.size};
+  height: ${styles.bookmark.desktop.size};
   flex-shrink: 0;
   background-color: transparent;
   border: none;
   cursor: pointer;
   padding: 0;

   @media (max-width: 430px) {
-    width: 19px;
-    height: 19px;
+    width: ${styles.bookmark.mobile.size};
+    height: ${styles.bookmark.mobile.size};
   }
`;
src/hooks/common/useIsMobile.ts (1)

14-16: 이벤트 리스너 최적화 필요

리사이즈 이벤트가 너무 자주 발생하면 성능에 영향을 줄 수 있습니다.

디바운스를 적용하는 것을 추천드립니다:

+import { debounce } from 'lodash';
+
 useEffect(() => {
-  checkIsMobile();
-  window.addEventListener('resize', checkIsMobile);
+  const debouncedCheck = debounce(checkIsMobile, 250);
+  checkIsMobile();
+  window.addEventListener('resize', debouncedCheck);
-  return () => window.removeEventListener('resize', checkIsMobile);
+  return () => {
+    window.removeEventListener('resize', debouncedCheck);
+    debouncedCheck.cancel();
+  };
 }, []);
src/stories/mobile/atoms/DraftSaveButton.stories.tsx (2)

7-23: 스토리 구성 개선 필요

스토리북 설정에 다음 사항들이 보완되면 좋을 것 같습니다:

  1. 모바일 뷰포트 설정이 없습니다
  2. 버튼의 다양한 상태를 보여주는 스토리가 없습니다

다음과 같이 개선하는 것을 추천드립니다:

 const meta: Meta<typeof DraftSaveButton> = {
   title: 'mobile/atoms/DraftSaveButton',
   component: DraftSaveButton,
   parameters: {
     layout: 'centered',
+    viewport: {
+      defaultViewport: 'mobile',
+    },
   },
   argTypes: {
-    onClick: { action: '클릭 이벤트 발생' },
+    onClick: { 
+      action: '임시저장 버튼 클릭',
+      description: '클릭 시 임시저장 로직이 실행됩니다',
+    },
   },
   decorators: [
     (Story) => (
       <BrowserRouter>
         <Story />
       </BrowserRouter>
     ),
   ],
 };

28-28: 스토리 변형 추가 필요

기본 스토리만으로는 컴포넌트의 다양한 상태를 테스트하기 어렵습니다.

다음과 같은 추가 스토리를 작성하는 것을 추천드립니다:

export const Loading: Story = {
  args: {
    isLoading: true,
  },
};

export const Disabled: Story = {
  args: {
    disabled: true,
  },
};

export const WithCustomText: Story = {
  args: {
    children: '커스텀 텍스트',
  },
};
src/stories/mobile/atoms/MobileToggleGroup.stories.tsx (1)

29-29: 스토리 구현을 보완하는 것이 좋습니다.

현재 Default 스토리가 비어있습니다. 컴포넌트의 다양한 상태와 사용 사례를 보여주는 스토리를 추가하면 좋겠습니다.

export const Default: Story = {
  args: {
    selectedValue: { field: 'views', order: 'desc' },
  },
};

export const WithDifferentSelection: Story = {
  args: {
    selectedValue: { field: 'latest', order: 'asc' },
  },
};
src/components/mobile/atoms/FloatingButton/FloatingButton.style.ts (2)

5-23: 전반적인 스타일 구조가 잘 설계되었습니다.

스타일 구조와 반응형 디자인이 잘 구현되어 있습니다. 다만, transition 속성을 더 구체적으로 지정하면 좋을 것 같습니다.

다음과 같이 수정을 제안드립니다:

-    transition: 'all 0.3s ease-in',
+    transition: 'box-shadow 0.3s ease-in',

12-19: 매직 넘버를 상수로 분리하는 것을 고려해보세요.

현재 하드코딩된 수치들(padding, gap, width 등)을 의미 있는 상수로 분리하면 유지보수성이 향상될 것 같습니다.

다음과 같은 방식을 제안드립니다:

const FLOATING_BUTTON = {
  PADDING: {
    LEFT: '21px',
    RIGHT: '5px',
  },
  GAP: '13px',
  WIDTH: {
    TALKPICK: '102px',
    GAME: '139px',
  },
  MARGIN: {
    TALKPICK: '37px',
  },
} as const;
src/components/atoms/Chips/Chips.style.ts (1)

15-15: 브레이크포인트 값을 상수로 분리하는 것을 추천드립니다.

여러 곳에서 사용되는 미디어 쿼리 브레이크포인트 값(430px)을 상수로 분리하면 유지보수성이 향상될 것 같습니다.

다음과 같은 방식을 제안드립니다:

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

// 사용 예시
import { BREAKPOINTS } from '@/styles/breakpoints';

`@media (max-width: ${BREAKPOINTS.MOBILE})`

Also applies to: 26-26

src/stories/mobile/atoms/MobileSideMenu.stories.tsx (1)

1-2: ESLint 비활성화 주석 개선 필요

전역 ESLint 비활성화 주석 대신 특정 라인에 대한 비활성화를 고려해주세요. 현재 방식은 파일 전체에 영향을 미치므로 코드 품질 관리에 어려움이 있을 수 있습니다.

-/* eslint-disable no-console */
-/* eslint-disable @typescript-eslint/no-unused-vars */
+// eslint-disable-next-line no-console, @typescript-eslint/no-unused-vars
src/stories/mobile/molecules/FloatingMenuButton.stories.tsx (1)

15-25: Provider 중첩 구조 개선 제안

현재 Provider 중첩이 다소 복잡해 보입니다. 테스트 환경 설정을 위한 별도의 래퍼 컴포넌트를 만들어 사용하는 것을 고려해보세요.

const TestWrapper = ({ children }: { children: React.ReactNode }) => (
  <Provider store={store}>
    <ReactQueryProvider>
      <Router>{children}</Router>
    </ReactQueryProvider>
  </Provider>
);

// decorators에서 사용
decorators: [(Story) => <TestWrapper><Story /></TestWrapper>]
src/components/mobile/atoms/MobileToggleGroup/MobileToggleGroup.style.ts (2)

10-21: 클릭된 토글의 스타일 구현에 대한 제안

현재 구현은 잘 작동하지만, 다음과 같은 개선을 고려해보세요:

  1. isOpen 상태에 따른 스타일 변화를 더 명확하게 구분
  2. 반복되는 스타일 값들을 상수로 분리

다음과 같이 개선해 보세요:

+const TOGGLE_PADDING = '4px 8px 4px 9px';
+const BORDER_RADIUS = '6px';

 export const clickedToggleStyle = (isOpen: boolean) =>
   css(typo.Mobile.Text.SemiBold_12, {
     color: color.MAIN,
     backgroundColor: color.WT_VIOLET,
     display: 'flex',
     alignItems: 'center',
     gap: '8px',
-    padding: '4px 8px 4px 9px',
+    padding: TOGGLE_PADDING,
     borderBottom: isOpen ? `0.6px solid ${color.SKYBLUE}` : undefined,
-    borderRadius: isOpen ? undefined : '6px',
+    borderRadius: isOpen ? undefined : BORDER_RADIUS,
     cursor: 'pointer',
   });

23-33: 미클릭 토글의 hover 효과 개선 제안

현재 hover 효과가 즉시 적용되는데, 부드러운 전환을 위해 배경색 변경에만 transition을 적용하는 것이 좋습니다.

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

 export const unClickedToggleStyle = css(typo.Mobile.Text.SemiBold_12, {
   color: color.GY[1],
   backgroundColor: color.WT,
   padding: '4px 26px 4px 9px',
-  transition: 'all .1s ease-in',
+  transition: 'background-color .1s ease-in',
   borderRadius: '0 0 6px 6px',
   cursor: 'pointer',
   '&:hover': {
     backgroundColor: color.WT_VIOLET,
   },
 });
src/pages/LandingPage/LandingPage.style.ts (1)

32-37: 검색 박스 스타일의 모바일 대응 필요

모바일 환경에서 마진과 갭이 너무 크게 설정되어 있습니다. 화면 크기에 따른 반응형 조정이 필요합니다.

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

 export const searchBoxStyle = css({
   margin: '30px 0',
   gap: '14px',
   display: 'flex',
   flexDirection: 'column',
+  '@media (max-width: 768px)': {
+    margin: '20px 0',
+    gap: '10px',
+  },
 });
src/components/atoms/CategoryButton/CategoryButton.tsx (1)

27-32: 모바일 조건부 렌더링 로직이 개선될 수 있습니다.

현재 구현은 작동하지만, 반복되는 삼항 연산자 패턴을 개선할 수 있습니다.

다음과 같이 리팩토링하는 것을 고려해보세요:

- ImageComponent = isMobile ? PickVoteSmall : PickVote;
+ const components = {
+   PickVote: { default: PickVote, mobile: PickVoteSmall },
+   RandomGame: { default: RandomGame, mobile: RandomGameSmall },
+   TodayPick: { default: TodayPick, mobile: TodayPick }
+ };
+ ImageComponent = components[imageType][isMobile ? 'mobile' : 'default'];
src/components/atoms/Bookmark/Bookmark.tsx (1)

27-32: renderIcon 함수 구현이 개선될 수 있습니다.

현재 구현도 잘 작동하지만, 조건부 렌더링을 더 간결하게 만들 수 있습니다.

다음과 같은 리팩토링을 제안합니다:

const renderIcon = () => {
-  if (isPressed) {
-    return isMobile ? <BookmarkPRSmall /> : <BookmarkPR css={S.icon} />;
-  }
-  return isMobile ? <BookmarkDFSmall /> : <BookmarkDF css={S.icon} />;
+  const Icon = isPressed
+    ? (isMobile ? BookmarkPRSmall : BookmarkPR)
+    : (isMobile ? BookmarkDFSmall : BookmarkDF);
+  return <Icon css={!isMobile ? S.icon : undefined} />;
};
src/components/organisms/BalanceGameList/BalanceGameList.style.ts (1)

6-12: 미디어 쿼리 브레이크포인트를 상수로 분리하는 것을 추천드립니다.

여러 곳에서 반복되는 430px 브레이크포인트를 상수로 분리하면 유지보수가 더욱 용이해질 것 같습니다.

다음과 같이 변경하는 것을 제안드립니다:

+ const MOBILE_BREAKPOINT = '430px';

export const containerStyle = css({
  width: '1158px',
- '@media (max-width: 430px)': {
+ `@media (max-width: ${MOBILE_BREAKPOINT})`: {
    maxWidth: '335px',
    // ...
  },
});

Also applies to: 20-25, 32-34, 41-43, 51-53

src/components/molecules/TopBanner/TodayTalkPickBanner/TodayTalkPickBanner.tsx (1)

5-6: 모바일 대응이 적절하게 구현되었습니다.

useIsMobile 훅을 사용하여 디바이스에 따라 적절한 크기의 아이콘을 렌더링하는 방식이 좋습니다.

단, CheckCheckSmall 컴포넌트의 props 타입을 명시하면 더 좋을 것 같습니다:

import { Check, CheckSmall } from '@/assets';
type CheckProps = {
  // 공통 props 정의
};

Also applies to: 20-20, 35-35

src/components/organisms/Header/Header.style.ts (1)

5-22: z-index 값을 상수로 관리하는 것을 추천드립니다.

고정 헤더의 z-index: 1000 값을 상수로 분리하여 관리하면 다른 컴포넌트들과의 레이어 관계를 더 명확하게 관리할 수 있을 것 같습니다.

다음과 같이 변경하는 것을 제안드립니다:

const Z_INDICES = {
  HEADER: 1000,
  MODAL: 1100,
  // 다른 z-index 값들...
} as const;

export const containerStyle = css`
  // ...
  z-index: ${Z_INDICES.HEADER};
`;
src/stories/mobile/atoms/FloatingButton.stories.tsx (1)

1-1: 콘솔 로그 제거 필요

프로덕션 코드에서는 console.log 문을 제거하는 것이 좋습니다. 디버깅 목적으로 사용된 콘솔 로그가 남아있습니다.

다음과 같이 수정하는 것을 제안합니다:

- /* eslint-disable no-console */
- onClick={() => console.log('TalkPick button clicked')}
+ onClick={() => {}}
- onClick={() => console.log('Game button clicked')}
+ onClick={() => {}}

Also applies to: 34-34, 42-42

src/components/molecules/TopBanner/TopBanner.style.ts (1)

8-10: 스타일 상수 추출 권장

반복되는 미디어 쿼리 브레이크포인트와 매직 넘버(예: 430px, 227px 등)를 상수로 추출하면 유지보수가 더 용이해질 것 같습니다.

다음과 같은 방식으로 상수를 추출하는 것을 제안합니다:

const BREAKPOINTS = {
  MOBILE: '430px',
} as const;

const DIMENSIONS = {
  MOBILE: {
    BANNER_HEIGHT: '227px',
    DOT_SIZE: '4px',
    DOT_GAP: '5px',
    ACTIVE_DOT_WIDTH: '32px',
  },
} as const;

Also applies to: 31-34, 46-50, 57-61

src/stories/molecules/CategoryBar.stories.tsx (1)

21-21: 스토리 문서화 개선 필요

activeTab의 빈 문자열 처리에 대한 설명이 부족합니다. 다음 사항들의 추가를 제안드립니다:

  1. 빈 문자열이 의미하는 상태 설명
  2. API 파라미터와의 연관성 명시
  3. 각 탭 상태별 동작 방식 설명
// Story 설명 예시
/**
 * activeTab이 빈 문자열('')일 경우:
 * - 인기 탭으로 간주
 * - API 호출 시 tagName 파라미터 제외
 * 
 * activeTab이 특정 값일 경우:
 * - 해당 태그로 필터링
 * - API 호출 시 tagName 파라미터 포함
 */

Also applies to: 55-55

src/stories/atoms/CategoryButton.stories.tsx (1)

52-74: Mobile 스토리의 구현 방식 개선이 필요합니다.

Mobile 스토리에서 다음과 같은 개선사항을 제안드립니다:

  1. TodayPick 케이스가 누락되어 있습니다.
  2. 모바일 환경에서의 레이아웃 테스트를 위해 스타일 속성을 추가하는 것이 좋습니다.

다음과 같이 수정하는 것을 제안드립니다:

export const Mobile: Story = {
  parameters: {
    viewport: {
      defaultViewport: 'mobile',
    },
  },
  render: () => (
    <ul css={[storyContainer, { padding: '0 16px' }]}>
      <li css={storyInnerContainer}>
        <h3>모바일 톡&픽 플레이스</h3>
        <CategoryButton imageType="PickVote" label="톡&픽 플레이스" isMobile />
      </li>
      <li css={storyInnerContainer}>
        <h3>모바일 오늘의 톡픽 모음</h3>
+       <CategoryButton imageType="TodayPick" label="오늘의 톡픽 모음.zip" isMobile />
      </li>
      <li css={storyInnerContainer}>
        <h3>모바일 랜덤 밸런스 게임</h3>
        <CategoryButton
          imageType="RandomGame"
          label="랜덤 밸런스 게임"
          isMobile
        />
      </li>
    </ul>
  ),
};
src/components/molecules/CategoryBar/CategoryBar.tsx (1)

Line range hint 28-40: getBadgeText 함수의 타입 안전성 개선이 필요합니다.

getBadgeText 함수에서 다음과 같은 개선이 필요합니다:

  1. 파라미터 타입을 CategoryTabType을 사용하도록 변경
  2. 반환 타입을 명시적으로 지정
- const getBadgeText = (tab: '' | '커플' | '취향' | '월드컵') => {
+ const getBadgeText = (tab: CategoryTabType): string => {
src/components/mobile/atoms/MobileToggleGroup/MobileToggleGroup.tsx (2)

51-72: 접근성 개선이 필요합니다.

토글 그룹의 접근성 향상을 위해 다음 사항들을 추가해주세요:

  1. ARIA 속성 추가
  2. 키보드 네비게이션 지원
  return (
-   <div css={S.toggleGroupStyle}>
+   <div css={S.toggleGroupStyle} role="group" aria-label="정렬 옵션">
      <button
        css={S.clickedToggleStyle(isOpen)}
        type="button"
+       aria-expanded={isOpen}
+       aria-haspopup="true"
        onClick={handleMenuClick}
+       onKeyDown={(e) => {
+         if (e.key === 'Escape') setIsOpen(false);
+       }}
      >

10-19: 상수 값의 분리가 필요합니다.

defaultItems를 별도의 상수 파일로 분리하여 재사용성을 높이는 것이 좋습니다.

+ // src/constants/toggle.ts
+ export const TOGGLE_ITEMS: ToggleGroupItem[] = [
+   {
+     label: '인기순',
+     value: { field: 'views', order: 'desc' },
+   },
+   {
+     label: '최신순',
+     value: { field: 'createdAt', order: 'desc' },
+   },
+ ];

- const defaultItems: ToggleGroupItem[] = [
-   {
-     label: '인기순',
-     value: { field: 'views', order: 'desc' },
-   },
-   {
-     label: '최신순',
-     value: { field: 'createdAt', order: 'desc' },
-   },
- ];
+ import { TOGGLE_ITEMS } from '@/constants/toggle';
+ const defaultItems = TOGGLE_ITEMS;
src/components/molecules/ContentsButton/ContentsButton.style.ts (2)

30-36: 크기 값을 상수로 분리하는 것이 좋겠습니다.

하드코딩된 크기 값들을 상수로 분리하면 유지보수가 더 용이해질 것 같습니다.

다음과 같이 개선해보세요:

const SIZES = {
  EXTRA_SMALL: {
    WIDTH: '162px',
    HEIGHT: '121px',
    INFO_HEIGHT: '40px',
    LABEL_MAX_WIDTH: '141px',
    IMAGE_HEIGHT: '81px',
  },
  // ... 다른 사이즈들도 동일하게 적용
} as const;

const sizeStyles = {
  extraSmall: SIZES.EXTRA_SMALL,
  // ... 나머지 사이즈
};

68-69: 모바일 반응형 스타일이 잘 구현되었습니다.

미디어 쿼리를 통한 모바일 대응이 적절하게 구현되었습니다. 다만, 브레이크포인트 값(430px)을 상수로 분리하면 더 좋을 것 같습니다.

브레이크포인트를 다음과 같이 분리해보세요:

const BREAKPOINTS = {
  MOBILE: '430px',
} as const;

// 사용 예시
@media (max-width: ${BREAKPOINTS.MOBILE}) {
  // ...
}

Also applies to: 115-117, 124-126

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

15-17: 미디어 쿼리 상수화 및 일관성 개선 필요

미디어 쿼리에서 반복적으로 사용되는 430px 값과 여러 간격 값들을 상수로 분리하여 관리하면 유지보수성이 향상될 것 같습니다.

다음과 같은 개선을 제안드립니다:

+ const BREAKPOINTS = {
+   MOBILE: '430px',
+ };
+ 
+ const SPACING = {
+   MOBILE: {
+     MARGIN_TOP: '2px',
+     MARGIN_BOTTOM: '2px',
+     MARGIN_LEFT: '2px',
+   },
+ };
+ 
  export const buttonStyle = css({
    // ...
-   '@media (max-width: 430px)': {
+   [`@media (max-width: ${BREAKPOINTS.MOBILE})`]: {
      width: '84px',
    },
  });

Also applies to: 26-28, 33-35, 41-43, 49-51, 60-62, 71-73


77-85: border-radius 값의 일관성 확보 필요

inactiveLineStyle 함수에서 하드코딩된 border-radius 값들을 상수로 분리하면 스타일의 일관성을 더 쉽게 유지할 수 있을 것 같습니다.

다음과 같은 개선을 제안드립니다:

+ const BORDER_RADIUS = {
+   DESKTOP: {
+     LEFT: '10px 0 0 10px',
+     RIGHT: '0 10px 10px 0',
+   },
+   MOBILE: {
+     LEFT: '3px 0 0 3px',
+     RIGHT: '0 3px 3px 0',
+   },
+ };

  export const inactiveLineStyle = (label: string) => {
    let baseBorderRadius = '0';
    let mobileBorderRadius = '0';

    if (label === '인기') {
-     baseBorderRadius = '10px 0 0 10px';
-     mobileBorderRadius = '3px 0 0 3px';
+     baseBorderRadius = BORDER_RADIUS.DESKTOP.LEFT;
+     mobileBorderRadius = BORDER_RADIUS.MOBILE.LEFT;
    } else if (label === '월드컵') {
-     baseBorderRadius = '0 10px 10px 0';
-     mobileBorderRadius = '0 3px 3px 0';
+     baseBorderRadius = BORDER_RADIUS.DESKTOP.RIGHT;
+     mobileBorderRadius = BORDER_RADIUS.MOBILE.RIGHT;
    }

Also applies to: 92-96

src/components/organisms/BalanceGameList/BalanceGameList.tsx (2)

20-24: 타입 정의 개선 필요

activeTab의 타입과 관련된 문자열 리터럴을 상수로 분리하여 재사용성과 유지보수성을 높일 수 있습니다.

다음과 같은 개선을 제안드립니다:

export const TAB_TYPES = {
  EMPTY: '',
  COUPLE: '커플',
  PREFERENCE: '취향',
  WORLDCUP: '월드컵',
} as const;

type TabType = typeof TAB_TYPES[keyof typeof TAB_TYPES];

export interface ContentListProps {
  // ...
  activeTab: TabType;
  setActiveTab: React.Dispatch<React.SetStateAction<TabType>>;
  // ...
}

64-74: 조건부 렌더링 로직 개선 필요

삼항 연산자를 사용한 조건부 렌더링이 가독성을 떨어뜨립니다. 컴포넌트를 분리하거나 더 명확한 방식으로 처리하면 좋을 것 같습니다.

다음과 같은 개선을 제안드립니다:

const ToggleGroupComponent = {
  mobile: MobileToggleGroup,
  desktop: ToggleGroup,
};

const Component = isMobile ? ToggleGroupComponent.mobile : ToggleGroupComponent.desktop;

return (
  <Component
    selectedValue={selectedValue}
    onClick={isMobile ? handleToggleChange : setSelectedValue}
  />
);
src/pages/LandingPage/LandingPage.tsx (1)

62-80: 모바일 뷰의 구조적 개선이 필요합니다.

모바일 뷰에서 많은 props를 전달하고 있습니다. 컴포넌트의 책임을 줄이고 유지보수성을 높이기 위해 다음과 같은 개선을 제안합니다.

- <BalanceGameList
-   isMobile
-   contents={contents}
-   selectedValue={selectedValue}
-   setSelectedValue={setSelectedValue}
-   activeTab={activeTab}
-   setActiveTab={setActiveTab}
- />
+ <BalanceGameList
+   isMobile
+   contents={contents}
+   selectedValue={selectedValue}
+   onValueChange={setSelectedValue}
+   activeTab={activeTab}
+   onTabChange={setActiveTab}
+ />
src/components/atoms/Button/Button.style.ts (1)

207-213: circle 버튼의 medium 사이즈 스타일 개선이 필요합니다.

SVG 아이콘의 크기가 너무 작아 보입니다. 가독성을 위해 크기를 약간 키우는 것을 제안합니다.

medium: css({
  padding: '8.5px',
  '& svg': {
-   width: '10.5px',
-   height: '10.5px',
+   width: '12px',
+   height: '12px',
  },
}),
src/components/organisms/Header/Header.tsx (1)

175-198: 데스크톱 뷰의 중첩된 컨테이너를 단순화해주세요.

불필요하게 중첩된 rightContainerStyle이 있습니다. 구조를 단순화하여 가독성을 개선할 수 있습니다.

- <div css={S.rightContainerStyle}>
  <button
    type="button"
    onClick={handleLoginButton}
    css={S.LoginButtonStyle}
  >
    {accessToken ? '로그아웃' : '로그인'}
  </button>
  <div css={S.notificationStyle}>
    {accessToken ? (
      <ProfileIcon
        interaction="custom"
        imgUrl={member?.profileImgUrl ?? DefaultProfile}
        onClick={handleProfileIcon}
      />
    ) : (
      <ProfileIcon
        interaction="default"
        onClick={handleProfileIcon}
      />
    )}
  </div>
- </div>
src/styles/typo.ts (2)

193-198: 일관성 있는 스타일 속성을 유지하세요.

SemiBold_12Medium_12에서 letterSpacing 속성이 일관되지 않게 적용되어 있습니다. 또한 다른 스타일들과 달리 lineHeight1.3으로 설정되어 있습니다.

      SemiBold_12: {
        fontFamily: 'Pretendard',
        fontSize: '12px',
        fontWeight: 600,
-       lineHeight: '1.3',
+       lineHeight: '1.6',
+       letterSpacing: `${12 * -0.05}px`,
      },

Also applies to: 218-223


Line range hint 232-235: 기술 부채 해결 계획을 수립하세요.

이전 타이포 타입에 대한 TODO 주석이 있습니다. 기술 부채를 해결하기 위한 이슈를 생성하고 계획을 수립하는 것이 좋습니다.

이전 타이포 타입 정리를 위한 GitHub 이슈를 생성하시겠습니까?

src/assets/index.ts (1)

Line range hint 104-127: 이전 SVG 정리가 필요합니다.

TODO 주석으로 표시된 이전 SVG 파일들의 정리가 필요합니다. 현재 사용 중인 컴포넌트들과의 연관성을 확인하고 정리하는 것이 좋습니다.

이전 SVG 정리를 위한 GitHub 이슈를 생성하시겠습니까?

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 955bc16 and c4a8688.

⛔ Files ignored due to path filters (18)
  • package-lock.json is excluded by !**/package-lock.json
  • src/assets/svg/bookmark-df-sm.svg is excluded by !**/*.svg
  • src/assets/svg/bookmark-pr-sm.svg is excluded by !**/*.svg
  • src/assets/svg/check-small.svg is excluded by !**/*.svg
  • src/assets/svg/circle-close.svg is excluded by !**/*.svg
  • src/assets/svg/circle-game.svg is excluded by !**/*.svg
  • src/assets/svg/circle-pencil.svg is excluded by !**/*.svg
  • src/assets/svg/circle-talkpick.svg is excluded by !**/*.svg
  • src/assets/svg/couple-small.svg is excluded by !**/*.svg
  • src/assets/svg/list.svg is excluded by !**/*.svg
  • src/assets/svg/logo-small.svg is excluded by !**/*.svg
  • src/assets/svg/pick-vote-small.svg is excluded by !**/*.svg
  • src/assets/svg/popular-small.svg is excluded by !**/*.svg
  • src/assets/svg/random-game-small.svg is excluded by !**/*.svg
  • src/assets/svg/taste-small.svg is excluded by !**/*.svg
  • src/assets/svg/triangle-down.svg is excluded by !**/*.svg
  • src/assets/svg/triangle-up.svg is excluded by !**/*.svg
  • src/assets/svg/worldcup-small.svg is excluded by !**/*.svg
📒 Files selected for processing (53)
  • .storybook/main.ts (1 hunks)
  • .storybook/preview.ts (2 hunks)
  • package.json (1 hunks)
  • public/index.html (1 hunks)
  • src/api/game.ts (1 hunks)
  • src/assets/index.ts (1 hunks)
  • src/components/atoms/BalanceGameCategoryButton/BalanceGameCategoryButton.style.ts (5 hunks)
  • src/components/atoms/Bookmark/Bookmark.style.ts (1 hunks)
  • src/components/atoms/Bookmark/Bookmark.tsx (3 hunks)
  • src/components/atoms/Button/Button.style.ts (5 hunks)
  • src/components/atoms/Button/Button.tsx (1 hunks)
  • src/components/atoms/CategoryButton/CategoryButton.style.ts (1 hunks)
  • src/components/atoms/CategoryButton/CategoryButton.tsx (1 hunks)
  • src/components/atoms/Chips/Chips.style.ts (1 hunks)
  • src/components/atoms/SearchBar/SearchBar.style.ts (2 hunks)
  • src/components/atoms/SearchBar/SearchBar.tsx (1 hunks)
  • src/components/mobile/atoms/DraftSaveButton/DraftSaveButton.style.ts (1 hunks)
  • src/components/mobile/atoms/DraftSaveButton/DraftSaveButton.tsx (1 hunks)
  • src/components/mobile/atoms/FloatingButton/FloatingButton.style.ts (1 hunks)
  • src/components/mobile/atoms/FloatingButton/FloatingButton.tsx (1 hunks)
  • src/components/mobile/atoms/MobileSideMenu/MobileSideMenu.style.ts (1 hunks)
  • src/components/mobile/atoms/MobileSideMenu/MobileSideMenu.tsx (1 hunks)
  • src/components/mobile/atoms/MobileToggleGroup/MobileToggleGroup.style.ts (1 hunks)
  • src/components/mobile/atoms/MobileToggleGroup/MobileToggleGroup.tsx (1 hunks)
  • src/components/mobile/molecules/FloatingMenuButton/FloatingMenuButton.style.ts (1 hunks)
  • src/components/mobile/molecules/FloatingMenuButton/FloatingMenuButton.tsx (1 hunks)
  • src/components/molecules/CategoryBar/CategoryBar.style.ts (1 hunks)
  • src/components/molecules/CategoryBar/CategoryBar.tsx (2 hunks)
  • src/components/molecules/CategoryBox/CategoryBox.style.ts (1 hunks)
  • src/components/molecules/CategoryBox/CategoryBox.tsx (1 hunks)
  • src/components/molecules/ContentsButton/ContentsButton.style.ts (3 hunks)
  • src/components/molecules/ContentsButton/ContentsButton.tsx (1 hunks)
  • src/components/molecules/SearchTagBar/SearchTagBar.tsx (2 hunks)
  • src/components/molecules/TopBanner/TodayTalkPickBanner/TodayTalkPickBanner.style.ts (3 hunks)
  • src/components/molecules/TopBanner/TodayTalkPickBanner/TodayTalkPickBanner.tsx (3 hunks)
  • src/components/molecules/TopBanner/TopBanner.style.ts (2 hunks)
  • src/components/organisms/BalanceGameList/BalanceGameList.style.ts (1 hunks)
  • src/components/organisms/BalanceGameList/BalanceGameList.tsx (5 hunks)
  • src/components/organisms/Header/Header.style.ts (1 hunks)
  • src/components/organisms/Header/Header.tsx (4 hunks)
  • src/hooks/common/useIsMobile.ts (1 hunks)
  • src/layout/layout.tsx (2 hunks)
  • src/pages/LandingPage/LandingPage.style.ts (2 hunks)
  • src/pages/LandingPage/LandingPage.tsx (2 hunks)
  • src/stories/atoms/Bookmark.stories.tsx (3 hunks)
  • src/stories/atoms/CategoryButton.stories.tsx (2 hunks)
  • src/stories/mobile/atoms/DraftSaveButton.stories.tsx (1 hunks)
  • src/stories/mobile/atoms/FloatingButton.stories.tsx (1 hunks)
  • src/stories/mobile/atoms/MobileSideMenu.stories.tsx (1 hunks)
  • src/stories/mobile/atoms/MobileToggleGroup.stories.tsx (1 hunks)
  • src/stories/mobile/molecules/FloatingMenuButton.stories.tsx (1 hunks)
  • src/stories/molecules/CategoryBar.stories.tsx (2 hunks)
  • src/styles/typo.ts (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • public/index.html
  • src/components/mobile/atoms/DraftSaveButton/DraftSaveButton.style.ts
  • src/components/mobile/molecules/FloatingMenuButton/FloatingMenuButton.style.ts
🧰 Additional context used
🪛 eslint
src/api/game.ts

[error] 64-64: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 81-81: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)

🔇 Additional comments (34)
src/components/molecules/CategoryBox/CategoryBox.style.ts (1)

5-11: 반응형 디자인 구현이 잘 되었습니다!

모바일 환경을 고려한 스타일링이 적절하게 구현되었습니다:

  • 중앙 정렬을 위한 alignItemsjustifyContent 속성 추가
  • 모바일 화면에서의 간격 조정을 위한 미디어 쿼리 적용
  • 컨테이너의 전체 너비 활용
src/components/molecules/CategoryBox/CategoryBox.tsx (1)

7-7: Props 인터페이스 정의가 명확합니다.

모바일 대응을 위한 isMobile 옵션 프롭이 적절하게 추가되었습니다.

src/components/molecules/SearchTagBar/SearchTagBar.tsx (2)

9-9: 인터페이스 정의가 적절합니다!

optional 플래그(?)를 사용하여 isMobile prop을 선택적으로 만든 것이 좋습니다. 이는 기존 코드와의 호환성을 유지하면서도 모바일 대응이 가능하게 합니다.


12-12: 컴포넌트 시그니처가 잘 구성되었습니다!

isMobile의 기본값을 false로 설정한 것이 적절합니다. 이는 기존 데스크톱 동작을 기본값으로 유지하면서 모바일 지원을 추가하는 좋은 접근 방식입니다.

src/components/molecules/CategoryBar/CategoryBar.style.ts (1)

7-9: 모바일 반응형 스타일링이 적절히 구현되었습니다!

미디어 쿼리를 통한 모바일 최적화가 잘 되어있으며, 430px 브레이크포인트는 모바일 디바이스에 적합합니다.

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

15-19: 모바일 반응형 스타일링이 적절히 구현되었습니다.

미디어 쿼리를 통한 모바일 뷰포트 대응이 잘 되어있습니다. 430px 브레이크포인트는 일반적인 모바일 기기 너비에 적합합니다.


29-33: 모바일 입력 필드 스타일링이 일관성있게 적용되었습니다.

typo.Mobile.Text.Medium_12를 사용하여 모바일 타이포그래피 시스템을 잘 따르고 있습니다. 패딩과 높이 값이 모바일 환경에 적절합니다.

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

28-36: 버튼 스타일링이 모바일 디자인 시스템을 잘 따르고 있습니다.

typo.Mobile.Text.Medium_12를 사용한 타이포그래피와 터치 영역을 고려한 패딩 값이 적절합니다. 모바일 사용성을 잘 고려한 구현입니다.

src/stories/atoms/Bookmark.stories.tsx (1)

14-14: prop 이름 변경이 일관성 있게 적용되었습니다!

bookmarkState에서 bookmarked로의 prop 이름 변경이 더 명확하고 의미론적으로 개선되었습니다. 모든 필요한 위치(argTypes, args, stories)에서 일관되게 변경되었습니다.

Also applies to: 17-17, 26-26, 35-35, 38-38

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

15-18: 모바일 반응형 스타일이 적절하게 구현되었습니다.

타이포그래피와 패딩이 모바일 환경에 맞게 잘 조정되었습니다. 디자인 시스템의 typo.Mobile.Text 사용이 적절합니다.

src/stories/mobile/atoms/MobileSideMenu.stories.tsx (1)

8-27: 컴포넌트 메타데이터 구성이 잘 되어있습니다.

스토리북 설정이 체계적으로 구성되어 있으며, 필요한 모든 props와 액션이 잘 정의되어 있습니다. BrowserRouter 데코레이터 사용으로 라우팅 기능도 적절히 테스트할 수 있습니다.

src/stories/mobile/molecules/FloatingMenuButton.stories.tsx (1)

26-26: 타입 안전성이 잘 구현되어 있습니다.

satisfies 연산자를 사용하여 타입 안전성을 보장한 것이 좋습니다.

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

5-26: 반응형 디자인 구현이 잘 되어있습니다.

모바일 환경을 고려한 스타일링이 적절히 구현되어 있으며, 디자인 시스템의 색상 상수(color.WT)를 잘 활용하고 있습니다. 트랜지션 효과도 자연스럽게 적용되어 있습니다.


32-38: 타이포그래피 시스템 활용이 훌륭합니다.

디자인 시스템의 타이포그래피를 스프레드 연산자로 확장하여 사용한 방식이 깔끔합니다. 모바일 환경에서의 폰트 크기 조정도 적절합니다.

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

5-8: 토글 그룹 스타일 구현이 적절합니다.

flex 컨테이너를 사용하여 수직 방향으로 토글 아이템을 정렬하는 구현이 깔끔합니다.

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

5-9: Props 인터페이스 정의가 명확합니다.

ComponentPropsWithRef를 확장하여 버튼의 기본 속성들을 모두 지원하면서도, 필요한 커스텀 속성들을 추가한 것이 좋습니다.

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

3-9: 인터페이스 변경 사항이 적절해 보입니다.

모바일 대응을 위한 이미지 컴포넌트 추가와 isMobile 프로퍼티 추가가 잘 되어있습니다. 선택적 프로퍼티(?)로 설정한 것도 적절합니다.

Also applies to: 15-15

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

2-8: 모바일 아이콘 임포트가 잘 구성되어 있습니다.

모바일용 북마크 아이콘 컴포넌트들이 깔끔하게 구성되어 있습니다.

src/components/organisms/BalanceGameList/BalanceGameList.style.ts (1)

15-25: 모바일 타이포그래피 스타일이 적절하게 적용되었습니다.

typo.Mobile.Text.Bold_16을 사용하여 모바일 환경에 맞는 타이포그래피를 적용한 것이 좋습니다.

src/components/organisms/Header/Header.style.ts (1)

44-51: 모바일 레이아웃 대응이 잘 구현되었습니다.

rightContainerStyle에서 모바일 환경일 때 flex: 1justify-content: flex-end를 사용하여 레이아웃을 적절하게 조정한 것이 좋습니다.

src/stories/mobile/atoms/FloatingButton.stories.tsx (1)

8-21: 스토리 구성이 잘 되어있습니다!

메타 설정과 데코레이터 구성이 적절하며, 라우팅 컨텍스트를 위한 BrowserRouter 래퍼 사용이 좋습니다.

src/components/molecules/TopBanner/TopBanner.style.ts (1)

38-38: CSS 리셋 속성 사용이 적절합니다

all: 'unset'display: 'inline-block'을 함께 사용하여 스타일 초기화와 레이아웃 동작을 명확하게 정의한 것이 좋습니다.

Also applies to: 45-45

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

13-13: 타입 안전성이 잘 구현되어 있습니다

isMobile prop의 타입 정의와 기본값 설정이 명확하게 되어있어 좋습니다.

Also applies to: 17-17

src/layout/layout.tsx (2)

6-6: 모바일 대응을 위한 Footer 조건부 렌더링이 적절히 구현되었습니다.

useIsMobile 훅을 사용하여 모바일 환경에서 Footer를 숨기는 방식이 깔끔하게 구현되었습니다.

Also applies to: 10-10, 24-24


17-19: 모바일 뷰포트에서의 패딩 조정이 일관되게 적용되었습니다.

Layout과 LayoutNoSearch 컴포넌트 모두에서 모바일 환경(430px 이하)에 대한 패딩 조정이 동일하게 적용되어 일관성이 잘 유지되었습니다.

Also applies to: 40-42

src/components/molecules/ContentsButton/ContentsButton.tsx (1)

14-14: size 타입에 'extraSmall' 옵션이 추가된 것을 확인해주세요.

스타일 파일에서 'extraSmall' 사이즈에 대한 스타일이 적절히 정의되어 있는지 확인이 필요합니다.

✅ Verification successful

'extraSmall' 사이즈에 대한 스타일이 올바르게 정의되어 있음을 확인했습니다.

스타일 파일에서 'extraSmall' 사이즈에 대해 다음과 같은 스타일 속성들이 명확하게 정의되어 있습니다:

  • width: 162px
  • height: 121px
  • infoHeight: 40px
  • labelMaxWidth: 141px
  • imageHeight: 81px
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# ContentsButton.style.ts 파일에서 extraSmall 스타일 정의 확인
rg "extraSmall" -A 5 "src/components/molecules/ContentsButton/ContentsButton.style.ts"

Length of output: 218

.storybook/main.ts (1)

14-14: Storybook viewport 애드온 추가가 적절합니다.

모바일 반응형 디자인 테스트를 위한 @storybook/addon-viewport 추가는 적절한 변경사항입니다. 다만, preview 파일에서 적절한 설정이 되어있는지 확인이 필요합니다.

✅ Verification successful

Viewport 애드온이 올바르게 구성되어 있습니다

preview.ts 파일에서 viewport 설정이 적절하게 구현되어 있습니다:

  • INITIAL_VIEWPORTS가 정상적으로 임포트되어 있음
  • 커스텀 모바일 뷰포트(430px)가 추가되어 있음
  • parameters에서 viewport 설정이 올바르게 구성됨
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# preview 파일에서 viewport 설정 확인
rg "viewport" ".storybook/preview.ts"

Length of output: 134


Script:

#!/bin/bash
# preview 파일의 viewport 설정 전체 내용 확인
rg -A 10 "viewport: {" ".storybook/preview.ts"

Length of output: 132


Script:

#!/bin/bash
# preview 파일의 전체 내용 확인
cat ".storybook/preview.ts"

Length of output: 627

src/stories/atoms/CategoryButton.stories.tsx (1)

11-11: 모바일 지원을 위한 설정이 적절히 추가되었습니다.

스토리북에 모바일 지원을 위한 viewport 설정과 isMobile 속성이 잘 구현되어 있습니다.

Also applies to: 19-20, 24-25

src/api/game.ts (1)

72-76: API 파라미터 처리가 개선되었습니다.

고정 파라미터와 조건부 파라미터를 분리하여 처리하는 방식이 깔끔합니다. 특히 인기 게임 조회 시 불필요한 tagName 파라미터를 제외하는 로직이 잘 구현되었습니다.

Also applies to: 89-93

src/components/mobile/molecules/FloatingMenuButton/FloatingMenuButton.tsx (1)

13-77: 컴포넌트 구현이 잘 되었습니다.

  • 인증 상태에 따른 네비게이션 처리가 적절합니다.
  • 이벤트 리스너의 정리(cleanup)가 잘 구현되었습니다.
  • 상태 관리와 이벤트 처리가 깔끔합니다.
src/pages/LandingPage/LandingPage.tsx (1)

25-27: activeTab 상태 타입 변경이 적절합니다.

빈 문자열을 허용하도록 상태 타입을 변경한 것은 PR 목표와 일치하며, 인기 게임 조회 시 태그 파라미터를 제외하는 요구사항을 잘 반영하고 있습니다.

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

173-181: outlineShadow 버튼의 small 사이즈 스타일이 적절합니다.

모바일 환경을 고려한 작은 크기의 버튼 스타일이 잘 정의되어 있습니다. SVG 아이콘의 크기도 적절하게 조정되었습니다.

src/components/organisms/Header/Header.tsx (1)

35-37: 메뉴 토글 함수가 간단명료합니다.

상태 업데이트 로직이 함수형 업데이트를 사용하여 안전하게 구현되었습니다.

src/assets/index.ts (1)

86-102: 모바일 대응을 위한 에셋 추가가 잘 되었습니다.

새로운 모바일용 아이콘들이 일관된 명명 규칙을 따라 잘 추가되었습니다.

Comment on lines +8 to +11
const mobile = window.matchMedia('(max-width: 430px)').matches;
setIsMobile(
mobile || ('ontouchstart' in window && window.innerWidth <= 430),
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

모바일 기기 감지 로직 개선 필요

현재 구현은 다음과 같은 잠재적 문제가 있습니다:

  1. 430px의 고정된 브레이크포인트는 유지보수성이 떨어집니다
  2. 터치 기능이 있는 노트북에서 잘못된 판단을 할 수 있습니다

다음과 같이 개선하는 것을 추천드립니다:

+const MOBILE_BREAKPOINT = 430; // 상수로 분리
+
 const checkIsMobile = () => {
-  const mobile = window.matchMedia('(max-width: 430px)').matches;
+  const mobile = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT}px)`).matches;
   setIsMobile(
-    mobile || ('ontouchstart' in window && window.innerWidth <= 430),
+    mobile || (window.navigator.maxTouchPoints > 0 && window.innerWidth <= MOBILE_BREAKPOINT),
   );
 };
📝 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 mobile = window.matchMedia('(max-width: 430px)').matches;
setIsMobile(
mobile || ('ontouchstart' in window && window.innerWidth <= 430),
);
const MOBILE_BREAKPOINT = 430; // 상수로 분리
const mobile = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT}px)`).matches;
setIsMobile(
mobile || (window.navigator.maxTouchPoints > 0 && window.innerWidth <= MOBILE_BREAKPOINT),
);

Comment on lines +5 to +14
const customViewports = {
mobile: {
name: 'mobile',
styles: {
width: '430px',
height: '400px',
},
type: 'mobile',
},
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

모바일 뷰포트 설정 개선 필요

현재 구성은 단일 모바일 해상도만 지원하고 있습니다. 다양한 모바일 기기를 지원하기 위해 추가 뷰포트 설정이 필요합니다.

다음과 같이 개선하는 것을 추천드립니다:

 const customViewports = {
   mobile: {
     name: 'mobile',
     styles: {
       width: '430px',
-      height: '400px',
+      height: '932px',
     },
     type: 'mobile',
   },
+  mobileSM: {
+    name: 'mobile-small',
+    styles: {
+      width: '360px',
+      height: '780px',
+    },
+    type: 'mobile',
+  },
+  mobileXL: {
+    name: 'mobile-large',
+    styles: {
+      width: '480px',
+      height: '1040px',
+    },
+    type: 'mobile',
+  },
 };
📝 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 customViewports = {
mobile: {
name: 'mobile',
styles: {
width: '430px',
height: '400px',
},
type: 'mobile',
},
};
const customViewports = {
mobile: {
name: 'mobile',
styles: {
width: '430px',
height: '932px',
},
type: 'mobile',
},
mobileSM: {
name: 'mobile-small',
styles: {
width: '360px',
height: '780px',
},
type: 'mobile',
},
mobileXL: {
name: 'mobile-large',
styles: {
width: '480px',
height: '1040px',
},
type: 'mobile',
},
};

Comment on lines +1 to +2
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/no-unused-vars */
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

ESLint 비활성화 주석을 제거하는 것이 좋습니다.

ESLint 규칙을 비활성화하는 대신 코드를 수정하여 린트 규칙을 준수하는 것이 좋습니다. 특히 no-console@typescript-eslint/no-unused-vars 규칙은 중요한 코드 품질 지표입니다.

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

Comment on lines +5 to +17
export const buttonGroupStyle = css({
position: 'fixed',
top: '55px',
right: 0,
width: '134px',
height: '100%',
backgroundColor: color.WT,
boxShadow: '0px 0 5px rgba(0, 0, 0, 0.1)',
zIndex: 1100,
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
});
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

z-index 값의 일관성 있는 관리가 필요합니다

현재 코드베이스에서 z-index 값들이 다음과 같이 산발적으로 사용되고 있습니다:

  • Header: 1000
  • MobileSideMenu: 1100
  • CommentsSection: 1, 10
  • ImageBoxButton: 1, 2

z-index 값의 체계적인 관리를 위해 다음 작업이 필요합니다:

  • constants 파일에 z-index 값을 상수로 정의
  • 컴포넌트 계층 구조에 따른 z-index 값 체계 수립
  • 모바일 메뉴가 Header보다 높은 z-index를 가져야 하는 이유 문서화

iOS Safari에서의 fixed positioning 관련 스크롤 이슈는 QA 단계에서 반드시 확인이 필요합니다.

🔗 Analysis chain

z-index 값에 대한 문서화가 필요합니다.

z-index: 1100의 값이 임의로 설정된 것으로 보입니다. z-index 값의 체계와 의미를 문서화하고, 전역 상수로 관리하는 것이 좋습니다.

또한 fixed positioning을 사용할 때 iOS Safari에서 스크롤 이슈가 발생할 수 있으니 테스트가 필요합니다.


Let me search for more z-index values to get a complete picture.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# z-index 상수 정의 여부 확인
rg -g '*.{ts,tsx}' 'z-index.*[0-9]{4}'

Length of output: 105


Script:

#!/bin/bash
# Search for all z-index values in the codebase
rg -g '*.{ts,tsx}' 'z-index:' -A 1

Length of output: 752

Comment on lines +19 to +25
'@media (max-width: 430px)': {
width: '164px',
height: '70px',
padding: '5px 50px 14px',
borderRadius: '7px',
border: '0.35px solid #dedede',
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

미디어 쿼리 브레이크포인트 상수화 필요

미디어 쿼리의 브레이크포인트(430px)가 하드코딩되어 있습니다. 이를 중앙 관리되는 상수로 분리하여 일관성을 유지하는 것이 좋습니다.

// src/styles/breakpoints.ts
export const BREAKPOINTS = {
  MOBILE: '430px',
  TABLET: '768px',
  // ... 기타 브레이크포인트
} as const;

// 사용 예시
'@media (max-width: ${BREAKPOINTS.MOBILE})': {
  // ... 스타일
}

@@ -46,6 +46,7 @@
"@storybook/addon-interactions": "^8.1.9",
"@storybook/addon-links": "^8.1.9",
"@storybook/addon-onboarding": "^8.1.9",
"@storybook/addon-viewport": "^8.4.7",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Storybook 의존성 버전 불일치

@storybook/addon-viewport의 버전(^8.4.7)이 다른 Storybook 의존성들의 버전(^8.1.9)과 일치하지 않습니다. 호환성 문제를 방지하기 위해 버전을 일치시키는 것이 좋습니다.

다음과 같이 수정을 제안드립니다:

-    "@storybook/addon-viewport": "^8.4.7",
+    "@storybook/addon-viewport": "^8.1.9",
📝 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
"@storybook/addon-viewport": "^8.4.7",
"@storybook/addon-viewport": "^8.1.9",

Comment on lines +1 to +2
/* eslint-disable no-alert */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

ESLint 비활성화 주석 범위 축소 필요

파일 전체에 대한 ESLint 규칙 비활성화보다는 특정 라인에만 적용하는 것이 더 안전합니다.

다음과 같이 수정을 제안드립니다:

- /* eslint-disable no-alert */
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */

그리고 필요한 라인에만 규칙을 비활성화:

// alert 사용하는 라인에만 적용
// eslint-disable-next-line no-alert
alert(ERROR.GAME.NOT_EXIST);

Comment on lines +82 to +94
<div css={S.contentWrapStyle}>
<SearchTagBar onSearch={handleSearch} />
<div css={S.categoryBoxStyle}>
<CategoryBox handleService={handleService} />
</div>
<BalanceGameList
contents={contents}
selectedValue={selectedValue}
setSelectedValue={setSelectedValue}
activeTab={activeTab}
setActiveTab={setActiveTab}
/>
</div>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

데스크톱 뷰와 모바일 뷰의 중복 코드를 제거해주세요.

BalanceGameList 컴포넌트에 전달되는 props가 중복되어 있습니다. 공통 props를 추출하여 코드 중복을 줄이는 것이 좋겠습니다.

+ const commonBalanceGameProps = {
+   contents,
+   selectedValue,
+   setSelectedValue,
+   activeTab,
+   setActiveTab,
+ };

{isMobile ? (
  <BalanceGameList
    isMobile
+   {...commonBalanceGameProps}
-   contents={contents}
-   selectedValue={selectedValue}
-   setSelectedValue={setSelectedValue}
-   activeTab={activeTab}
-   setActiveTab={setActiveTab}
  />
) : (
  <BalanceGameList
+   {...commonBalanceGameProps}
-   contents={contents}
-   selectedValue={selectedValue}
-   setSelectedValue={setSelectedValue}
-   activeTab={activeTab}
-   setActiveTab={setActiveTab}
  />
)}

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

Comment on lines +153 to 170
{isMobile ? (
<>
<button
type="button"
aria-label="headerList"
onClick={handleMenuToggle}
css={S.listButtonStyle}
>
<ListIcon />
</button>
{isMenuOpen && (
<MobileSideMenu
isOpen={isMenuOpen}
setIsOpen={setIsMenuOpen}
accessToken={accessToken}
handleLoginButton={handleLoginButton}
/>
) : (
<ProfileIcon interaction="default" onClick={handleProfileIcon} />
)}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

모바일 메뉴 접근성 개선이 필요합니다.

모바일 메뉴 버튼과 사이드 메뉴의 접근성을 개선하기 위해 다음 사항들을 제안합니다:

<button
  type="button"
  aria-label="headerList"
+ aria-expanded={isMenuOpen}
+ aria-controls="mobile-side-menu"
  onClick={handleMenuToggle}
  css={S.listButtonStyle}
>
  <ListIcon />
</button>
{isMenuOpen && (
  <MobileSideMenu
+   id="mobile-side-menu"
+   role="dialog"
+   aria-modal="true"
    isOpen={isMenuOpen}
    setIsOpen={setIsMenuOpen}
    accessToken={accessToken}
    handleLoginButton={handleLoginButton}
  />
)}
📝 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
{isMobile ? (
<>
<button
type="button"
aria-label="headerList"
onClick={handleMenuToggle}
css={S.listButtonStyle}
>
<ListIcon />
</button>
{isMenuOpen && (
<MobileSideMenu
isOpen={isMenuOpen}
setIsOpen={setIsMenuOpen}
accessToken={accessToken}
handleLoginButton={handleLoginButton}
/>
) : (
<ProfileIcon interaction="default" onClick={handleProfileIcon} />
)}
{isMobile ? (
<>
<button
type="button"
aria-label="headerList"
aria-expanded={isMenuOpen}
aria-controls="mobile-side-menu"
onClick={handleMenuToggle}
css={S.listButtonStyle}
>
<ListIcon />
</button>
{isMenuOpen && (
<MobileSideMenu
id="mobile-side-menu"
role="dialog"
aria-modal="true"
isOpen={isMenuOpen}
setIsOpen={setIsMenuOpen}
accessToken={accessToken}
handleLoginButton={handleLoginButton}
/>
)}

Comment on lines +144 to +149
Medium_16: {
fontFamily: 'Pretendard',
fontSize: '16px',
lineHeight: '1.6',
letterSpacing: `${16 * -0.05}px`,
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

중복된 스타일 정의를 통합하세요.

Mobile.Main.Medium_16Mobile.Text.Medium_16이 동일한 스타일을 정의하고 있습니다. 코드 중복을 피하기 위해 하나의 정의로 통합하는 것이 좋습니다.

  Mobile: {
    Main: {
-     Medium_16: {
-       fontFamily: 'Pretendard',
-       fontSize: '16px',
-       lineHeight: '1.6',
-       letterSpacing: `${16 * -0.05}px`,
-     },
      // ... other styles
    },
    Text: {
      // ... other styles
      Medium_16: {
        fontFamily: 'Pretendard',
        fontSize: '16px',
+       fontWeight: 500,
        lineHeight: '1.6',
        letterSpacing: `${16 * -0.05}px`,
      },
    },
  }

Also applies to: 212-217

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: 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 c4a8688 and f27e036.

📒 Files selected for processing (1)
  • src/pages/LandingPage/LandingPage.tsx (2 hunks)
🧰 Additional context used
🪛 eslint
src/pages/LandingPage/LandingPage.tsx

[error] 31-31: React Hook "useBestGameList" is called conditionally. React Hooks must be called in the exact same order in every component render.

(react-hooks/rules-of-hooks)


[error] 36-36: React Hook "useLatestGameList" is called conditionally. React Hooks must be called in the exact same order in every component render.

(react-hooks/rules-of-hooks)

🔇 Additional comments (3)
src/pages/LandingPage/LandingPage.tsx (3)

13-14: 모바일 대응을 위한 import 추가가 적절합니다.

모바일 기능 구현을 위한 컴포넌트와 훅의 추가가 잘 되어있습니다.

Also applies to: 18-18


64-97: 모바일/데스크톱 뷰의 중복 코드가 있습니다.

이전 리뷰에서 지적된 BalanceGameList 컴포넌트의 props 중복 문제가 아직 해결되지 않았습니다.


25-27: activeTab 상태 변경이 요구사항과 일치합니다.

빈 문자열을 포함하도록 타입을 변경한 것이 인기 게임 조회 시 태그 파라미터를 제외하는 요구사항과 잘 부합합니다.

다음 스크립트로 관련 컴포넌트들의 타입 정의를 확인해보세요:

✅ Verification successful

activeTab 타입 변경이 일관되게 적용되었습니다.

검색 결과를 통해 다음과 같이 확인되었습니다:

  • CategoryBar 컴포넌트 (src/components/molecules/CategoryBar/CategoryBar.tsx)
  • BalanceGameList 컴포넌트 (src/components/organisms/BalanceGameList/BalanceGameList.tsx)
  • LandingPage 컴포넌트 (src/pages/LandingPage/LandingPage.tsx)

모든 관련 컴포넌트에서 activeTab 타입이 '' | '커플' | '취향' | '월드컵'으로 일관되게 정의되어 있어 타입 변경이 올바르게 적용되었습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# activeTab 타입이 일관되게 적용되었는지 확인
ast-grep --pattern 'type $_ = {
  $$$
  activeTab: $_;
  $$$
}'

Length of output: 65


Script:

#!/bin/bash
# activeTab 관련 타입과 사용처를 검색
rg "activeTab.*['\"]커플['\"].*['\"]취향['\"].*['\"]월드컵['\"]" -A 2 -B 2

# activeTab 상태 관리 코드 검색
ast-grep --pattern 'const [$_, $_] = useState<$_>($$$)'

# 관련 Props 타입 정의 검색
rg "interface.*Props" -A 5 -B 1

Length of output: 72387

Comment on lines +29 to +37
const { bestGames } =
activeTab === '' || selectedValue.field === 'views'
? useBestGameList(activeTab)
: { bestGames: undefined };

const { bestGames } = useBestGameList(activeTab);
const { latestGames } = useLatestGameList(activeTab);
const { latestGames } =
activeTab !== '' && selectedValue.field !== 'views'
? useLatestGameList(activeTab)
: { latestGames: undefined };
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Hook 호출 규칙 위반을 수정해주세요.

현재 구현은 React의 Hook 규칙을 위반하고 있습니다. Hook은 조건부로 호출될 수 없습니다.

다음과 같이 수정을 제안드립니다:

- const { bestGames } =
-   activeTab === '' || selectedValue.field === 'views'
-     ? useBestGameList(activeTab)
-     : { bestGames: undefined };

- const { latestGames } =
-   activeTab !== '' && selectedValue.field !== 'views'
-     ? useLatestGameList(activeTab)
-     : { latestGames: undefined };

+ const { bestGames } = useBestGameList(activeTab);
+ const { latestGames } = useLatestGameList(activeTab);
+ 
+ const filteredBestGames = (activeTab === '' || selectedValue.field === 'views') 
+   ? bestGames 
+   : undefined;
+ 
+ const filteredLatestGames = (activeTab !== '' && selectedValue.field !== 'views')
+   ? latestGames
+   : undefined;
+ 
- const contents = bestGames || latestGames || [];
+ const contents = filteredBestGames || filteredLatestGames || [];
📝 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 { bestGames } =
activeTab === '' || selectedValue.field === 'views'
? useBestGameList(activeTab)
: { bestGames: undefined };
const { bestGames } = useBestGameList(activeTab);
const { latestGames } = useLatestGameList(activeTab);
const { latestGames } =
activeTab !== '' && selectedValue.field !== 'views'
? useLatestGameList(activeTab)
: { latestGames: undefined };
const { bestGames } = useBestGameList(activeTab);
const { latestGames } = useLatestGameList(activeTab);
const filteredBestGames = (activeTab === '' || selectedValue.field === 'views')
? bestGames
: undefined;
const filteredLatestGames = (activeTab !== '' && selectedValue.field !== 'views')
? latestGames
: undefined;
const contents = filteredBestGames || filteredLatestGames || [];
🧰 Tools
🪛 eslint

[error] 31-31: React Hook "useBestGameList" is called conditionally. React Hooks must be called in the exact same order in every component render.

(react-hooks/rules-of-hooks)


[error] 36-36: React Hook "useLatestGameList" is called conditionally. React Hooks must be called in the exact same order in every component render.

(react-hooks/rules-of-hooks)

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 14 to +20

export interface CategoryBarProps {
activeTab: '인기' | '커플' | '취향' | '월드컵';
activeTab: '' | '커플' | '취향' | '월드컵';
setActiveTab: React.Dispatch<
React.SetStateAction<'인기' | '커플' | '취향' | '월드컵'>
React.SetStateAction<'' | '커플' | '취향' | '월드컵'>
>;
isMobile?: boolean;
Copy link
Collaborator

Choose a reason for hiding this comment

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

activeTab에 빈 문자열을 넣는 것 보단 '인기' 문자열을 넣고 tagName을 받는 함수에서 tagName이 인기가 아닐 경우에만 params에 tagName이 추가되도록 하는 건 어떨까요??? 4가지의 탭을 제어하는 컴포넌트이다보니 빈 문자열보단 각 태그의 이름이 들어가야 한다고 생각해요!!

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 +29 to +37
const { bestGames } =
activeTab === '' || selectedValue.field === 'views'
? useBestGameList(activeTab)
: { bestGames: undefined };

const { bestGames } = useBestGameList(activeTab);
const { latestGames } = useLatestGameList(activeTab);
const { latestGames } =
activeTab !== '' && selectedValue.field !== 'views'
? useLatestGameList(activeTab)
: { latestGames: undefined };
Copy link
Collaborator

Choose a reason for hiding this comment

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

해당 훅을 조건부로 호출하는 방식 대신에 react-query 훅 내부에 enabled 옵션을 통해 특정 조건을 만족할 경우 수행하도록 수행하는 것도 좋아보입니다 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
👩🏻‍💻 frontend 프론트엔드 작업 🪄refactor 리팩토링
Projects
None yet
Development

Successfully merging this pull request may close these issues.

변경된 밸런스게임 조회 api 파라미터 수정
3 participants