Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions src/_apis/crew/crew-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,24 @@ export async function getCrewList(condition: ConditionTypes, pageable: PageableT
const { keyword, mainLocation, mainCategory, subCategory, sortType } = condition;
const { page, size, sort = ['string'] } = pageable;

const response: { data: MainCrewListResponse } = await fetchApi(
`/api/crews/search?keyword=${keyword}&mainLocation=${mainLocation}&mainCategory=${mainCategory}&subCategory=${subCategory}&sortType=${sortType}&page=${page}&size=${size}&sort=${sort}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
try {
const response: { data: MainCrewListResponse } = await fetchApi(
`/api/crews/search?keyword=${keyword}&mainLocation=${mainLocation}&mainCategory=${mainCategory}&subCategory=${subCategory}&sortType=${sortType}&page=${page}&size=${size}&sort=${sort}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // 인증 정보를 요청에 포함
},
credentials: 'include', // 인증 정보를 요청에 포함
},
);

return response?.data;
);
if (!response.data) {
throw new Error('Failed to get crew list: No data received');
}
return response.data;
} catch (error) {
// eslint-disable-next-line no-console
console.error(`크루 목록 조회 실패`);
return null;
}
}
27 changes: 27 additions & 0 deletions src/_apis/crew/my-crew-hosted-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { fetchApi } from '@/src/utils/api';
import { MyCrewListResponse, PageableTypes } from '@/src/types/crew-card';

export async function getMyCrewHostedList(pageable: PageableTypes) {
const { page, size, sort = ['string'] } = pageable;

try {
const response: { data: MyCrewListResponse } = await fetchApi(
`/api/crews/hosted?page=${page}&size=${size}&sort=${sort}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // 인증 정보를 요청에 포함
},
);
if (!response.data) {
throw new Error('Failed to get my crew hosted list');
}
return response.data;
} catch (error) {
// eslint-disable-next-line no-console
console.error(`내가 개설한 크루 목록 조회 실패`);
return null;
}
}
27 changes: 27 additions & 0 deletions src/_apis/crew/my-crew-joined-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { fetchApi } from '@/src/utils/api';
import { MyCrewListResponse, PageableTypes } from '@/src/types/crew-card';

export async function getMyCrewJoinedList(pageable: PageableTypes) {
const { page, size, sort = ['string'] } = pageable;

try {
const response: { data: MyCrewListResponse } = await fetchApi(
`/api/crews/joined?page=${page}&size=${size}&sort=${sort}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // 인증 정보를 요청에 포함
},
);
if (!response.data) {
throw new Error('Failed to get my crew joined list');
}
return response.data;
} catch (error) {
// eslint-disable-next-line no-console
console.error(`내가 가입한 크루 목록 조회 실패`);
return null;
}
}
29 changes: 19 additions & 10 deletions src/_queries/crew/crew-list-queries.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { getCrewList } from '@/src/_apis/crew/crew-list';
import { ConditionTypes, MainCrewListResponse, PageableTypes } from '@/src/types/crew-card';
import { getCrewList } from '../../_apis/crew/crew-list';

export function useGetCrewListQuery(condition: ConditionTypes) {
export function useGetCrewListQuery({
condition,
pageable,
}: {
condition: ConditionTypes;
pageable: PageableTypes;
}) {
const { size, sort = ['string'] } = pageable;
return {
queryKey: [
condition.keyword,
Expand All @@ -11,14 +18,16 @@ export function useGetCrewListQuery(condition: ConditionTypes) {
condition.sortType,
],
queryFn: ({ pageParam = 0 }) =>
getCrewList(condition, { page: pageParam, size: 6, sort: [condition.sortType] }).then(
(response) => {
if (response === undefined) {
throw new Error('Response is null');
}
return response;
},
),
getCrewList(condition, {
page: pageParam,
size,
sort,
}).then((response) => {
if (response === undefined || response === null) {
throw new Error('Response is undefined');
}
return response;
}),
getNextPageParam: (lastPage: MainCrewListResponse, allPages: MainCrewListResponse[]) =>
lastPage.hasNext ? allPages.length : undefined,
};
Expand Down
18 changes: 18 additions & 0 deletions src/_queries/crew/my-crew-hosted-list-query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getMyCrewHostedList } from '@/src/_apis/crew/my-crew-hosted-list';
import { MyCrewListResponse, PageableTypes } from '@/src/types/crew-card';

export function useGetMyCrewHostedQuery({ pageable }: { pageable: PageableTypes }) {
const { size, sort = ['string'] } = pageable;
return {
queryKey: ['myCrewHosted'],
queryFn: ({ pageParam = 0 }) =>
getMyCrewHostedList({ page: pageParam, size, sort }).then((response) => {
if (response === undefined || response === null) {
throw new Error('크루 목록을 불러오는데 실패했습니다.');
}
return response;
}),
getNextPageParam: (lastPage: MyCrewListResponse, allPages: MyCrewListResponse[]) =>
lastPage.hasNext ? allPages.length : undefined,
};
}
18 changes: 18 additions & 0 deletions src/_queries/crew/my-crew-joined-list-query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getMyCrewJoinedList } from '@/src/_apis/crew/my-crew-joined-list';
import { MyCrewListResponse, PageableTypes } from '@/src/types/crew-card';

export function useGetMyCrewJoinedQuery({ pageable }: { pageable: PageableTypes }) {
const { size, sort = ['string'] } = pageable;
return {
Comment on lines +4 to +6
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

정렬 파라미터를 더 유연하게 설정하세요.

현재 정렬 파라미터가 ['string']으로 고정되어 있어 유연성이 떨어집니다. 이를 외부에서 입력받을 수 있도록 변경하는 것이 좋겠습니다. 예를 들어, 기본값을 ['createdAt,desc']로 설정하고, 필요에 따라 변경할 수 있도록 합니다.

queryKey: ['myCrewJoined'],
queryFn: ({ pageParam = 0 }) =>
getMyCrewJoinedList({ page: pageParam, size, sort }).then((response) => {
if (response === undefined || response === null) {
throw new Error('크루 목록을 불러오는데 실패했습니다.');
}
return response;
}),
getNextPageParam: (lastPage: MyCrewListResponse, allPages: MyCrewListResponse[]) =>
lastPage.hasNext ? allPages.length : undefined,
};
}
31 changes: 31 additions & 0 deletions src/app/(crew)/my-crew/hosted/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use client';

import { Loader } from '@mantine/core';
import { useGetMyCrewHostedQuery } from '@/src/_queries/crew/my-crew-hosted-list-query';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
import CrewCardList from '@/src/components/common/crew-list/crew-card-list';

export default function MyCrewHostedPage() {
const { data, status, ref, isFetchingNextPage } = useInfiniteScroll(
useGetMyCrewHostedQuery({
pageable: { page: 0, size: 6, sort: ['createdAt,desc'] },
}),
);
return (
<div>
<CrewCardList
inWhere="my-crew"
data={data ?? { pages: [], pageParams: [] }}
isFetchingNextPage={isFetchingNextPage}
/>
{status === 'pending' ? (
<div className="flex justify-center py-10">
<Loader size="sm" />
</div>
) : (
<div ref={ref} className="h-[1px]" />
)}
{status === 'error' && <p className="py-10 text-center">에러가 발생했습니다.</p>}
</div>
);
}
31 changes: 31 additions & 0 deletions src/app/(crew)/my-crew/joined/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use client';

import { Loader } from '@mantine/core';
import { useGetMyCrewJoinedQuery } from '@/src/_queries/crew/my-crew-joined-list-query';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
import CrewCardList from '@/src/components/common/crew-list/crew-card-list';

export default function MyCrewJoinedPage() {
const { data, status, ref, isFetchingNextPage } = useInfiniteScroll(
useGetMyCrewJoinedQuery({
pageable: { page: 0, size: 6, sort: ['createdAt,desc'] },
}),
);
return (
<div>
<CrewCardList
inWhere="my-crew"
data={data ?? { pages: [], pageParams: [] }}
isFetchingNextPage={isFetchingNextPage}
/>
{status === 'pending' ? (
<div className="flex justify-center py-10">
<Loader size="sm" />
</div>
) : (
<div ref={ref} className="h-[1px]" />
)}
{status === 'error' && <p className="py-10 text-center">에러가 발생했습니다.</p>}
</div>
);
}
41 changes: 41 additions & 0 deletions src/app/(crew)/my-crew/layout.tsx
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/joined' },
{ label: '내가 만든 크루', id: 'hosted-crew', route: '/my-crew/hosted' },
];
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
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

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

targetRoute가 없는 경우에 대한 처리가 누락되어 있습니다. 사용자에게 적절한 피드백을 제공하는 것이 좋습니다.

다음과 같이 수정해보세요:

 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: 사용자에게 에러 메시지 표시
+  }
 };

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


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>
);
}
37 changes: 2 additions & 35 deletions src/app/(crew)/my-crew/page.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,7 @@
'use client';

import { useState } from 'react';
import Tabs from '@/src/components/common/tab';
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/joined');
}
26 changes: 18 additions & 8 deletions src/app/(crew)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@

import { useRef, useState } from 'react';
import Image from 'next/image';
import { Divider, TextInput } from '@mantine/core';
import { Divider, Loader, TextInput } from '@mantine/core';
import { useGetCrewListQuery } from '@/src/_queries/crew/crew-list-queries';
import regionData from '@/src/data/region.json';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
import CategoryContainer from '@/src/app/_components/category/category-container';
import HeroCrew from '@/src/app/_components/hero/hero-crew';
import CrewCardList from '@/src/components/common/crew-list/crew-card-list';
import DropDown from '@/src/components/common/input/drop-down';
import { MainCrewListResponse } from '@/src/types/crew-card';
import IcoSearch from '@/public/assets/icons/ic-search.svg';

export default function HomePage() {
Expand All @@ -35,13 +34,16 @@ export default function HomePage() {
}
};

const { data, ref, isFetchingNextPage } = useInfiniteScroll(
const { data, status, isFetchingNextPage, ref } = useInfiniteScroll(
useGetCrewListQuery({
keyword: search,
mainLocation: handleRegionChange(region),
mainCategory,
subCategory,
sortType: sort === 'latest' ? 'LATEST' : 'POPULAR',
condition: {
keyword: search,
mainLocation: handleRegionChange(region),
mainCategory,
subCategory,
sortType: sort === 'latest' ? 'LATEST' : 'POPULAR',
},
pageable: { page: 0, size: 6, sort: ['createdAt,desc'] },
}),
);

Expand Down Expand Up @@ -124,6 +126,14 @@ export default function HomePage() {
</div>
<div className="mt-8 px-3 md:px-8 lg:px-11.5">
{data && <CrewCardList data={data} ref={ref} isFetchingNextPage={isFetchingNextPage} />}
{status === 'pending' ? (
<div className="flex justify-center py-10">
<Loader size="sm" />
</div>
) : (
<div ref={ref} className="h-[1px]" />
)}
{status === 'error' && <p className="py-10 text-center">에러가 발생했습니다.</p>}
</div>
</div>
);
Expand Down
1 change: 0 additions & 1 deletion src/app/_components/hero/hero-crew.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Image from 'next/image';
import Link from 'next/link';
import { useAuthStore } from '@/src/store/use-auth-store';
import Button from '@/src/components/common/input/button';
import ImgHeroCrew from '@/public/assets/icons/ic-dumbbell.svg';

export default function HeroCrew() {
Expand Down
Loading