Skip to content

Conversation

@yulrang
Copy link
Contributor

@yulrang yulrang commented Nov 12, 2024

🔖 Issue Ticket

#98

✍️ Description

크루 찾기 페이지

  • 백엔드 API 연결
  • 지역전체 필터링 추가
  • 카테고리, 필터 동작 개선
  • 검색기능 추가 및 동작 개선

✅ Checklist

PR

  • Branch Convention 확인

    feat/ 피쳐, fix/ 버그 수정, refactor/ 개선

  • Base Branch 확인
  • 적절한 Label 지정
  • Assignee 및 Reviewer 지정

Test

  • 로컬 작동 확인

Screenshot 2024-11-12 at 15 43 36

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • FindCrew 컴포넌트 추가: 사용자 기준에 따라 승무원 검색 및 필터링 기능 제공.
    • ReactQueryDevtools 추가: 개발 도구를 통해 쿼리 상태를 시각화 가능.
    • region.json에 "지역 전체" 항목 추가: 모든 지역을 포함하는 범주 제공.
  • 변경 사항

    • getCrewList API 호출 방식 변경: 여러 조건을 기반으로 데이터 요청.
    • CrewCardListCrewCard 컴포넌트의 데이터 구조 업데이트: 새로운 프로퍼티 사용.
    • useGetCrewQueryuseGetCrewListQuery로 변경: 데이터 가져오는 방식 개선.
    • CategoryContainerInternalCategory 컴포넌트의 상태 관리 간소화.
    • Home 컴포넌트를 비동기 함수로 변경하여 데이터 가져오기 방식 개선.
    • TextInput 컴포넌트의 register prop 통합: 폼 처리 기능 개선.
    • CrewCardList 컴포넌트의 데이터 접근 방식 및 렌더링 로직 조정: 더 강력한 데이터 처리 구현.
  • 버그 수정

    • useInfiniteScroll 훅에 refetch 기능 추가: 데이터 새로 고침 가능.

commit 51cfe2f
Author: Lee Youl <[email protected]>
Date:   Sat Nov 9 11:40:05 2024 +0900

    🐛 Fix: MockData 날짜 형식 수정

commit 7b68352
Author: Lee Youl <[email protected]>
Date:   Sat Nov 9 11:38:06 2024 +0900

    🐛 Fix: 이전날짜 선택 방지, isToday 날짜 비교 수정

commit f101987
Author: Lee Youl <[email protected]>
Date:   Sat Nov 9 11:19:20 2024 +0900

    🐛 Fix: 폼 동작 개선

commit c408058
Author: Lee Youl <[email protected]>
Date:   Sat Nov 9 10:51:40 2024 +0900

    🐛 Fix: isToday 함수 개선, 데이터 한국시간 기준으로 변경

commit 0683f5a
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 21:49:45 2024 +0900

    🐛 Fix: 버튼 링크로 교체

commit 43cdfa7
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 21:43:11 2024 +0900

    🚨 Fix: 린트 오류 제거

commit 9657201
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 21:34:56 2024 +0900

    🐛 Fix: 스크롤바 두개로 보이는 문제 수정

commit 63a8e1c
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 21:27:25 2024 +0900

    🐛 Fix: 유효성 검사 날짜 선택 오류 수정

commit 80f8554
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 21:24:46 2024 +0900

    🐛 Fix: 에러상태인데 새로 값 채울 때 에러 해제하기, 리팩토링

commit af9fb91
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 20:46:00 2024 +0900

    🐛 Fix: 크루 생성시 디테일 페이지로 이동, 리팩토링

commit f1fe204
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 20:31:17 2024 +0900

    🐛 Fix: 텍스트 수정(약속 잡기 > 약속 만들기)

commit 5cc6746
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 20:29:52 2024 +0900

    🐛 Fix: 드롭다운 값 선택시 포커스 아웃 되도록 수정
@coderabbitai
Copy link

coderabbitai bot commented Nov 12, 2024

Caution

Review failed

The pull request is closed.

Walkthrough

이 풀 리퀘스트는 여러 파일에서의 변경 사항을 포함하고 있습니다. 주요 변경 사항으로는 package.json에 새로운 개발 종속성을 추가하고, getCrewList 함수의 매개변수를 업데이트하여 API 요청을 더 복잡하게 조정하는 것입니다. 또한, 여러 컴포넌트에서의 데이터 처리 방식이 변경되었으며, 새로운 FindCrew 컴포넌트가 추가되었습니다. 전반적으로, 데이터 요청 및 상태 관리를 개선하기 위한 구조적 변화가 이루어졌습니다.

Changes

파일 경로 변경 요약
package.json 새로운 개발 종속성 @tanstack/react-query-devtools 추가.
src/_apis/crew/get-crew-list.ts getCrewList 함수의 매개변수를 업데이트하여 더 복잡한 쿼리 문자열을 사용하도록 변경.
src/_queries/crew-queries.tsx useGetCrewQueryuseGetCrewListQuery로 이름 변경 및 매개변수 변경.
src/app/(crew)/page.tsx Home 컴포넌트를 HomePage로 이름 변경하고 비동기 함수로 변경. 데이터 가져오기 로직 수정.
src/app/_components/category/category-container/index.tsx useEffect 훅 제거 및 상태 관리 간소화.
src/app/_components/category/internal-category/index.tsx onChange 핸들러 수정 및 버튼의 활성 상태 결정 조건 변경.
src/app/_components/category/main-category/index.tsx 클릭 이벤트 핸들러 수정 및 버튼 배경색 결정 조건 변경.
src/components/client-provider.tsx ReactQueryDevtools 컴포넌트를 추가하여 상태 관리 도구 통합.
src/components/common/crew-list/crew-card-list.tsx 데이터 접근 방식 변경 및 여러 속성 업데이트.
src/components/common/crew-list/crew-card.tsx CrewCardProps 인터페이스 업데이트 및 렌더링 로직 수정.
src/data/region.json 새로운 지역 항목 추가.
src/types/crew-card.d.ts 새로운 인터페이스 ConditionTypesPageableTypes 추가, 기존 타입 수정.
src/app/(crew)/my-crew/page.tsx useGetCrewQueryuseGetCrewListQuery로 변경.
src/components/common/crew-list/crew-card-list.stories.tsx 쿼리 훅 변경 및 데이터 가져오기 방식 수정.
src/hooks/use-infinite-scroll.ts useInfiniteScroll 훅에 refetch 함수 추가.
src/app/_components/find-crew/find-crew.tsx 새로운 FindCrew 컴포넌트 추가 및 상태 관리 로직 구현.
src/components/common/input/text-input/index.tsx register prop을 MantineTextInput에 적용하여 폼 등록 기능 향상.

Possibly related PRs

  • Feat/101/login signup api #106: 새로운 React Query Devtools 관련 종속성을 추가하는 변경 사항이 포함되어 있으며, 이는 로그인 및 회원가입 API 상호작용을 개선하는 auth-apis.tsx 파일의 수정과 관련이 있습니다.

Suggested labels

fix

Suggested reviewers

  • HaeJungg
  • Rangbyeolang
  • minkyung5x5

🐰 변화의 소식이 들려와,
새로운 도구로 더 나은 길을 가네.
쿼리도 더 똑똑해지고,
데이터도 쉽게 얻어지네.
모두 함께 더 나은 세상으로,
크루를 찾아 나서는 여정이여! 🌟

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/components/client-provider.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't determine the plugin "react-hooks" uniquely.

  • /node_modules/eslint-plugin-react-hooks/index.js (loaded in ".eslintrc.js")
  • /node_modules/eslint-config-next/node_modules/eslint-plugin-react-hooks/index.js (loaded in ".eslintrc.js » eslint-config-next/core-web-vitals » /node_modules/eslint-config-next/index.js » plugin:react-hooks/recommended")

Please remove the "plugins" setting from either config or remove either plugin installation.

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.


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

@yulrang yulrang linked an issue Nov 12, 2024 that may be closed by this pull request
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: 11

🧹 Outside diff range and nitpick comments (6)
src/app/_components/category/category-container/index.tsx (1)

34-38: 코드 최적화 제안

현재 구현에서 category[categoryIndex ?? 0]가 여러 번 반복되고 있습니다. 이를 최적화하여 가독성과 유지보수성을 향상시킬 수 있습니다.

다음과 같이 개선하는 것을 제안드립니다:

+ const selectedCategory = category[categoryIndex ?? 0];
- category={category[categoryIndex ?? 0].items}
+ category={selectedCategory.items}
  onChange={(newValue) => {
    setSubCategory(newValue);
-   setMainCategory(category[categoryIndex ?? 0].title.label);
+   setMainCategory(selectedCategory.title.label);
  }}
src/types/crew-card.d.ts (2)

13-17: 정렬 필드의 타입 안전성 개선이 필요합니다

sort 필드가 현재 string[]로 정의되어 있어 타입 안전성이 부족합니다. 허용되는 정렬 기준을 명확히 정의하는 것이 좋겠습니다.

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

+type SortField = 'createdDate' | 'participantCount';
+type SortDirection = 'asc' | 'desc';
+type SortOption = `${SortField},${SortDirection}`;

 export interface PageableTypes {
   page: number;
   size: number;
-  sort: string[];
+  sort: SortOption[];
 }

24-37: 타입 일관성 검토 및 문서화가 필요합니다

  1. mainCategorysubCategoryConditionTypes에서는 필수지만 여기서는 선택적입니다. 이러한 불일치가 의도된 것인지 확인이 필요합니다.
  2. 각 필드의 의미와 제약사항에 대한 문서화가 있으면 좋겠습니다.

다음과 같이 문서화를 추가하는 것을 제안합니다:

 export interface CrewCardListTypes {
+  /** 크루의 고유 식별자 */
   id: number;
+  /** 메인 카테고리 (예: '운동', '취미' 등) */
   mainCategory?: string;
+  /** 서브 카테고리 (예: '축구', '농구' 등) */
   subCategory?: string;
   // ... 나머지 필드에 대해서도 비슷한 방식으로 문서화 추가
 }
src/components/common/crew-list/crew-card.tsx (1)

Line range hint 83-98: 참여자 수 표시와 ProgressBar 구현이 적절합니다.

현재 참여자 수와 전체 인원 수가 명확히 표시되며, ProgressBar 컴포넌트와도 잘 연동되어 있습니다.

다만, 한 가지 제안사항이 있습니다:

참여자 수가 전체 인원 수를 초과하지 않도록 유효성 검사를 추가하는 것이 좋을 것 같습니다:

+const safeParticipantCount = Math.min(participantCount, totalCount);
 <span className="text-base font-medium">
-  {participantCount}/{totalCount}
+  {safeParticipantCount}/{totalCount}
 </span>
src/app/(crew)/page.tsx (1)

23-27: 지역 처리 로직 개선이 필요합니다.

현재 구현에서 다음 사항들을 고려해보시기 바랍니다:

  • 유효하지 않은 newValue 처리
  • selectedRegion이 undefined일 때의 처리

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

 const handleRegionChange = (newValue: string) => {
+  if (!newValue) return '';
   const selectedRegion = regionData.find((dataItem) => dataItem.main.value === newValue);
   if (selectedRegion?.main.label === '지역 전체') return '';
-  return selectedRegion ? selectedRegion.main.label : '';
+  return selectedRegion?.main.label ?? '';
 };
src/data/region.json (1)

2-5: 성능 최적화를 위한 제안

지역 필터링 시 전체 배열을 순회하는 것을 방지하기 위해, 상수나 별도의 플래그를 사용하는 것을 고려해보세요.

-    "main": { "label": "지역 전체", "value": "" },
+    "main": { "label": "지역 전체", "value": "ALL" },
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5bb737f and 22f3307.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • public/assets/images/img-default.jpg is excluded by !**/*.jpg
📒 Files selected for processing (14)
  • next.config.mjs (1 hunks)
  • package.json (1 hunks)
  • src/_apis/crew/get-crew-list.ts (1 hunks)
  • src/_queries/crew-queries.tsx (1 hunks)
  • src/app/(crew)/page.tsx (3 hunks)
  • src/app/_components/category/category-container/index.tsx (2 hunks)
  • src/app/_components/category/internal-category/index.tsx (1 hunks)
  • src/app/_components/category/main-category/index.tsx (1 hunks)
  • src/components/client-provider.tsx (2 hunks)
  • src/components/common/crew-list/crew-card-list.tsx (2 hunks)
  • src/components/common/crew-list/crew-card.tsx (4 hunks)
  • src/data/region.json (1 hunks)
  • src/hooks/useInfiniteScroll.ts (2 hunks)
  • src/types/crew-card.d.ts (1 hunks)
🔇 Additional comments (21)
src/hooks/useInfiniteScroll.ts (2)

13-13: refetch 기능 추가가 적절합니다.

useInfiniteQuery에서 refetch 함수를 추출하여 수동으로 데이터를 새로고침할 수 있는 기능을 추가한 것이 좋습니다. 이는 사용자 인터랙션에 따라 데이터를 갱신해야 하는 경우에 유용할 것 같습니다.


28-28: refetch 노출에 따른 사용처 확인이 필요합니다.

refetch 기능을 외부로 노출함으로써 컴포넌트에서 데이터를 수동으로 새로고침할 수 있게 되었습니다. 이 기능이 crew 목록을 새로고침하는데 적절히 활용되는지 확인해주세요.

src/components/client-provider.tsx (1)

5-5: 적절한 import 구문 추가

React Query DevTools를 위한 import 구문이 올바르게 추가되었습니다.

next.config.mjs (1)

36-38: 환경 변수 유효성 검사가 필요합니다.

NEXT_PUBLIC_API_BASE_URL 환경 변수가 설정되지 않은 경우에 대한 처리가 필요합니다.

다음 스크립트로 환경 변수 설정을 확인할 수 있습니다:

환경 변수 검증을 위해 다음과 같은 수정을 제안합니다:

  async rewrites() {
+   const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
+   if (!apiBaseUrl) {
+     throw new Error('NEXT_PUBLIC_API_BASE_URL 환경 변수가 설정되지 않았습니다.');
+   }
    return [
      {
        source: '/api/:path*',
-       destination: `${process.env.NEXT_PUBLIC_API_BASE_URL}/:path*`,
+       destination: `${apiBaseUrl}/:path*`,
      },
    ];
  },
src/app/_components/category/category-container/index.tsx (2)

26-29: 메인 카테고리 변경 시 서브 카테고리 초기화 처리가 적절합니다

메인 카테고리가 변경될 때 서브 카테고리를 초기화하는 것은 올바른 접근 방식입니다. 이는 유효하지 않은 카테고리 조합을 방지할 수 있습니다.


19-19: categoryIndex의 null 처리 검증 필요

categoryIndexnull로 초기화하는 것은 잠재적인 런타임 에러를 발생시킬 수 있습니다. 컴포넌트의 다른 부분에서 categoryIndexnull일 때의 처리가 올바르게 되어있는지 확인이 필요합니다.

✅ Verification successful

categoryIndex의 null 처리가 안전하게 구현되어 있습니다

categoryIndex가 null일 경우 널 병합 연산자(??)를 사용하여 기본값 0으로 안전하게 처리되고 있습니다. 다음과 같은 부분에서 확인됩니다:

  • category[categoryIndex ?? 0].items
  • category[categoryIndex ?? 0].title.label

따라서 초기값이 null이어도 런타임 에러가 발생하지 않습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: categoryIndex가 null일 때의 처리가 있는지 확인

# categoryIndex 사용 부분 검색
rg -t typescript "categoryIndex" src/

Length of output: 72


Script:

#!/bin/bash
# Search for categoryIndex usage with proper file extensions
rg "categoryIndex" --type-add 'ts:*.{ts,tsx}' --type ts src/

Length of output: 673

src/types/crew-card.d.ts (1)

19-22: 응답 구조 변경에 따른 영향도 확인이 필요합니다

응답 구조가 변경되어 기존 코드에 영향을 줄 수 있습니다. 특히 data에서 content로의 변경과 hasNextPage에서 hasNext로의 변경은 주의가 필요합니다.

✅ Verification successful

Let me gather more information about the usage of the new field names to verify the impact.


응답 구조 변경에 대한 코드베이스 영향 확인 완료

CrewCardInformResponse 타입의 필드명 변경이 이미 관련 코드에 반영되어 있습니다:

  • crew-queries.tsx에서 hasNext를 정상적으로 사용 중
  • 기존 data 필드와 hasNextPage 필드는 다른 응답 타입들(WritableGatheringResponse, ReviewResponse 등)에서 사용되는 것으로, 이번 변경과는 무관
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 변경된 필드명 사용 여부 확인

# data -> content로의 변경 영향 확인
rg "\.data\." --type ts

# hasNextPage -> hasNext로의 변경 영향 확인
rg "hasNextPage" --type ts

Length of output: 2169


Script:

#!/bin/bash
# Check for usage of new field names
rg "\.content\." --type ts
rg "\.hasNext\b" --type ts

# Check for CrewCardInformResponse usage
ast-grep --pattern 'CrewCardInformResponse'

Length of output: 781

src/app/_components/category/internal-category/index.tsx (2)

34-34: 🛠️ Refactor suggestion

pathname 매칭 로직 검토가 필요합니다

pathname?.includes(item.label ?? value)는 다음과 같은 잠재적 문제가 있습니다:

  1. URL에 라벨이 포함된 다른 문자열이 있을 경우 잘못된 매칭이 발생할 수 있습니다
  2. 라벨에 URL에서 사용할 수 없는 특수문자가 포함된 경우 매칭이 실패할 수 있습니다
#!/bin/bash
# URL 라우팅 패턴 확인
rg -A 5 "path|route" "src/app/page.tsx"

# 실제 사용되는 카테고리 값 확인
ast-grep --pattern 'const $_ = [{
  $$$
}] as const'

다음과 같이 정확한 매칭을 구현하는 것을 제안합니다:

-pathname?.includes(item.label ?? value)
+pathname?.includes(`/category/${encodeURIComponent(item.label ?? value)}`)

33-33: 🛠️ Refactor suggestion

타입 안전성 개선이 필요합니다

item.label을 사용하는 것은 CategoryItem 타입에서 필수 필드임을 보장해야 합니다. 또한 부모 컴포넌트에서 기대하는 값과 일치하는지 확인이 필요합니다.

다음과 같이 타입 안전성을 개선하는 것을 제안합니다:

export interface CategoryItem {
-  label?: string;
+  label: string;  // 필수 필드로 변경
   value: string;
}
✅ Verification successful

Let me gather more information about the CategoryItem interface and its usage.


타입 안전성 검토 완료

CategoryItem 인터페이스에서 label 필드가 이미 필수 필드(string)로 정의되어 있어 타입 안전성이 보장되어 있습니다. 또한 부모 컴포넌트에서도 onChange 핸들러가 올바르게 문자열 값을 처리하고 있습니다.

  • src/types/category.d.ts에서 label이 필수 문자열 필드로 정의됨
  • InternalCategoryPropsonChange 타입이 (value: string) => void로 정확히 정의됨
  • 부모 컴포넌트들이 일관된 방식으로 값을 처리하고 있음
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# CategoryItem 타입 정의와 부모 컴포넌트의 사용법 확인
ast-grep --pattern 'interface CategoryItem {
  $$$
}'

# 부모 컴포넌트에서 InternalCategory 사용 패턴 확인
rg -A 5 '<InternalCategory'

Length of output: 1992


Script:

#!/bin/bash
# Check for CategoryItem interface definition
ast-grep --pattern 'interface CategoryItem {
  $$$
}'

# Check for type definitions in the component
ast-grep --pattern 'interface InternalCategoryProps {
  $$$
}'

# Check how item.label is used in the component
rg -A 2 'item\.label' src/app/_components/category/internal-category/

Length of output: 1871

src/components/common/crew-list/crew-card-list.tsx (3)

Line range hint 1-56: 전반적인 구현이 잘 되어있습니다

  • 무한 스크롤 구현이 적절합니다
  • 로딩 상태 처리가 잘 되어있습니다
  • 반응형 그리드 레이아웃이 효과적으로 구현되어있습니다
  • 코드가 깔끔하고 유지보수가 용이합니다

34-42: CrewCard 컴포넌트 속성 이름이 개선되었습니다

기존의 모호했던 속성 이름들이 더 명확하고 의미있게 변경되었습니다:

  • locationmainLocation
  • detailedLocationsubLocation
  • nametitle
  • thumbnailimageUrl
✅ Verification successful

CrewCard 컴포넌트의 속성 변경이 올바르게 적용되었습니다

CrewCardListTypes 인터페이스와 실제 컴포넌트 구현에서 변경된 속성들이 일관되게 적용되어 있음을 확인했습니다:

  • title, mainLocation, subLocation, imageUrl 등의 새로운 속성명이 타입 정의와 일치합니다
  • 컴포넌트에서 이러한 속성들이 올바르게 사용되고 있습니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# CrewCard 컴포넌트의 props 타입 정의 확인
ast-grep --pattern 'interface CrewCardProps {
  $$$
}'

Length of output: 56


Script:

#!/bin/bash
# CrewCard 컴포넌트의 props 타입 정의를 찾기 위한 다른 방법 시도
rg -A 15 "type CrewCardProps|interface CrewCardProps" --type typescript

# CrewCard 컴포넌트 파일 찾기
fd "crew-card" -e tsx -e ts

Length of output: 431


Script:

#!/bin/bash
# CrewCard 컴포넌트와 타입 정의 파일의 내용 확인
cat src/components/common/crew-list/crew-card.tsx
cat src/types/crew-card.d.ts

Length of output: 4755


17-17: API 응답 구조 변경 확인 필요

백엔드 API의 응답 구조가 data에서 content로 변경된 것으로 보입니다. 이 변경이 API 계약과 일치하는지 확인이 필요합니다.

✅ Verification successful

API 응답 구조가 올바르게 적용되었습니다

page.content를 사용하는 것이 정확합니다. API 응답 타입 CrewCardInformResponse와 페이지네이션 로직이 일관되게 구현되어 있으며, useGetCrewListQuery에서 반환되는 데이터 구조와도 일치합니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# API 응답 구조 변경이 다른 파일에도 영향을 미치는지 확인
rg -g '*.ts*' 'pages\.data' 

Length of output: 29


Script:

#!/bin/bash
# Check for any usage of page.content in TypeScript files
rg -g '*.ts*' 'page\.content' -A 2

# Search for API response type definitions
ast-grep --pattern 'interface $_ {
  $$$
  content: $_
  $$$
}'

# Look for pagination-related types
fd -e ts -e tsx | xargs rg 'type.*Page.*=' -A 2

Length of output: 445


Script:

#!/bin/bash
# API 응답 타입 정의 검색
ast-grep --pattern 'type Page = {
  $$$
}'

# API 호출 관련 코드 검색
rg -g '*.ts*' 'useQuery|useInfiniteQuery' -B 2 -A 2

# 페이지네이션 관련 타입 임포트 검색
rg -g '*.ts*' 'import.*Page.*from' -A 1

Length of output: 3921


Script:

#!/bin/bash
# 크루 카드 타입 정의 확인
cat src/types/crew-card.ts

# 크루 리스트 API 호출 구현 확인
cat src/_apis/crew/get-crew-list.ts

# 크루 쿼리 구현 확인
cat src/_queries/crew-queries.tsx

Length of output: 1750

src/app/_components/category/main-category/index.tsx (1)

65-66: 라벨 기반 카테고리 처리로의 전환 검증 필요

카테고리 처리 방식이 value에서 label 기반으로 변경되었습니다. 이는 사용자 경험 측면에서 더 직관적일 수 있으나, 다음 사항들을 확인해 주시기 바랍니다:

  1. 라우팅 시스템이 한글 URL을 올바르게 처리하는지
  2. 다국어 지원 시 발생할 수 있는 문제는 없는지
✅ Verification successful

label 기반 카테고리 처리 방식이 일관되게 구현되어 있음을 확인

코드베이스 분석 결과, 다음과 같은 사항들이 확인되었습니다:

  • MainCategoryInternalCategory 컴포넌트 모두 label 기반으로 일관되게 구현되어 있습니다.
  • 라우팅 처리도 label 값을 기준으로 올바르게 동작하고 있습니다.
  • create-crew-form에서 발견된 title.value 사용은 별도의 컨텍스트에서 사용되는 것으로, 현재 변경사항과 충돌하지 않습니다.

카테고리 처리 방식의 변경이 전체 시스템에서 일관성 있게 적용되어 있어 문제가 없을 것으로 판단됩니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of label vs value in related components
# Check for any inconsistencies in category handling

# Search for title.value usage that might need to be updated
rg "title\.value" --type typescript

# Search for routing logic that might need adjustment
rg "usePathname.*includes" --type typescript

Length of output: 154


Script:

#!/bin/bash
# Search for title.value usage that might need to be updated
rg "title\.value"

# Search for routing logic that might need adjustment
rg "usePathname.*includes"

# Search for files containing both pathname and label
rg "pathname.*label"

# Find all TypeScript/JavaScript files in the category components
fd "\.(tsx?|jsx?)$" "src/app/_components/category"

Length of output: 1196


Script:

#!/bin/bash
# Check the implementation of category data structure
cat src/app/_components/category/main-category/index.tsx

# Check internal category implementation
cat src/app/_components/category/internal-category/index.tsx

# Look for category type definitions
rg "type.*Category" -A 5

Length of output: 4368

src/components/common/crew-list/crew-card.tsx (3)

7-7: 타입 임포트와 이미지 에셋 임포트가 적절히 구성되었습니다.

새로운 타입과 기본 이미지가 잘 임포트되었습니다.

Also applies to: 10-10


13-29: Props 인터페이스가 CrewCardListTypes를 확장하도록 개선되었습니다.

타입 정의가 더 체계적으로 구성되었으며, 선택적 속성 inWhere를 통해 마이크루 페이지에서의 사용성도 고려되었습니다.


67-74: 텍스트 표시 방식이 개선되었습니다.

제목과 위치 정보가 명확하게 구분되어 표시되며, 현재 약속 개수도 직관적으로 표현되었습니다.

src/app/(crew)/page.tsx (3)

6-6: LGTM: API 쿼리 훅 변경이 적절히 이루어졌습니다.

useGetCrewListQuery 로의 변경이 새로운 데이터 구조와 잘 맞습니다.


29-37: 쿼리 파라미터 타입 검증이 필요합니다.

useGetCrewListQuery에 전달되는 파라미터들의 타입이 ConditionTypes와 일치하는지 확인이 필요합니다.

#!/bin/bash
# Description: 쿼리 타입 정의 확인

# ConditionTypes 정의 확인
ast-grep --pattern 'type ConditionTypes = {
  $$$
}'

# 쿼리 훅 구현 확인
ast-grep --pattern 'useGetCrewListQuery = (condition: ConditionTypes) => {
  $$$
}'

17-21: 상태 초기값 검증이 필요합니다.

빈 문자열로 초기화된 상태값들이 애플리케이션의 다른 부분에 영향을 미치지 않는지 확인이 필요합니다.

✅ Verification successful

상태값 초기화 변경은 안전해 보입니다.

파일 내에서 상태값들이 지역적으로 관리되고 있으며, 빈 문자열로 초기화하는 것이 문제가 되지 않을 것으로 판단됩니다. 상태값들은 컴포넌트 내부에서만 사용되는 필터링 용도로 보이며, 빈 문자열은 필터가 적용되지 않은 초기 상태를 나타내는 적절한 값입니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 상태값이 빈 문자열일 때의 처리 검증

# 상태값 사용처 확인
rg -l "mainCategory|subCategory|region" --type tsx

Length of output: 140


Script:

#!/bin/bash
# 상태값 사용처를 더 정확하게 확인하기 위한 검색
rg "mainCategory|subCategory|region" --type tsx -A 3 -B 3

# 관련 타입 정의 확인
ast-grep --pattern 'type $_ = {
  mainCategory?: $_
  subCategory?: $_
  region?: $_
  $$$
}'

# API 호출이나 데이터 처리 로직 확인
ast-grep --pattern 'const $_ = ({mainCategory, subCategory, region}: $_) => {
  $$$
}'

Length of output: 272


Script:

#!/bin/bash
# TypeScript/React 파일에서 상태값 사용처 확인
rg "mainCategory|subCategory|region" -t ts -t tsx -A 3 -B 3

# 조건부 렌더링이나 데이터 필터링 확인
ast-grep --pattern 'if ($$$mainCategory$$$) {
  $$$
}'

# API 요청이나 데이터 처리 로직 확인
ast-grep --pattern 'useQuery($$$, {
  $$$
  mainCategory,
  subCategory,
  region,
  $$$
})'

Length of output: 241

src/data/region.json (1)

2-5: 새로운 "지역 전체" 옵션이 적절하게 추가되었습니다.

필터링 기능을 위한 전체 지역 옵션의 구조가 기존 데이터 형식과 일관성있게 구현되었습니다.

src/_apis/crew/get-crew-list.ts (1)

9-9: ⚠️ Potential issue

'sort' 기본값 확인 필요

sort의 기본값이 ['string']으로 설정되어 있습니다. 의도한 값인지 확인해주세요. 만약 실제 정렬 기준을 의미한다면 적절한 값으로 수정하는 것이 좋습니다.


return (
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools initialIsOpen={false} />
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

프로덕션 환경에서 ReactQueryDevtools 조건부 렌더링 필요

ReactQueryDevtools가 프로덕션 환경에서도 포함될 수 있는 상태입니다. 다음과 같이 수정이 필요합니다:

  • src/components/client-provider.tsx에서 process.env.NODE_ENV를 확인하여 개발 환경에서만 ReactQueryDevtools를 렌더링하도록 수정해야 합니다.
{process.env.NODE_ENV === 'development' && <ReactQueryDevtools initialIsOpen={false} />}
🔗 Analysis chain

개발 환경에서만 사용되도록 확인 필요

ReactQueryDevtools가 적절하게 추가되었고 initialIsOpen이 false로 설정된 것이 좋습니다. 다만, 프로덕션 빌드에서는 이 컴포넌트가 제외되어야 합니다.

다음 스크립트로 프로덕션 빌드 설정을 확인하겠습니다:


Let me check the actual implementation to verify if the ReactQueryDevtools is conditionally rendered based on the environment.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 프로덕션 빌드 설정에서 DevTools가 제외되는지 확인

# next.config.js 또는 next.config.mjs 파일에서 프로덕션 빌드 설정 확인
fd -e js -e mjs -g "next.config.*" --exec cat {} | grep -A 5 "production"

# package.json의 build 스크립트 확인
cat package.json | jq '.scripts.build'

Length of output: 127


Script:

#!/bin/bash
# Check how ReactQueryDevtools is imported and used
rg -A 3 "ReactQueryDevtools" --type tsx --type jsx

Length of output: 78


Script:

#!/bin/bash
# Check the implementation of client-provider.tsx and how ReactQueryDevtools is used
cat src/components/client-provider.tsx

Length of output: 808

Comment on lines 33 to 40
async rewrites() {
return [
{
source: '/:path*',
destination: `${process.env.NEXT_PUBLIC_API_BASE_URL}/:path*`,
},
];
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

API 경로 재작성 구현이 필요한 경로로 제한되어야 합니다.

현재 구현은 모든 경로(/:path*)에 대해 API 재작성을 수행합니다. 이는 의도하지 않은 요청까지 API 서버로 전달될 수 있습니다.

다음과 같이 API 관련 경로만 재작성하도록 수정을 제안합니다:

  async rewrites() {
    return [
      {
-       source: '/:path*',
+       source: '/api/:path*',
        destination: `${process.env.NEXT_PUBLIC_API_BASE_URL}/:path*`,
      },
    ];
  },
📝 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
async rewrites() {
return [
{
source: '/:path*',
destination: `${process.env.NEXT_PUBLIC_API_BASE_URL}/:path*`,
},
];
},
async rewrites() {
return [
{
source: '/api/:path*',
destination: `${process.env.NEXT_PUBLIC_API_BASE_URL}/:path*`,
},
];
},

Comment on lines +5 to +11
export interface ConditionTypes {
keyword: string;
mainLocation: string;
mainCategory: string;
subCategory: string;
sortType: 'LATEST' | 'POPULAR';
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

필터 조건의 선택적 필드 처리가 필요합니다

현재 모든 필드가 필수로 설정되어 있습니다. 실제 사용 시나리오를 고려할 때, 일부 필드는 선택적으로 처리되어야 할 것 같습니다.

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

 export interface ConditionTypes {
-  keyword: string;
-  mainLocation: string;
-  mainCategory: string;
-  subCategory: string;
+  keyword?: string;
+  mainLocation?: string;
+  mainCategory?: string;
+  subCategory?: string;
   sortType: 'LATEST' | 'POPULAR';
 }
📝 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 interface ConditionTypes {
keyword: string;
mainLocation: string;
mainCategory: string;
subCategory: string;
sortType: 'LATEST' | 'POPULAR';
}
export interface ConditionTypes {
keyword?: string;
mainLocation?: string;
mainCategory?: string;
subCategory?: string;
sortType: 'LATEST' | 'POPULAR';
}

"@storybook/nextjs": "^8.3.5",
"@storybook/react": "^8.3.5",
"@storybook/testing-library": "^0.2.2",
"@tanstack/react-query-devtools": "^5.59.20",
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

React Query와 DevTools 버전이 호환되지 않습니다

@tanstack/react-query-devtools@^5.59.20은 @tanstack/react-query@^5.59.20을 peer dependency로 요구하지만, 현재 프로젝트는 ^5.59.16을 사용하고 있습니다. 다음 중 하나의 조치가 필요합니다:

  • @tanstack/react-query를 ^5.59.20으로 업그레이드
  • @tanstack/react-query-devtools를 ^5.59.16으로 다운그레이드
🔗 Analysis chain

React Query DevTools 의존성이 적절히 추가되었습니다.

개발 도구로서 devDependencies에 올바르게 배치되었습니다. 다만 몇 가지 고려사항이 있습니다:

  1. 버전 호환성을 확인해주세요
  2. 재현 가능한 빌드를 위해 정확한 버전을 고정하는 것을 고려해보세요

패키지 버전 호환성을 확인하기 위해 다음 스크립트를 실행하세요:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify version compatibility between react-query and its devtools

# Extract and compare versions
QUERY_VERSION=$(cat package.json | jq -r '.dependencies["@tanstack/react-query"]')
DEVTOOLS_VERSION=$(cat package.json | jq -r '.devDependencies["@tanstack/react-query-devtools"]')

echo "React Query version: $QUERY_VERSION"
echo "DevTools version: $DEVTOOLS_VERSION"

# Check npm for compatibility information
npm view @tanstack/react-query-devtools@$DEVTOOLS_VERSION peerDependencies

Length of output: 679

Comment on lines 55 to 60
<Image
fill
objectFit="cover"
alt={title}
src={imageUrl === 'string' ? ImgDefault : imageUrl}
/>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

이미지 처리 로직 개선이 필요합니다.

imageUrl === 'string' 비교는 적절하지 않아 보입니다. 이는 실제 URL 문자열과 'string' 리터럴을 비교하게 됩니다.

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

-          src={imageUrl === 'string' ? ImgDefault : imageUrl}
+          src={imageUrl || ImgDefault}
📝 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
<Image
fill
objectFit="cover"
alt={title}
src={imageUrl === 'string' ? ImgDefault : imageUrl}
/>
<Image
fill
objectFit="cover"
alt={title}
src={imageUrl || ImgDefault}
/>

Comment on lines 73 to 75
onChange={(newValue) => {
setRegion(newValue as string);
}}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

타입 캐스팅 개선이 필요합니다.

onChange 핸들러에서의 타입 캐스팅을 더 안전하게 처리할 수 있습니다.

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

-onChange={(newValue) => {
-  setRegion(newValue as string);
-}}
+onChange={(newValue: string | null) => {
+  if (newValue) setRegion(newValue);
+}}

-onChange={(newValue) => {
-  setSort(newValue as string);
-}}
+onChange={(newValue: string | null) => {
+  if (newValue) setSort(newValue);
+}}

Also applies to: 87-89

Comment on lines +2 to +5
{
"main": { "label": "지역 전체", "value": "" },
"areas": []
},
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

중복된 지역 value 값이 발견되었습니다.

각 광역시/도의 구/군 단위에서 동일한 value 값이 중복 사용되고 있습니다:

  • "jung" (중구) - 6개 지역에서 사용
  • "dong" (동구) - 6개 지역에서 사용
  • "seo" (서구) - 5개 지역에서 사용
  • "nam" (남구) - 4개 지역에서 사용
  • "buk" (북구) - 4개 지역에서 사용
  • "gangseo" (강서구) - 2개 지역에서 사용
  • "goseong" (고성군) - 2개 지역에서 사용

빈 문자열("")은 다른 지역과 중복되지 않지만, 위의 value들은 여러 지역에서 중복 사용되어 구분이 어려울 수 있습니다. 각 지역을 고유하게 식별할 수 있도록 상위 지역명을 prefix로 추가하는 등의 수정이 필요합니다.

🔗 Analysis chain

지역 value 값들의 중복 여부를 확인해주세요.

빈 문자열("")을 value로 사용하는 것이 다른 지역들의 value와 충돌하지 않는지 확인이 필요합니다.


Let me gather more context to understand the full structure of the region data.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for duplicate value entries in region.json

# Extract and count all values to find duplicates
jq -r '.[].main.value' src/data/region.json | sort | uniq -c | awk '$1 > 1 { print }'

# Also check area values within each region
jq -r '.[].areas[].value' src/data/region.json | sort | uniq -c | awk '$1 > 1 { print }'

Length of output: 272


Script:

#!/bin/bash
# Get the complete structure of region.json to understand the context of these duplicates
cat src/data/region.json

Length of output: 11425

Comment on lines +6 to +12
queryKey: [
condition.keyword,
condition.mainLocation,
condition.mainCategory,
condition.subCategory,
condition.sortType,
],
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

queryKey에 undefined 또는 null 값이 포함되지 않도록 처리하세요.

queryKey 배열에 condition 객체의 속성들이 포함되는데, 만약 어떤 속성이 undefined 또는 null인 경우 캐싱 키가 예상대로 작동하지 않을 수 있습니다. 이를 방지하기 위해 기본 값을 지정하거나 falsy한 값을 필터링하는 것이 좋습니다.

예를 들어, undefined나 null 값을 제거하려면 다음과 같이 수정할 수 있습니다:

queryKey: [
  condition.keyword,
  condition.mainLocation,
  condition.mainCategory,
  condition.subCategory,
  condition.sortType,
].filter(Boolean),

condition.sortType,
],
queryFn: ({ pageParam = 0 }) =>
getCrewList(condition, { page: pageParam, size: 6, sort: ['string'] }),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

'sort' 옵션에 올바른 정렬 기준을 사용하세요.

현재 sort: ['string']으로 설정되어 있어 실제 정렬 기준이 적용되지 않을 수 있습니다. condition.sortType을 사용하여 동적으로 정렬 기준을 지정하는 것이 좋습니다.

다음과 같이 수정할 수 있습니다:

- getCrewList(condition, { page: pageParam, size: 6, sort: ['string'] }),
+ getCrewList(condition, { page: pageParam, size: 6, sort: [condition.sortType] }),

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

try {
const response = await fetchApi<CrewCardInformResponse>(
`/crews?_page=${page + 1}&_limit=${limit}`,
`/crews/search?keyword=${keyword}&mainLocation=${mainLocation}&mainCategory=${mainCategory}&subCategory=${subCategory}&sortType=${sortType}&page=${page}&size=${size}&sort=${sort}`,
Copy link

@coderabbitai coderabbitai bot Nov 12, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

쿼리 파라미터의 URL 인코딩 필요

쿼리 파라미터를 직접 문자열로 결합하면 특수 문자나 예기치 않은 입력으로 인해 오류가 발생할 수 있습니다. URLSearchParams를 사용하여 파라미터를 적절히 인코딩하는 것을 권장합니다.

수정 제안:

+    const params = new URLSearchParams({
+      keyword,
+      mainLocation,
+      mainCategory,
+      subCategory,
+      sortType,
+      page: page.toString(),
+      size: size.toString(),
+      sort: sort.join(','),
+    });
+    const response = await fetchApi<CrewCardInformResponse>(
+      `/crews/search?${params.toString()}`,
       {
         method: 'GET',
         headers: {
           'Content-Type': 'application/json',
         },
         credentials: 'include', // 인증 정보를 요청에 포함
       },
     );

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

Copy link
Contributor

Choose a reason for hiding this comment

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

params.toString 사용해서 코드 수정하면 좋을 것 같습니다!

Copy link

Choose a reason for hiding this comment

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

@minkyung5x5, 네, params.toString()을 사용하여 코드를 수정하면 좋을 것 같습니다! 수정해 주셔서 감사합니다.


If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!

@github-actions
Copy link

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

🧹 Outside diff range and nitpick comments (10)
src/_queries/crew-queries.tsx (1)

13-16: 페이지 크기를 구성 가능하도록 개선하세요.

현재 페이지 크기가 6으로 하드코딩되어 있습니다. 다양한 사용 사례에 대응하기 위해 이를 매개변수화하는 것이 좋습니다.

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

-export function useGetCrewListQuery(condition: ConditionTypes) {
+export function useGetCrewListQuery(condition: ConditionTypes, pageSize: number = 6) {
   return {
     queryKey: [
       condition.keyword,
       condition.mainLocation,
       condition.mainCategory,
       condition.subCategory,
       condition.sortType,
     ],
     queryFn: ({ pageParam = 0 }) =>
-      getCrewList(condition, { page: pageParam, size: 6, sort: [condition.sortType] }),
+      getCrewList(condition, { page: pageParam, size: pageSize, sort: [condition.sortType] }),
src/hooks/use-infinite-scroll.ts (1)

28-28: 반환 타입 명시 추천

타입 안정성을 높이기 위해 명시적인 반환 타입을 추가하는 것이 좋습니다.

다음과 같이 반환 타입을 명시하는 것을 추천드립니다:

- return { data, ref, isFetchingNextPage, refetch };
+ return { data, ref, isFetchingNextPage, refetch } as const;

또는 인터페이스를 정의하여 사용:

interface InfiniteScrollResult<TData> {
  data: InfiniteData<TData> | undefined;
  ref: (node?: Element | null) => void;
  isFetchingNextPage: boolean;
  refetch: () => Promise<void>;
}
next.config.mjs (1)

보안: CORS 및 이미지 설정 수정이 필요합니다.

코드베이스 분석 결과, 다음과 같은 보안 개선이 필요합니다:

  1. API 요청이 src/utils/api.ts에서 중앙 집중화되어 있으며, NEXT_PUBLIC_API_BASE_URL을 사용하고 있습니다. 따라서 CORS 설정을 API 요청 경로에만 제한하는 것이 안전합니다.

  2. 이미지 도메인 설정도 API 서버와 동일한 방식으로 환경 변수를 통해 제한해야 합니다.

수정 제안:

  images: {
    remotePatterns: [
      {
        protocol: 'https',
-       hostname: '**', // 모든 도메인 허용
+       hostname: process.env.NEXT_PUBLIC_API_BASE_URL 
+         ? new URL(process.env.NEXT_PUBLIC_API_BASE_URL).hostname
+         : 'foggy-sideways-saltasaurus.glitch.me',
      },
    ],
  },
  async headers() {
    return [
      {
-       source: '/:path*', // TODO: 모든 경로에 적용, 추후 수정
+       source: '/api/:path*', // API 경로에만 CORS 적용
        headers: [
          // ... existing headers ...
        ],
      },
    ];
  },
🔗 Analysis chain

Line range hint 3-29: 보안: CORS 및 이미지 설정 검토가 필요합니다.

현재 구성에서 발견된 잠재적인 보안 문제:

  1. 이미지 호스트네임이 모든 도메인('**')을 허용하고 있습니다.
  2. CORS 헤더가 모든 경로('/:path*')에 적용되어 있습니다.
  3. TODO 주석에서 언급된 대로 경로 제한이 필요합니다.

다음과 같은 수정을 제안합니다:

  images: {
    remotePatterns: [
      {
        protocol: 'https',
-       hostname: '**', // 모든 도메인 허용
+       hostname: process.env.NEXT_PUBLIC_IMAGE_DOMAIN, // 특정 도메인만 허용
      },
    ],
  },
  async headers() {
    return [
      {
-       source: '/:path*', // TODO: 모든 경로에 적용, 추후 수정
+       source: '/api/:path*', // API 경로에만 CORS 적용
        headers: [
          // ... existing headers ...
        ],
      },
    ];
  },

CORS 설정이 필요한 API 엔드포인트를 확인하기 위해 다음 스크립트를 실행하세요:


Let me analyze the API endpoints further to make a more informed decision about the CORS configuration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# API 관련 파일들을 검색하여 엔드포인트 확인
fd -e ts -e js -e tsx -e jsx --exclude node_modules --exclude .next | xargs rg -l "fetch|axios|api"

Length of output: 1199


Script:

#!/bin/bash
# Check API routes and their patterns
rg -A 5 "export.*handler|route.*=.*" src/app/api/

# Check actual API calls to external domains
rg -A 2 "fetch\(|axios\." src/_apis/

Length of output: 90


Script:

#!/bin/bash
# Check API implementation and external service calls
rg -A 3 "fetch\(|axios\.|baseURL|NEXT_PUBLIC_API" src/

# Check for environment variable usage
rg "NEXT_PUBLIC" .env* || true

Length of output: 1184

src/components/common/crew-list/crew-card-list.stories.tsx (1)

31-39: 쿼리 파라미터 구조가 개선되었습니다만, 기본값 처리를 검토해주세요.

빈 문자열을 사용하는 대신 의미있는 기본값을 설정하거나 옵셔널 파라미터로 처리하는 것이 좋을 것 같습니다.

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

  const { data, ref, isFetchingNextPage } = useInfiniteScroll(
    useGetCrewListQuery({
-     keyword: '',
-     mainLocation: '',
-     mainCategory: '',
-     subCategory: '',
+     sortType: 'LATEST',
+     // 선택적 파라미터로 처리
+     ...(keyword && { keyword }),
+     ...(mainLocation && { mainLocation }),
+     ...(mainCategory && { mainCategory }),
+     ...(subCategory && { subCategory }),
-     sortType: 'LATEST',
    }),
  );
src/app/(crew)/my-crew/page.tsx (2)

Line range hint 15-17: TODO 주석에 대한 후속 조치가 필요합니다.

현재 두 개의 TODO 주석이 있습니다:

  1. fetchCrewData 함수를 사용하여 데이터를 불러오기
  2. 리스트와는 다른 데이터 사용 필요성

이러한 요구사항들이 명확하게 정의되어 있지 않아 구현이 지연될 수 있습니다.

이러한 TODO 항목들을 추적하고 구현하기 위한 GitHub 이슈를 생성해드릴까요?


Line range hint 1-40: 컴포넌트 구조 개선이 필요합니다.

현재 컴포넌트에서 다음과 같은 개선사항들이 필요해 보입니다:

  1. 무한 스크롤 로직이 주석 처리되어 있어 페이지네이션이 동작하지 않습니다.
  2. 탭 전환 시 데이터 로딩 상태 처리가 누락되어 있습니다.
  3. 에러 상태 처리가 구현되어 있지 않습니다.

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

  1. 로딩 상태를 표시하는 스켈레톤 UI 추가
  2. 에러 바운더리 구현
  3. 탭 전환 시 데이터 리프레시 로직 추가
src/components/common/crew-list/crew-card-list.tsx (1)

71-71: 조건문 로직 단순화 승인

isConfirmed 속성의 조건문이 삼항 연산자에서 논리 AND 연산자로 변경되었습니다. 더 간결하고 명확한 구현으로 보입니다.

추가적인 개선사항으로, 타입 가드를 사용하여 타입 캐스팅을 줄일 수 있습니다:

function isMainCrewList(inform: MainCrewList | MyCrewList): inform is MainCrewList {
  return 'isConfirmed' in inform;
}

이후 조건문에서 다음과 같이 사용할 수 있습니다:

-isConfirmed={inWhere !== 'my-crew' && (inform as MainCrewList).isConfirmed}
+isConfirmed={isMainCrewList(inform) && inform.isConfirmed}
src/app/(crew)/page.tsx (3)

17-20: 상태 초기화 방식이 개선되었습니다.

카테고리와 지역 상태의 초기값을 빈 문자열로 설정한 것은 좋은 접근입니다. 다만, 이러한 상태 관리 로직이 다른 컴포넌트에서도 재사용될 수 있으므로, 커스텀 훅으로 분리하는 것을 고려해보세요.


23-27: region 처리 로직을 개선할 수 있습니다.

현재 구현은 작동하지만, 더 간단하고 안전하게 리팩토링할 수 있습니다.

-const handleRegionChange = (newValue: string) => {
-  const selectedRegion = regionData.find((dataItem) => dataItem.main.value === newValue);
-  if (selectedRegion?.main.label === '지역 전체') return '';
-  return selectedRegion ? selectedRegion.main.label : '';
-};
+const handleRegionChange = (newValue: string) => {
+  const selectedRegion = regionData.find((dataItem) => dataItem.main.value === newValue)?.main;
+  return selectedRegion?.label === '지역 전체' ? '' : selectedRegion?.label ?? '';
+};

29-37: 쿼리 파라미터의 타입 안전성을 개선할 수 있습니다.

현재 구현은 잘 작동하지만, 타입 안전성을 높이기 위해 상수와 타입을 추가하는 것이 좋습니다.

// src/constants/sort-types.ts
export const SORT_TYPES = {
  LATEST: 'LATEST',
  POPULAR: 'POPULAR',
} as const;

export type SortType = typeof SORT_TYPES[keyof typeof SORT_TYPES];

그리고 다음과 같이 적용하세요:

-sortType: sort === 'latest' ? 'LATEST' : 'POPULAR',
+sortType: sort === 'latest' ? SORT_TYPES.LATEST : SORT_TYPES.POPULAR,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 22f3307 and 1026125.

📒 Files selected for processing (11)
  • next.config.mjs (1 hunks)
  • src/_apis/crew/get-crew-list.ts (1 hunks)
  • src/_queries/crew-queries.tsx (1 hunks)
  • src/app/(crew)/my-crew/page.tsx (2 hunks)
  • src/app/(crew)/page.tsx (3 hunks)
  • src/app/_components/category/internal-category/index.tsx (1 hunks)
  • src/components/common/crew-list/crew-card-list.stories.tsx (2 hunks)
  • src/components/common/crew-list/crew-card-list.tsx (2 hunks)
  • src/components/common/crew-list/crew-card.tsx (2 hunks)
  • src/hooks/use-infinite-scroll.ts (2 hunks)
  • src/types/crew-card.d.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/app/_components/category/internal-category/index.tsx
  • src/components/common/crew-list/crew-card.tsx
  • src/types/crew-card.d.ts
🔇 Additional comments (14)
src/_queries/crew-queries.tsx (2)

1-2: 임포트 구문이 적절합니다!

필요한 타입과 API 함수가 올바르게 임포트되어 있습니다.


6-12: 이전 리뷰 코멘트가 여전히 유효합니다.

queryKey 배열의 undefined/null 처리에 대한 이전 리뷰 코멘트를 참조해 주세요.

src/hooks/use-infinite-scroll.ts (1)

13-13: refetch 기능 추가에 대한 승인

useInfiniteQuery에서 refetch 함수를 추출하여 외부에서 데이터를 수동으로 새로고침할 수 있게 된 것은 좋은 개선사항입니다. 이를 통해 사용자 액션에 따른 데이터 갱신이 가능해졌습니다.

src/_apis/crew/get-crew-list.ts (5)

1-3: 타입 선언이 잘 구성되어 있습니다!

필요한 타입들이 깔끔하게 import되어 있습니다.


4-7: 함수 시그니처가 명확하게 정의되어 있습니다!

ConditionTypesPageableTypes를 사용하여 매개변수 타입이 잘 정의되어 있습니다.


19-19: 인증 설정이 적절히 추가되었습니다!

credentials: 'include' 설정으로 인증 정보가 요청에 포함되도록 처리된 것이 좋습니다.


8-9: ⚠️ Potential issue

sort 매개변수의 기본값 검토 필요

sort = ['string']의 기본값이 의도된 값인지 확인이 필요합니다. 이는 실제 정렬에 사용되는 적절한 값이 아닌 것으로 보입니다.

다음과 같이 수정하는 것을 고려해보세요:

- const { page, size, sort = ['string'] } = pageable;
+ const { page, size, sort = ['createdAt,desc'] } = pageable;

13-13: ⚠️ Potential issue

쿼리 파라미터 처리 개선 필요

  1. URL 인코딩 누락: 특수 문자나 한글이 포함된 파라미터가 있을 경우 문제가 발생할 수 있습니다.
  2. undefined 값 처리 누락: 파라미터가 undefined일 경우 'undefined' 문자열이 쿼리에 포함될 수 있습니다.

다음과 같이 수정하는 것을 추천드립니다:

- `/crews/search?keyword=${keyword}&mainLocation=${mainLocation}&mainCategory=${mainCategory}&subCategory=${subCategory}&sortType=${sortType}&page=${page}&size=${size}&sort=${sort}`,
+ const params = new URLSearchParams();
+ if (keyword) params.append('keyword', keyword);
+ if (mainLocation) params.append('mainLocation', mainLocation);
+ if (mainCategory) params.append('mainCategory', mainCategory);
+ if (subCategory) params.append('subCategory', subCategory);
+ if (sortType) params.append('sortType', sortType);
+ if (page) params.append('page', page.toString());
+ if (size) params.append('size', size.toString());
+ if (sort?.length) params.append('sort', sort.join(','));
+ `/crews/search?${params.toString()}`,
next.config.mjs (1)

34-41: API 경로 재작성이 올바르게 구현되었습니다.

이전 리뷰 의견에 따라 API 경로(/api/:path*)에 대해서만 재작성이 적용되도록 수정되었습니다.

src/components/common/crew-list/crew-card-list.stories.tsx (1)

2-2: 쿼리 훅 임포트가 올바르게 업데이트되었습니다.

API 변경사항에 맞춰 useGetCrewQuery에서 useGetCrewListQuery로 임포트가 정상적으로 변경되었습니다.

src/app/(crew)/my-crew/page.tsx (2)

4-4: 쿼리 훅 업데이트가 확인되었습니다.

useGetCrewQuery에서 useGetCrewListQuery로의 변경이 올바르게 이루어졌습니다.


20-20: ⚠️ Potential issue

주석 처리된 코드의 업데이트가 필요합니다.

주석 처리된 코드에서 useGetCrewListQuery()가 파라미터 없이 호출되고 있습니다. API 변경사항에 따라 필요한 파라미터를 전달해야 합니다.

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

- useInfiniteScroll<MyCrewListResponse>(useGetCrewListQuery());
+ useInfiniteScroll<MyCrewListResponse>(
+   useGetCrewListQuery({
+     condition: {
+       // TODO: Add necessary parameters based on my-crew requirements
+     }
+   })
+ );

Likely invalid or redundant comment.

src/components/common/crew-list/crew-card-list.tsx (1)

35-35: 데이터 구조 변경 검증 필요

백엔드 API 응답 구조가 data에서 content로 변경되었습니다. 이 변경이 다른 컴포넌트나 페이지에 영향을 미치지 않는지 확인이 필요합니다.

src/app/(crew)/page.tsx (1)

6-6: API 변경이 올바르게 적용되었습니다.

useGetCrewQuery에서 useGetCrewListQuery로의 변경이 잘 이루어졌습니다.

Comment on lines 31 to 39
const { data, ref, isFetchingNextPage } = useInfiniteScroll(
useGetCrewListQuery({
keyword: '',
mainLocation: '',
mainCategory: '',
subCategory: '',
sortType: 'LATEST',
}),
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

스토리북 테스트 케이스 보강이 필요합니다.

현재는 기본 케이스만 테스트하고 있습니다. 다양한 필터 조건에 대한 테스트 케이스를 추가하면 좋을 것 같습니다.

다음과 같은 테스트 케이스들을 추가해보시는 것을 추천드립니다:

export const WithKeywordSearch: Story = {
  render: () => (
    <RenderCrewCardList initialCondition={{ keyword: '개발자', sortType: 'LATEST' }} />
  ),
};

export const WithLocationFilter: Story = {
  render: () => (
    <RenderCrewCardList initialCondition={{ mainLocation: '서울', sortType: 'LATEST' }} />
  ),
};

export const WithCategoryFilter: Story = {
  render: () => (
    <RenderCrewCardList 
      initialCondition={{ 
        mainCategory: '개발', 
        subCategory: '웹개발',
        sortType: 'LATEST' 
      }} 
    />
  ),
};

@github-actions
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
.github/workflows/ci.yml (1)

80-81: 시크릿 사용에 대한 문서화가 필요합니다.

repository secrets에 대한 설정 방법과 필요한 값을 README나 문서에 추가하면 다른 개발자들의 설정에 도움이 될 것 같습니다.

다음과 같은 내용을 README.md에 추가하는 것을 제안합니다:

+## 환경 변수 설정
+
+GitHub Actions에서 사용되는 환경 변수:
+
+- `NEXT_PUBLIC_API_BASE_URL`: API 서버의 기본 URL
+  - 형식: `https://api.example.com`
+  - GitHub repository settings > Secrets > Actions에서 설정
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1026125 and 56bea37.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml (1 hunks)
🔇 Additional comments (1)
.github/workflows/ci.yml (1)

80-81: 환경 변수 설정이 올바르게 추가되었습니다.

API 베이스 URL을 GitHub 시크릿에서 가져오는 것은 보안상 좋은 방법입니다. 하지만 이 URL이 올바른 환경을 가리키는지 확인이 필요합니다.

다음 스크립트를 실행하여 환경 변수가 워크플로우에서 올바르게 사용되는지 확인하세요:

✅ Verification successful

환경 변수가 올바르게 구성되어 있음을 확인했습니다

환경 변수 NEXT_PUBLIC_API_BASE_URL가 다음 위치에서 적절하게 사용되고 있습니다:

  • next.config.mjs의 프록시 설정에서 API 대상 URL로 사용
  • src/utils/api.ts에서 API 기본 URL로 사용되며, 로컬 개발 환경을 위한 대체 값도 적절히 설정됨
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: API 베이스 URL이 next.config.mjs에서 사용되는지 확인

# next.config.mjs에서 환경 변수 사용 확인
rg -l "NEXT_PUBLIC_API_BASE_URL" "next.config*"

# 다른 설정 파일에서도 확인
rg -l "NEXT_PUBLIC_API_BASE_URL" ".env*"

Length of output: 187


Script:

#!/bin/bash
# Check for Next.js configuration files and environment files with any extension
fd -e js -e mjs -e ts "next.config" 

# Search for environment variable usage in the codebase
rg "NEXT_PUBLIC_API_BASE_URL"

# Look for any configuration or environment setup files
fd -g ".env*"
fd -g "*.config.*"

Length of output: 640

@github-actions
Copy link

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: 4

🧹 Outside diff range and nitpick comments (4)
src/components/common/crew-list/crew-card-list.tsx (2)

35-35: 타입 안전성 개선이 필요합니다.

데이터 구조 변경이 잘 이루어졌으나, 타입 단언(type assertion)을 사용하는 대신 타입 가드를 사용하면 더 안전한 타입 체크가 가능할 것 같습니다.

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

-data?.pages?.flatMap((page) => page.content as MainCrewList[]) ?? [];
+data?.pages?.flatMap((page) => {
+  if (!page.content) return [];
+  return page.content;
+}) ?? [];

Line range hint 1-85: 컴포넌트 책임 분리 검토가 필요합니다.

현재 CrewCardList 컴포넌트가 메인 크루 목록과 마이 크루 목록을 모두 처리하고 있습니다. 이는 단일 책임 원칙(SRP)에 위배될 수 있으며, 향후 유지보수를 어렵게 만들 수 있습니다.

다음과 같은 개선을 고려해보세요:

  1. MainCrewCardListMyCrewCardList 컴포넌트로 분리
  2. 공통 로직을 커스텀 훅으로 추출
  3. 제네릭을 활용한 재사용 가능한 BaseCrewCardList 컴포넌트 구현
src/app/_components/find-crew/find-crew.tsx (2)

22-29: 상태 관리 개선을 위한 제안

필터링 관련 상태들을 하나의 객체로 그룹화하면 상태 관리가 더욱 효율적일 것 같습니다.

-  const [mainCategory, setMainCategory] = useState('');
-  const [subCategory, setSubCategory] = useState('');
-  const [sort, setSort] = useState<string | null>('latest');
-  const [region, setRegion] = useState<string>('');
-  const [search, setSearch] = useState('');
+  const [filters, setFilters] = useState({
+    mainCategory: '',
+    subCategory: '',
+    sort: 'latest' as string | null,
+    region: '',
+    search: ''
+  });

69-129: 접근성 및 스타일 개선 제안

UI 구현이 잘 되어있지만, 다음 사항들을 개선하면 좋을 것 같습니다:

  1. 검색 입력란에 aria-label 추가
  2. 매직 넘버로 되어있는 패딩값들을 상수로 분리
   <TextInput
     value={search}
     onChange={(e) => setSearch(e.target.value)}
     leftSectionPointerEvents="none"
+    aria-label="크루 검색"
     leftSection={
       <Image src={IcoSearch} alt="search" width={21} height={21} className="-mr-4" />
     }
     placeholder="크루 이름, 위치를 검색하세요."
     inputClassNames="w-full h-11 pl-12 placeholder:text-gray-500 font-pretendard text-base font-medium text-gray-800 rounded-xl"
   />
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 56bea37 and 1d430b1.

📒 Files selected for processing (3)
  • src/app/(crew)/page.tsx (1 hunks)
  • src/app/_components/find-crew/find-crew.tsx (1 hunks)
  • src/components/common/crew-list/crew-card-list.tsx (2 hunks)
🔇 Additional comments (4)
src/app/_components/find-crew/find-crew.tsx (2)

1-20: 코드가 깔끔하고 잘 구성되어 있습니다!

필요한 모든 의존성이 명확하게 임포트되어 있으며, Props 인터페이스가 잘 정의되어 있습니다.


38-50: 무한 스크롤 성능 검증이 필요합니다

무한 스크롤 구현이 잘 되어있지만, 데이터가 많아질 경우의 성능 영향을 확인해야 합니다.

✅ Verification successful

무한 스크롤 구현이 적절하게 최적화되어 있습니다

코드베이스 분석 결과:

  • useInfiniteScroll 훅이 @tanstack/react-queryuseInfiniteQuery를 기반으로 구현되어 있어 데이터 캐싱이 적절히 처리됩니다
  • 페이지네이션 로직(getNextPageParam)이 각 컴포넌트에서 일관되게 구현되어 있습니다
  • 데이터 타입이 제네릭으로 잘 관리되고 있어 타입 안정성이 보장됩니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential performance bottlenecks in infinite scroll implementation

# Search for other infinite scroll implementations to compare
rg -l "useInfiniteScroll|InfiniteData" --type typescript

# Check for memory management patterns
ast-grep --pattern 'useEffect($$$) {
  return () => {
    $$$
  }
}'

Length of output: 164


Script:

#!/bin/bash
# Search for infinite scroll implementations and related patterns
rg -t ts -t tsx "useInfiniteScroll|InfiniteData"

# Look for cleanup patterns in useEffect
rg -t ts -t tsx "useEffect.*return \(\) =>" -A 3

# Check pagination or data fetching logic
rg -t ts -t tsx "getNextPageParam|fetchNextPage" -A 2

# Search for scroll event listeners
rg -t ts -t tsx "addEventListener.*scroll|onScroll" -A 2

Length of output: 328


Script:

#!/bin/bash
# Search for infinite scroll and related patterns without file type flags
rg "useInfiniteScroll|InfiniteData"

# Look for cleanup patterns in useEffect
rg "useEffect.*return \(\) =>" -A 3

# Check pagination logic
rg "getNextPageParam|fetchNextPage" -A 2

# Find scroll event handlers
rg "addEventListener.*scroll|onScroll" -A 2

# Find the implementation of useInfiniteScroll hook
fd useInfiniteScroll

Length of output: 6047

src/app/(crew)/page.tsx (2)

11-16: 'sortType'와 'sort' 파라미터의 일관성 확인 필요

'getCrewList' 함수 호출 시 sortType은 문자열 'LATEST'를 사용하고, sort는 배열 ['LATEST']를 사용하고 있습니다. 이러한 차이가 의도된 것인지 확인 부탁드립니다.


25-25: 'initialData'가 null일 경우에 대한 처리 필요

getCrewList 호출 실패 시 initialDatanull 또는 undefined가 될 수 있으므로, FindCrew 컴포넌트에 전달하기 전에 해당 상황에 대한 처리가 필요합니다.

}
crewMembers={inWhere === 'my-crew' ? (inform as MyCrewList).crewMembers : undefined}
isConfirmed={inWhere !== 'my-crew' ? (inform as MainCrewList).isConfirmed : undefined}
isConfirmed={inWhere !== 'my-crew' && (inform as MainCrewList).isConfirmed}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

타입 안전성과 가독성 개선이 필요합니다.

현재 구현은 간결하지만, 타입 단언과 부정 조건을 함께 사용하고 있어 코드의 의도를 파악하기 어려울 수 있습니다.

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

-isConfirmed={inWhere !== 'my-crew' && (inform as MainCrewList).isConfirmed}
+isConfirmed={inWhere === 'my-crew' ? false : inform.isConfirmed}

또한, 타입 가드를 사용하여 타입 안전성을 높이는 것을 고려해보세요:

function isMainCrewList(crew: MainCrewList | MyCrewList): crew is MainCrewList {
  return 'isConfirmed' in crew;
}

Comment on lines +32 to +36
const handleRegionChange = (newValue: string) => {
const selectedRegion = regionData.find((dataItem) => dataItem.main.value === newValue);
if (selectedRegion?.main.label === '지역 전체') return '';
return selectedRegion ? selectedRegion.main.label : '';
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

지역 처리 로직 개선이 필요합니다

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

  1. regionData가 undefined일 경우에 대한 처리가 없습니다
  2. 존재하지 않는 지역값이 전달될 경우의 처리가 미흡합니다

다음과 같이 개선하는 것을 제안드립니다:

   const handleRegionChange = (newValue: string) => {
+    if (!newValue) return '';
     const selectedRegion = regionData.find((dataItem) => dataItem.main.value === newValue);
-    if (selectedRegion?.main.label === '지역 전체') return '';
-    return selectedRegion ? selectedRegion.main.label : '';
+    return selectedRegion?.main.label === '지역 전체' ? '' : selectedRegion?.main.label ?? '';
   };
📝 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 handleRegionChange = (newValue: string) => {
const selectedRegion = regionData.find((dataItem) => dataItem.main.value === newValue);
if (selectedRegion?.main.label === '지역 전체') return '';
return selectedRegion ? selectedRegion.main.label : '';
};
const handleRegionChange = (newValue: string) => {
if (!newValue) return '';
const selectedRegion = regionData.find((dataItem) => dataItem.main.value === newValue);
return selectedRegion?.main.label === '지역 전체' ? '' : selectedRegion?.main.label ?? '';
};

Comment on lines +5 to +18
const initialData = await getCrewList(
{
keyword: '',
mainLocation: '',
mainCategory: '',
subCategory: '',
sortType: 'LATEST',
},
{
page: 0,
size: 6,
sort: ['LATEST'],
},
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

'getCrewList' 호출에 대한 에러 처리 구현 권장

getCrewList 호출 시 발생할 수 있는 에러를 처리하기 위해 try-catch 블록을 추가하는 것을 권장합니다. 이는 애플리케이션의 안정성을 높여줍니다.

코드 수정 예시:

 export default async function HomePage() {
+  let initialData;
+  try {
     initialData = await getCrewList(
       {
         keyword: '',
         mainLocation: '',
         mainCategory: '',
         subCategory: '',
         sortType: 'LATEST',
       },
       {
         page: 0,
         size: 6,
         sort: ['LATEST'],
       },
     );
+  } catch (error) {
+    // 에러 처리 로직 추가
+    console.error('Crew 리스트를 가져오는 중 에러 발생:', error);
+    initialData = null;
+  }

   const infiniteData = {
     pages: [initialData],
     pageParams: [],
   };

   return <FindCrew initialData={infiniteData} />;
 }

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

@CodeitFESI4-Team1 CodeitFESI4-Team1 deleted a comment from coderabbitai bot Nov 12, 2024
@github-actions
Copy link

@yulrang yulrang changed the title Feat/98/crew api Feat/98/crew api 연결 Nov 12, 2024
@github-actions
Copy link

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

🧹 Outside diff range and nitpick comments (1)
src/components/common/crew-list/crew-card-list.tsx (1)

41-41: 사용자 경험 개선을 위한 제안

단순히 "데이터가 없습니다"라는 메시지보다 더 구체적인 안내나 행동 유도가 필요해 보입니다.

다음과 같은 개선을 고려해보세요:

-<p>데이터가 없습니다.</p>
+<div className="text-center">
+  <p className="mb-2">아직 등록된 크루가 없습니다.</p>
+  <p className="text-sm text-gray-500">새로운 크루를 찾아보세요!</p>
+</div>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b4b356c and b9b5cb5.

📒 Files selected for processing (3)
  • src/_apis/crew/get-crew-list.ts (1 hunks)
  • src/app/_components/find-crew/find-crew.tsx (1 hunks)
  • src/components/common/crew-list/crew-card-list.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/_components/find-crew/find-crew.tsx
🔇 Additional comments (4)
src/_apis/crew/get-crew-list.ts (3)

1-7: 함수 시그니처가 잘 정의되어 있습니다!

타입 정의와 함수 시그니처가 명확하게 작성되어 있습니다.


9-9: sort 매개변수의 기본값이 적절하지 않습니다

['string']이라는 기본값은 의미가 없습니다. 실제 정렬 기준을 반영하는 값으로 변경해주세요.


14-21: API 호출 설정이 적절합니다!

인증 정보 포함 설정과 헤더 구성이 잘 되어있습니다.

src/components/common/crew-list/crew-card-list.tsx (1)

71-71: 이전 리뷰 코멘트가 여전히 유효합니다.

Comment on lines 24 to 26
// eslint-disable-next-line no-console
console.error(error);
return { content: [], hasNext: false };
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

에러 처리 방식 개선이 필요합니다

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

  1. 프로덕션 환경에서 console.error 사용
  2. 에러를 숨기고 빈 결과를 반환하여 문제 진단이 어려움
  3. 호출자에게 적절한 에러 정보를 제공하지 않음

다음과 같이 개선하는 것을 제안합니다:

  } catch (error) {
-    // eslint-disable-next-line no-console
-    console.error(error);
-    return { content: [], hasNext: false };
+    const errorMessage = error instanceof Error 
+      ? error.message 
+      : '크루 목록을 가져오는데 실패했습니다';
+    throw new Error(errorMessage);
  }
📝 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-next-line no-console
console.error(error);
return { content: [], hasNext: false };
} catch (error) {
const errorMessage = error instanceof Error
? error.message
: '크루 목록을 가져오는데 실패했습니다';
throw new Error(errorMessage);
}

try {
const response = await fetchApi<MainCrewListResponse>(
`/crews?_page=${page + 1}&_limit=${limit}`,
`/api/crews/search?keyword=${keyword}&mainLocation=${mainLocation}&mainCategory=${mainCategory}&subCategory=${subCategory}&sortType=${sortType}&page=${page}&size=${size}&sort=${sort}`,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

쿼리 파라미터 처리 개선이 필요합니다

  1. URL 인코딩이 누락되어 있어 특수문자나 한글이 포함된 경우 문제가 발생할 수 있습니다.
  2. 템플릿 리터럴을 사용한 직접적인 문자열 결합은 보안상 위험할 수 있습니다.

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

-      `/api/crews/search?keyword=${keyword}&mainLocation=${mainLocation}&mainCategory=${mainCategory}&subCategory=${subCategory}&sortType=${sortType}&page=${page}&size=${size}&sort=${sort}`,
+      const params = new URLSearchParams({
+        keyword,
+        mainLocation,
+        mainCategory,
+        subCategory,
+        sortType,
+        page: page.toString(),
+        size: size.toString(),
+        sort: sort.join(','),
+      });
+      `/api/crews/search?${params.toString()}`,

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

(inWhere === 'my-crew'
? data?.pages.flatMap((page) => page.data as MyCrewList[])
: data?.pages.flatMap((page) => page.data as MainCrewList[])) ?? [];
: data?.pages?.flatMap((page) => page.content as MainCrewList[])) ?? [];
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

데이터 구조 변경에 대한 타입 안전성 개선이 필요합니다.

타입 단언(as)을 사용하는 대신 타입 가드를 활용하여 런타임 안전성을 높이는 것이 좋습니다.

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

function isMainCrewListResponse(page: MainCrewListResponse | MyCrewListResponse): page is MainCrewListResponse {
  return 'content' in page;
}

// 사용 예시
const crewDataList = data?.pages.flatMap((page) => 
  isMainCrewListResponse(page) ? page.content : page.data
) ?? [];

@github-actions
Copy link

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: 2

🧹 Outside diff range and nitpick comments (4)
src/_queries/crew-queries.tsx (3)

1-1: 사용하지 않는 import 문을 제거하세요.

UseInfiniteQueryOptions를 import 했지만 코드에서 사용하지 않고 있습니다.

-import { UseInfiniteQueryOptions } from '@tanstack/react-query';

17-19: 에러 메시지를 더 구체적으로 작성하세요.

현재 에러 메시지가 너무 일반적입니다. API 응답이 null인 상황에 대한 더 자세한 정보를 포함하면 디버깅에 도움이 될 것 같습니다.

-            throw new Error('Response is null');
+            throw new Error('크루 목록을 가져오는데 실패했습니다. 서버 응답이 null입니다.');

23-24: 타입 안전성을 개선하세요.

getNextPageParam 함수의 반환 타입을 명시적으로 지정하면 타입 안전성이 향상될 것 같습니다.

-    getNextPageParam: (lastPage: MainCrewListResponse, allPages: MainCrewListResponse[]) =>
+    getNextPageParam: (lastPage: MainCrewListResponse, allPages: MainCrewListResponse[]): number | undefined =>
src/components/common/crew-list/crew-card-list.tsx (1)

38-51: 로딩 상태 처리가 개선되었습니다.

초기 로딩과 빈 데이터 상태를 구분하여 처리한 것은 좋은 개선입니다. 하지만 사용자 경험을 위해 로딩 메시지와 빈 데이터 메시지를 상수로 분리하는 것이 좋겠습니다.

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

const MESSAGES = {
  NO_DATA: '데이터가 없습니다.',
} as const;

// 컴포넌트에서 사용
<p>{MESSAGES.NO_DATA}</p>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b9b5cb5 and 5687085.

📒 Files selected for processing (4)
  • src/_apis/crew/get-crew-list.ts (1 hunks)
  • src/_queries/crew-queries.tsx (1 hunks)
  • src/app/_components/find-crew/find-crew.tsx (1 hunks)
  • src/components/common/crew-list/crew-card-list.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/_components/find-crew/find-crew.tsx
🔇 Additional comments (6)
src/_apis/crew/get-crew-list.ts (4)

16-16: 인증 정보 포함이 적절히 구현되었습니다

credentials: 'include' 설정으로 인증이 필요한 API 요청을 올바르게 처리할 수 있습니다.


10-10: ⚠️ Potential issue

URL 매개변수 처리 방식 개선이 필요합니다

현재 구현은 다음과 같은 문제점이 있습니다:

  1. URL 인코딩이 되어있지 않아 한글이나 특수문자 처리에 문제가 발생할 수 있습니다
  2. 템플릿 리터럴을 사용한 직접적인 문자열 결합은 보안상 위험합니다

다음과 같이 URLSearchParams를 사용하여 개선하는 것을 권장합니다:

- `/api/crews/search?keyword=${keyword}&mainLocation=${mainLocation}&mainCategory=${mainCategory}&subCategory=${subCategory}&sortType=${sortType}&page=${page}&size=${size}&sort=${sort}`,
+ const params = new URLSearchParams({
+   keyword,
+   mainLocation,
+   mainCategory,
+   subCategory,
+   sortType,
+   page: page.toString(),
+   size: size.toString(),
+   sort: sort.join(','),
+ });
+ `/api/crews/search?${params.toString()}`,

21-23: ⚠️ Potential issue

에러 처리 로직의 개선이 필요합니다

현재 에러 처리에는 다음과 같은 문제점이 있습니다:

  1. 프로덕션 환경에서 console.error 사용
  2. null 반환으로 인한 타입 안전성 저하
  3. 호출자에게 의미 있는 에러 정보를 제공하지 않음

다음과 같이 개선하는 것을 권장합니다:

- // eslint-disable-next-line no-console
- console.error(error);
- return null;
+ const errorMessage = error instanceof Error 
+   ? error.message 
+   : '크루 목록을 가져오는데 실패했습니다';
+ throw new Error(errorMessage);

6-6: ⚠️ Potential issue

sort 매개변수의 기본값이 적절하지 않습니다

['string']이라는 기본값은 의미가 불분명하며 실제 정렬에 사용하기에 부적절합니다. 다음과 같이 명확한 정렬 기준을 설정하는 것이 좋습니다:

- const { page, size, sort = ['string'] } = pageable;
+ const { page, size, sort = ['createdAt,desc'] } = pageable;

Likely invalid or redundant comment.

src/_queries/crew-queries.tsx (1)

7-13: 이전 리뷰 의견이 여전히 유효합니다.

queryKey에서 undefined나 null 값을 처리하는 로직이 아직 구현되지 않았습니다.

src/components/common/crew-list/crew-card-list.tsx (1)

14-14: Props 타입 정의가 더 엄격해졌습니다.

데이터 타입에서 undefined를 제거한 것은 좋은 변경이지만, 실제로 데이터가 항상 존재한다는 것을 보장할 수 있는지 확인이 필요합니다.

Also applies to: 20-20

✅ Verification successful

데이터가 항상 정의되어 있습니다.

CrewCardList가 사용되는 모든 위치에서 data가 정의된 상태로 전달되고 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if data is always defined in component usage

# Search for CrewCardList usage
rg -A 5 "CrewCardList"

Length of output: 7904

Comment on lines +34 to +35
? data?.pages.flatMap((page) => page?.data as MyCrewList[])
: data?.pages?.flatMap((page) => page?.content as MainCrewList[])) ?? [];
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

타입 단언 대신 타입 가드를 사용하는 것이 좋습니다.

현재 구현은 타입 단언(as)을 사용하고 있어 런타임 시 타입 안전성을 보장할 수 없습니다.

다음과 같이 타입 가드를 사용하여 개선해보세요:

function isMyCrewList(crew: any): crew is MyCrewList {
  return 'data' in crew;
}

function isMainCrewList(crew: any): crew is MainCrewList {
  return 'content' in crew;
}

const crewDataList = data?.pages.flatMap((page) => 
  inWhere === 'my-crew'
    ? (isMyCrewList(page) ? page.data : [])
    : (isMainCrewList(page) ? page.content : [])
) ?? [];

Comment on lines +59 to +79
<li key={inform?.id} className="w-full">
<CrewCard
inWhere={inWhere}
id={inform.id}
title={inform.title}
mainLocation={inform.mainLocation}
subLocation={inform.subLocation}
imageUrl={inform.imageUrl}
totalCount={inform.totalCount}
id={inform?.id}
title={inform?.title}
mainLocation={inform?.mainLocation}
subLocation={inform?.subLocation}
imageUrl={inform?.imageUrl}
totalCount={inform?.totalCount}
participantCount={
inWhere === 'my-crew'
? (inform as MyCrewList).currentCount
: (inform as MainCrewList).participantCount
? (inform as MyCrewList)?.currentCount
: (inform as MainCrewList)?.participantCount
}
totalGatheringCount={
inWhere === 'my-crew'
? (inform as MyCrewList).totalGathering
: (inform as MainCrewList).totalGatheringCount
? (inform as MyCrewList)?.totalGathering
: (inform as MainCrewList)?.totalGatheringCount
}
crewMembers={inWhere === 'my-crew' ? (inform as MyCrewList).crewMembers : undefined}
isConfirmed={inWhere !== 'my-crew' ? (inform as MainCrewList).isConfirmed : undefined}
crewMembers={inWhere === 'my-crew' ? (inform as MyCrewList)?.crewMembers : undefined}
isConfirmed={inWhere !== 'my-crew' && (inform as MainCrewList)?.isConfirmed}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

CrewCard props 전달 방식 개선이 필요합니다.

현재 구현은 과도한 타입 단언과 옵셔널 체이닝을 사용하고 있습니다. 이는 코드의 안전성과 가독성을 저해할 수 있습니다.

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

// 타입 가드 함수 사용
function getCrewCardProps(inform: MainCrewList | MyCrewList, inWhere?: 'my-crew') {
  const baseProps = {
    id: inform.id,
    title: inform.title,
    mainLocation: inform.mainLocation,
    subLocation: inform.subLocation,
    imageUrl: inform.imageUrl,
    totalCount: inform.totalCount,
  };

  if (inWhere === 'my-crew' && 'currentCount' in inform) {
    return {
      ...baseProps,
      participantCount: inform.currentCount,
      totalGatheringCount: inform.totalGathering,
      crewMembers: inform.crewMembers,
      isConfirmed: false,
    };
  }

  if ('participantCount' in inform) {
    return {
      ...baseProps,
      participantCount: inform.participantCount,
      totalGatheringCount: inform.totalGatheringCount,
      crewMembers: undefined,
      isConfirmed: inform.isConfirmed,
    };
  }

  throw new Error('Invalid crew data type');
}

// 컴포넌트에서 사용
<CrewCard
  inWhere={inWhere}
  {...getCrewCardProps(inform, inWhere)}
/>

@github-actions
Copy link

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

🧹 Outside diff range and nitpick comments (3)
src/types/crew-card.d.ts (1)

9-12: 정렬 필드의 타입 안정성 개선이 필요합니다

sort 필드가 현재 string[] 타입으로 정의되어 있어 잘못된 값이 전달될 수 있습니다. 유효한 정렬 옵션을 명시적으로 정의하는 것이 좋습니다.

 export interface PageableTypes {
   page: number;
   size: number;
-  sort: string[];
+  sort: Array<'createdAt' | 'participantCount'>;
 }
src/components/common/crew-list/crew-card-list.stories.tsx (1)

1-4: import 구문 정리가 필요합니다

관련된 import들을 그룹화하여 가독성을 높이는 것이 좋겠습니다:

  1. React 관련
  2. 외부 라이브러리
  3. 내부 컴포넌트/훅
  4. 타입

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

// React
import { useEffect, useState } from 'react';

// External libraries
import type { Meta, StoryObj } from '@storybook/react';
import { InfiniteData } from '@tanstack/react-query';

// Internal imports
import { useGetCrewListQuery } from '@/src/_queries/crew-queries';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
import ClientProvider from '@/src/components/client-provider';

// Types
import { MainCrewListResponse } from '@/src/types/crew-card';
src/components/common/crew-list/crew-card-list.tsx (1)

38-51: 로딩 상태 처리 로직 개선이 필요합니다.

현재 구현은 초기 로딩과 빈 데이터 상태를 별도로 처리하고 있어 일관성이 떨어집니다. 다음과 같은 개선을 제안합니다:

type LoadingState = 'initial' | 'empty' | 'loaded';

function getLoadingState(data: CrewCardListProps['data']): LoadingState {
  if (data?.pages[0] === null) return 'initial';
  if (!data?.pages.some(page => page?.content?.length || page?.data?.length)) return 'empty';
  return 'loaded';
}

const LoadingStateComponent: Record<LoadingState, JSX.Element> = {
  initial: <div className="flex justify-center py-10"><Loader size="sm" /></div>,
  empty: <div className="flex justify-center py-10"><p>데이터가 없습니다.</p></div>,
  loaded: null
};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5687085 and c3382b1.

📒 Files selected for processing (5)
  • src/app/_components/find-crew/find-crew.tsx (1 hunks)
  • src/components/common/crew-list/crew-card-list.stories.tsx (2 hunks)
  • src/components/common/crew-list/crew-card-list.tsx (2 hunks)
  • src/components/common/crew-list/crew-card.tsx (4 hunks)
  • src/types/crew-card.d.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/app/_components/find-crew/find-crew.tsx
  • src/components/common/crew-list/crew-card.tsx
🔇 Additional comments (5)
src/types/crew-card.d.ts (2)

1-7: 이전 리뷰 의견이 여전히 유효합니다

필터 조건의 선택적 필드 처리에 대한 이전 리뷰 의견이 아직 반영되지 않았습니다.


15-18: API 응답 구조와의 일관성 확인이 필요합니다

data에서 content로의 필드명 변경과 null 타입 추가가 백엔드 API 응답 구조와 일치하는지 확인해주세요.

src/components/common/crew-list/crew-card-list.stories.tsx (1)

62-62: 이전 리뷰 코멘트와 동일: 스토리북 테스트 케이스 보강 필요

src/components/common/crew-list/crew-card-list.tsx (2)

34-35: 이전 리뷰 코멘트 참조

타입 단언 관련 이슈는 이전 리뷰 코멘트에서 이미 다루어졌습니다.


59-79: 이전 리뷰 코멘트 참조

CrewCard props 전달 방식 개선에 대한 내용은 이전 리뷰 코멘트에서 이미 다루어졌습니다.

Comment on lines +22 to +23
mainCategory?: string;
subCategory?: string;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

CrewMemberList 타입이 정의되어 있지 않습니다

crewMembers 필드가 CrewMemberList[] 타입을 참조하고 있으나, 해당 타입이 파일 내에 정의되어 있지 않습니다. CrewMember 인터페이스를 사용해야 할 것 같습니다.

 export interface MainCrewList {
   // ...
-  crewMembers?: CrewMemberList[];
+  crewMembers?: CrewMember[];
 }

Also applies to: 32-32

Comment on lines 32 to 56
function RenderCrewCardList({
initialData,
}: {
initialData: InfiniteData<MainCrewListResponse | null>;
}) {
const [data, setData] = useState<InfiniteData<MainCrewListResponse | null>>(initialData);
const {
data: CrewCardListData,
ref,
isFetchingNextPage,
} = useInfiniteScroll(
useGetCrewListQuery({
keyword: '',
mainLocation: '',
mainCategory: '',
subCategory: '',
sortType: 'LATEST',
}),
);

useEffect(() => {
if (CrewCardListData) {
setData(CrewCardListData);
}
}, [CrewCardListData]);
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. 타입 안전성: MainCrewListResponse | null에 대한 명시적인 타입가드가 필요합니다.
  2. 에러 처리: API 호출 실패에 대한 처리가 없습니다.
  3. 로딩 상태: 초기 로딩 상태 처리가 필요합니다.

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

function RenderCrewCardList({
  initialData,
}: {
  initialData: InfiniteData<MainCrewListResponse | null>;
}) {
  const [data, setData] = useState<InfiniteData<MainCrewListResponse | null>>(initialData);
  const [error, setError] = useState<Error | null>(null);
  
  const {
    data: CrewCardListData,
    ref,
    isFetchingNextPage,
    isLoading,
    error: queryError,
  } = useInfiniteScroll(
    useGetCrewListQuery({
      keyword: '',
      mainLocation: '',
      mainCategory: '',
      subCategory: '',
      sortType: 'LATEST',
    }),
  );

  useEffect(() => {
    if (queryError) {
      setError(queryError as Error);
    }
    if (CrewCardListData) {
      setData(CrewCardListData);
    }
  }, [CrewCardListData, queryError]);

  if (error) {
    return <ErrorComponent error={error} />;
  }

  if (isLoading) {
    return <LoadingSpinner />;
  }

  return (
    <CrewCardList 
      data={data} 
      ref={ref} 
      isFetchingNextPage={isFetchingNextPage} 
    />
  );
}

// CrewCardListProps 타입을 구분하여 정의
interface MainCrewCardListProps {
data: InfiniteData<MainCrewListResponse> | undefined;
data: InfiniteData<MainCrewListResponse | null>;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

타입 정의의 안전성 개선이 필요합니다.

MainCrewListResponse | null과 같은 유니온 타입은 런타임에서 예기치 않은 동작을 유발할 수 있습니다. 다음과 같은 개선을 제안합니다:

  1. null 대신 undefined를 사용하여 옵셔널 값을 표현
  2. 명시적인 타입 가드를 통한 null 체크
interface MainCrewCardListProps {
  data: InfiniteData<MainCrewListResponse | undefined>;
  // ...
}

// 타입 가드 예시
function isValidMainCrewResponse(response: MainCrewListResponse | undefined): response is MainCrewListResponse {
  return response !== undefined;
}

Also applies to: 20-20

@github-actions
Copy link

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: 2

🧹 Outside diff range and nitpick comments (4)
src/_queries/crew-queries.tsx (3)

1-1: 사용하지 않는 import 문을 제거하세요.

UseInfiniteQueryOptions를 import 했지만 코드에서 사용하지 않고 있습니다.

다음과 같이 수정하세요:

-import { UseInfiniteQueryOptions } from '@tanstack/react-query';

14-22: 에러 처리를 더 구체적으로 개선하세요.

현재 에러 처리가 너무 단순합니다. 다음과 같은 개선사항을 제안합니다:

  1. 더 구체적인 에러 메시지를 제공하세요
  2. 에러 타입을 구분하여 처리하세요

다음과 같이 수정하세요:

  queryFn: ({ pageParam = 0 }) =>
    getCrewList(condition, { page: pageParam, size: 6, sort: [condition.sortType] }).then(
      (response) => {
        if (response === undefined) {
-         throw new Error('Response is null');
+         throw new Error(`크루 목록을 가져오는데 실패했습니다. 조건: ${JSON.stringify(condition)}`);
        }
        return response;
      },
    ),

23-24: getNextPageParam 로직을 더 명시적으로 작성하세요.

현재 구현이 동작은 하지만, 의도를 더 명확하게 표현할 수 있습니다.

다음과 같이 수정하세요:

- getNextPageParam: (lastPage: MainCrewListResponse, allPages: MainCrewListResponse[]) =>
-   lastPage.hasNext ? allPages.length : undefined,
+ getNextPageParam: (lastPage: MainCrewListResponse, allPages: MainCrewListResponse[]) => {
+   const nextPage = lastPage.hasNext ? allPages.length : undefined;
+   return nextPage;
+ },
src/types/crew-card.d.ts (1)

9-12: 페이지네이션 타입 개선이 필요합니다

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

  1. sort 필드의 타입을 구체적으로 정의하는 것이 좋습니다
  2. pagesize에 대한 유효성 검사가 필요합니다
 export interface PageableTypes {
-  page: number;
-  size: number;
-  sort: string[];
+  page: number & { __brand: 'NonNegativeInteger' };
+  size: number & { __brand: 'PositiveInteger' };
+  sort: Array<'asc' | 'desc'>;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c3382b1 and be1480d.

📒 Files selected for processing (6)
  • src/_apis/crew/get-crew-list.ts (1 hunks)
  • src/_queries/crew-queries.tsx (1 hunks)
  • src/app/_components/find-crew/find-crew.tsx (1 hunks)
  • src/components/common/crew-list/crew-card-list.stories.tsx (2 hunks)
  • src/components/common/crew-list/crew-card-list.tsx (2 hunks)
  • src/types/crew-card.d.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/app/_components/find-crew/find-crew.tsx
  • src/components/common/crew-list/crew-card-list.tsx
🔇 Additional comments (9)
src/_apis/crew/get-crew-list.ts (2)

6-6: ⚠️ Potential issue

정렬 매개변수의 기본값 수정 필요

sort 매개변수의 기본값으로 ['string']을 사용하는 것은 적절하지 않습니다. 실제 정렬 기준을 반영하는 의미 있는 기본값으로 변경해주세요.

- const { page, size, sort = ['string'] } = pageable;
+ const { page, size, sort = ['createdAt,desc'] } = pageable;

Likely invalid or redundant comment.


10-10: ⚠️ Potential issue

URL 매개변수 처리 개선 필요

쿼리 파라미터를 직접 문자열로 연결하는 것은 보안상 위험할 수 있으며, 특수문자나 한글이 포함된 경우 문제가 발생할 수 있습니다.

- `/api/crews/search?keyword=${keyword}&mainLocation=${mainLocation}&mainCategory=${mainCategory}&subCategory=${subCategory}&sortType=${sortType}&page=${page}&size=${size}&sort=${sort}`,
+ const params = new URLSearchParams({
+   keyword,
+   mainLocation,
+   mainCategory,
+   subCategory,
+   sortType,
+   page: page.toString(),
+   size: size.toString(),
+   sort: sort.join(','),
+ });
+ `/api/crews/search?${params.toString()}`,

Likely invalid or redundant comment.

src/_queries/crew-queries.tsx (1)

7-13: 이전 리뷰 의견이 아직 해결되지 않았습니다.

queryKey 처리에 대한 이전 리뷰 의견이 아직 반영되지 않았습니다.

src/types/crew-card.d.ts (3)

1-7: 이전 리뷰 의견이 여전히 유효합니다

필터 조건의 필드들이 여전히 모두 필수로 설정되어 있습니다.


22-23: 카테고리 필드의 선택적 처리가 적절합니다

mainCategorysubCategory를 선택적 필드로 변경한 것은 좋은 개선입니다. 이는 필터 조건의 유연성을 높여줍니다.


32-32: 이전 리뷰 의견이 여전히 유효합니다

CrewMemberList[] 타입 관련 이슈가 해결되지 않았습니다.

src/components/common/crew-list/crew-card-list.stories.tsx (3)

1-1: 필요한 의존성이 올바르게 추가되었습니다.

React Query와 상태 관리를 위한 필수 의존성들이 적절하게 import 되었습니다.

Also applies to: 3-4


32-56: ⚠️ Potential issue

에러 처리와 로딩 상태 관리가 필요합니다.

이전 리뷰에서 언급된 개선사항들이 아직 반영되지 않았습니다:

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

 function RenderCrewCardList({
   initialData,
 }: {
   initialData: InfiniteData<MainCrewListResponse | undefined>;
 }) {
   const [data, setData] = useState<InfiniteData<MainCrewListResponse | undefined>>(initialData);
+  const [error, setError] = useState<Error | null>(null);
   const {
     data: CrewCardListData,
     ref,
     isFetchingNextPage,
+    isLoading,
+    error: queryError,
   } = useInfiniteScroll(
     useGetCrewListQuery({
       keyword: '',
       mainLocation: '',
       mainCategory: '',
       subCategory: '',
       sortType: 'LATEST',
     }),
   );

   useEffect(() => {
+    if (queryError) {
+      setError(queryError as Error);
+    }
     if (CrewCardListData) {
       setData(CrewCardListData);
     }
-  }, [CrewCardListData]);
+  }, [CrewCardListData, queryError]);

+  if (error) {
+    return <ErrorComponent error={error} />;
+  }
+
+  if (isLoading) {
+    return <LoadingSpinner />;
+  }

   return <CrewCardList data={data} ref={ref} isFetchingNextPage={isFetchingNextPage} />;
 }

62-63: 🛠️ Refactor suggestion

다양한 테스트 케이스 추가가 필요합니다.

기본 케이스만 구현되어 있어 컴포넌트의 다양한 상태를 테스트하기 어렵습니다.

다음과 같은 테스트 케이스 추가를 제안드립니다:

export const WithFilters: Story = {
  render: () => (
    <RenderCrewCardList
      initialData={{
        pages: [],
        pageParams: [],
      }}
      initialFilters={{
        keyword: '개발자',
        mainLocation: '서울',
        mainCategory: '개발',
        subCategory: '웹개발',
      }}
    />
  ),
};

export const WithError: Story = {
  render: () => (
    <RenderCrewCardList
      initialData={{
        pages: [],
        pageParams: [],
      }}
      shouldError={true}
    />
  ),
};

export const Loading: Story = {
  render: () => (
    <RenderCrewCardList
      initialData={{
        pages: [],
        pageParams: [],
      }}
      isLoading={true}
    />
  ),
};

Comment on lines +21 to +23
// eslint-disable-next-line no-console
console.error(error);
return 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

에러 처리 방식 개선 필요

현재 에러 처리 방식에는 다음과 같은 문제가 있습니다:

  1. 프로덕션 환경에서 console.error 사용
  2. 에러를 숨기고 undefined를 반환하여 문제 진단이 어려움
  3. 호출자에게 적절한 에러 정보를 제공하지 않음
  } catch (error) {
-   // eslint-disable-next-line no-console
-   console.error(error);
-   return undefined;
+   const errorMessage = error instanceof Error 
+     ? error.message 
+     : '크루 목록을 가져오는데 실패했습니다';
+   throw new Error(errorMessage);
  }
📝 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-next-line no-console
console.error(error);
return undefined;
const errorMessage = error instanceof Error
? error.message
: '크루 목록을 가져오는데 실패했습니다';
throw new Error(errorMessage);

Comment on lines +15 to +18
export type MainCrewListResponse = {
content: MainCrewList[] | undefined;
hasNext: boolean;
};
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

API 응답 구조 변경으로 인한 영향이 발견되었습니다

다음 파일에서 data 필드를 사용하고 있습니다. content로 변경이 필요합니다:

  • src/app/api/mock-api/review.ts
  • src/app/(crew)/api/mock-api/writable-gathering.ts
  • src/app/(crew)/crew/detail/[id]/_components/crew-review-list.stories.tsx
  • src/_queries/auth/auth-queries.tsx
🔗 Analysis chain

응답 구조 변경에 대한 검증이 필요합니다

data에서 content로의 필드명 변경과 undefined 타입 추가는 API 응답 구조의 변경을 의미합니다. 이 변경이 프론트엔드 전반에 미치는 영향을 확인해야 합니다.


rg 명령어에서 tsx 파일 형식을 인식하지 못했습니다.

API 응답 구조 변경의 영향을 받는 코드를 검색하기 위해 .ts.tsx 파일을 대상으로 명령어를 수정하겠습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# API 응답 구조 변경의 영향을 받는 코드 검색
rg -l "\.data\." --type ts --type tsx

Length of output: 67


Script:

#!/bin/bash
# API 응답 구조 변경의 영향을 받는 코드 검색
rg -l "\\.data\\." -g "*.ts" -g "*.tsx"

Length of output: 228

Copy link
Contributor

@HaeJungg HaeJungg left a comment

Choose a reason for hiding this comment

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

정렬이나 검색이 많아 복잡한 부분인데 수고하셨습니다👏👏

Comment on lines +22 to +23
console.error(error);
return undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

이 에러처리를 굳이 여기서 하지 않고 페이지에서 한번에 api 유틸에 있는 ApiError를 사용해서 처리해도 좋을거같습니다!


return (
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools initialIsOpen={false} />
Copy link
Contributor

Choose a reason for hiding this comment

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

위에 코드 래빗의 의견처럼 디버깅 도구라 dev환경에서만 실행되도록 조건부 랜더링을 추가해야될거같아요!

fill
objectFit="cover"
alt={title}
src={imageUrl === 'string' ? ImgDefault : imageUrl}
Copy link
Contributor

Choose a reason for hiding this comment

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

이미지 디폴트 처리가 필요할까요...??👀 어차피 폼에서 이미지를 안고르면 생성이 안되는걸루 알고 있어서요..!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

아핫 수정했습니다~~~ 잘못된 크루데이터는 삭제했어요~~

@yulrang yulrang merged commit 7c0c126 into develop Nov 13, 2024
@github-actions
Copy link

@coderabbitai coderabbitai bot mentioned this pull request Nov 13, 2024
5 tasks
HaeJungg pushed a commit that referenced this pull request Nov 13, 2024
* Squashed commit of the following:

commit 51cfe2f
Author: Lee Youl <[email protected]>
Date:   Sat Nov 9 11:40:05 2024 +0900

    🐛 Fix: MockData 날짜 형식 수정

commit 7b68352
Author: Lee Youl <[email protected]>
Date:   Sat Nov 9 11:38:06 2024 +0900

    🐛 Fix: 이전날짜 선택 방지, isToday 날짜 비교 수정

commit f101987
Author: Lee Youl <[email protected]>
Date:   Sat Nov 9 11:19:20 2024 +0900

    🐛 Fix: 폼 동작 개선

commit c408058
Author: Lee Youl <[email protected]>
Date:   Sat Nov 9 10:51:40 2024 +0900

    🐛 Fix: isToday 함수 개선, 데이터 한국시간 기준으로 변경

commit 0683f5a
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 21:49:45 2024 +0900

    🐛 Fix: 버튼 링크로 교체

commit 43cdfa7
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 21:43:11 2024 +0900

    🚨 Fix: 린트 오류 제거

commit 9657201
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 21:34:56 2024 +0900

    🐛 Fix: 스크롤바 두개로 보이는 문제 수정

commit 63a8e1c
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 21:27:25 2024 +0900

    🐛 Fix: 유효성 검사 날짜 선택 오류 수정

commit 80f8554
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 21:24:46 2024 +0900

    🐛 Fix: 에러상태인데 새로 값 채울 때 에러 해제하기, 리팩토링

commit af9fb91
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 20:46:00 2024 +0900

    🐛 Fix: 크루 생성시 디테일 페이지로 이동, 리팩토링

commit f1fe204
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 20:31:17 2024 +0900

    🐛 Fix: 텍스트 수정(약속 잡기 > 약속 만들기)

commit 5cc6746
Author: Lee Youl <[email protected]>
Date:   Fri Nov 8 20:29:52 2024 +0900

    🐛 Fix: 드롭다운 값 선택시 포커스 아웃 되도록 수정

* [WIP] Feat: GetCrewList API 연결

* ✨ Feat: 백엔드 api 연결

* 🐛 Fix: 처음 로딩시 카테고리 초기화

* 🐛 Fix: 카테고리 동작 개선

* 🐛 Fix: 지역 필터링 동작 개선

* ✨ Feat: 지역 전체 필터 추가

* 🚨 Fix: 타입 개선, 빌드 오류 수정

* 🚧 Chore: workflow 수정

* ♻️ Refactor 코드 개선

* 🐛 Fix: 코드 개선

* ✨ Feat: 검색 버튼 추가

* 🐛 Fix: 동작 개선

* 🚧 Chore: 경로 변경

* 🐛 Fix: 콘솔에러 추가

* ⚡️ Fix: 검색 엔터방식으로 변경

* 🐛 Fix: 동작개선, 에러메시지 보이기

* 💄 Design: 스타일 수정

* 🐛 Fix: 에러처리 추가

* 🚨 Fix: 빌드 오류 수정

* 🐛 Fix: 타입 수정

* 🐛 Fix: 디폴트이미지 삭제, 데브툴 조건부렌더링
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

크루 찾기 API 연결

4 participants