Skip to content

Conversation

@HaeJungg
Copy link
Contributor

@HaeJungg HaeJungg commented Nov 12, 2024

πŸ”– Issue Ticket

#103

✍️ Description

λ””ν…ŒμΌ νŽ˜μ΄μ§€ get으둜 μš”μ²­ λ˜λŠ” λΆ€λΆ„ μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€!

  • λ””ν…ŒμΌ μΉ΄λ“œ
  • 약속 리슀트
  • 약속 λ””ν…ŒμΌ 데이터
    파일이 λ„ˆλ¬΄ λ§Žμ•„μ Έμ„œ λ‹€λ₯Έ μš”μ²­μ€ λ‹€λ₯Έ λΈŒλ ŒμΉ˜μ— μΆ”κ°€ν•˜κ² μŠ΅λ‹ˆλ‹€!
    λ””ν…ŒμΌ νŽ˜μ΄μ§€ μˆ˜μ •μ‚¬ν•­μ€ μ–΄μ°¨ν”Ό λ””μžμΈμ΄ λ°”λ€Œλ©΄ λ‹€μ‹œ μž‘μ—…ν•΄μ•Όν•˜κΈ°λ•Œλ¬Έμ—,,, λ‚˜μ€‘μ— μˆ˜μ •ν•˜κ² μŠ΅λ‹ˆλ‹€!

μ–΄μ œ 쀌으둜 μ „λ‹¬ν–ˆμ§€λ§Œ fetch api에 baseUrl을 μΆ”κ°€ν•˜κ³ , next config rewrite 뢀뢄을 μ‚­μ œν–ˆμŠ΅λ‹ˆλ‹€!

βœ… Checklist

PR

  • Branch Convention 확인

    feat/ 피쳐, fix/ 버그 μˆ˜μ •, refactor/ κ°œμ„ 

  • Base Branch 확인
  • μ μ ˆν•œ Label μ§€μ •
  • Assignee 및 Reviewer μ§€μ •

Test

  • 둜컬 μž‘λ™ 확인

Summary by CodeRabbit

  • μƒˆλ‘œμš΄ κΈ°λŠ₯
    • DetailCrewSection 및 GatheringListSection μ»΄ν¬λ„ŒνŠΈ μΆ”κ°€λ‘œ 크루 및 λͺ¨μž„ 세뢀정보 ν‘œμ‹œ κΈ°λŠ₯ ν–₯상.
    • useGetCrewDetailQuery, useGetGatheringDetailQuery, useGetGatheringListQuery ν›… μΆ”κ°€λ‘œ 데이터 패칭 및 캐싱 κ°„μ†Œν™”.
  • λ³€κ²½ 사항
    • API 호좜 및 응닡 처리 방식 κ°œμ„ μœΌλ‘œ 데이터 처리 μœ μ—°μ„± 증가.
    • GatheringCardCarousel 및 GatheringCard μ»΄ν¬λ„ŒνŠΈμ— crewId ν”„λ‘œνΌν‹° μΆ”κ°€.
  • 버그 μˆ˜μ •
    • μ—λŸ¬ 처리 둜직 κ°œμ„ μœΌλ‘œ μ‚¬μš©μžμ—κ²Œ 더 λͺ…ν™•ν•œ ν”Όλ“œλ°± 제곡.

minkyung5x5 and others added 30 commits November 4, 2024 17:04
* ✨ Feat: calendar-filter μ»΄ν¬λ„ŒνŠΈ μž‘μ„±

* πŸ§ͺ Test: μŠ€ν† λ¦¬λΆ μΆ”κ°€

* πŸ’š CI: λΉŒλ“œ 였λ₯˜ μˆ˜μ •

* πŸ“¦ Chore: νŽ˜μ΄μ§€ 폴더 λ³€κ²½

* πŸ“¦ Chore: νŽ˜μ΄μ§€ 폴더 λ³€κ²½, νŒ¨ν‚€μ§€ μΆ”κ°€

* πŸ’„ Design : λ°˜μ‘ν˜• μŠ€νƒ€μΌ 적용

* 🚚 Chore: 폴더 μœ„μΉ˜ λ³€κ²½

* Update and rename deploy.yml to trigger.yml

* Update dispatch.yml

* Update and rename trigger.yml to deploy.yml

* Update dispatch.yml

* Create dispatch_develop.yml

* Create deploy_develop.yml

* Update dispatch_develop.yml

* Update deploy_develop.yml

* Update deploy.yml

* Update deploy_develop.yml

* Update dispatch.yml

* Update dispatch_develop.yml

* ✨ Feat: ν…μŠ€νŠΈμΈν’‹, λ“œλ‘­λ‹€μš΄, νŒŒμΌμΈν’‹ μΆ”κ°€

* ♻️ Refactor: λ“œλ‘­λ‹€μš΄ μˆ˜μ • 반영

* ✨ Feat: νŽ˜μ΄μ§€ μ΄ˆμ•ˆ μž‘μ„±

* πŸ’„ Style: 프리티어 적용

* πŸ’„ Design: λ””μžμΈ 적용, 파일 이동

* πŸ’„ Design: λ””μžμΈ 적용, 파일 이동

* 🚨 Fix: 린트 였λ₯˜ μˆ˜μ •

* 🚨 Fix: λΉŒλ“œ 였λ₯˜ μˆ˜μ •

* πŸ§ͺ Test: μŠ€ν† λ¦¬λΆ μΆ”κ°€κ°€

* πŸ› Fix: λΉŒλ“œ 였λ₯˜ μˆ˜μ •

* 🚨 Fix: λΉŒλ“œ 였λ₯˜ μˆ˜μ •

* 🚚 Chore: 파일 이동

* ✨ Feat: μœ νš¨μ„± 검사 μΆ”κ°€

* πŸ”§ Chore: μŠ€ν† λ¦¬λΆ λΉŒλ“œ 였λ₯˜ λ•Œλ¬Έμ— μ„€μ • μˆ˜μ •

* πŸ”§ Chore: μ„€μ • 제거

* πŸ› Fix: dropdown λ‹€λ₯Έ 곳에 영ν–₯ μ•ˆκ°€λ„λ‘ μˆ˜μ •

* πŸ› Fix: onBlur λΉΌλ‚΄κΈ°

* 🚚 Chore: 파일 이동, CSR둜 μ „ν™˜

* 🎨 Style : λ¦°νŠΈν”„λ¦¬ν‹°μ–΄ 적용

* πŸ› Fix: 였λ₯˜ μˆ˜μ •

* πŸ› Fix: λ²„νŠΌ ꡐ체

* πŸ› Fix: TextInput ꡐ체

* πŸ”§ Chore: config λ³€κ²½

* πŸ› Fix: μŠ€ν† λ¦¬λΆ λΉŒλ“œμ˜€λ₯˜ μˆ˜μ •

* πŸ› Fix: μŠ€ν† λ¦¬λΆ λΉŒλ“œμ˜€λ₯˜ μˆ˜μ •

* 🚚 Chore: 파일 이동

* 🚨 Fix: 린트 였λ₯˜ μˆ˜μ •

* πŸ› Fix: 같은 파일 μ—…λ‘œλ“œμ‹œ μ—…λ‘œλ“œ λ˜μ§€ μ•ŠλŠ” 문제 ν•΄κ²°

* πŸ› Fix: ν•œκΈ€μž…λ ₯μ‹œ 21μžμ—μ„œ λ˜λŒμ•„κ°€λŠ” 문제 μˆ˜μ •

* πŸ› Fix: λΈ”λŸ¬μ‹œ ν•¨μˆ˜ 좩돌문제 ν•΄κ²°
@coderabbitai
Copy link

coderabbitai bot commented Nov 12, 2024

Walkthrough

next.config.mjs νŒŒμΌμ—μ„œ URL μž¬μž‘μ„± κΈ°λŠ₯이 μ œκ±°λ˜μ—ˆμœΌλ©°, λŒ€μ‹  CORS μ„€μ •κ³Ό 이미지 μ†ŒμŠ€ μœ μ—°μ„±μ„ κ°•μ‘°ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. API ν˜ΈμΆœμ„ μœ„ν•œ μ—¬λŸ¬ ν•¨μˆ˜μ˜ μ‹œκ·Έλ‹ˆμ²˜κ°€ μˆ˜μ •λ˜μ–΄ 동적 μ—”λ“œν¬μΈνŠΈλ₯Ό μ‚¬μš©ν•˜κ³ , μƒˆλ‘œμš΄ 비동기 ν•¨μˆ˜κ°€ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€. React Queryλ₯Ό ν™œμš©ν•œ μ»€μŠ€ν…€ 훅이 λ„μž…λ˜μ–΄ 데이터 패칭이 κ°œμ„ λ˜μ—ˆμœΌλ©°, μ—¬λŸ¬ μ»΄ν¬λ„ŒνŠΈκ°€ μƒˆλ‘­κ²Œ κ΅¬μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€. μ „λ°˜μ μœΌλ‘œ API μš”μ²­ 처리 및 였λ₯˜ 관리가 κ°•ν™”λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

Changes

파일 경둜 λ³€κ²½ μš”μ•½
next.config.mjs rewrites ν•¨μˆ˜ 제거, CORS μ„€μ • κ°•μ‘°, 이미지 μ†ŒμŠ€ νŒ¨ν„΄ μˆ˜μ •
src/_apis/detail/get-crew-detail.ts getCrewDetail ν•¨μˆ˜ μ‹œκ·Έλ‹ˆμ²˜ μˆ˜μ •, 동적 API μ—”λ“œν¬μΈνŠΈ μ‚¬μš©
src/_apis/detail/get-gathering-detail.ts μƒˆλ‘œμš΄ GetGatheringDetail ν•¨μˆ˜ μΆ”κ°€, 동적 API μ—”λ“œν¬μΈνŠΈ μ‚¬μš©
src/_apis/detail/get-gathering-list.ts getGatheringList ν•¨μˆ˜ μ‹œκ·Έλ‹ˆμ²˜ μˆ˜μ •, 동적 API μ—”λ“œν¬μΈνŠΈ μ‚¬μš©
src/_queries/detail/crew-detail-queries.ts μƒˆλ‘œμš΄ useGetCrewDetailQuery ν›… μΆ”κ°€
src/_queries/detail/gathering-detail-queries.ts μƒˆλ‘œμš΄ useGetGatheringDetailQuery ν›… μΆ”κ°€
src/_queries/detail/gathering-list-queries.ts μƒˆλ‘œμš΄ useGetGatheringListQuery ν›… μΆ”κ°€
src/app/(crew)/crew/detail/[id]/_components/detail-crew-section.tsx μƒˆλ‘œμš΄ DetailCrewSection μ»΄ν¬λ„ŒνŠΈ μΆ”κ°€
src/app/(crew)/crew/detail/[id]/_components/gathering-list-section.tsx μƒˆλ‘œμš΄ GatheringListSection μ»΄ν¬λ„ŒνŠΈ μΆ”κ°€
src/app/(crew)/crew/detail/[id]/page.tsx CrewDetailPage μ»΄ν¬λ„ŒνŠΈ μˆ˜μ •, μƒˆλ‘œμš΄ μ„Ήμ…˜μœΌλ‘œ μž¬κ΅¬μ„±
src/components/common/crew-list/detail-crew-card.stories.tsx Storybook ꡬ성 μˆ˜μ •, DetailCrewCard둜 이름 λ³€κ²½
src/components/common/crew-list/detail-crew-card.tsx DetailCrewCardProps μΈν„°νŽ˜μ΄μŠ€ μˆ˜μ •, 데이터 ꡬ쑰 λ³€κ²½
src/components/common/gathering-card/container.tsx GatheringCard μ»΄ν¬λ„ŒνŠΈμ—μ„œ API ν˜ΈμΆœμ„ 쿼리 기반 μ ‘κ·ΌμœΌλ‘œ λ³€κ²½
src/components/common/gathering-card/gathering-card.stories.tsx React Query 톡합, Storybook ꡬ성 μˆ˜μ •
src/components/common/gathering-card/presenter.tsx cn μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜μ˜ import 경둜 μˆ˜μ •
src/components/gathering-list/gathering-card-carousel.tsx crewId μΆ”κ°€, λ ˆμ΄μ•„μ›ƒ 및 μŠ€νƒ€μΌ μˆ˜μ •
src/components/gathering-list/gathering-carousel.stories.tsx React Query 톡합, Storybook ꡬ성 μˆ˜μ •
src/components/gathering-list/gathering-list.tsx μΉ΄λ“œ λ Œλ”λ§ 둜직 μΌμ‹œμ μœΌλ‘œ 주석 처리
src/utils/api.ts ApiError 클래슀 및 fetchApi ν•¨μˆ˜ μˆ˜μ •, API μš”μ²­ 처리 및 였λ₯˜ 관리 κ°œμ„ 
.gitignore .env ν•­λͺ© μΆ”κ°€

Possibly related PRs

  • Feat/101/login signup apiΒ #106: 이 PR은 next.config.mjsμ—μ„œ μƒˆλ‘œμš΄ rewrites λ©”μ„œλ“œλ₯Ό λ„μž…ν•˜μ—¬, μ£Ό PR의 ꡬ성 파일 λ³€κ²½κ³Ό μ§μ ‘μ μœΌλ‘œ 관련이 μžˆμŠ΅λ‹ˆλ‹€.

Suggested labels

pages

Suggested reviewers

  • yulrang
  • Rangbyeolang
  • minkyung5x5

🐰 λ³€ν™”μ˜ λ°”λžŒμ΄ λΆˆμ–΄μ™€
μƒˆλ‘œμš΄ 길을 μ—΄μ–΄μ£Όλ„€,
데이터도 μ΄μ œλŠ” μΎŒμ ν•˜κ²Œ,
쿼리둜 μ‰½κ²Œ μ°Ύμ•„κ°€λ„€.
크루와 λͺ¨μž„μ˜ 이야기λ₯Ό,
ν•¨κ»˜ λ‚˜λˆ„λŠ” 즐거움이여!
πŸ₯•βœ¨


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.

minkyung5x5 and others added 13 commits November 12, 2024 16:40
…age-edit

Feat/92/my gathering page edit
* 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: λ””ν΄νŠΈμ΄λ―Έμ§€ μ‚­μ œ, 데브툴 μ‘°κ±΄λΆ€λ Œλ”λ§
@HaeJungg HaeJungg marked this pull request as ready for review November 13, 2024 02:22
@HaeJungg HaeJungg self-assigned this Nov 13, 2024
@HaeJungg HaeJungg added the api label Nov 13, 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: 11

🧹 Outside diff range and nitpick comments (18)
src/_queries/detail/crew-detail-queries.ts (1)

4-9: μ»€μŠ€ν…€ ν›…μ˜ κ°œμ„  사항을 μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€.

ν˜„μž¬ κ΅¬ν˜„μ€ 기본적인 κΈ°λŠ₯을 잘 μˆ˜ν–‰ν•˜κ³  μžˆμ§€λ§Œ, λ‹€μŒκ³Ό 같은 κ°œμ„ μ‚¬ν•­λ“€μ„ κ³ λ €ν•΄λ³΄μ‹œλ©΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€:

  1. νƒ€μž… μ•ˆμ „μ„± κ°•ν™”
  2. 캐싱 μ „λž΅ μ΅œμ ν™”
  3. μ—λŸ¬ 처리 κ°œμ„ 

λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•΄λ³΄μ‹œλŠ” 것은 μ–΄λ–¨κΉŒμš”?:

+import { CrewDetailResponse } from '@/src/types/crew';
+
-export function useGetCrewDetailQuery(id: number) {
+export function useGetCrewDetailQuery(id: number) {
+  if (!id) {
+    throw new Error('크루 IDκ°€ ν•„μš”ν•©λ‹ˆλ‹€');
+  }
+
   return useQuery({
     queryKey: ['crewDetail', id],
     queryFn: () => getCrewDetail(id),
+    staleTime: 5 * 60 * 1000, // 5λΆ„
+    retry: 1,
+    select: (data: CrewDetailResponse) => {
+      return data;
+    },
   });
 }
src/_queries/detail/gathering-detail-queries.ts (1)

4-9: μ—λŸ¬ μ²˜λ¦¬μ™€ λ‘œλ”© μƒνƒœ 관리λ₯Ό κ°œμ„ ν•˜λ©΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€.

ν˜„μž¬ κ΅¬ν˜„μ€ 기본적인 κΈ°λŠ₯은 잘 λ™μž‘ν•˜μ§€λ§Œ, λ‹€μŒκ³Ό 같은 κ°œμ„ μ‚¬ν•­μ„ κ³ λ €ν•΄λ³΄μ‹œλ©΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€:

  1. 쿼리 μ˜΅μ…˜μ— μ—λŸ¬ μž¬μ‹œλ„ μ„€μ • μΆ”κ°€
  2. μΊμ‹œ μ‹œκ°„ μ„€μ •
  3. μŠ€ν†¨ νƒ€μž„ μ„€μ •

λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•΄λ³΄μ‹œλŠ” 건 μ–΄λ–¨κΉŒμš”?:

 export function useGetGatheringDetailQuery(crewId: number, gatheringId: number) {
   return useQuery({
     queryKey: ['gatheringDetail', crewId, gatheringId],
     queryFn: () => GetGatheringDetail(crewId, gatheringId),
+    retry: 1,
+    staleTime: 5 * 60 * 1000, // 5λΆ„
+    cacheTime: 30 * 60 * 1000, // 30λΆ„
   });
 }
src/_queries/detail/gathering-list-queries.ts (1)

5-11: μ»€μŠ€ν…€ 훅이 잘 κ΅¬ν˜„λ˜μ—ˆμœΌλ‚˜, λͺ‡ κ°€μ§€ κ°œμ„ μ‚¬ν•­μ„ μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€.

React Queryλ₯Ό ν™œμš©ν•œ κ΅¬ν˜„μ΄ 잘 λ˜μ–΄μžˆμŠ΅λ‹ˆλ‹€. λ‹€λ§Œ λ‹€μŒκ³Ό 같은 κ°œμ„ μ‚¬ν•­λ“€μ„ κ³ λ €ν•΄λ³΄μ‹œλ©΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€:

  1. JSDoc λ¬Έμ„œν™” μΆ”κ°€
  2. μ—λŸ¬ 처리 κ°•ν™”
  3. μž¬μ‹œλ„(retry) 둜직 μ„€μ • κ³ λ €

λ‹€μŒκ³Ό 같이 κ°œμ„ ν•΄λ³΄μ‹œλŠ” 건 μ–΄λ–¨κΉŒμš”?:

+/**
+ * λͺ¨μž„ λͺ©λ‘μ„ μ‘°νšŒν•˜λŠ” 쿼리 ν›…
+ * @param id 크루 ID
+ * @returns λͺ¨μž„ λͺ©λ‘ 쿼리 κ²°κ³Ό
+ */
 export function useGetGatheringListQuery(id: number) {
   return useQuery<GatheringType[], Error>({
     queryKey: ['gatheringList', id],
     queryFn: () => getGatheringList(id),
     enabled: !!id,
+    retry: 1,
+    onError: (error) => {
+      console.error('λͺ¨μž„ λͺ©λ‘ 쑰회 μ‹€νŒ¨:', error);
+    },
   });
 }
src/_apis/detail/get-gathering-list.ts (1)

13-13: 응닡 데이터 처리 κ°œμ„ μ΄ ν•„μš”ν•©λ‹ˆλ‹€.

데이터가 μ—†λŠ” κ²½μš°μ— λŒ€ν•œ μ²˜λ¦¬κ°€ ν•„μš”ν•©λ‹ˆλ‹€. λ‹€μŒκ³Ό 같은 κ°œμ„ μ„ μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€:

-  return response.data;
+  if (!response.data) {
+    throw new Error('λͺ¨μž„ 데이터λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.');
+  }
+  return response.data;
src/app/(crew)/crew/detail/[id]/_components/gathering-list-section.tsx (1)

10-20: μ‚¬μš©μž κ²½ν—˜ κ°œμ„ μ„ μœ„ν•œ λ¦¬νŒ©ν† λ§ μ œμ•ˆ

ν˜„μž¬ κ΅¬ν˜„μ€ κΈ°λŠ₯μ μœΌλ‘œλŠ” λ¬Έμ œκ°€ μ—†μœΌλ‚˜, λ‹€μŒκ³Ό 같은 κ°œμ„ μ‚¬ν•­μ„ μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€:

  1. λ‘œλ”© μƒνƒœμ— λ‹¨μˆœ ν…μŠ€νŠΈ λŒ€μ‹  μŠ€μΌˆλ ˆν†€ UIλ‚˜ μŠ€ν”Όλ„ˆλ₯Ό μ‚¬μš©
  2. μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό μ‚¬μš©μž μΉœν™”μ μœΌλ‘œ μˆ˜μ •
  3. 데이터 μ—†μŒ μƒνƒœμ— 더 μžμ„Έν•œ μ•ˆλ‚΄ λ©”μ‹œμ§€ μΆ”κ°€

λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•˜λŠ” 것을 μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€:

-  if (isLoading) return <p>λ‘œλ”© 쀑...</p>;
+  if (isLoading) return <LoadingSkeleton />;

-  if (error) return <p>데이터λ₯Ό λΆˆλŸ¬μ˜€λŠ” 데 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€: {error.message}</p>;
+  if (error) return (
+    <ErrorMessage
+      message="λͺ¨μž„ λͺ©λ‘μ„ λΆˆλŸ¬μ˜€λŠ” 쀑 λ¬Έμ œκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€."
+      suggestion="μž μ‹œ ν›„ λ‹€μ‹œ μ‹œλ„ν•΄ μ£Όμ„Έμš”."
+    />
+  );

-  if (!gatheringList || gatheringList.length === 0) return <p>데이터가 μ—†μŠ΅λ‹ˆλ‹€.</p>;
+  if (!gatheringList || gatheringList.length === 0) return (
+    <EmptyState
+      message="아직 λ“±λ‘λœ λͺ¨μž„이 μ—†μŠ΅λ‹ˆλ‹€."
+      suggestion="μƒˆλ‘œμš΄ λͺ¨μž„을 λ§Œλ“€μ–΄λ³΄μ„Έμš”!"
+    />
+  );
src/app/(crew)/crew/detail/[id]/_components/detail-crew-section.tsx (4)

7-9: μΈν„°νŽ˜μ΄μŠ€μ— JSDoc λ¬Έμ„œλ₯Ό μΆ”κ°€ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

μΈν„°νŽ˜μ΄μŠ€μ˜ λͺ©μ κ³Ό id ν”„λ‘œνΌν‹°μ˜ μš©λ„λ₯Ό λͺ…ν™•νžˆ μ„€λͺ…ν•˜λŠ” λ¬Έμ„œλ₯Ό μΆ”κ°€ν•˜λ©΄ μ½”λ“œμ˜ 가독성이 ν–₯상될 것 κ°™μŠ΅λ‹ˆλ‹€.

+/**
+ * 크루 상세 정보 μ„Ήμ…˜μ˜ ν”„λ‘œνΌν‹°
+ * @property {number} id - μ‘°νšŒν•  크루의 고유 μ‹λ³„μž
+ */
 interface DetailCrewSectionProps {
   id: number;
 }

11-13: μ—λŸ¬ λ°”μš΄λ”λ¦¬ 톡합을 κ³ λ €ν•΄λ³΄μ„Έμš”.

μ»΄ν¬λ„ŒνŠΈ μˆ˜μ€€μ—μ„œ μ—λŸ¬λ₯Ό μž‘μ•„λ‚΄κ³  μ²˜λ¦¬ν•˜λŠ” 것도 μ’‹μ§€λ§Œ, μ—λŸ¬ λ°”μš΄λ”λ¦¬λ₯Ό μ‚¬μš©ν•˜λ©΄ 더 체계적인 μ—λŸ¬ μ²˜λ¦¬κ°€ κ°€λŠ₯ν•  것 κ°™μŠ΅λ‹ˆλ‹€.


14-15: λ‘œλ”© μƒνƒœ UIλ₯Ό κ°œμ„ ν•΄μ£Όμ„Έμš”.

λ‹¨μˆœν•œ ν…μŠ€νŠΈ λŒ€μ‹  μŠ€μΌˆλ ˆν†€ UIλ‚˜ λ‘œλ”© μŠ€ν”Όλ„ˆλ₯Ό μ‚¬μš©ν•˜λ©΄ μ‚¬μš©μž κ²½ν—˜μ΄ ν–₯상될 것 κ°™μŠ΅λ‹ˆλ‹€.

-  if (isLoading) return <p>Loading...</p>;
+  if (isLoading) return <DetailCrewCardSkeleton />;

32-34: λΆˆν•„μš”ν•œ 주석을 μ œκ±°ν•΄μ£Όμ„Έμš”.

쑰건뢀 λ Œλ”λ§ 둜직이 λͺ…ν™•ν•˜μ—¬ 주석이 없어도 μ½”λ“œμ˜ μ˜λ„λ₯Ό 이해할 수 μžˆμŠ΅λ‹ˆλ‹€.

-  // dataκ°€ μžˆμ„ λ•Œλ§Œ DetailCrewCardλ₯Ό λ Œλ”λ§
   return data ? <DetailCrewCard data={data} /> : null;
src/app/(crew)/crew/detail/[id]/page.tsx (3)

1-9: μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” import 문을 μ œκ±°ν•΄μ£Όμ„Έμš”

CrewReviewSection μ»΄ν¬λ„ŒνŠΈκ°€ 주석 μ²˜λ¦¬λ˜μ–΄ μžˆμœΌλ―€λ‘œ ν•΄λ‹Ή import 문도 μ œκ±°ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

import { getGatheringList } from '@/src/_apis/detail/get-gathering-list';
import CreateGathering from './_components/create-gathering';
import DetailCrewSection from './_components/detail-crew-section';
import GatheringListSection from './_components/gathering-list-section';
-import CrewReviewSection from './_components/review-section';

1-2: μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” import 문듀을 μ •λ¦¬ν•΄μ£Όμ„Έμš”

getGatheringList와 CreateGathering은 ν˜„μž¬ μ½”λ“œμ—μ„œ μ‚¬μš©λ˜μ§€ μ•Šκ³  μžˆμŠ΅λ‹ˆλ‹€.

-import { getGatheringList } from '@/src/_apis/detail/get-gathering-list';
-import CreateGathering from './_components/create-gathering';

26-26: TODO 및 주석 처리된 μ½”λ“œμ— λŒ€ν•œ 좔적이 ν•„μš”ν•©λ‹ˆλ‹€

CreateGathering μ»΄ν¬λ„ŒνŠΈμ™€ 리뷰 μ„Ήμ…˜μ΄ 주석 μ²˜λ¦¬λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ λ―Έμ™„μ„± κΈ°λŠ₯듀을 μΆ”μ ν•˜κΈ° μœ„ν•œ 이슈 생성이 ν•„μš”ν•΄ λ³΄μž…λ‹ˆλ‹€.

μ΄λŸ¬ν•œ TODO ν•­λͺ©λ“€μ„ μΆ”μ ν•˜κΈ° μœ„ν•œ GitHub 이슈λ₯Ό μƒμ„±ν•΄λ“œλ¦΄κΉŒμš”?

Also applies to: 33-39

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

15-39: 데이터 μœ νš¨μ„± 검증 μΆ”κ°€λ₯Ό κ³ λ €ν•΄μ£Όμ„Έμš”.

data 객체둜 propsλ₯Ό κ΅¬μ‘°ν™”ν•œ 것은 쒋은 κ°œμ„ μ΄μ§€λ§Œ, λ‹€μŒ 사항듀을 κ³ λ €ν•΄λ³΄μ‹œλ©΄ μ’‹κ² μŠ΅λ‹ˆλ‹€:

  1. ν•„μˆ˜ ν•„λ“œμ— λŒ€ν•œ νƒ€μž… 검증
  2. 숫자 ν•„λ“œ(participantCount, totalCount λ“±)의 유효 λ²”μœ„ 검증
  3. imageUrlκ³Ό profileImageUrl의 μœ νš¨μ„± 검증

μ˜ˆμ‹œ μ½”λ“œ:

interface CrewMember {
  id: number;
  nickname: string;
  profileImageUrl: string;
}

interface DetailCrewData {
  id: number;
  title: string;
  mainLocation: string;
  subLocation: string;
  participantCount: number;
  totalCount: number;
  confirmed: boolean;
  imageUrl: string;
  totalGatheringCount: number;
  crewMembers: CrewMember[];
}

// μœ νš¨μ„± 검증 ν•¨μˆ˜
const validateDetailCrewData = (data: DetailCrewData): boolean => {
  return (
    data.participantCount <= data.totalCount &&
    data.participantCount >= 0 &&
    data.totalCount > 0
  );
};
src/components/common/gathering-card/gathering-card.stories.tsx (2)

28-34: QueryClient κΈ°λ³Έ μ„€μ • μΆ”κ°€λ₯Ό κ³ λ €ν•΄λ³΄μ„Έμš”.

Storybook ν™˜κ²½μ—μ„œμ˜ 더 λ‚˜μ€ ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•΄ QueryClient의 κΈ°λ³Έ 섀정을 μΆ”κ°€ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•΄λ³΄μ„Έμš”:

- const queryClient = new QueryClient();
+ const queryClient = new QueryClient({
+   defaultOptions: {
+     queries: {
+       retry: false,
+       cacheTime: 0,
+     },
+   },
+ });

43-43: ν…ŒμŠ€νŠΈ λ°μ΄ν„°μ˜ λ‚ μ§œλ₯Ό 더 ν˜„μ‹€μ μœΌλ‘œ μ„€μ •ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

ν˜„μž¬ μ„€μ •λœ 2024λ…„ λ‚ μ§œλ“€μ€ λ„ˆλ¬΄ λ¨Ό 미래의 λ‚ μ§œμž…λ‹ˆλ‹€. μŠ€ν† λ¦¬λΆμ—μ„œ λ‹€μ–‘ν•œ μ‹œλ‚˜λ¦¬μ˜€λ₯Ό ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•΄μ„œλŠ” 더 ν˜„μ‹€μ μΈ λ‚ μ§œ λ²”μœ„λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같은 λ‚ μ§œ λ²”μœ„λ₯Ό κ³ λ €ν•΄λ³΄μ„Έμš”:

  • κ°€κΉŒμš΄ 미래 (1-2μ£Ό 이내)
  • 당일
  • μ „λ‚ 
  • λ‹€μŒ 달

μ˜ˆμ‹œ:

- dateTime: '2024-11-30T00:30',
+ dateTime: '2023-12-20T00:30',

Also applies to: 57-57

src/components/gathering-list/gathering-card-carousel.tsx (1)

Line range hint 109-122: 인디케이터 μŠ€νƒ€μΌλ§ κ°œμ„ μ΄ ν•„μš”ν•©λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같은 κ°œμ„ μ‚¬ν•­μ„ μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€:

  1. ν•˜λ“œμ½”λ”©λœ 색상 값을 Tailwind 색상 ν† ν°μœΌλ‘œ ꡐ체
  2. κ°€λŠ₯ν•˜λ‹€λ©΄ μΈλ””μΌ€μ΄ν„°μ˜ 크기도 λ””μžμΈ ν† ν°μœΌλ‘œ 관리
-              backgroundColor:
-                i === Math.floor(currentIndex / slidesToShow) ? '#3b82f6' : '#dbeafe',
+              backgroundColor:
+                i === Math.floor(currentIndex / slidesToShow) ? 'rgb(var(--color-primary))' : 'rgb(var(--color-secondary))',
src/components/common/crew-list/detail-crew-card.tsx (2)

Line range hint 137-143: TODO 주석에 λŒ€ν•œ 후속 μ‘°μΉ˜κ°€ ν•„μš”ν•©λ‹ˆλ‹€.

μ£Όμ„μœΌλ‘œ ν‘œμ‹œλœ captainκ³Ό crew κ΄€λ ¨ 둜직이 아직 κ΅¬ν˜„λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. μ΄λŠ” μ‚¬μš©μž κΆŒν•œμ— λ”°λ₯Έ μ€‘μš”ν•œ κΈ°λŠ₯으둜 λ³΄μž…λ‹ˆλ‹€.

이 κΈ°λŠ₯ κ΅¬ν˜„μ„ μœ„ν•œ μ½”λ“œλ₯Ό μƒμ„±ν•˜κ±°λ‚˜ GitHub 이슈λ₯Ό μƒμ„±ν•˜λŠ” 것을 λ„μ™€λ“œλ¦΄κΉŒμš”?


Line range hint 137-143: 확인 μƒνƒœ ν‘œμ‹œ 둜직이 κ°œμ„ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

confirmed μƒνƒœμ— λ”°λ₯Έ 쑰건뢀 λ Œλ”λ§μ΄ 잘 κ΅¬ν˜„λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ ‘κ·Όμ„± ν–₯상을 μœ„ν•΄ λͺ‡ κ°€μ§€ κ°œμ„ μ‚¬ν•­μ„ μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같이 aria-label을 μΆ”κ°€ν•˜μ—¬ 슀크린 리더 지원을 κ°œμ„ ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

-              {confirmed && (
-                <span className="flex items-center gap-[1px] text-blue-600">
-                  <Image src={Check} alt="확인" width={24} height={24} />
-                  <span className="text-sm font-medium"> κ°œμ„€ ν™•μ •</span>
-                </span>
-              )}
+              {confirmed && (
+                <span className="flex items-center gap-[1px] text-blue-600" aria-label="크루 κ°œμ„€μ΄ ν™•μ •λ˜μ—ˆμŠ΅λ‹ˆλ‹€">
+                  <Image src={Check} alt="ν™•μ • μƒνƒœ μ•„μ΄μ½˜" width={24} height={24} />
+                  <span className="text-sm font-medium"> κ°œμ„€ ν™•μ •</span>
+                </span>
+              )}
πŸ“œ Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 7c0c126 and 608fe12.

πŸ“’ Files selected for processing (20)
  • .env (1 hunks)
  • next.config.mjs (0 hunks)
  • src/_apis/detail/get-crew-detail.ts (1 hunks)
  • src/_apis/detail/get-gathering-detail.ts (1 hunks)
  • src/_apis/detail/get-gathering-list.ts (1 hunks)
  • src/_queries/detail/crew-detail-queries.ts (1 hunks)
  • src/_queries/detail/gathering-detail-queries.ts (1 hunks)
  • src/_queries/detail/gathering-list-queries.ts (1 hunks)
  • src/app/(crew)/crew/detail/[id]/_components/detail-crew-section.tsx (1 hunks)
  • src/app/(crew)/crew/detail/[id]/_components/gathering-list-section.tsx (1 hunks)
  • src/app/(crew)/crew/detail/[id]/page.tsx (1 hunks)
  • src/components/common/crew-list/detail-crew-card.stories.tsx (2 hunks)
  • src/components/common/crew-list/detail-crew-card.tsx (2 hunks)
  • src/components/common/gathering-card/container.tsx (3 hunks)
  • src/components/common/gathering-card/gathering-card.stories.tsx (3 hunks)
  • src/components/common/gathering-card/presenter.tsx (1 hunks)
  • src/components/gathering-list/gathering-card-carousel.tsx (5 hunks)
  • src/components/gathering-list/gathering-carousel.stories.tsx (3 hunks)
  • src/components/gathering-list/gathering-list.tsx (2 hunks)
  • src/utils/api.ts (2 hunks)
πŸ’€ Files with no reviewable changes (1)
  • next.config.mjs
βœ… Files skipped from review due to trivial changes (3)
  • .env
  • src/components/common/gathering-card/presenter.tsx
  • src/components/gathering-list/gathering-list.tsx
πŸ”‡ Additional comments (27)
src/_queries/detail/crew-detail-queries.ts (1)

1-2: μž„ν¬νŠΈ ꡬ문이 적절히 κ΅¬μ„±λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

ν•„μš”ν•œ μ˜μ‘΄μ„±λ“€μ΄ λͺ…ν™•ν•˜κ²Œ μ •μ˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

src/_queries/detail/gathering-detail-queries.ts (2)

1-2: ν•„μš”ν•œ μ˜μ‘΄μ„±λ“€μ΄ μ˜¬λ°”λ₯΄κ²Œ μž„ν¬νŠΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€.

React Query와 API ν•¨μˆ˜κ°€ μ μ ˆν•˜κ²Œ μž„ν¬νŠΈλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.


6-6: 쿼리 ν‚€κ°€ μ μ ˆν•˜κ²Œ κ΅¬μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

쿼리 ν‚€κ°€ κ³„μΈ΅μ μœΌλ‘œ 잘 κ΅¬μ„±λ˜μ–΄ μžˆμ–΄ μΊμ‹œ λ¬΄νš¨ν™”λ‚˜ 관리가 μš©μ΄ν•  κ²ƒμœΌλ‘œ λ³΄μž…λ‹ˆλ‹€.

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

7-12: fetchApi νƒ€μž… μ •μ˜κ°€ λͺ…ν™•ν•©λ‹ˆλ‹€.

응닡 λ°μ΄ν„°μ˜ νƒ€μž…μ„ μ œλ„€λ¦­μ„ 톡해 λͺ…ν™•ν•˜κ²Œ μ •μ˜ν•œ 것이 μ’‹μŠ΅λ‹ˆλ‹€.

src/_queries/detail/gathering-list-queries.ts (1)

1-3: ν•„μš”ν•œ μ˜μ‘΄μ„±λ“€μ΄ μ˜¬λ°”λ₯΄κ²Œ μž„ν¬νŠΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€.

νƒ€μž…μŠ€ν¬λ¦½νŠΈ νƒ€μž…κ³Ό ν•„μˆ˜ λΌμ΄λΈŒλŸ¬λ¦¬λ“€μ΄ μ μ ˆν•˜κ²Œ μž„ν¬νŠΈλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

src/_apis/detail/get-gathering-list.ts (1)

4-4: ν•¨μˆ˜ μ‹œκ·Έλ‹ˆμ²˜κ°€ 적절히 μˆ˜μ •λ˜μ—ˆμŠ΅λ‹ˆλ‹€!

νƒ€μž… μ•ˆμ •μ„±μ΄ 잘 μœ μ§€λ˜μ—ˆμœΌλ©°, λ§€κ°œλ³€μˆ˜ 이름이 λͺ…ν™•ν•©λ‹ˆλ‹€.

src/_apis/detail/get-gathering-detail.ts (1)

1-2: ν•„μš”ν•œ μ˜μ‘΄μ„±λ“€μ΄ μ˜¬λ°”λ₯΄κ²Œ μž„ν¬νŠΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€.

νƒ€μž…κ³Ό μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜κ°€ μ μ ˆν•˜κ²Œ μž„ν¬νŠΈλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

src/app/(crew)/crew/detail/[id]/_components/gathering-list-section.tsx (2)

1-9: μ½”λ“œ ꡬ쑰가 κΉ”λ”ν•˜κ³  νƒ€μž…μ΄ 잘 μ •μ˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€!

'use client' μ§€μ‹œλ¬Έκ³Ό ν•„μš”ν•œ import문이 잘 κ΅¬μ„±λ˜μ–΄ 있으며, Props μΈν„°νŽ˜μ΄μŠ€κ°€ λͺ…ν™•ν•˜κ²Œ μ •μ˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.


11-11: 쿼리 ν›… κ΅¬ν˜„ 확인이 ν•„μš”ν•©λ‹ˆλ‹€

useGetGatheringListQuery ν›…μ˜ κ΅¬ν˜„μ„ ν™•μΈν•˜μ—¬ λ‹€μŒ 사항듀이 적절히 처리되고 μžˆλŠ”μ§€ 검증이 ν•„μš”ν•©λ‹ˆλ‹€:

  1. 잘λͺ»λœ id νŒŒλΌλ―Έν„°μ— λŒ€ν•œ 처리
  2. λ„€νŠΈμ›Œν¬ 였λ₯˜ 처리
βœ… Verification successful

쿼리 ν›… κ΅¬ν˜„ 확인 μ™„λ£Œ

useGetGatheringListQuery 훅이 μ˜¬λ°”λ₯΄κ²Œ κ΅¬ν˜„λ˜μ—ˆμœΌλ©°, μ—λŸ¬ μ²˜λ¦¬μ™€ id νŒŒλΌλ―Έν„°μ˜ μ‚¬μš©μ΄ μ μ ˆν•˜κ²Œ 처리되고 μžˆμŠ΅λ‹ˆλ‹€.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify query hook implementation

# Check query hook implementation
ast-grep --pattern 'export function useGetGatheringListQuery($_) {
  $$$
}'

# Check error handling in the hook
rg -A 5 "useGetGatheringListQuery"

Length of output: 2416

src/utils/api.ts (2)

54-54: ⚠️ Potential issue

λ°˜ν™˜ νƒ€μž… λ³€κ²½μœΌλ‘œ μΈν•œ 영ν–₯ 확인이 ν•„μš”ν•©λ‹ˆλ‹€

응닡 데이터λ₯Ό { data: T } ν˜•νƒœλ‘œ κ°μ‹ΈλŠ” 변경은 κΈ°μ‘΄ APIλ₯Ό μ‚¬μš©ν•˜λŠ” λͺ¨λ“  μ»΄ν¬λ„ŒνŠΈμ— 영ν–₯을 쀄 수 μžˆμŠ΅λ‹ˆλ‹€.

λ‹€μŒ 슀크립트둜 영ν–₯을 λ°›λŠ” μ½”λ“œλ₯Ό ν™•μΈν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€:

#!/bin/bash
# Description: Find all files that use fetchApi

# Search for fetchApi usage
rg "fetchApi[<(]" --type ts --type tsx -l

# Search for response destructuring patterns that might need updates
rg "const \{(?!data\s*[}])|= await fetchApi" --type ts --type tsx

38-39: πŸ› οΈ Refactor suggestion

ν™˜κ²½ λ³€μˆ˜ μ‚¬μš© 확인이 ν•„μš”ν•©λ‹ˆλ‹€

NEXT_PUBLIC_API_BASE_URL ν™˜κ²½ λ³€μˆ˜κ°€ λˆ„λ½λœ 경우 λŸ°νƒ€μž„ 였λ₯˜κ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν™˜κ²½ λ³€μˆ˜μ˜ 쑴재 μ—¬λΆ€λ₯Ό ν™•μΈν•˜λŠ” 검증 λ‘œμ§μ„ μΆ”κ°€ν•˜λŠ” 것이 μ’‹κ² μŠ΅λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•˜λŠ” 것을 μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€:

-    const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}${url}`, fetchOptions);
+    const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
+    if (!baseUrl) {
+      throw new Error('NEXT_PUBLIC_API_BASE_URL ν™˜κ²½ λ³€μˆ˜κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.');
+    }
+    const response = await fetch(`${baseUrl}${url}`, fetchOptions);

ν™˜κ²½ λ³€μˆ˜κ°€ μ„€μ •λ˜μ–΄ μžˆλŠ”μ§€ ν™•μΈν•˜κΈ° μœ„ν•΄ λ‹€μŒ 슀크립트λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€:

src/components/gathering-list/gathering-carousel.stories.tsx (3)

2-2: React Query 섀정이 적절히 κ΅¬ν˜„λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

QueryClient μΈμŠ€ν„΄μŠ€κ°€ μ˜¬λ°”λ₯΄κ²Œ μƒμ„±λ˜μ—ˆμœΌλ©°, ν•„μš”ν•œ import문이 μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

Also applies to: 42-43


51-57: μŠ€ν† λ¦¬λΆ λ°μ½”λ ˆμ΄ν„° 섀정이 잘 κ΅¬ν˜„λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

QueryClientProviderλ₯Ό 톡해 React Query μ»¨ν…μŠ€νŠΈκ°€ 적절히 제곡되고 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” μ»΄ν¬λ„ŒνŠΈκ°€ μ‹€μ œ ν™˜κ²½κ³Ό μœ μ‚¬ν•œ μ‘°κ±΄μ—μ„œ ν…ŒμŠ€νŠΈλ  수 μžˆλ„λ‘ 보μž₯ν•©λ‹ˆλ‹€.


67-67: crewId prop 좔가에 λŒ€ν•œ 검증이 ν•„μš”ν•©λ‹ˆλ‹€.

crewIdκ°€ μΆ”κ°€λ˜μ—ˆμ§€λ§Œ, 이 값이 μ‹€μ œ API ν˜ΈμΆœμ—μ„œ μ–΄λ–»κ²Œ μ‚¬μš©λ˜λŠ”μ§€ 확인이 ν•„μš”ν•©λ‹ˆλ‹€.

βœ… Verification successful

crewId prop μΆ”κ°€ 검증 μ™„λ£Œ

crewIdκ°€ GatheringCardCarouselProps μΈν„°νŽ˜μ΄μŠ€μ— μΆ”κ°€λ˜μ—ˆμœΌλ©°, API ν˜ΈμΆœμ—μ„œλ„ μ˜¬λ°”λ₯΄κ²Œ μ‚¬μš©λ˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: crewId μ‚¬μš© 방식 확인

# GatheringCardCarousel μ»΄ν¬λ„ŒνŠΈμ—μ„œ crewId μ‚¬μš© 확인
ast-grep --pattern 'interface GatheringCardCarouselProps {
  $$$
  crewId: $_
  $$$
}'

# API ν˜ΈμΆœμ—μ„œ crewId μ‚¬μš© 확인
rg -A 5 "crewId.*gathering" 

Length of output: 1431

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

2-2: μ»΄ν¬λ„ŒνŠΈ 이름 변경이 적절히 μ΄λ£¨μ–΄μ‘ŒμŠ΅λ‹ˆλ‹€!

μ»΄ν¬λ„ŒνŠΈ 이름이 CrewCardμ—μ„œ DetailCrewCard둜 λ³€κ²½λ˜μ—ˆκ³ , 이에 따라 메타 섀정도 일관성 있게 μ—…λ°μ΄νŠΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€.

Also applies to: 5-6

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

2-2: React Query 섀정이 μ˜¬λ°”λ₯΄κ²Œ κ΅¬ν˜„λ˜μ—ˆμŠ΅λ‹ˆλ‹€!

QueryClient의 섀정이 React Query 곡식 λ¬Έμ„œμ˜ ꢌμž₯ 사항을 잘 λ”°λ₯΄κ³  μžˆμŠ΅λ‹ˆλ‹€.

Also applies to: 5-5

src/components/gathering-list/gathering-card-carousel.tsx (3)

11-13: μΈν„°νŽ˜μ΄μŠ€ 변경이 μ μ ˆν•©λ‹ˆλ‹€!

crewId ν”„λ‘œνΌν‹°κ°€ μ μ ˆν•˜κ²Œ νƒ€μž…μ΄ μ§€μ •λ˜μ–΄ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.


15-18: μ»΄ν¬λ„ŒνŠΈ μ‹œκ·Έλ‹ˆμ²˜κ°€ μ˜¬λ°”λ₯΄κ²Œ μ—…λ°μ΄νŠΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€!

μΈν„°νŽ˜μ΄μŠ€ 변경사항이 μ»΄ν¬λ„ŒνŠΈ μ‹œκ·Έλ‹ˆμ²˜μ— μ •ν™•ν•˜κ²Œ λ°˜μ˜λ˜μ—ˆμŠ΅λ‹ˆλ‹€.


77-78: μŠ€νƒ€μΌλ§ 변경사항 검증이 ν•„μš”ν•©λ‹ˆλ‹€.

λ§ˆμ§„ 값이 λ³€κ²½λ˜κ³  μ΅œμ†Œ λ„ˆλΉ„κ°€ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€. λ‹€μŒ 사항듀을 ν™•μΈν•΄μ£Όμ„Έμš”:

  • mb-5둜의 변경이 전체 λ ˆμ΄μ•„μ›ƒ 간격에 λ―ΈμΉ˜λŠ” 영ν–₯
  • 큰 ν™”λ©΄μ—μ„œ lg:min-w-[362px]κ°€ μ˜λ„ν•œ λŒ€λ‘œ μž‘λ™ν•˜λŠ”μ§€
src/components/common/crew-list/detail-crew-card.tsx (2)

14-25: Props μΈν„°νŽ˜μ΄μŠ€ ꡬ쑰가 κ°œμ„ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

데이터 κ΄€λ ¨ 속성듀을 ν•˜λ‚˜μ˜ 객체둜 κ·Έλ£Ήν™”ν•œ 것은 쒋은 μ ‘κ·Όμž…λ‹ˆλ‹€. μ΄λŠ” μ»΄ν¬λ„ŒνŠΈμ˜ μœ μ§€λ³΄μˆ˜μ„±μ„ ν–₯μƒμ‹œν‚€κ³  props 전달을 λ‹¨μˆœν™”ν•©λ‹ˆλ‹€.


28-40: 데이터 ꡬ쑰 변경에 λ”°λ₯Έ μ μ ˆν•œ κ΅¬ν˜„μž…λ‹ˆλ‹€.

객체 ꡬ쑰 λΆ„ν•΄ 할당을 톡해 ν•„μš”ν•œ 속성듀을 λͺ…ν™•ν•˜κ²Œ μΆ”μΆœν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. μ½”λ“œμ˜ 가독성이 ν–₯μƒλ˜μ—ˆμŠ΅λ‹ˆλ‹€.

src/components/common/gathering-card/container.tsx (6)

5-6: LGTM!

ν•„μš”ν•œ λͺ¨λ“ˆλ“€μ„ μ •ν™•ν•˜κ²Œ μž„ν¬νŠΈν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.


14-14: LGTM!

crewId 속성을 μΈν„°νŽ˜μ΄μŠ€μ— μΆ”κ°€ν•˜μ—¬ ν•„μš”ν•œ 데이터λ₯Ό 전달할 수 있게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.


27-27: LGTM!

ν•¨μˆ˜μ—μ„œ crewIdλ₯Ό μ •ν™•ν•˜κ²Œ λ°›μ•„μ˜€κ³  μžˆμŠ΅λ‹ˆλ‹€.


31-31: LGTM!

isLiked μƒνƒœλ₯Ό μ˜¬λ°”λ₯΄κ²Œ μ΄ˆκΈ°ν™”ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.


70-72: LGTM!

openModal ν•¨μˆ˜κ°€ μ μ ˆν•˜κ²Œ μ •μ˜λ˜μ–΄ 있으며, λͺ¨λ‹¬μ„ μ—΄κΈ° μœ„ν•΄ μ œλŒ€λ‘œ μ‚¬μš©λ˜κ³  μžˆμŠ΅λ‹ˆλ‹€.


50-50: 데이터 패칭 둜직 확인 ν•„μš”

useGetGatheringDetailQuery 훅을 μ‚¬μš©ν•˜μ—¬ 데이터λ₯Ό κ°€μ Έμ˜€κ³  μžˆμŠ΅λ‹ˆλ‹€. crewId와 idκ°€ μ˜¬λ°”λ₯΄κ²Œ μ „λ‹¬λ˜κ³  μžˆλŠ”μ§€ ν™•μΈν•΄μ£Όμ„Έμš”.

λ‹€μŒ 슀크립트λ₯Ό μ‚¬μš©ν•˜μ—¬ GatheringCard μ»΄ν¬λ„ŒνŠΈμ— μ „λ‹¬λ˜λŠ” crewId와 id의 μ‚¬μš©μ„ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€:

@@ -0,0 +1,9 @@
import { useQuery } from '@tanstack/react-query';
import { GetGatheringDetail } from '@/src/_apis/detail/get-gathering-detail';
Copy link

Choose a reason for hiding this comment

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

πŸ’‘ Codebase verification

GetGatheringDetail ν•¨μˆ˜κ°€ κ΅¬ν˜„λ˜μ–΄ μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

GetGatheringDetail ν•¨μˆ˜μ˜ κ΅¬ν˜„μ„ μΆ”κ°€ν•˜μ—¬ μ˜¬λ°”λ₯Έ λ™μž‘μ„ 보μž₯ν•΄μ£Όμ„Έμš”.

πŸ”— Analysis chain

API ν•¨μˆ˜ κ΅¬ν˜„μ„ ν™•μΈν•΄μ£Όμ„Έμš”.

GetGatheringDetail ν•¨μˆ˜μ˜ κ΅¬ν˜„μ„ ν™•μΈν•˜μ—¬ μ˜¬λ°”λ₯Έ νƒ€μž…κ³Ό μ—λŸ¬ μ²˜λ¦¬κ°€ λ˜μ–΄μžˆλŠ”μ§€ 검증이 ν•„μš”ν•©λ‹ˆλ‹€.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# API ν•¨μˆ˜ κ΅¬ν˜„ 확인
ast-grep --pattern 'export function GetGatheringDetail($_: number, $_: number) {
  $$$
}'

# νƒ€μž… μ •μ˜ 확인
rg -g '*.ts' -g '*.tsx' "interface.*GatheringDetail" -A 10

Length of output: 3807

Comment on lines 4 to 13
export async function getCrewDetail(id: number): Promise<CrewDetail> {
const url = `/api/crews/${id}`;

const response = await fetchApi<{ data: CrewDetail }>(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});

return { data: response[0] };
return response.data;
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. API 호좜 μ‹€νŒ¨ μ‹œ μ—λŸ¬ μ²˜λ¦¬κ°€ μ—†μŠ΅λ‹ˆλ‹€.
  2. id νŒŒλΌλ―Έν„°μ— λŒ€ν•œ μœ νš¨μ„± 검사가 ν•„μš”ν•©λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같이 κ°œμ„ ν•˜λŠ” 것을 μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€:

 export async function getCrewDetail(id: number): Promise<CrewDetail> {
+  if (!Number.isInteger(id) || id <= 0) {
+    throw new Error('μœ νš¨ν•˜μ§€ μ•Šμ€ crew IDμž…λ‹ˆλ‹€.');
+  }
+
   const url = `/api/crews/${id}`;

-  const response = await fetchApi<{ data: CrewDetail }>(url, {
-    method: 'GET',
-    headers: {
-      'Content-Type': 'application/json',
-    },
-  });
-  return response.data;
+  try {
+    const response = await fetchApi<{ data: CrewDetail }>(url, {
+      method: 'GET',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+    });
+    return response.data;
+  } catch (error) {
+    throw new Error(`크루 상세 정보λ₯Ό κ°€μ Έμ˜€λŠ”λ° μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€: ${error.message}`);
+  }
 }
πŸ“ 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 async function getCrewDetail(id: number): Promise<CrewDetail> {
const url = `/api/crews/${id}`;
const response = await fetchApi<{ data: CrewDetail }>(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
return { data: response[0] };
return response.data;
export async function getCrewDetail(id: number): Promise<CrewDetail> {
if (!Number.isInteger(id) || id <= 0) {
throw new Error('μœ νš¨ν•˜μ§€ μ•Šμ€ crew IDμž…λ‹ˆλ‹€.');
}
const url = `/api/crews/${id}`;
try {
const response = await fetchApi<{ data: CrewDetail }>(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
return response.data;
} catch (error) {
throw new Error(`크루 상세 정보λ₯Ό κ°€μ Έμ˜€λŠ”λ° μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€: ${error.message}`);
}
}

Comment on lines 5 to 11
const url = `/api/crews/${id}/gatherings`;

const response = await fetchApi<{ data: GatheringType[] }>(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
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 λ¬Έμ„œμ— ν•΄λ‹Ή μ—”λ“œν¬μΈνŠΈκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

  • src/_apis/detail/get-gathering-detail.ts
  • src/_apis/detail/get-gathering-list.ts
πŸ”— Analysis chain

API μ—”λ“œν¬μΈνŠΈ 검증이 ν•„μš”ν•©λ‹ˆλ‹€.

잘λͺ»λœ IDκ°€ μ „λ‹¬λ˜μ—ˆμ„ λ•Œμ˜ μ—λŸ¬ μ²˜λ¦¬κ°€ ν•„μš”ν•  수 μžˆμŠ΅λ‹ˆλ‹€. API λ¬Έμ„œμ—μ„œ 이 μ—”λ“œν¬μΈνŠΈμ˜ 쑴재 여뢀와 응닡 ν˜•μ‹μ„ ν™•μΈν•΄μ£Όμ„Έμš”.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# API μ—”λ“œν¬μΈνŠΈ μ‚¬μš© 검증

# 1. API λ¬Έμ„œ 파일 검색
echo "API λ¬Έμ„œ 파일 검색 쀑..."
fd -e md -e yaml -e json "api|swagger|openapi"

# 2. κ΄€λ ¨ μ—”λ“œν¬μΈνŠΈ μ‚¬μš© 검색
echo "μ—”λ“œν¬μΈνŠΈ μ‚¬μš© 검색 쀑..."
rg -l "/api/crews/[^/]+/gatherings"

Length of output: 254

Comment on lines 4 to 7
export async function GetGatheringDetail(
crewId: number,
gatheringId: number,
): Promise<GatheringDetailType> {
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

ν•¨μˆ˜ 넀이밍 μ»¨λ²€μ…˜ κ°œμ„ μ΄ ν•„μš”ν•©λ‹ˆλ‹€.

ν•¨μˆ˜λͺ…이 파슀칼 μΌ€μ΄μŠ€(PascalCase)둜 μž‘μ„±λ˜μ–΄ μžˆλŠ”λ°, 일반적인 JavaScript/TypeScript ν•¨μˆ˜ 넀이밍 μ»¨λ²€μ…˜μ— 따라 카멜 μΌ€μ΄μŠ€(camelCase)둜 λ³€κ²½ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

-export async function GetGatheringDetail(
+export async function getGatheringDetail(
   crewId: number,
   gatheringId: number,
): Promise<GatheringDetailType>
πŸ“ 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 async function GetGatheringDetail(
crewId: number,
gatheringId: number,
): Promise<GatheringDetailType> {
export async function getGatheringDetail(
crewId: number,
gatheringId: number,
): Promise<GatheringDetailType> {

Comment on lines 8 to 17
const url = `/api/crews/${crewId}/gatherings/${gatheringId}`;

const response = await fetchApi<{ data: GatheringDetailType }>(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
return response.data;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

μ—λŸ¬ 처리 둜직 μΆ”κ°€κ°€ ν•„μš”ν•©λ‹ˆλ‹€.

API 호좜 μ‹œ λ°œμƒν•  수 μžˆλŠ” λ‹€μ–‘ν•œ μ—λŸ¬ 상황(λ„€νŠΈμ›Œν¬ 였λ₯˜, μ„œλ²„ 였λ₯˜ λ“±)에 λŒ€ν•œ μ²˜λ¦¬κ°€ λˆ„λ½λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ crewId와 gatheringIdκ°€ μœ νš¨ν•˜μ§€ μ•Šμ€ κ²½μš°μ— λŒ€ν•œ μ²˜λ¦¬λ„ ν•„μš”ν•©λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같은 κ°œμ„ μ„ μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€:

 export async function getGatheringDetail(
   crewId: number,
   gatheringId: number,
 ): Promise<GatheringDetailType> {
+  if (!crewId || !gatheringId) {
+    throw new Error('Invalid crewId or gatheringId');
+  }
+
   const url = `/api/crews/${crewId}/gatherings/${gatheringId}`;
 
-  const response = await fetchApi<{ data: GatheringDetailType }>(url, {
-    method: 'GET',
-    headers: {
-      'Content-Type': 'application/json',
-    },
-  });
-  return response.data;
+  try {
+    const response = await fetchApi<{ data: GatheringDetailType }>(url, {
+      method: 'GET',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+    });
+    return response.data;
+  } catch (error) {
+    if (error instanceof Error) {
+      throw new Error(`λͺ¨μž„ 상세 정보λ₯Ό κ°€μ Έμ˜€λŠ”λ° μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€: ${error.message}`);
+    }
+    throw new Error('λͺ¨μž„ 상세 정보λ₯Ό κ°€μ Έμ˜€λŠ”λ° μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€');
+  }
 }
πŸ“ 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 url = `/api/crews/${crewId}/gatherings/${gatheringId}`;
const response = await fetchApi<{ data: GatheringDetailType }>(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
return response.data;
}
export async function getGatheringDetail(
crewId: number,
gatheringId: number,
): Promise<GatheringDetailType> {
if (!crewId || !gatheringId) {
throw new Error('Invalid crewId or gatheringId');
}
const url = `/api/crews/${crewId}/gatherings/${gatheringId}`;
try {
const response = await fetchApi<{ data: GatheringDetailType }>(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
return response.data;
} catch (error) {
if (error instanceof Error) {
throw new Error(`λͺ¨μž„ 상세 정보λ₯Ό κ°€μ Έμ˜€λŠ”λ° μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€: ${error.message}`);
}
throw new Error('λͺ¨μž„ 상세 정보λ₯Ό κ°€μ Έμ˜€λŠ”λ° μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€');
}
}

Comment on lines 17 to 30
if (error) {
if (error instanceof ApiError) {
try {
const errorData = JSON.parse(error.message);

if (errorData.status === 'NOT_FOUND') {
return <p>크루 정보λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€</p>;
}
} catch {
return <p>{`Error ${error.status}: ${error.message}`}</p>;
}
}
return <p>데이터 톡신에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.</p>;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

μ—λŸ¬ 처리 λ‘œμ§μ„ κ°œμ„ ν•΄μ£Όμ„Έμš”.

ν˜„μž¬ μ—λŸ¬ 처리 둜직이 λ‹€μ†Œ λ³΅μž‘ν•˜λ©°, JSON νŒŒμ‹± μ‹œλ„λŠ” 잠재적인 μœ„ν—˜μ΄ μžˆμŠ΅λ‹ˆλ‹€. λ‹€μŒκ³Ό 같은 κ°œμ„ μ‚¬ν•­μ„ μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€:

  1. μ—λŸ¬ νƒ€μž…μ„ λͺ…ν™•νžˆ μ •μ˜
  2. JSON νŒŒμ‹± λŒ€μ‹  νƒ€μž… κ°€λ“œ μ‚¬μš©
  3. μ—λŸ¬ λ©”μ‹œμ§€ μƒμˆ˜ν™”
+const ERROR_MESSAGES = {
+  NOT_FOUND: '크루 정보λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€',
+  DEFAULT: '데이터 톡신에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€',
+} as const;
+
 if (error) {
-    if (error instanceof ApiError) {
-      try {
-        const errorData = JSON.parse(error.message);
-
-        if (errorData.status === 'NOT_FOUND') {
-          return <p>크루 정보λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€</p>;
-        }
-      } catch {
-        return <p>{`Error ${error.status}: ${error.message}`}</p>;
-      }
-    }
-    return <p>데이터 톡신에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.</p>;
+  if (error instanceof ApiError && error.status === 404) {
+    return <ErrorMessage message={ERROR_MESSAGES.NOT_FOUND} />;
+  }
+  return <ErrorMessage message={ERROR_MESSAGES.DEFAULT} />;
 }

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

Comment on lines 11 to 12
export default async function CrewDetailPage({ params }: CrewDetailPageProps) {
const id = Number(params.id);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

id νŒŒλΌλ―Έν„° λ³€ν™˜ μ‹œ μœ νš¨μ„± 검사가 ν•„μš”ν•©λ‹ˆλ‹€

Number() λ³€ν™˜ μ‹œ 잘λͺ»λœ λ¬Έμžμ—΄μ΄ λ“€μ–΄μ˜¬ 경우 NaN이 λ°˜ν™˜λ  수 μžˆμŠ΅λ‹ˆλ‹€. μœ νš¨μ„± 검사λ₯Ό μΆ”κ°€ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

-  const id = Number(params.id);
+  const id = Number(params.id);
+  if (isNaN(id)) {
+    throw new Error('Invalid crew ID');
+  }
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export default async function CrewDetailPage({ params }: CrewDetailPageProps) {
const id = Number(params.id);
export default async function CrewDetailPage({ params }: CrewDetailPageProps) {
const id = Number(params.id);
if (isNaN(id)) {
throw new Error('Invalid crew ID');
}

Comment on lines 19 to 31
</article>
</section>
<section className="w-full space-y-6">
<article className="space-y-6">
<div className="flex items-center justify-between">
<h2 className="text-2xl font-semibold">크루 약속</h2>
<CreateGathering />
{/* <CreateGathering /> */}
</div>
<div className="flex w-full">
<GatheringCardCarousel gatheringData={gatheringList} />
<GatheringListSection id={id} />
</div>
</article>
</section>
Copy link

Choose a reason for hiding this comment

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

πŸ’‘ Codebase verification

μ„Ήμ…˜ μ»΄ν¬λ„ŒνŠΈλ“€μ˜ μ—λŸ¬ μ²˜λ¦¬μ— λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€

  • DetailCrewSection μ»΄ν¬λ„ŒνŠΈμ˜ μ—λŸ¬ μ²˜λ¦¬μ— TODO 주석이 남아 μžˆμŠ΅λ‹ˆλ‹€.
  • GatheringListSection μ»΄ν¬λ„ŒνŠΈμ˜ μ—λŸ¬ λ©”μ‹œμ§€κ°€ μ‚¬μš©μžμ—κ²Œ μΆ©λΆ„ν•œ 정보λ₯Ό μ œκ³΅ν•˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.
πŸ”— Analysis chain

μ„Ήμ…˜ μ»΄ν¬λ„ŒνŠΈλ“€μ˜ μ—λŸ¬ 처리 검증이 ν•„μš”ν•©λ‹ˆλ‹€

DetailCrewSectionκ³Ό GatheringListSection μ»΄ν¬λ„ŒνŠΈμ— μ „λ‹¬λ˜λŠ” idκ°€ μœ νš¨ν•˜μ§€ μ•Šμ„ 경우의 μ—λŸ¬ μ²˜λ¦¬κ°€ 적절히 κ΅¬ν˜„λ˜μ–΄ μžˆλŠ”μ§€ 확인이 ν•„μš”ν•©λ‹ˆλ‹€.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify error handling in section components

# Check DetailCrewSection implementation
ast-grep --pattern 'function DetailCrewSection($_) {
  $$$
}'

# Check GatheringListSection implementation
ast-grep --pattern 'function GatheringListSection($_) {
  $$$
}'

Length of output: 3735

Comment on lines 47 to 78
args: {
totalCount: 20,
participantCount: 10,
isConfirmed: true,
data: {
id: 1,
title: '같이 λ¬Όμž₯κ΅¬μΉ μ‚¬λžŒ',
mainLocation: 'λŒ€μ „κ΄‘μ—­μ‹œ',
subLocation: 'μœ μ„±κ΅¬',
participantCount: 10,
totalCount: 20,
confirmed: true,
imageUrl: 'https://i.pinimg.com/564x/f8/8d/c5/f88dc5b857caf6c303ae5ef9dd12e7fb.jpg',
totalGatheringCount: 5,
crewMembers: [], // 빈 배열이라도 κΈ°λ³Έκ°’μœΌλ‘œ μ„€μ •
},
},
};

export const NotConfirmed: Story = {
args: {
totalCount: 10,
participantCount: 1,
isConfirmed: false,
},
};

export const Fulled: Story = {
args: {
totalCount: 5,
participantCount: 5,
isConfirmed: true,
data: {
id: 2,
title: 'λ¬Όμž₯ꡬ λ™ν˜ΈνšŒ',
mainLocation: 'μ„œμšΈνŠΉλ³„μ‹œ',
subLocation: '강남ꡬ',
participantCount: 5,
totalCount: 15,
confirmed: false,
imageUrl: 'https://i.pinimg.com/564x/e2/25/bb/e225bb492dc7a20a549f3c0abec28eb8.jpg',
totalGatheringCount: 3,
crewMembers: [],
},
},
};
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. μ΅œλŒ€ 인원이 μ°¬ 경우
  2. crewMembersκ°€ μžˆλŠ” 경우
  3. κΈ΄ 제λͺ©μ΄λ‚˜ μœ„μΉ˜ ν…μŠ€νŠΈμ˜ 처리
  4. 이미지 λ‘œλ”© μ‹€νŒ¨ 상황

μ˜ˆμ‹œ μ½”λ“œ:

export const FullParticipants: Story = {
  args: {
    data: {
      ...Default.args.data,
      participantCount: 20,
      totalCount: 20,
    },
  },
};

export const WithCrewMembers: Story = {
  args: {
    data: {
      ...Default.args.data,
      crewMembers: [
        {
          id: 1,
          nickname: '맀우 κΈ΄ λ‹‰λ„€μž„ ν…ŒμŠ€νŠΈ',
          profileImageUrl: 'invalid-url',
        },
      ],
    },
  },
};

Comment on lines 53 to 68
if (error) {
if (error instanceof ApiError) {
try {
const errorData = JSON.parse(error.message);

if (opened) {
fetchGatheringDetail();
if (errorData.status === 'NOT_FOUND') {
Toast({ message: 'λͺ¨μž„ 정보λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.', type: 'error' });
}
} catch {
Toast({ message: `Error ${error.status}: ${error.message}`, type: 'error' });
}
} else {
Toast({ message: '데이터 톡신에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.', type: 'error' });
}
}
}, [opened]);
}, [error]);
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

μ—λŸ¬ 처리 둜직 κ°œμ„  ν•„μš”

ν˜„μž¬ μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό νŒŒμ‹±ν•˜μ—¬ μƒνƒœλ₯Ό ν™•μΈν•˜κ³  μžˆμœΌλ‚˜, error 객체에 이미 ν•„μš”ν•œ 정보가 ν¬ν•¨λ˜μ–΄ μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. JSON.parse(error.message) λŒ€μ‹  error.statusλ₯Ό 직접 μ‚¬μš©ν•˜μ—¬ μ—λŸ¬ 처리λ₯Ό λ‹¨μˆœν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ μ˜ˆμ™Έ 처리 λ‘œμ§μ„ κ°„μ†Œν™”ν•˜κ³  잠재적인 νŒŒμ‹± 였λ₯˜λ₯Ό λ°©μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같이 μ½”λ“œ μˆ˜μ •μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€:

useEffect(() => {
  if (error) {
-    if (error instanceof ApiError) {
-      try {
-        const errorData = JSON.parse(error.message);
-
-        if (errorData.status === 'NOT_FOUND') {
-          Toast({ message: 'λͺ¨μž„ 정보λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.', type: 'error' });
-        }
-      } catch {
-        Toast({ message: `Error ${error.status}: ${error.message}`, type: 'error' });
-      }
-    } else {
-      Toast({ message: '데이터 톡신에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.', type: 'error' });
-    }
+    if (error.status === 404) {
+      Toast({ message: 'λͺ¨μž„ 정보λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.', type: 'error' });
+    } else {
+      Toast({ message: `Error ${error.status}: ${error.message}`, type: 'error' });
+    }
  }
}, [error]);
πŸ“ 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
if (error) {
if (error instanceof ApiError) {
try {
const errorData = JSON.parse(error.message);
if (opened) {
fetchGatheringDetail();
if (errorData.status === 'NOT_FOUND') {
Toast({ message: 'λͺ¨μž„ 정보λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.', type: 'error' });
}
} catch {
Toast({ message: `Error ${error.status}: ${error.message}`, type: 'error' });
}
} else {
Toast({ message: '데이터 톡신에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€.', type: 'error' });
}
}
}, [opened]);
}, [error]);
if (error) {
if (error.status === 404) {
Toast({ message: 'λͺ¨μž„ 정보λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.', type: 'error' });
} else {
Toast({ message: `Error ${error.status}: ${error.message}`, type: 'error' });
}
}
}, [error]);

@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)
.gitignore (1)

30-30: ν™˜κ²½ λ³€μˆ˜ 파일이 μ˜¬λ°”λ₯΄κ²Œ μ œμ™Έλ˜λ„λ‘ μ„€μ •λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

.env νŒŒμΌμ„ Gitμ—μ„œ μ œμ™Έν•˜λŠ” 것은 λ³΄μ•ˆμƒ 쒋은 κ΄€ν–‰μž…λ‹ˆλ‹€. ν•˜μ§€λ§Œ λ‹€λ₯Έ κ°œλ°œμžλ“€μ„ μœ„ν•΄ ν•„μš”ν•œ ν™˜κ²½ λ³€μˆ˜λ“€μ„ λ¬Έμ„œν™”ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

.env.example νŒŒμΌμ„ μƒμ„±ν•˜μ—¬ ν•„μš”ν•œ ν™˜κ²½ λ³€μˆ˜λ“€μ˜ μ˜ˆμ‹œλ₯Ό μ œκ³΅ν•˜λŠ” 것을 μΆ”μ²œλ“œλ¦½λ‹ˆλ‹€:

+# .env.example
+NEXT_PUBLIC_API_BASE_URL=https://api.example.com
πŸ“œ Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 608fe12 and cb6c122.

πŸ“’ Files selected for processing (1)
  • .gitignore (1 hunks)
πŸ”‡ Additional comments (1)
.gitignore (1)

30-30: Git νžˆμŠ€ν† λ¦¬μ—μ„œ ν™˜κ²½ λ³€μˆ˜ 파일 확인이 ν•„μš”ν•©λ‹ˆλ‹€.

이전에 μ‹€μˆ˜λ‘œ μ»€λ°‹λœ ν™˜κ²½ λ³€μˆ˜ 파일이 μžˆλŠ”μ§€ 확인이 ν•„μš”ν•©λ‹ˆλ‹€.

@HaeJungg HaeJungg closed this Nov 13, 2024
@HaeJungg HaeJungg force-pushed the Feat/103/DetailPageGet branch from cb6c122 to 74bc0b1 Compare November 13, 2024 05:38
@HaeJungg HaeJungg deleted the Feat/103/DetailPageGet branch November 13, 2024 08:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants