-
Notifications
You must be signed in to change notification settings - Fork 3
Feat/103/detail page get #108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
* β¨ 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: λΈλ¬μ ν¨μ μΆ©λλ¬Έμ ν΄κ²°
Feat/cr 72/signup page
Walkthrough
Changes
Possibly related PRs
Suggested labels
Suggested reviewers
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? πͺ§ TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
β¦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: λν΄νΈμ΄λ―Έμ§ μμ , λ°λΈν΄ 쑰건λΆλ λλ§
|
πstorybook: https://67206cc6ff9d7a05a3528ff8-vaulzkyegj.chromatic.com/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
π§Ή Outside diff range and nitpick comments (18)
src/_queries/detail/crew-detail-queries.ts (1)
4-9: 컀μ€ν ν μ κ°μ μ¬νμ μ μλ립λλ€.νμ¬ κ΅¬νμ κΈ°λ³Έμ μΈ κΈ°λ₯μ μ μννκ³ μμ§λ§, λ€μκ³Ό κ°μ κ°μ μ¬νλ€μ κ³ λ €ν΄λ³΄μλ©΄ μ’μ κ² κ°μ΅λλ€:
- νμ μμ μ± κ°ν
- μΊμ± μ λ΅ μ΅μ ν
- μλ¬ μ²λ¦¬ κ°μ
λ€μκ³Ό κ°μ΄ μμ ν΄λ³΄μλ κ²μ μ΄λ¨κΉμ?:
+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: μλ¬ μ²λ¦¬μ λ‘λ© μν κ΄λ¦¬λ₯Ό κ°μ νλ©΄ μ’μ κ² κ°μ΅λλ€.νμ¬ κ΅¬νμ κΈ°λ³Έμ μΈ κΈ°λ₯μ μ λμνμ§λ§, λ€μκ³Ό κ°μ κ°μ μ¬νμ κ³ λ €ν΄λ³΄μλ©΄ μ’μ κ² κ°μ΅λλ€:
- 쿼리 μ΅μ μ μλ¬ μ¬μλ μ€μ μΆκ°
- μΊμ μκ° μ€μ
- μ€ν¨ νμ μ€μ
λ€μκ³Ό κ°μ΄ μμ ν΄λ³΄μλ 건 μ΄λ¨κΉμ?:
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λ₯Ό νμ©ν ꡬνμ΄ μ λμ΄μμ΅λλ€. λ€λ§ λ€μκ³Ό κ°μ κ°μ μ¬νλ€μ κ³ λ €ν΄λ³΄μλ©΄ μ’μ κ² κ°μ΅λλ€:
- JSDoc λ¬Έμν μΆκ°
- μλ¬ μ²λ¦¬ κ°ν
- μ¬μλ(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: μ¬μ©μ κ²½ν κ°μ μ μν 리ν©ν λ§ μ μνμ¬ κ΅¬νμ κΈ°λ₯μ μΌλ‘λ λ¬Έμ κ° μμΌλ, λ€μκ³Ό κ°μ κ°μ μ¬νμ μ μλ립λλ€:
- λ‘λ© μνμ λ¨μ ν μ€νΈ λμ μ€μΌλ ν€ UIλ μ€νΌλλ₯Ό μ¬μ©
- μλ¬ λ©μμ§λ₯Ό μ¬μ©μ μΉνμ μΌλ‘ μμ
- λ°μ΄ν° μμ μνμ λ μμΈν μλ΄ λ©μμ§ μΆκ°
λ€μκ³Ό κ°μ΄ μμ νλ κ²μ μ μλ립λλ€:
- 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λ₯Ό ꡬ쑰νν κ²μ μ’μ κ°μ μ΄μ§λ§, λ€μ μ¬νλ€μ κ³ λ €ν΄λ³΄μλ©΄ μ’κ² μ΅λλ€:
- νμ νλμ λν νμ κ²μ¦
- μ«μ νλ(
participantCount,totalCountλ±)μ μ ν¨ λ²μ κ²μ¦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: μΈλμΌμ΄ν° μ€νμΌλ§ κ°μ μ΄ νμν©λλ€.λ€μκ³Ό κ°μ κ°μ μ¬νμ μ μλ립λλ€:
- νλμ½λ©λ μμ κ°μ Tailwind μμ ν ν°μΌλ‘ κ΅μ²΄
- κ°λ₯νλ€λ©΄ μΈλμΌμ΄ν°μ ν¬κΈ°λ λμμΈ ν ν°μΌλ‘ κ΄λ¦¬
- 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
π 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 ν μ ꡬνμ νμΈνμ¬ λ€μ μ¬νλ€μ΄ μ μ ν μ²λ¦¬λκ³ μλμ§ κ²μ¦μ΄ νμν©λλ€:
- μλͺ»λ id νλΌλ―Έν°μ λν μ²λ¦¬
- λ€νΈμν¬ μ€λ₯ μ²λ¦¬
β 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:
λ°ν νμ λ³κ²½μΌλ‘ μΈν μν₯ νμΈμ΄ νμν©λλ€
μλ΅ λ°μ΄ν°λ₯Ό { 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 tsx38-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'; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π‘ 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
| 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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
κΈ°λ³Έ ꡬνμ΄ μ λμ΄μμΌλ μλ¬ μ²λ¦¬κ° νμν©λλ€.
ν¨μμ κΈ°λ³Έ ꡬνμ μ λμ΄ μμ§λ§, λ€μ μ¬νλ€μ κ³ λ €ν΄ μ£ΌμκΈ° λ°λλλ€:
- API νΈμΆ μ€ν¨ μ μλ¬ μ²λ¦¬κ° μμ΅λλ€.
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.
| 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}`); | |
| } | |
| } |
| const url = `/api/crews/${id}/gatherings`; | ||
|
|
||
| const response = await fetchApi<{ data: GatheringType[] }>(url, { | ||
| method: 'GET', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π‘ Codebase verification
API λ¬Έμμ ν΄λΉ μλν¬μΈνΈκ° μ‘΄μ¬νμ§ μμ΅λλ€.
src/_apis/detail/get-gathering-detail.tssrc/_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
| export async function GetGatheringDetail( | ||
| crewId: number, | ||
| gatheringId: number, | ||
| ): Promise<GatheringDetailType> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
ν¨μ λ€μ΄λ° 컨벀μ κ°μ μ΄ νμν©λλ€.
ν¨μλͺ μ΄ νμ€μΉΌ μΌμ΄μ€(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.
| export async function GetGatheringDetail( | |
| crewId: number, | |
| gatheringId: number, | |
| ): Promise<GatheringDetailType> { | |
| export async function getGatheringDetail( | |
| crewId: number, | |
| gatheringId: number, | |
| ): Promise<GatheringDetailType> { |
| const url = `/api/crews/${crewId}/gatherings/${gatheringId}`; | ||
|
|
||
| const response = await fetchApi<{ data: GatheringDetailType }>(url, { | ||
| method: 'GET', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }); | ||
| return response.data; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
μλ¬ μ²λ¦¬ λ‘μ§ μΆκ°κ° νμν©λλ€.
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.
| 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('λͺ¨μ μμΈ μ 보λ₯Ό κ°μ Έμ€λλ° μ€ν¨νμ΅λλ€'); | |
| } | |
| } |
| 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>; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
μλ¬ μ²λ¦¬ λ‘μ§μ κ°μ ν΄μ£ΌμΈμ.
νμ¬ μλ¬ μ²λ¦¬ λ‘μ§μ΄ λ€μ 볡μ‘νλ©°, JSON νμ± μλλ μ μ¬μ μΈ μνμ΄ μμ΅λλ€. λ€μκ³Ό κ°μ κ°μ μ¬νμ μ μλ립λλ€:
- μλ¬ νμ μ λͺ νν μ μ
- JSON νμ± λμ νμ κ°λ μ¬μ©
- μλ¬ λ©μμ§ μμν
+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.
| export default async function CrewDetailPage({ params }: CrewDetailPageProps) { | ||
| const id = Number(params.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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'); | |
| } |
| </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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π‘ 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
| 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: [], | ||
| }, | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
ν μ€νΈ μΌμ΄μ€ λ€μνκ° νμν©λλ€.
νμ¬ μ€ν 리λ κΈ°λ³Έ μΌμ΄μ€μ λ―ΈνμΈ μΌμ΄μ€λ§ λ€λ£¨κ³ μμ΅λλ€. λ€μκ³Ό κ°μ μΆκ° μΌμ΄μ€λ€μ κ³ λ €ν΄λ³΄μΈμ:
- μ΅λ μΈμμ΄ μ°¬ κ²½μ°
crewMembersκ° μλ κ²½μ°- κΈ΄ μ λͺ©μ΄λ μμΉ ν μ€νΈμ μ²λ¦¬
- μ΄λ―Έμ§ λ‘λ© μ€ν¨ μν©
μμ μ½λ:
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',
},
],
},
},
};| 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]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
μλ¬ μ²λ¦¬ λ‘μ§ κ°μ νμ
νμ¬ μλ¬ λ©μμ§λ₯Ό νμ±νμ¬ μνλ₯Ό νμΈνκ³ μμΌλ, 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.
| 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]); |
|
πstorybook: https://67206cc6ff9d7a05a3528ff8-yzxwsnplhi.chromatic.com/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
π§Ή 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
π Files selected for processing (1)
.gitignore(1 hunks)
π Additional comments (1)
.gitignore (1)
30-30: Git νμ€ν 리μμ νκ²½ λ³μ νμΌ νμΈμ΄ νμν©λλ€.
μ΄μ μ μ€μλ‘ μ»€λ°λ νκ²½ λ³μ νμΌμ΄ μλμ§ νμΈμ΄ νμν©λλ€.
cb6c122 to
74bc0b1
Compare
π Issue Ticket
#103
βοΈ Description
λν μΌ νμ΄μ§ getμΌλ‘ μμ² λλ λΆλΆ μΆκ°νμ΅λλ€!
νμΌμ΄ λ무 λ§μμ Έμ λ€λ₯Έ μμ²μ λ€λ₯Έ λΈλ μΉμ μΆκ°νκ² μ΅λλ€!
λν μΌ νμ΄μ§ μμ μ¬νμ μ΄μ°¨νΌ λμμΈμ΄ λ°λλ©΄ λ€μ μμ ν΄μΌνκΈ°λλ¬Έμ,,, λμ€μ μμ νκ² μ΅λλ€!
μ΄μ μ€μΌλ‘ μ λ¬νμ§λ§ fetch apiμ baseUrlμ μΆκ°νκ³ , next config rewrite λΆλΆμ μμ νμ΅λλ€!
β Checklist
PR
Test
Summary by CodeRabbit
DetailCrewSectionλ°GatheringListSectionμ»΄ν¬λνΈ μΆκ°λ‘ ν¬λ£¨ λ° λͺ¨μ μΈλΆμ 보 νμ κΈ°λ₯ ν₯μ.useGetCrewDetailQuery,useGetGatheringDetailQuery,useGetGatheringListQueryν μΆκ°λ‘ λ°μ΄ν° ν¨μΉ λ° μΊμ± κ°μν.GatheringCardCarouselλ°GatheringCardμ»΄ν¬λνΈμcrewIdνλ‘νΌν° μΆκ°.