From 8e8d23a05a1b25ff4717613d5044e1d1e00ef170 Mon Sep 17 00:00:00 2001 From: csk6314 <37896060+csk6314@users.noreply.github.com> Date: Tue, 10 Dec 2024 04:23:33 +0900 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=EB=AC=B4=ED=95=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A1=A4=20=ED=9B=85=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EC=85=98=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=ED=95=98=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/hook/useCustomInfiniteQuery.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/shared/hook/useCustomInfiniteQuery.ts b/src/shared/hook/useCustomInfiniteQuery.ts index 51b847e..8774b47 100644 --- a/src/shared/hook/useCustomInfiniteQuery.ts +++ b/src/shared/hook/useCustomInfiniteQuery.ts @@ -1,3 +1,4 @@ +import type { GetNextPageParamFunction } from '@tanstack/react-query'; import { useInfiniteQuery } from '@tanstack/react-query'; import throttle from 'lodash-es/throttle'; import { useMemo, useEffect } from 'react'; @@ -12,8 +13,8 @@ export const useCustomInfiniteQuery = < >( queryKey: (string | number)[], queryFn: (context: { pageParam: number }) => Promise, - pageSize: number, dataKey: string, + getNextPageParam: GetNextPageParamFunction, enabled: boolean = false, staleTime: number = 0, ) => { @@ -21,13 +22,7 @@ export const useCustomInfiniteQuery = < useInfiniteQuery({ queryKey, queryFn: ({ pageParam = 0 }) => queryFn({ pageParam: pageParam as number }), - getNextPageParam: (lastPage, allPages) => { - if (Array.isArray(lastPage.data[dataKey][dataKey])) { - const isLastPage = lastPage.data[dataKey][dataKey]?.length < pageSize; - return isLastPage ? null : allPages.length; - } - return null; - }, + getNextPageParam, initialPageParam: 0, enabled: enabled, staleTime, From a7237ab496e4ad1fc259fc43cf076ffc59043915 Mon Sep 17 00:00:00 2001 From: csk6314 <37896060+csk6314@users.noreply.github.com> Date: Tue, 10 Dec 2024 04:23:57 +0900 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=EC=9C=A0=EC=A0=80=20=EC=95=84?= =?UTF-8?q?=EC=B9=B4=EC=9D=B4=EB=B8=8C=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/archive/archive.api.ts | 5 ++-- src/features/archive/archive.dto.ts | 5 ++++ src/features/archive/archive.hook.ts | 42 ++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/features/archive/archive.api.ts b/src/features/archive/archive.api.ts index a3458dd..125d793 100644 --- a/src/features/archive/archive.api.ts +++ b/src/features/archive/archive.api.ts @@ -1,5 +1,6 @@ import type { getArchiveColorApiResponse, + GetArchiveUserListApiResponse, PatchArchiveOrderDTO, PostCommentApiResponse, } from './archive.dto'; @@ -85,10 +86,10 @@ export const getPopularArchive = () => export const getUserArchiveList = (userId: number, page: number) => api - .get(`/user/${userId}/archives`, { + .get(`/user/${userId}/archives`, { params: { size: 8, - page, + nextArchiveId: page ? page : undefined, }, }) .then(res => res.data); diff --git a/src/features/archive/archive.dto.ts b/src/features/archive/archive.dto.ts index 307e327..df85b6d 100644 --- a/src/features/archive/archive.dto.ts +++ b/src/features/archive/archive.dto.ts @@ -98,4 +98,9 @@ export type GetArchiveListApiResponse = ApiResponse<{ archives: ArchiveCardDTO[]; slice: Meta; }>; +export type GetArchiveUserListApiResponse = ApiResponse<{ + archives: ArchiveCardDTO[]; + hasNext: boolean; + nextArchiveId: number | null; +}>; export type getArchiveColorApiResponse = ApiResponse; diff --git a/src/features/archive/archive.hook.ts b/src/features/archive/archive.hook.ts index 47896b5..11db19d 100644 --- a/src/features/archive/archive.hook.ts +++ b/src/features/archive/archive.hook.ts @@ -29,6 +29,7 @@ import type { PatchArchiveOrderDTO, CommentsPageDTO, ArchivePageDTO, + GetArchiveUserListApiResponse, } from './archive.dto'; import type { Color } from './colors.type'; @@ -74,8 +75,14 @@ export const useComments = (archiveId: number) => { return useCustomInfiniteQuery( ['/archive', archiveId, 'comment'], ({ pageParam }) => getComments(archiveId, 10, pageParam), - 10, 'comments', + (lastPage, allPages) => { + if (Array.isArray(lastPage.data)) { + const isLastPage = lastPage.data.length < 9; + return isLastPage ? null : allPages.length; + } + return null; + }, ); }; @@ -269,8 +276,14 @@ export const useArchiveList = (sort: string, color: Color) => { return useCustomInfiniteQuery( ['/archive', 'list', sort, color], ({ pageParam }) => getArchiveList(sort, pageParam, color === 'DEFAULT' ? null : color), - 9, 'archives', + (lastPage, allPages) => { + if (Array.isArray(lastPage.data!['archives'])) { + const isLastPage = lastPage.data!['archives']?.length < 9; + return isLastPage ? null : allPages.length; + } + return null; + }, true, ); }; @@ -279,8 +292,14 @@ export const useSearchArchive = (searchKeyword: string) => { return useCustomInfiniteQuery( ['/archive', 'list', 'search', searchKeyword], ({ pageParam }) => getSearchArchive(searchKeyword, pageParam), - 9, 'archives', + (lastPage, allPages) => { + if (Array.isArray(lastPage.data!['archives'])) { + const isLastPage = lastPage.data!['archives']?.length < 9; + return isLastPage ? null : allPages.length; + } + return null; + }, true, ); }; @@ -289,8 +308,14 @@ export const useLikeArchiveList = () => { return useCustomInfiniteQuery( ['/user', 'list', 'me', 'like'], ({ pageParam }) => getLikeArchiveList(pageParam), - 9, 'archives', + (lastPage, allPages) => { + if (Array.isArray(lastPage.data!['archives'])) { + const isLastPage = lastPage.data!['archives']?.length < 9; + return isLastPage ? null : allPages.length; + } + return null; + }, true, ); }; @@ -436,11 +461,16 @@ export const useUpdateArchiveOrder = () => { }; export const useUserArchiveList = (userId: number) => - useCustomInfiniteQuery( + useCustomInfiniteQuery( ['/user', userId, 'archive', 'list'], ({ pageParam }) => getUserArchiveList(userId, pageParam), - 8, 'archives', + lastPage => { + if (!lastPage.data?.hasNext) { + return undefined; + } + return lastPage.data.nextArchiveId ?? undefined; + }, true, ); From 0379d7f4a94939d0316bb0121dd29af4c2fb2159 Mon Sep 17 00:00:00 2001 From: csk6314 <37896060+csk6314@users.noreply.github.com> Date: Tue, 10 Dec 2024 04:24:20 +0900 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=EC=9C=A0=EC=A0=80=20=EA=B2=8C?= =?UTF-8?q?=EB=8D=94=EB=A7=81=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/gathering/api/gathering.api.ts | 15 ++++++++++++++- .../gathering/lib/hooks/useUserGathering.ts | 18 ++++++++++++++++++ .../gathering/model/dto/gathering.dto.ts | 9 +++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/features/gathering/lib/hooks/useUserGathering.ts diff --git a/src/features/gathering/api/gathering.api.ts b/src/features/gathering/api/gathering.api.ts index a3b1c92..4ca4ae6 100644 --- a/src/features/gathering/api/gathering.api.ts +++ b/src/features/gathering/api/gathering.api.ts @@ -1,4 +1,8 @@ -import type { GatheringPageResponse, GatheringListParams } from '../model/dto/gathering.dto'; +import type { + GatheringPageResponse, + GatheringListParams, + UserGatheringPageResponse, +} from '../model/dto/gathering.dto'; import type { GatheringDetailResponse, CreateGatheringRequest, @@ -59,4 +63,13 @@ export const gatheringApi = { completeGathering: async (gatheringId: string): Promise => { await api.patch(`/gathering/${gatheringId}`); }, + getUserGathering: (userId: number, nextGatheringId: number) => + api + .get(`/user/${userId}/gatherings`, { + params: { + ...(nextGatheringId && { nextGatheringId }), + size: 8, + }, + }) + .then(res => res.data), }; diff --git a/src/features/gathering/lib/hooks/useUserGathering.ts b/src/features/gathering/lib/hooks/useUserGathering.ts new file mode 100644 index 0000000..7968db0 --- /dev/null +++ b/src/features/gathering/lib/hooks/useUserGathering.ts @@ -0,0 +1,18 @@ +import { gatheringApi } from '../../api/gathering.api'; +import type { GatheringItem, UserGatheringPageResponse } from '../../model'; + +import { useCustomInfiniteQuery } from '@/shared/hook'; + +export const useUserGathering = (userId: number) => + useCustomInfiniteQuery( + ['/user', userId, 'gathering', 'list'], + ({ pageParam }) => gatheringApi.getUserGathering(userId, pageParam), + 'gatherings', + lastPage => { + if (!lastPage.data.hasNext) { + return undefined; + } + return lastPage.data.nextLikeId ?? undefined; + }, + true, + ); diff --git a/src/features/gathering/model/dto/gathering.dto.ts b/src/features/gathering/model/dto/gathering.dto.ts index 2f54e6d..6371ed4 100644 --- a/src/features/gathering/model/dto/gathering.dto.ts +++ b/src/features/gathering/model/dto/gathering.dto.ts @@ -48,6 +48,7 @@ export interface GatheringPageResponse { }; timeStamp: string; } + export interface GatheringListParams { page: number; size: number; @@ -61,3 +62,11 @@ export interface GatheringListParams { contact?: GatheringContactType; } // +export interface UserGatheringPageResponse { + data: { + gatherings: GatheringItem[]; + hasNext: boolean; + nextLikeId: number | null; + }; + timeStamp: string; +} From e270fe480557b34de54c2aacfba2cd4c67de61fd Mon Sep 17 00:00:00 2001 From: csk6314 <37896060+csk6314@users.noreply.github.com> Date: Tue, 10 Dec 2024 04:24:45 +0900 Subject: [PATCH 4/5] feat: User Archive, Gathering Content --- src/widgets/UserContents/UserContents.tsx | 37 ++++++++++++----------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/widgets/UserContents/UserContents.tsx b/src/widgets/UserContents/UserContents.tsx index 456f5a5..d9f5cc8 100644 --- a/src/widgets/UserContents/UserContents.tsx +++ b/src/widgets/UserContents/UserContents.tsx @@ -2,19 +2,21 @@ import styles from './UserContents.module.scss'; import { ArchiveGrid } from '../ArchiveGrid'; //import { GatheringGrid } from '../GatheringGrid'; import { ContentsTab } from './ContentsTab'; +import { GatheringGrid } from '../GatheringGrid'; import { useUserTab } from './hook/useUserTab'; import type { ColorCountDTO } from '@/features'; import { ColorMap, useUserArchiveColors, useUserArchiveList } from '@/features'; //import type { GatheringItemDto } from '@/features/gathering/model/gathering.dto'; +import { useUserGathering } from '@/features/gathering/lib/hooks/useUserGathering'; import { Loader } from '@/shared/ui'; import { PieChart } from '@/shared/ui/Chart/PieChart'; -interface ArchiveContentProps { +interface ContentProps { userId: number; } -const ArchiveContent = ({ userId }: ArchiveContentProps) => { +const ArchiveContent = ({ userId }: ContentProps) => { const { items: archives, isFetchingNextPage, isPending, ref } = useUserArchiveList(userId); const { data: colorData, isPending: isColorPending } = useUserArchiveColors(userId); @@ -44,24 +46,23 @@ const ArchiveContent = ({ userId }: ArchiveContentProps) => { ); }; -// const dummyGatherings: GatheringItemDto<'프로젝트'>[] = Array.from({ length: 9 }, (_, i) => ({ -// gatheringId: i.toString(), -// title: `Sample Gathering ${i + 1}`, -// userId: `user_${i}`, -// username: '홍길동', -// sort: '프로젝트', -// subject: '개발', // ProjectSubjectType만 허용 -// tags: ['React', 'TypeScript', 'Next.js'], -// deadLine: '2024-11-28', -// position: ['개발자', '디자이너'], // 여러 포지션 가능 -// contactType: '온라인', -// period: '3개월', -// personnel: '3', -// })); -// const GatheringContent = () => ; +const GatheringContent = ({ userId }: ContentProps) => { + const { items: gatherings, isFetchingNextPage, isPending, ref } = useUserGathering(userId); + console.log(gatherings); + if (isPending) { + return ; + } + + return ( +
+ +
{isFetchingNextPage && }
+
+ ); +}; const ContentComponents = { - gathering: ArchiveContent, + gathering: GatheringContent, archive: ArchiveContent, }; From 64e1a3eb8e14d93fc573223ecf84d0509d133ed9 Mon Sep 17 00:00:00 2001 From: csk6314 <37896060+csk6314@users.noreply.github.com> Date: Tue, 10 Dec 2024 04:42:11 +0900 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20=EB=A8=B8=EC=A7=80=20=ED=9B=84=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=EB=90=9C=20=EC=BD=94=EB=93=9C=20=EB=B3=B5?= =?UTF-8?q?=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/widgets/UserContents/UserContents.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/widgets/UserContents/UserContents.tsx b/src/widgets/UserContents/UserContents.tsx index 3a04b1d..d9f5cc8 100644 --- a/src/widgets/UserContents/UserContents.tsx +++ b/src/widgets/UserContents/UserContents.tsx @@ -6,7 +6,7 @@ import { GatheringGrid } from '../GatheringGrid'; import { useUserTab } from './hook/useUserTab'; import type { ColorCountDTO } from '@/features'; -import { ColorMap, useMyArchiveList, useUserArchiveColors } from '@/features'; +import { ColorMap, useUserArchiveColors, useUserArchiveList } from '@/features'; //import type { GatheringItemDto } from '@/features/gathering/model/gathering.dto'; import { useUserGathering } from '@/features/gathering/lib/hooks/useUserGathering'; import { Loader } from '@/shared/ui'; @@ -20,7 +20,7 @@ const ArchiveContent = ({ userId }: ContentProps) => { const { items: archives, isFetchingNextPage, isPending, ref } = useUserArchiveList(userId); const { data: colorData, isPending: isColorPending } = useUserArchiveColors(userId); - if (!colorData?.data || isColorPending || isPending || !archives?.data) { + if (!colorData?.data || isColorPending || isPending) { return ; } @@ -40,7 +40,8 @@ const ArchiveContent = ({ userId }: ContentProps) => { - + +
{isFetchingNextPage && }
); };