From ad44f0cac5c876d4146717cd2e092e040b988f0a Mon Sep 17 00:00:00 2001 From: gilpop8663 Date: Thu, 20 Jul 2023 22:14:42 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20(#110)=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EB=AA=A9=EB=A1=9D=20=ED=8C=A8=EC=B9=98=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EB=B0=8F=20=ED=9B=85=EC=97=90=EC=84=9C=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=EB=B3=84=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EB=AA=A9=EB=A1=9D=EC=9D=84=20=EB=B6=88=EB=9F=AC?= =?UTF-8?q?=EC=98=A4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/__test__/api/postList.test.ts | 11 ++++++++ .../__test__/hooks/query/usePostList.test.tsx | 13 +++++++++- frontend/src/api/wus/postList.ts | 25 +++++++++++++++---- frontend/src/hooks/query/usePostList.tsx | 8 +++--- frontend/src/mocks/handlers.ts | 4 +-- frontend/src/mocks/wus/post.ts | 2 +- 6 files changed, 51 insertions(+), 12 deletions(-) diff --git a/frontend/__test__/api/postList.test.ts b/frontend/__test__/api/postList.test.ts index ae3826b26..bea57a8c3 100644 --- a/frontend/__test__/api/postList.test.ts +++ b/frontend/__test__/api/postList.test.ts @@ -20,4 +20,15 @@ describe('전체 게시글 목록을 패치하는 로직이 의도한대로 작 expect(data.pageNumber).toEqual(3); }); + + test('카테고리별 게시글 페이지의 정보를 불러온다.', async () => { + const data = await getPostList({ + postStatus: 'closed', + postSorting: 'popular', + pageNumber: 3, + categoryId: 1, + }); + + expect(data.postList).toEqual(MOCK_POST_LIST[3]); + }); }); diff --git a/frontend/__test__/hooks/query/usePostList.test.tsx b/frontend/__test__/hooks/query/usePostList.test.tsx index 006cbc8ea..6f6a385ad 100644 --- a/frontend/__test__/hooks/query/usePostList.test.tsx +++ b/frontend/__test__/hooks/query/usePostList.test.tsx @@ -14,7 +14,7 @@ const wrapper = ({ children }: { children: ReactNode }) => ( ); describe('usePostList 훅이 의도한대로 작동하는 지 확인한다.', () => { - test('게시글 목록을 불러온다.', async () => { + test('전체 게시글 목록을 불러온다.', async () => { const { result } = renderHook( () => usePostList({ postSorting: 'popular', postStatus: 'all' }), { @@ -24,4 +24,15 @@ describe('usePostList 훅이 의도한대로 작동하는 지 확인한다.', () await waitFor(() => expect(result.current.data?.pages[0].postList).toEqual(MOCK_POST_LIST[0])); }); + + test('카테고리별 게시글 목록을 불러온다.', async () => { + const { result } = renderHook( + () => usePostList({ postSorting: 'popular', postStatus: 'all', categoryId: 1 }), + { + wrapper, + } + ); + + await waitFor(() => expect(result.current.data?.pages[0].postList).toEqual(MOCK_POST_LIST[0])); + }); }); diff --git a/frontend/src/api/wus/postList.ts b/frontend/src/api/wus/postList.ts index b2cf83b60..02c91d461 100644 --- a/frontend/src/api/wus/postList.ts +++ b/frontend/src/api/wus/postList.ts @@ -4,10 +4,11 @@ import type { PostSorting, PostStatus } from '@components/post/PostListPage/type import { getFetch } from '@utils/fetch'; -interface GetPostList { +interface PostListByOption { postStatus: PostStatus; postSorting: PostSorting; pageNumber: number; + categoryId?: number; } const REQUEST_STATUS_OPTION: Record = { @@ -21,13 +22,27 @@ const REQUEST_SORTING_OPTION: Record = { popular: 'HOT', }; -export const getPostList = async ({ postStatus, postSorting, pageNumber }: GetPostList) => { +const getPostListUrl = ({ categoryId, postStatus, postSorting, pageNumber }: PostListByOption) => { const requestedStatus = REQUEST_STATUS_OPTION[postStatus]; const requestedSorting = REQUEST_SORTING_OPTION[postSorting]; - const postList = await getFetch( - `/posts?status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}` - ); + if (categoryId) { + return `/posts?categoryId=${categoryId}&status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}`; + } + + return `/posts?status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}`; +}; + +export const getPostList = async ({ + postStatus, + postSorting, + pageNumber, + categoryId, +}: PostListByOption) => { + const postListUrl = getPostListUrl({ pageNumber, postSorting, postStatus, categoryId }); + + const postList = await getFetch(postListUrl); + return { pageNumber, postList, diff --git a/frontend/src/hooks/query/usePostList.tsx b/frontend/src/hooks/query/usePostList.tsx index 948133a56..70b801a9d 100644 --- a/frontend/src/hooks/query/usePostList.tsx +++ b/frontend/src/hooks/query/usePostList.tsx @@ -9,15 +9,17 @@ import { PostSorting, PostStatus } from '@components/post/PostListPage/types'; interface UsePostList { postSorting: PostSorting; postStatus: PostStatus; + categoryId?: number; } const MAX_LIST_LENGTH = 10; -export const usePostList = ({ postSorting, postStatus }: UsePostList) => { +export const usePostList = ({ postSorting, postStatus, categoryId }: UsePostList) => { const { data, error, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery( - ['posts', postSorting, postStatus], - ({ pageParam = 0 }) => getPostList({ postSorting, postStatus, pageNumber: pageParam }), + ['posts', postSorting, postStatus, categoryId], + ({ pageParam = 0 }) => + getPostList({ postSorting, postStatus, pageNumber: pageParam, categoryId }), { getNextPageParam: lastPage => { if (lastPage.postList.length !== MAX_LIST_LENGTH) return; diff --git a/frontend/src/mocks/handlers.ts b/frontend/src/mocks/handlers.ts index dabec3733..722ba7d98 100644 --- a/frontend/src/mocks/handlers.ts +++ b/frontend/src/mocks/handlers.ts @@ -1,7 +1,7 @@ import { example } from './example/get'; - import { mockVoteResult } from './getVoteDetail'; import { mockPost } from './post'; import { mockVote } from './vote'; +import { mockPostList } from './wus/post'; -export const handlers = [...example, ...mockPost, ...mockVoteResult, ...mockVote]; +export const handlers = [...example, ...mockPost, ...mockVoteResult, ...mockVote, ...mockPostList]; diff --git a/frontend/src/mocks/wus/post.ts b/frontend/src/mocks/wus/post.ts index 68517f899..98e7dcfa2 100644 --- a/frontend/src/mocks/wus/post.ts +++ b/frontend/src/mocks/wus/post.ts @@ -2,7 +2,7 @@ import { rest } from 'msw'; import { MOCK_POST_LIST } from '@mocks/mockData/postList'; -export const postListHandlers = [ +export const mockPostList = [ rest.get('/posts', (req, res, ctx) => { const pages = Number(req.url.searchParams.get('pages')); From b6282b49eae72555c0585d778cc4ad6a4d9abaa6 Mon Sep 17 00:00:00 2001 From: gilpop8663 Date: Fri, 21 Jul 2023 01:27:11 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20(#110)=20PostList=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=97=90=EC=84=9C=20categoryId?= =?UTF-8?q?=EB=A5=BC=20=EC=9D=B4=EC=9A=A9=ED=95=B4=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=EB=B3=84=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=EC=9D=84=20=EC=9A=94=EC=B2=AD=ED=95=A0=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/post/PostList/index.tsx | 7 +++++++ frontend/src/constants/post.ts | 2 ++ 2 files changed, 9 insertions(+) diff --git a/frontend/src/components/post/PostList/index.tsx b/frontend/src/components/post/PostList/index.tsx index 8f40fb9a9..3e677bf01 100644 --- a/frontend/src/components/post/PostList/index.tsx +++ b/frontend/src/components/post/PostList/index.tsx @@ -10,6 +10,8 @@ import Skeleton from '@components/common/Skeleton'; import { SORTING_OPTION, STATUS_OPTION } from '@components/post/PostListPage/constants'; import type { PostSorting, PostStatus } from '@components/post/PostListPage/types'; +import { CATEGORY_ID } from '@constants/post'; + import * as S from './style'; export default function PostList() { @@ -23,9 +25,14 @@ export default function PostList() { const { selectedOption: selectedSortingOption, handleOptionChange: handleSortingOptionChange } = useSelect('latest'); + const URL = new URLSearchParams(window.location.search); + + const categoryId = URL.get(CATEGORY_ID); + const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = usePostList({ postSorting: selectedSortingOption, postStatus: selectedStatusOption, + categoryId: Number(categoryId), }); useEffect(() => { diff --git a/frontend/src/constants/post.ts b/frontend/src/constants/post.ts index 143371efb..6eac885b0 100644 --- a/frontend/src/constants/post.ts +++ b/frontend/src/constants/post.ts @@ -1,3 +1,5 @@ export const POST = { NOT_VOTE: 0, }; + +export const CATEGORY_ID = 'categoryId'; From d3b71b27a1402b182c0ee3d85f9545b89ea78a36 Mon Sep 17 00:00:00 2001 From: gilpop8663 Date: Sun, 23 Jul 2023 21:13:42 +0900 Subject: [PATCH 3/6] =?UTF-8?q?refactor:=20(#110)=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=EC=84=9C=EB=A7=8C=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EB=90=98=EB=8A=94=20=EC=83=81=EC=88=98=EC=9D=98=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/post/PostList/constants.ts | 1 + frontend/src/constants/post.ts | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) create mode 100644 frontend/src/components/post/PostList/constants.ts diff --git a/frontend/src/components/post/PostList/constants.ts b/frontend/src/components/post/PostList/constants.ts new file mode 100644 index 000000000..99b8288e3 --- /dev/null +++ b/frontend/src/components/post/PostList/constants.ts @@ -0,0 +1 @@ +export const CATEGORY_ID = 'categoryId'; diff --git a/frontend/src/constants/post.ts b/frontend/src/constants/post.ts index 237177044..2fae12bc1 100644 --- a/frontend/src/constants/post.ts +++ b/frontend/src/constants/post.ts @@ -14,5 +14,3 @@ export const REQUEST_SORTING_OPTION: Record = { latest: 'LATEST', popular: 'HOT', }; - -export const CATEGORY_ID = 'categoryId'; From af0e438574fdeab0b6f5abec392b919de81053c9 Mon Sep 17 00:00:00 2001 From: gilpop8663 Date: Sun, 23 Jul 2023 21:16:16 +0900 Subject: [PATCH 4/6] =?UTF-8?q?refactor:=20(#110)=20URLSearchParams?= =?UTF-8?q?=EC=97=90=EC=84=9C=20useSearchParams=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/post/PostList/index.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/post/PostList/index.tsx b/frontend/src/components/post/PostList/index.tsx index 3e677bf01..32a1ec514 100644 --- a/frontend/src/components/post/PostList/index.tsx +++ b/frontend/src/components/post/PostList/index.tsx @@ -1,4 +1,5 @@ import React, { useEffect } from 'react'; +import { useSearchParams } from 'react-router-dom'; import { usePostList } from '@hooks/query/usePostList'; import { useIntersectionObserver } from '@hooks/useIntersectionObserver'; @@ -10,11 +11,11 @@ import Skeleton from '@components/common/Skeleton'; import { SORTING_OPTION, STATUS_OPTION } from '@components/post/PostListPage/constants'; import type { PostSorting, PostStatus } from '@components/post/PostListPage/types'; -import { CATEGORY_ID } from '@constants/post'; - +import { CATEGORY_ID } from './constants'; import * as S from './style'; export default function PostList() { + const [searchParams] = useSearchParams(); const { targetRef, isIntersecting } = useIntersectionObserver({ root: null, rootMargin: '', @@ -25,9 +26,7 @@ export default function PostList() { const { selectedOption: selectedSortingOption, handleOptionChange: handleSortingOptionChange } = useSelect('latest'); - const URL = new URLSearchParams(window.location.search); - - const categoryId = URL.get(CATEGORY_ID); + const categoryId = searchParams.get(CATEGORY_ID); const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = usePostList({ postSorting: selectedSortingOption, From ad86c28264001bdc371ca572156ca70ba825d12b Mon Sep 17 00:00:00 2001 From: gilpop8663 Date: Sun, 23 Jul 2023 21:17:18 +0900 Subject: [PATCH 5/6] =?UTF-8?q?refactor:=20(#110)=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=EB=B3=84=20=EA=B8=80=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?URL=EC=9D=84=20=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EC=9D=98=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=B0=8F=20=EB=B0=98=EB=B3=B5=EB=90=98=EB=8A=94=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/api/wus/postList.ts | 10 ++++++---- frontend/src/mocks/handlers.ts | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/frontend/src/api/wus/postList.ts b/frontend/src/api/wus/postList.ts index 51c166d76..24bcd6702 100644 --- a/frontend/src/api/wus/postList.ts +++ b/frontend/src/api/wus/postList.ts @@ -13,7 +13,7 @@ interface PostListByOption { categoryId?: number; } -export const getPostListUrl = ({ +export const makePostListUrl = ({ categoryId, postStatus, postSorting, @@ -22,11 +22,13 @@ export const getPostListUrl = ({ const requestedStatus = REQUEST_STATUS_OPTION[postStatus]; const requestedSorting = REQUEST_SORTING_OPTION[postSorting]; + const OPTION_URL = `status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}`; + if (categoryId) { - return `/posts?categoryId=${categoryId}&status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}`; + return `/posts?categoryId=${categoryId}&${OPTION_URL}`; } - return `/posts?status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}`; + return `/posts?${OPTION_URL}`; }; export const getPostList = async ({ @@ -35,7 +37,7 @@ export const getPostList = async ({ pageNumber, categoryId, }: PostListByOption) => { - const postListUrl = getPostListUrl({ pageNumber, postSorting, postStatus, categoryId }); + const postListUrl = makePostListUrl({ pageNumber, postSorting, postStatus, categoryId }); const postList = await getFetch(postListUrl); diff --git a/frontend/src/mocks/handlers.ts b/frontend/src/mocks/handlers.ts index 1dc815eff..410fecc5c 100644 --- a/frontend/src/mocks/handlers.ts +++ b/frontend/src/mocks/handlers.ts @@ -2,6 +2,7 @@ import { example } from './example/get'; import { mockVoteResult } from './getVoteDetail'; import { mockPost } from './post'; import { mockVote } from './vote'; +import { mockCategoryHandlers } from './wus/categoryList'; import { mockPostList } from './wus/post'; import { mockUserInfo } from './wus/userInfo'; @@ -11,5 +12,6 @@ export const handlers = [ ...mockVoteResult, ...mockVote, ...mockPostList, + ...mockCategoryHandlers, ...mockUserInfo, ]; From e8a4b522c420c43c5051135be0139a5562cd0205 Mon Sep 17 00:00:00 2001 From: Gilpop8663 Date: Tue, 25 Jul 2023 13:10:13 +0900 Subject: [PATCH 6/6] =?UTF-8?q?refactor:=20(#110)=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=EB=B3=84=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20URL?= =?UTF-8?q?=20=EA=B2=BD=EB=A1=9C=20=EB=B0=8F=20API=20=EC=97=B0=EB=8F=99=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/api/wus/postList.ts | 7 +++++-- frontend/src/components/post/PostList/index.tsx | 7 ++----- frontend/src/routes/router.tsx | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/frontend/src/api/wus/postList.ts b/frontend/src/api/wus/postList.ts index 24bcd6702..1c7fa068e 100644 --- a/frontend/src/api/wus/postList.ts +++ b/frontend/src/api/wus/postList.ts @@ -13,6 +13,8 @@ interface PostListByOption { categoryId?: number; } +const BASE_URL = process.env.VOTOGETHER_MOCKING_URL; + export const makePostListUrl = ({ categoryId, postStatus, @@ -22,13 +24,14 @@ export const makePostListUrl = ({ const requestedStatus = REQUEST_STATUS_OPTION[postStatus]; const requestedSorting = REQUEST_SORTING_OPTION[postSorting]; + const POST_BASE_URL = `${BASE_URL}/posts`; const OPTION_URL = `status=${requestedStatus}&sorting=${requestedSorting}&pages=${pageNumber}`; if (categoryId) { - return `/posts?categoryId=${categoryId}&${OPTION_URL}`; + return `${POST_BASE_URL}?categoryId=${categoryId}&${OPTION_URL}`; } - return `/posts?${OPTION_URL}`; + return `${POST_BASE_URL}?${OPTION_URL}`; }; export const getPostList = async ({ diff --git a/frontend/src/components/post/PostList/index.tsx b/frontend/src/components/post/PostList/index.tsx index 32a1ec514..c79dbd140 100644 --- a/frontend/src/components/post/PostList/index.tsx +++ b/frontend/src/components/post/PostList/index.tsx @@ -1,5 +1,5 @@ import React, { useEffect } from 'react'; -import { useSearchParams } from 'react-router-dom'; +import { useParams } from 'react-router-dom'; import { usePostList } from '@hooks/query/usePostList'; import { useIntersectionObserver } from '@hooks/useIntersectionObserver'; @@ -11,11 +11,10 @@ import Skeleton from '@components/common/Skeleton'; import { SORTING_OPTION, STATUS_OPTION } from '@components/post/PostListPage/constants'; import type { PostSorting, PostStatus } from '@components/post/PostListPage/types'; -import { CATEGORY_ID } from './constants'; import * as S from './style'; export default function PostList() { - const [searchParams] = useSearchParams(); + const { categoryId } = useParams<{ categoryId?: string }>(); const { targetRef, isIntersecting } = useIntersectionObserver({ root: null, rootMargin: '', @@ -26,8 +25,6 @@ export default function PostList() { const { selectedOption: selectedSortingOption, handleOptionChange: handleSortingOptionChange } = useSelect('latest'); - const categoryId = searchParams.get(CATEGORY_ID); - const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = usePostList({ postSorting: selectedSortingOption, postStatus: selectedStatusOption, diff --git a/frontend/src/routes/router.tsx b/frontend/src/routes/router.tsx index cb7001d9d..a1292f9ee 100644 --- a/frontend/src/routes/router.tsx +++ b/frontend/src/routes/router.tsx @@ -27,6 +27,7 @@ const router = createBrowserRouter([ path: 'posts/result/:postId', element: , }, + { path: 'posts/category/:categoryId', element: }, ], }, ]);