-
Notifications
You must be signed in to change notification settings - Fork 3
DetailPage api 연결 #114
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
DetailPage api 연결 #114
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,14 @@ | ||
| import { fetchApi } from '@/src/utils/api'; | ||
| import { CrewDetail } from '@/src/types/crew-card'; | ||
|
|
||
| export async function getCrewDetail(): Promise<{ data: CrewDetail }> { | ||
| const response = await fetchApi<CrewDetail[]>('/crewDetail', { | ||
| 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; | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,17 @@ | ||||||||||||||||||||||||||||||||||||||||||
| import { fetchApi } from '@/src/utils/api'; | ||||||||||||||||||||||||||||||||||||||||||
| import { GatheringDetailType } from '@/src/types/gathering-data'; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| export async function GetGatheringDetail( | ||||||||||||||||||||||||||||||||||||||||||
| crewId: number, | ||||||||||||||||||||||||||||||||||||||||||
| gatheringId: number, | ||||||||||||||||||||||||||||||||||||||||||
| ): Promise<GatheringDetailType> { | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+4
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
| const url = `/api/crews/${crewId}/gatherings/${gatheringId}`; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const response = await fetchApi<{ data: GatheringDetailType }>(url, { | ||||||||||||||||||||||||||||||||||||||||||
| method: 'GET', | ||||||||||||||||||||||||||||||||||||||||||
| headers: { | ||||||||||||||||||||||||||||||||||||||||||
| 'Content-Type': 'application/json', | ||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+10
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 에러 처리 로직이 필요합니다 API 호출 시 발생할 수 있는 다양한 에러 상황(네트워크 오류, 서버 오류 등)에 대한 처리가 없습니다. 다음과 같은 에러 처리를 추가하는 것을 제안합니다: - const response = await fetchApi<{ data: GatheringDetailType }>(url, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
- });
+ 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
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
| return response.data; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,11 +1,14 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { fetchApi } from '@/src/utils/api'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { GatheringType } from '@/src/types/gathering-data'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function getGatheringList(): Promise<GatheringType[]> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return fetchApi<GatheringType[]>('/gatherings', { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function getGatheringList(id: number): Promise<GatheringType[]> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const url = `/api/crews/${id}/gatherings`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const response = await fetchApi<{ data: GatheringType[] }>(url, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| method: 'GET', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| headers: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Content-Type': 'application/json', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return response.data; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+5
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion API 응답 처리 개선이 필요합니다. API 응답 처리에서 몇 가지 개선이 필요합니다:
다음과 같이 개선하는 것을 제안드립니다: export async function getGatheringList(id: number): Promise<GatheringType[]> {
const url = `/api/crews/${id}/gatherings`;
+ try {
const response = await fetchApi<{ data: GatheringType[] }>(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
+
+ if (!response.data) {
+ throw new Error('데이터가 존재하지 않습니다');
+ }
+
return response.data;
+ } catch (error) {
+ console.error('모임 목록을 가져오는데 실패했습니다:', error);
+ throw error;
+ }
}또한 API 응답의 타입 안전성을 위해 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { useQuery } from '@tanstack/react-query'; | ||
| import { getCrewDetail } from '@/src/_apis/detail/get-crew-detail'; | ||
|
|
||
| export function useGetCrewDetailQuery(id: number) { | ||
| return useQuery({ | ||
| queryKey: ['crewDetail', id], | ||
| queryFn: () => getCrewDetail(id), | ||
| }); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { useQuery } from '@tanstack/react-query'; | ||
| import { GetGatheringDetail } from '@/src/_apis/detail/get-gathering-detail'; | ||
|
|
||
| export function useGetGatheringDetailQuery(crewId: number, gatheringId: number) { | ||
| return useQuery({ | ||
| queryKey: ['gatheringDetail', crewId, gatheringId], | ||
| queryFn: () => GetGatheringDetail(crewId, gatheringId), | ||
| }); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { useQuery } from '@tanstack/react-query'; | ||
| import { getGatheringList } from '@/src/_apis/detail/get-gathering-list'; | ||
| import { GatheringType } from '@/src/types/gathering-data'; | ||
|
|
||
| export function useGetGatheringListQuery(id: number) { | ||
| return useQuery<GatheringType[], Error>({ | ||
| queryKey: ['gatheringList', id], | ||
| queryFn: () => getGatheringList(id), | ||
| enabled: !!id, | ||
| }); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,34 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'use client'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useGetCrewDetailQuery } from '@/src/_queries/detail/crew-detail-queries'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ApiError } from '@/src/utils/api'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import DetailCrewCard from '@/src/components/common/crew-list/detail-crew-card'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface DetailCrewSectionProps { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default function DetailCrewSection({ id }: DetailCrewSectionProps) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { data, isLoading, error } = useGetCrewDetailQuery(id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO: 추후 에러 처리 수정 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isLoading) return <p>Loading...</p>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+17
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 에러 처리 로직 개선 필요 현재 에러 처리 로직이 복잡하고 중첩된 조건문을 사용하고 있어 유지보수가 어려울 수 있습니다. 다음과 같이 에러 처리를 단순화하는 것을 제안합니다: - 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) {
+ const getErrorMessage = () => {
+ if (!(error instanceof ApiError)) {
+ return '데이터 통신에 실패했습니다.';
+ }
+ try {
+ const errorData = JSON.parse(error.message);
+ return errorData.status === 'NOT_FOUND'
+ ? '크루 정보를 찾을 수 없습니다'
+ : `Error ${error.status}: ${error.message}`;
+ } catch {
+ return `Error ${error.status}: ${error.message}`;
+ }
+ };
+ return <p>{getErrorMessage()}</p>;
+ }📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // data가 있을 때만 DetailCrewCard를 렌더링 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return data ? <DetailCrewCard data={data} /> : null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| 'use client'; | ||
|
|
||
| import { useGetGatheringListQuery } from '@/src/_queries/detail/gathering-list-queries'; | ||
| import GatheringCardCarousel from '@/src/components/gathering-list/gathering-card-carousel'; | ||
|
|
||
| interface GatheringListSectionProps { | ||
| id: number; | ||
| } | ||
|
|
||
| export default function GatheringListSection({ id }: GatheringListSectionProps) { | ||
| const { data: gatheringList, isLoading, error } = useGetGatheringListQuery(id); | ||
|
|
||
| if (isLoading) return <p>로딩 중...</p>; | ||
|
|
||
| if (error) return <p>데이터를 불러오는 데 실패했습니다: {error.message}</p>; | ||
|
|
||
| if (!gatheringList || gatheringList.length === 0) return <p>데이터가 없습니다.</p>; | ||
|
|
||
| return <GatheringCardCarousel gatheringData={gatheringList} crewId={id} />; | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,40 +1,42 @@ | ||||||||||||||||
| import { getCrewDetail } from '@/src/_apis/detail/get-crew-detail'; | ||||||||||||||||
| import { getGatheringList } from '@/src/_apis/detail/get-gathering-list'; | ||||||||||||||||
| import DetailCrewCard from '@/src/components/common/crew-list/detail-crew-card'; | ||||||||||||||||
| import GatheringCardCarousel from '@/src/components/gathering-list/gathering-card-carousel'; | ||||||||||||||||
| 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'; | ||||||||||||||||
|
|
||||||||||||||||
| export default async function CrewDetailPage() { | ||||||||||||||||
| const { data: crewDetail } = await getCrewDetail(); | ||||||||||||||||
| const gatheringList = await getGatheringList(); | ||||||||||||||||
| interface CrewDetailPageProps { | ||||||||||||||||
| params: { id: string }; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| export default async function CrewDetailPage({ params }: CrewDetailPageProps) { | ||||||||||||||||
| const id = Number(params.id); | ||||||||||||||||
|
Comment on lines
+11
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. params.id의 타입 변환 처리를 개선해 주세요.
다음과 같이 개선하는 것을 추천드립니다: - const id = Number(params.id);
+ const id = parseInt(params.id, 10);
+ if (isNaN(id)) {
+ throw new Error('Invalid ID format');
+ }📝 Committable suggestion
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
| return ( | ||||||||||||||||
| <div className="mx-auto min-h-screen w-full max-w-full overflow-x-hidden"> | ||||||||||||||||
| <div className="mx-3 my-7 space-y-10 md:mx-7 md:my-11 lg:mx-11 lg:my-16"> | ||||||||||||||||
| <section className="w-full"> | ||||||||||||||||
| <article> | ||||||||||||||||
| {/* //TODO: 추후 confirmed부분 수정 */} | ||||||||||||||||
| <DetailCrewCard isConfirmed={false} {...crewDetail} /> | ||||||||||||||||
| <DetailCrewSection id={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> | ||||||||||||||||
| <section className="w-full"> | ||||||||||||||||
| {/* // TODO: 리뷰 완성되면 수정 */} | ||||||||||||||||
| {/* <section className="w-full"> | ||||||||||||||||
| <article className="space-y-6"> | ||||||||||||||||
| <h2 className="text-2xl font-semibold">크루 리뷰</h2> | ||||||||||||||||
| <CrewReviewSection /> | ||||||||||||||||
| </article> | ||||||||||||||||
| </section> | ||||||||||||||||
| </section> */} | ||||||||||||||||
| </div> | ||||||||||||||||
| </div> | ||||||||||||||||
| ); | ||||||||||||||||
|
|
||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,9 @@ | ||
| // CrewCard 스토리북 파일 | ||
| import type { Meta, StoryObj } from '@storybook/react'; | ||
| import CrewCard from './detail-crew-card'; | ||
| import DetailCrewCard from './detail-crew-card'; | ||
|
|
||
| const meta: Meta = { | ||
| title: 'Components/CrewCardList/CrewCard', | ||
| component: CrewCard, | ||
| title: 'Components/CrewCardList/DetailCrewCard', | ||
| component: DetailCrewCard, | ||
| parameters: { | ||
| layout: 'centered', | ||
| nextjs: { | ||
|
|
@@ -13,50 +12,67 @@ const meta: Meta = { | |
| }, | ||
| tags: ['autodocs'], | ||
| args: { | ||
| id: 0, | ||
| title: '같이 물장구칠사람', | ||
| mainLocation: '대전광역시', | ||
| subLocation: '유성구', | ||
| imageUrl: 'https://i.pinimg.com/564x/f8/8d/c5/f88dc5b857caf6c303ae5ef9dd12e7fb.jpg', | ||
| totalGatheringCount: 5, // 기본 값 추가 | ||
| crewMembers: [ | ||
| { | ||
| id: 1, | ||
| nickname: 'John', | ||
| profileImageUrl: 'https://i.pinimg.com/564x/e2/25/bb/e225bb492dc7a20a549f3c0abec28eb8.jpg', | ||
| }, | ||
| { | ||
| id: 2, | ||
| nickname: 'Jane', | ||
| profileImageUrl: 'https://i.pinimg.com/564x/e2/25/bb/e225bb492dc7a20a549f3c0abec28eb8.jpg', | ||
| }, | ||
| ], // 기본 프로필 리스트 추가 | ||
| data: { | ||
| id: 1, | ||
| title: '같이 물장구칠사람', | ||
| mainLocation: '대전광역시', | ||
| subLocation: '유성구', | ||
| participantCount: 10, | ||
| totalCount: 20, | ||
| confirmed: true, | ||
| imageUrl: 'https://i.pinimg.com/564x/f8/8d/c5/f88dc5b857caf6c303ae5ef9dd12e7fb.jpg', | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 이미지 URL을 상수로 분리하세요 하드코딩된 이미지 URL들이 여러 곳에서 반복되고 있습니다. 이는 유지보수를 어렵게 만들 수 있습니다. 스토리북 설정 파일에 상수로 분리하는 것을 제안합니다: const MOCK_IMAGES = {
CREW_DEFAULT: 'https://i.pinimg.com/564x/f8/8d/c5/f88dc5b857caf6c303ae5ef9dd12e7fb.jpg',
PROFILE_DEFAULT: 'https://i.pinimg.com/564x/e2/25/bb/e225bb492dc7a20a549f3c0abec28eb8.jpg'
} as const;Also applies to: 29-30, 35-36, 56-56, 73-73 |
||
| totalGatheringCount: 5, | ||
| crewMembers: [ | ||
| { | ||
| id: 1, | ||
| nickname: 'John', | ||
| profileImageUrl: | ||
| 'https://i.pinimg.com/564x/e2/25/bb/e225bb492dc7a20a549f3c0abec28eb8.jpg', | ||
| }, | ||
| { | ||
| id: 2, | ||
| nickname: 'Jane', | ||
| profileImageUrl: | ||
| 'https://i.pinimg.com/564x/e2/25/bb/e225bb492dc7a20a549f3c0abec28eb8.jpg', | ||
| }, | ||
| ], | ||
| }, | ||
| }, | ||
| } satisfies Meta<typeof CrewCard>; | ||
| } satisfies Meta<typeof DetailCrewCard>; | ||
|
|
||
| export default meta; | ||
| type Story = StoryObj<typeof meta>; | ||
|
|
||
| export const Default: Story = { | ||
| 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
에러 처리 로직 추가 검토 필요
API 호출 실패 시의 에러 처리가 명시적으로 구현되어 있지 않습니다. 사용자 경험 향상을 위해 에러 처리 로직 추가를 고려해 주세요.
다음과 같은 구현을 제안드립니다:
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 response.data; + try { + const response = await fetchApi<{ data: CrewDetail }>(url, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); + return response.data; + } catch (error) { + console.error('크루 상세 정보를 가져오는데 실패했습니다:', error); + throw new Error('크루 상세 정보를 불러올 수 없습니다.'); + } }📝 Committable suggestion