-
Notifications
You must be signed in to change notification settings - Fork 3
Feat/105/my crew api 연결 #109
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
Changes from 4 commits
2c8278b
aea88e1
91b6927
013b2de
58be236
5faea7f
26d1701
f5472c7
ff655e2
a5fbad9
e466861
9ad835f
ad03a87
4d4dcd9
e946b5e
fd76ffb
bdb86e1
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 | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,24 @@ | ||||||||||||||||||||
| import { fetchApi } from '@/src/utils/api'; | ||||||||||||||||||||
| import { MyCrewListResponse, PageableTypes } from '@/src/types/crew-card'; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| export async function getMyCrewCreationList(pageable: PageableTypes) { | ||||||||||||||||||||
| const { page, size, sort = ['string'] } = pageable; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| try { | ||||||||||||||||||||
| const response = await fetchApi<MyCrewListResponse>( | ||||||||||||||||||||
| `/api/crews/hosted?page=${page}&size=${size}&sort=${sort}`, | ||||||||||||||||||||
| { | ||||||||||||||||||||
|
||||||||||||||||||||
| method: 'GET', | ||||||||||||||||||||
| headers: { | ||||||||||||||||||||
| 'Content-Type': 'application/json', | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| credentials: 'include', // 인증 정보를 요청에 포함 | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| ); | ||||||||||||||||||||
| return response; | ||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||
| // eslint-disable-next-line no-console | ||||||||||||||||||||
| console.error(error); | ||||||||||||||||||||
| return undefined; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
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 에러 처리 로직을 개선해주세요. 현재 에러 처리에 몇 가지 개선이 필요해 보입니다:
다음과 같은 개선된 구현을 제안드립니다: - } catch (error) {
- // eslint-disable-next-line no-console
- console.error(error);
- return undefined;
+ } catch (error: unknown) {
+ const errorMessage = error instanceof Error ? error.message : '크루 목록을 불러오는 중 오류가 발생했습니다';
+ throw new Error(errorMessage);
}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||
| } | ||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,24 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { fetchApi } from '@/src/utils/api'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { MyCrewListResponse, PageableTypes } from '@/src/types/crew-card'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function getMyCrewParticipationList(pageable: PageableTypes) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { page, size, sort = ['string'] } = pageable; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function getMyCrewParticipationList(pageable: PageableTypes) { | |
| const { page, size, sort = ['string'] } = pageable; | |
| export async function getMyCrewParticipationList(pageable: PageableTypes) { | |
| const { page, size, sort = ['createdAt,desc'] } = pageable; |
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
에러 처리 개선이 필요합니다.
현재 구현은 모든 에러를 콘솔에 출력하고 undefined를 반환하고 있습니다. 이는 다음과 같은 문제가 있습니다:
- 에러 타입에 따른 구체적인 처리가 없습니다
- 사용자에게 적절한 에러 메시지를 전달할 수 없습니다
다음과 같이 개선을 제안드립니다:
try {
const response = await fetchApi<MyCrewListResponse>(
`/api/crews/joined?page=${page}&size=${size}&sort=${sort}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
},
);
return response;
} catch (error) {
- // eslint-disable-next-line no-console
- console.error(error);
- return undefined;
+ 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.
| try { | |
| const response = await fetchApi<MyCrewListResponse>( | |
| `/api/crews/joined?page=${page}&size=${size}&sort=${sort}`, | |
| { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| credentials: 'include', // 인증 정보를 요청에 포함 | |
| }, | |
| ); | |
| return response; | |
| } catch (error) { | |
| try { | |
| const response = await fetchApi<MyCrewListResponse>( | |
| `/api/crews/joined?page=${page}&size=${size}&sort=${sort}`, | |
| { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| credentials: 'include', | |
| }, | |
| ); | |
| return response; | |
| } catch (error) { | |
| if (error instanceof Error) { | |
| throw new Error(`크루 참여 목록을 가져오는데 실패했습니다: ${error.message}`); | |
| } | |
| throw new Error('알 수 없는 에러가 발생했습니다'); | |
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,17 @@ | ||||||
| import { getMyCrewCreationList } from '@/src/_apis/crew/my-crew-creation-list'; | ||||||
| import { MyCrewListResponse } from '@/src/types/crew-card'; | ||||||
|
|
||||||
| export function useGetMyCrewCreationQuery() { | ||||||
| return { | ||||||
| queryKey: ['my-crew-creation'], | ||||||
| queryFn: ({ pageParam = 0 }) => | ||||||
| getMyCrewCreationList({ page: pageParam, size: 6, sort: ['string'] }).then((response) => { | ||||||
|
||||||
| getMyCrewCreationList({ page: pageParam, size: 6, sort: ['string'] }).then((response) => { | |
| getMyCrewCreationList({ page: pageParam, size: 6, sort: ['createdAt,DESC'] }).then((response) => { |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { getMyCrewParticipationList } from '@/src/_apis/crew/my-crew-participation-list'; | ||
| import { MyCrewListResponse } from '@/src/types/crew-card'; | ||
|
|
||
| export function useGetMyCrewParticipationQuery() { | ||
| return { | ||
| queryKey: ['my-crew-participation'], | ||
| queryFn: ({ pageParam = 0 }) => | ||
| getMyCrewParticipationList({ page: pageParam, size: 6, sort: ['string'] }).then( | ||
| (response) => { | ||
| if (response === undefined) { | ||
| throw new Error('Response is undefined'); | ||
| } | ||
| return response; | ||
| }, | ||
| ), | ||
| getNextPageParam: (lastPage: MyCrewListResponse, allPages: MyCrewListResponse[]) => | ||
| lastPage.hasNext ? allPages.length : undefined, | ||
| }; | ||
| } | ||
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,19 @@ | ||||||
| 'use client'; | ||||||
|
|
||||||
| import { useGetMyCrewCreationQuery } from '@/src/_queries/crew/my-crew-creation-list-query'; | ||||||
| import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll'; | ||||||
| import CrewCardList from '@/src/components/common/crew-list/crew-card-list'; | ||||||
|
|
||||||
| export default function MyCrewParticipationPage() { | ||||||
|
||||||
| export default function MyCrewParticipationPage() { | |
| export default function MyCrewCreationPage() { |
Outdated
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
에러 처리와 로딩 상태 관리가 필요합니다.
다음 개선사항들을 고려해주세요:
- 쿼리 실패 시 에러 처리
- 초기 로딩 상태 처리
- 데이터 타입 안전성 강화
다음과 같이 수정하는 것을 제안드립니다:
export default function MyCrewParticipationPage() {
- const { data, ref, isFetchingNextPage } = useInfiniteScroll(useGetMyCrewCreationQuery());
+ const { data, ref, isFetchingNextPage, isError, error, isLoading } = useInfiniteScroll(useGetMyCrewCreationQuery());
+
+ if (isError) {
+ return <div>에러가 발생했습니다: {error.message}</div>;
+ }
+
+ if (isLoading) {
+ return <div>로딩 중...</div>;
+ }
return (
<div>
<CrewCardList
inWhere="my-crew"
data={data ?? { pages: [], pageParams: [] }}
ref={ref}
isFetchingNextPage={isFetchingNextPage}
/>
</div>
);
}Committable suggestion skipped: line range outside the PR's diff.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| 'use client'; | ||
|
|
||
| import { ReactNode, useEffect, useState } from 'react'; | ||
| import { usePathname, useRouter } from 'next/navigation'; | ||
| import Tabs from '@/src/components/common/tab'; | ||
|
|
||
| export default function MyCrewLayout({ children }: { children: ReactNode }) { | ||
| const router = useRouter(); | ||
| const currentPath = usePathname(); | ||
| const myCrewTabs = [ | ||
| { label: '내가 참여한 크루', id: 'joined-crew', route: '/my-crew/participation' }, | ||
| { label: '내가 만든 크루', id: 'made-crew', route: '/my-crew/creation' }, | ||
| ]; | ||
| const [currentTab, setCurrentTab] = useState(myCrewTabs[0].id); | ||
|
|
||
| const handleTabClick = (id: string) => { | ||
| const targetRoute = myCrewTabs.find((tab) => tab.id === id)?.route; | ||
| if (targetRoute) router.push(targetRoute); | ||
| }; | ||
|
Comment on lines
+16
to
+19
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 에러 처리 개선이 필요합니다
다음과 같이 수정해보세요: const handleTabClick = (id: string) => {
const targetRoute = myCrewTabs.find((tab) => tab.id === id)?.route;
- if (targetRoute) router.push(targetRoute);
+ if (targetRoute) {
+ router.push(targetRoute);
+ } else {
+ console.error(`탭 ID ${id}에 해당하는 경로를 찾을 수 없습니다.`);
+ // TODO: 사용자에게 에러 메시지 표시
+ }
};
|
||
|
|
||
| useEffect(() => { | ||
| const activeTabId = myCrewTabs.find((tab) => tab.route === currentPath)?.id; | ||
| if (activeTabId) setCurrentTab(activeTabId); | ||
| }, [currentPath]); | ||
|
|
||
| return ( | ||
| <div className="py-8 md:py-12.5"> | ||
| <div className="px-3 md:px-8 lg:px-11.5"> | ||
| <Tabs | ||
| variant="default" | ||
| tabs={myCrewTabs} | ||
| activeTab={currentTab} | ||
| onTabClick={(id) => { | ||
| handleTabClick(id); | ||
| }} | ||
| /> | ||
| </div> | ||
| <div className="mt-8 px-3 md:px-8 lg:px-11.5">{children}</div> | ||
| </div> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,44 +1,5 @@ | ||
| 'use client'; | ||
|
|
||
| import { useState } from 'react'; | ||
| import { useGetCrewListQuery } from '@/src/_queries/crew-queries'; | ||
| import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll'; | ||
| import CrewCardList from '@/src/components/common/crew-list/crew-card-list'; | ||
| import Tabs from '@/src/components/common/tab'; | ||
| import { MyCrewListResponse } from '@/src/types/crew-card'; | ||
| import { redirect } from 'next/navigation'; | ||
|
|
||
| export default function MyCrewPage() { | ||
| const myPageTabs = [ | ||
| { label: '내가 참여한 크루', id: 'joined-crew' }, | ||
| { label: '내가 만든 크루', id: 'made-crew' }, | ||
| ]; | ||
| const [currentTab, setCurrentTab] = useState(myPageTabs[0].id); | ||
|
|
||
| // TODO: fetchCrewData 함수를 사용하여 데이터를 불러오기 : 파라미터 수정 필요 | ||
| // TODO: 리스트와는 다른 데이터를 사용해야해서 우선 주석처리 했습니다. | ||
| // const { data, ref, isFetchingNextPage } = | ||
| // useInfiniteScroll<MyCrewListResponse>(useGetCrewListQuery()); | ||
|
|
||
| return ( | ||
| <div className="py-8 md:py-12.5"> | ||
| <div className="px-3 md:px-8 lg:px-11.5"> | ||
| <Tabs | ||
| variant="default" | ||
| tabs={myPageTabs} | ||
| activeTab={currentTab} | ||
| onTabClick={(id) => { | ||
| setCurrentTab(id); | ||
| }} | ||
| /> | ||
| </div> | ||
| <div className="mt-8 px-3 md:px-8 lg:px-11.5"> | ||
| {/* <CrewCardList | ||
| inWhere="my-crew" | ||
| data={data} | ||
| ref={ref} | ||
| isFetchingNextPage={isFetchingNextPage} | ||
| /> */} | ||
| </div> | ||
| </div> | ||
| ); | ||
| redirect('/my-crew/participation'); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| 'use client'; | ||
|
|
||
| import { useGetMyCrewParticipationQuery } from '@/src/_queries/crew/my-crew-participation-list-query'; | ||
| import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll'; | ||
| import CrewCardList from '@/src/components/common/crew-list/crew-card-list'; | ||
|
|
||
| export default function MyCrewParticipationPage() { | ||
| const { data, ref, isFetchingNextPage } = useInfiniteScroll(useGetMyCrewParticipationQuery()); | ||
| return ( | ||
| <div> | ||
| <CrewCardList | ||
| inWhere="my-crew" | ||
| data={data ?? { pages: [], pageParams: [] }} | ||
| ref={ref} | ||
| isFetchingNextPage={isFetchingNextPage} | ||
| /> | ||
| </div> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,29 +10,21 @@ import { | |||||||||||||||||||||||||||
| import CrewCard from './crew-card'; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // CrewCardListProps 타입을 구분하여 정의 | ||||||||||||||||||||||||||||
| interface MainCrewCardListProps { | ||||||||||||||||||||||||||||
| data: InfiniteData<MainCrewListResponse | undefined>; | ||||||||||||||||||||||||||||
| interface CrewCardListProps { | ||||||||||||||||||||||||||||
| data: InfiniteData<MainCrewListResponse | MyCrewListResponse | undefined>; | ||||||||||||||||||||||||||||
| isFetchingNextPage: boolean; | ||||||||||||||||||||||||||||
| inWhere?: undefined; | ||||||||||||||||||||||||||||
| inWhere?: 'my-crew' | 'main-crew'; | ||||||||||||||||||||||||||||
|
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. 타입 안전성 개선이 필요합니다.
다음과 같이 수정하는 것을 제안드립니다: interface CrewCardListProps {
data: InfiniteData<MainCrewListResponse | MyCrewListResponse | undefined>;
isFetchingNextPage: boolean;
- inWhere?: 'my-crew' | 'main-crew';
+ inWhere: 'my-crew' | 'main-crew' | undefined;
}
|
||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| interface MyCrewCardListProps { | ||||||||||||||||||||||||||||
| data: InfiniteData<MyCrewListResponse>; | ||||||||||||||||||||||||||||
| isFetchingNextPage: boolean; | ||||||||||||||||||||||||||||
| inWhere: 'my-crew'; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // 유니온 타입으로 정의 | ||||||||||||||||||||||||||||
| type CrewCardListProps = MainCrewCardListProps | MyCrewCardListProps; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| function CrewCardList( | ||||||||||||||||||||||||||||
| { data, isFetchingNextPage, inWhere }: CrewCardListProps, | ||||||||||||||||||||||||||||
| ref: React.Ref<HTMLDivElement>, | ||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||
| const crewDataList = | ||||||||||||||||||||||||||||
| (inWhere === 'my-crew' | ||||||||||||||||||||||||||||
| ? data?.pages.flatMap((page) => page?.data as MyCrewList[]) | ||||||||||||||||||||||||||||
| ? data?.pages.flatMap((page) => page?.content as MyCrewList[]) | ||||||||||||||||||||||||||||
| : data?.pages?.flatMap((page) => page?.content as MainCrewList[])) ?? []; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
| ? data?.pages.flatMap((page) => page?.content as MyCrewList[]) | |
| : data?.pages?.flatMap((page) => page?.content as MainCrewList[])) ?? []; | |
| (inWhere === 'my-crew' | |
| ? data?.pages.flatMap((page) => | |
| Array.isArray(page?.content) && page.content.every(item => 'currentCount' in item) | |
| ? page.content | |
| : [] | |
| ) | |
| : data?.pages?.flatMap((page) => | |
| Array.isArray(page?.content) && page.content.every(item => 'isConfirmed' in item) | |
| ? page.content | |
| : [] | |
| )) ?? []; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,6 @@ export interface ConditionTypes { | |
| subCategory: string; | ||
| sortType: 'LATEST' | 'POPULAR'; | ||
| } | ||
|
|
||
| export interface PageableTypes { | ||
| page: number; | ||
| size: number; | ||
|
|
@@ -65,6 +64,6 @@ export interface MyCrewList { | |
| } | ||
|
|
||
| export interface MyCrewListResponse { | ||
| data: MyCrewList[]; | ||
| content: MyCrewList[] | undefined; | ||
|
||
| hasNext: boolean; | ||
| } | ||
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
정렬 기본값 수정이 필요합니다
코드베이스 분석 결과, 다음과 같은 문제점들이 확인되었습니다:
['string']이라는 기본값이 여러 crew API 호출에서 동일하게 사용되고 있습니다find-crew컴포넌트에서는'latest'를 기본 정렬값으로 사용하고 있습니다ConditionTypes에서는sortType이'LATEST' | 'POPULAR'타입으로 정의되어 있습니다개선 제안:
sort기본값을['createdAt,desc']와 같이 의미 있는 값으로 변경PageableTypes인터페이스의sort타입을 더 구체적으로 정의하여 유효한 정렬 옵션만 허용하도록 수정🔗 Analysis chain
sort 매개변수의 기본값을 검토해주세요.
sort의 기본값으로 설정된['string']이 의미 있는 정렬 기준으로 보이지 않습니다. 다음과 같은 개선을 제안드립니다:🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
Length of output: 41
Script:
Length of output: 1081
Script:
Length of output: 4722