From bc2e3d0a027d4cdb312ad6fed9a0e3174c32e48b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EA=B8=B8/KIM=20YOUNG=20GIL?= <80146176+Gilpop8663@users.noreply.github.com> Date: Thu, 3 Aug 2023 11:37:54 +0900 Subject: [PATCH] =?UTF-8?q?=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC,=20?= =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EB=AA=A9=EB=A1=9D=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99=20=EB=B0=8F=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81=20?= =?UTF-8?q?(#219)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: (#205) 카테고리에 관련된 API 서버와 연동 wus폴더에 있던 파일들 밖으로 이동 * feat: (#205) 게시글 작성 페이지에서 카테고리 리스트를 불러와 옵션으로 변환하는 기능 구현 * refactor: (#205) 마감 시간을 구하는 유틸 함수 분리 * refactor: (#205) sua 폴더에 있던 post.ts MSW 코드를 밖의 post.ts 파일과 병합 * refactor: (#205) wus 폴더에 있던 유저 MSW 코드 밖으로 이동 * refactor: (#205) wus 폴더의 게시글 목록 MSW 코드를 밖으로 분리 및 파일명 변경 * refactor: (#205) api 폴더에 있던 wus 폴더 삭제 및 파일 이동 * refactor: (#205) 댓글을 제외한 나머지 api에 BASE_URL 코드 추가 * refactor: (#205) AuthContext에서 User 타입 변경 및 액세스 토큰이 있을 경우 isLogged:true로 수정 * fix: (#205) 게시글의 카테고리 리스트에 ?를 붙혀 없어도 에러가 나지 않게 수정 * feat: (#205) 게시글 서버에서 받는 타입 명세 선언 * refactor: (#205) 서버에서 받은 게시글 목록을 클라이언트에서 사용하는 게시글 목록 명세로 변환 * refactor: (#205) 게시글 명세인 startTime, endTime의 이름을 변경 --- frontend/__test__/api/categoryList.test.ts | 2 +- frontend/__test__/api/postList.test.ts | 12 +-- frontend/__test__/api/user.test.ts | 2 +- .../__test__/changeCategoryToOption.test.ts | 27 ++++++ frontend/__test__/getDeadlineTime.test.ts | 53 ++++++++++++ .../hooks/query/useCategoryList.test.tsx | 48 +++++++++++ .../__test__/hooks/query/usePostList.test.tsx | 22 +++-- frontend/src/api/{wus => }/categoryList.ts | 10 ++- frontend/src/api/comment.ts | 1 + frontend/src/api/post.ts | 43 ++++++++-- frontend/src/api/postList.ts | 10 ++- frontend/src/api/{wus => }/userInfo.ts | 2 +- frontend/src/api/voteResult.ts | 6 +- .../components/PostForm/PostForm.stories.tsx | 4 +- frontend/src/components/PostForm/index.tsx | 52 ++++-------- .../src/components/common/Layout/index.tsx | 7 +- frontend/src/components/common/Post/index.tsx | 8 +- .../src/components/common/Post/mockData.ts | 8 +- frontend/src/hooks/context/auth.tsx | 2 +- .../category/useCategoryFavoriteToggle.ts | 2 +- .../hooks/query/category/useCategoryList.ts | 2 +- frontend/src/hooks/query/usePostList.tsx | 1 + frontend/src/hooks/query/user/useUserInfo.ts | 6 +- frontend/src/index.tsx | 12 +-- frontend/src/mocks/{wus => }/categoryList.ts | 0 frontend/src/mocks/handlers.ts | 6 +- frontend/src/mocks/mockData/post.ts | 12 ++- frontend/src/mocks/mockData/postList.ts | 53 ++++++------ frontend/src/mocks/post.ts | 28 ++++++- .../src/mocks/{wus/post.ts => postList.ts} | 0 frontend/src/mocks/sua/post.ts | 82 ------------------- frontend/src/mocks/{wus => }/userInfo.ts | 0 frontend/src/pages/MyInfo/index.tsx | 19 ++--- frontend/src/pages/post/EditPost/index.tsx | 4 +- frontend/src/pages/post/PostDetail/index.tsx | 2 +- frontend/src/types/post.ts | 28 ++++++- frontend/src/types/user.ts | 3 +- .../src/utils/post/changeCategoryToOption.ts | 7 ++ frontend/src/utils/post/getDeadlineTime.ts | 33 ++++++++ frontend/src/utils/time.ts | 4 +- 40 files changed, 395 insertions(+), 228 deletions(-) create mode 100644 frontend/__test__/changeCategoryToOption.test.ts create mode 100644 frontend/__test__/getDeadlineTime.test.ts create mode 100644 frontend/__test__/hooks/query/useCategoryList.test.tsx rename frontend/src/api/{wus => }/categoryList.ts (65%) rename frontend/src/api/{wus => }/userInfo.ts (93%) rename frontend/src/mocks/{wus => }/categoryList.ts (100%) rename frontend/src/mocks/{wus/post.ts => postList.ts} (100%) delete mode 100644 frontend/src/mocks/sua/post.ts rename frontend/src/mocks/{wus => }/userInfo.ts (100%) create mode 100644 frontend/src/utils/post/changeCategoryToOption.ts create mode 100644 frontend/src/utils/post/getDeadlineTime.ts diff --git a/frontend/__test__/api/categoryList.test.ts b/frontend/__test__/api/categoryList.test.ts index eaf34f352..ccc34acb5 100644 --- a/frontend/__test__/api/categoryList.test.ts +++ b/frontend/__test__/api/categoryList.test.ts @@ -4,7 +4,7 @@ import { getUserCategoryList, removeFavoriteCategory, transformCategoryListResponse, -} from '@api/wus/categoryList'; +} from '@api/categoryList'; import { MOCK_CATEGORY_LIST, MOCK_GUEST_CATEGORY_LIST } from '@mocks/mockData/categoryList'; diff --git a/frontend/__test__/api/postList.test.ts b/frontend/__test__/api/postList.test.ts index 57f594d3a..33ae82d61 100644 --- a/frontend/__test__/api/postList.test.ts +++ b/frontend/__test__/api/postList.test.ts @@ -2,7 +2,7 @@ import { getPostList } from '@api/postList'; import { POST_TYPE, SORTING, STATUS } from '@constants/post'; -import { MOCK_POST_LIST } from '@mocks/mockData/postList'; +import { MOCK_TRANSFORM_POST_LIST } from '@mocks/mockData/postList'; describe('서버와 통신하여 전체 게시글 목록을 불러오는지 확인한다.', () => { test('게시글 목록의 개수는 10개씩 불러온다.', async () => { @@ -36,7 +36,7 @@ describe('서버와 통신하여 전체 게시글 목록을 불러오는지 확 } ); - expect(data.postList).toEqual(MOCK_POST_LIST); + expect(data.postList).toEqual(MOCK_TRANSFORM_POST_LIST); }); test('게시글 페이지의 정보를 불러온다.', async () => { @@ -70,7 +70,7 @@ describe('서버와 통신하여 전체 게시글 목록을 불러오는지 확 } ); - expect(data.postList).toEqual(MOCK_POST_LIST); + expect(data.postList).toEqual(MOCK_TRANSFORM_POST_LIST); }); test('내가 작성한 게시글 페이지의 정보를 불러온다.', async () => { @@ -87,7 +87,7 @@ describe('서버와 통신하여 전체 게시글 목록을 불러오는지 확 } ); - expect(data.postList).toEqual(MOCK_POST_LIST); + expect(data.postList).toEqual(MOCK_TRANSFORM_POST_LIST); }); test('내가 투표한 게시글 페이지의 정보를 불러온다.', async () => { @@ -104,7 +104,7 @@ describe('서버와 통신하여 전체 게시글 목록을 불러오는지 확 } ); - expect(data.postList).toEqual(MOCK_POST_LIST); + expect(data.postList).toEqual(MOCK_TRANSFORM_POST_LIST); }); test('내가 검색한 게시글 페이지의 정보를 불러온다.', async () => { @@ -121,6 +121,6 @@ describe('서버와 통신하여 전체 게시글 목록을 불러오는지 확 } ); - expect(data.postList).toEqual(MOCK_POST_LIST); + expect(data.postList).toEqual(MOCK_TRANSFORM_POST_LIST); }); }); diff --git a/frontend/__test__/api/user.test.ts b/frontend/__test__/api/user.test.ts index 870bc36f4..aef7a4a3d 100644 --- a/frontend/__test__/api/user.test.ts +++ b/frontend/__test__/api/user.test.ts @@ -3,7 +3,7 @@ import { getUserInfo, modifyNickname, transformUserInfoResponse, -} from '@api/wus/userInfo'; +} from '@api/userInfo'; import { MOCK_USER_INFO } from '@mocks/mockData/user'; diff --git a/frontend/__test__/changeCategoryToOption.test.ts b/frontend/__test__/changeCategoryToOption.test.ts new file mode 100644 index 000000000..5f1d34d71 --- /dev/null +++ b/frontend/__test__/changeCategoryToOption.test.ts @@ -0,0 +1,27 @@ +import { Category } from '@type/category'; + +import { Option } from '@components/common/MultiSelect/types'; + +import { changeCategoryToOption } from '@utils/post/changeCategoryToOption'; + +describe('changeCategoryToOption 함수를 이용해서 카테고리 리스트를 셀렉트 컴포넌트에 사용되는 옵션 리스트로 변환한다.', () => { + test('카테고리 리스트로 옵션 리스트를 만든다.', () => { + const categoryList: Category[] = [ + { id: 1, isFavorite: false, name: '갤럭시' }, + { id: 2, isFavorite: true, name: '애플' }, + ]; + + const result: Option[] = changeCategoryToOption(categoryList); + + expect(result).toEqual([ + { + id: 1, + name: '갤럭시', + }, + { + id: 2, + name: '애플', + }, + ]); + }); +}); diff --git a/frontend/__test__/getDeadlineTime.test.ts b/frontend/__test__/getDeadlineTime.test.ts new file mode 100644 index 000000000..162e19740 --- /dev/null +++ b/frontend/__test__/getDeadlineTime.test.ts @@ -0,0 +1,53 @@ +import { getDeadlineTime } from '@utils/post/getDeadlineTime'; + +describe('getDeadlineTime를 이용하여 사용자에게 마감 시간을 알려준다.', () => { + test('5분을 설정했을 때 5분으로 표시된다', () => { + const result = getDeadlineTime({ + day: 0, + hour: 0, + minute: 5, + }); + + expect(result).toBe('5분 후에 마감됩니다.'); + }); + + test('1시간 5분을 설정했을 때 1시간 5분으로 표시된다', () => { + const result = getDeadlineTime({ + day: 0, + hour: 1, + minute: 5, + }); + + expect(result).toBe('1시간 5분 후에 마감됩니다.'); + }); + + test('2일 23시간 59분을 설정했을 때 2일 23시간 59분으로 표시된다', () => { + const result = getDeadlineTime({ + day: 2, + hour: 23, + minute: 59, + }); + + expect(result).toBe('2일 23시간 59분 후에 마감됩니다.'); + }); + + test('0일 0시간 0분을 설정했을 때 "마감 시간을 선택해주세요"를 표시된다', () => { + const result = getDeadlineTime({ + day: 0, + hour: 0, + minute: 0, + }); + + expect(result).toBe('마감 시간을 선택해주세요'); + }); + + test('-1일 -1시간 -1분을 설정했을 때 "마감 시간을 다시 설정해주세요"를 표시된다', () => { + const result = getDeadlineTime({ + day: -1, + hour: -1, + minute: -1, + }); + + expect(result).toBe('마감 시간을 다시 설정해주세요'); + }); +}); diff --git a/frontend/__test__/hooks/query/useCategoryList.test.tsx b/frontend/__test__/hooks/query/useCategoryList.test.tsx new file mode 100644 index 000000000..d7fd1a04e --- /dev/null +++ b/frontend/__test__/hooks/query/useCategoryList.test.tsx @@ -0,0 +1,48 @@ +import React, { ReactNode } from 'react'; + +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { renderHook, waitFor } from '@testing-library/react'; + +import { useCategoryList } from '@hooks/query/category/useCategoryList'; + +import { transformCategoryListResponse } from '@api/categoryList'; + +import { MOCK_CATEGORY_LIST, MOCK_GUEST_CATEGORY_LIST } from '@mocks/mockData/categoryList'; + +const queryClient = new QueryClient(); + +const wrapper = ({ children }: { children: ReactNode }) => ( + {children} +); + +describe('useCategoryList 훅이 카테고리 목록을 불러오는지 확인한다.', () => { + test('비회원 카테고리 목록을 불러온다.', async () => { + const { result } = renderHook(() => useCategoryList(false), { + wrapper, + }); + + await waitFor(() => + expect(result.current.data).toEqual(transformCategoryListResponse(MOCK_GUEST_CATEGORY_LIST)) + ); + }); + + test('회원 카테고리 목록을 불러온다.', async () => { + const { result } = renderHook(() => useCategoryList(true), { + wrapper, + }); + + await waitFor(() => + expect(result.current.data).toEqual(transformCategoryListResponse(MOCK_CATEGORY_LIST)) + ); + }); + + test('회원 카테고리 목록을 불러온다.', async () => { + const { result } = renderHook(() => useCategoryList(true), { + wrapper, + }); + + await waitFor(() => + expect(result.current.data).toEqual(transformCategoryListResponse(MOCK_CATEGORY_LIST)) + ); + }); +}); diff --git a/frontend/__test__/hooks/query/usePostList.test.tsx b/frontend/__test__/hooks/query/usePostList.test.tsx index 1595cf016..9f4944712 100644 --- a/frontend/__test__/hooks/query/usePostList.test.tsx +++ b/frontend/__test__/hooks/query/usePostList.test.tsx @@ -7,7 +7,7 @@ import { usePostList } from '@hooks/query/usePostList'; import { POST_TYPE, SORTING, STATUS } from '@constants/post'; -import { MOCK_POST_LIST } from '@mocks/mockData/postList'; +import { MOCK_TRANSFORM_POST_LIST } from '@mocks/mockData/postList'; const queryClient = new QueryClient(); @@ -35,7 +35,9 @@ describe('usePostList 훅이 게시글 목록을 불러오는지 확인한다.', } ); - await waitFor(() => expect(result.current.data?.pages[0].postList).toEqual(MOCK_POST_LIST)); + await waitFor(() => + expect(result.current.data?.pages[0].postList).toEqual(MOCK_TRANSFORM_POST_LIST) + ); }); test('카테고리별 게시글 목록을 불러온다.', async () => { @@ -57,7 +59,9 @@ describe('usePostList 훅이 게시글 목록을 불러오는지 확인한다.', } ); - await waitFor(() => expect(result.current.data?.pages[0].postList).toEqual(MOCK_POST_LIST)); + await waitFor(() => + expect(result.current.data?.pages[0].postList).toEqual(MOCK_TRANSFORM_POST_LIST) + ); }); test('내가 작성한 게시글 목록을 불러온다.', async () => { @@ -79,7 +83,9 @@ describe('usePostList 훅이 게시글 목록을 불러오는지 확인한다.', } ); - await waitFor(() => expect(result.current.data?.pages[0].postList).toEqual(MOCK_POST_LIST)); + await waitFor(() => + expect(result.current.data?.pages[0].postList).toEqual(MOCK_TRANSFORM_POST_LIST) + ); }); test('내가 투표한 게시글 목록을 불러온다.', async () => { @@ -101,7 +107,9 @@ describe('usePostList 훅이 게시글 목록을 불러오는지 확인한다.', } ); - await waitFor(() => expect(result.current.data?.pages[0].postList).toEqual(MOCK_POST_LIST)); + await waitFor(() => + expect(result.current.data?.pages[0].postList).toEqual(MOCK_TRANSFORM_POST_LIST) + ); }); test('내가 검색한 게시글 목록을 불러온다.', async () => { @@ -123,6 +131,8 @@ describe('usePostList 훅이 게시글 목록을 불러오는지 확인한다.', } ); - await waitFor(() => expect(result.current.data?.pages[0].postList).toEqual(MOCK_POST_LIST)); + await waitFor(() => + expect(result.current.data?.pages[0].postList).toEqual(MOCK_TRANSFORM_POST_LIST) + ); }); }); diff --git a/frontend/src/api/wus/categoryList.ts b/frontend/src/api/categoryList.ts similarity index 65% rename from frontend/src/api/wus/categoryList.ts rename to frontend/src/api/categoryList.ts index d899874af..7b329df08 100644 --- a/frontend/src/api/wus/categoryList.ts +++ b/frontend/src/api/categoryList.ts @@ -10,22 +10,24 @@ export const transformCategoryListResponse = (categoryList: CategoryResponse[]) })); }; +const BASE_URL = process.env.VOTOGETHER_BASE_URL; + export const getUserCategoryList = async () => { - const categoryList = await getFetch('/categories'); + const categoryList = await getFetch(`${BASE_URL}/categories`); return transformCategoryListResponse(categoryList); }; export const getGuestCategoryList = async () => { - const categoryList = await getFetch('/categories/guest'); + const categoryList = await getFetch(`${BASE_URL}/categories/guest`); return transformCategoryListResponse(categoryList); }; export const addFavoriteCategory = async (categoryId: number) => { - await postFetch(`/categories/${categoryId}/like`, ''); + await postFetch(`${BASE_URL}/categories/${categoryId}/like`, ''); }; export const removeFavoriteCategory = async (categoryId: number) => { - await deleteFetch(`/categories/${categoryId}/like`); + await deleteFetch(`${BASE_URL}/categories/${categoryId}/like`); }; diff --git a/frontend/src/api/comment.ts b/frontend/src/api/comment.ts index 1f87c568d..5f82e0088 100644 --- a/frontend/src/api/comment.ts +++ b/frontend/src/api/comment.ts @@ -11,6 +11,7 @@ export const transformCommentListResponse = (commentList: CommentResponse[]): Co isEdit: comment.createdAt !== comment.updatedAt, })); }; + export const getCommentList = async (postId: number): Promise => { const commentList = await getFetch(`/posts/${postId}/comments`); diff --git a/frontend/src/api/post.ts b/frontend/src/api/post.ts index 4666b886b..b570bb74b 100644 --- a/frontend/src/api/post.ts +++ b/frontend/src/api/post.ts @@ -1,4 +1,4 @@ -import { PostInfo } from '@type/post'; +import { PostInfo, PostInfoResponse } from '@type/post'; import { getFetch, @@ -11,8 +11,35 @@ import { const BASE_URL = process.env.VOTOGETHER_BASE_URL; +export const transformPostResponse = (post: PostInfoResponse): PostInfo => { + return { + category: post.categories.map(category => ({ id: category.id, name: category.name })), + content: post.content, + deadline: post.deadline, + imageUrl: post.imageUrl, + postId: post.postId, + createTime: post.createdAt, + title: post.title, + voteInfo: { + allPeopleCount: post.voteInfo.totalVoteCount, + selectedOptionId: post.voteInfo.selectedOptionId, + options: post.voteInfo.options.map(option => ({ + id: option.optionId, + text: option.content, + peopleCount: option.voteCount, + percent: option.votePercent, + imageUrl: option.imageUrl, + })), + }, + writer: { + id: post.writer.id, + nickname: post.writer.nickname, + }, + }; +}; + export const votePost = async (postId: number, optionId: number) => { - return await postFetch(`/posts/${postId}/options/${optionId}`, ''); + return await postFetch(`${BASE_URL}/posts/${postId}/options/${optionId}`, ''); }; interface OptionData { @@ -22,12 +49,14 @@ interface OptionData { export const changeVotedOption = async (postId: number, optionData: OptionData) => { return await patchFetch( - `/posts/${postId}/options?source=${optionData.originOptionId}&target=${optionData.newOptionId}` + `${BASE_URL}/posts/${postId}/options?source=${optionData.originOptionId}&target=${optionData.newOptionId}` ); }; export const getPost = async (postId: number): Promise => { - return await getFetch(`/posts/${postId}`); + const post = await getFetch(`${BASE_URL}/posts/${postId}`); + + return transformPostResponse(post); }; export const createPost = async (newPost: FormData) => { @@ -35,13 +64,13 @@ export const createPost = async (newPost: FormData) => { }; export const editPost = async (postId: number, updatedPost: FormData) => { - return await multiPutFetch(`http://3.35.232.54/api/posts/${postId}`, updatedPost); + return await multiPutFetch(`${BASE_URL}/posts/${postId}`, updatedPost); }; export const removePost = async (postId: number) => { - return await deleteFetch(`/posts/${postId}`); + return await deleteFetch(`${BASE_URL}/posts/${postId}`); }; export const setEarlyClosePost = async (postId: number) => { - return await patchFetch(`/posts/${postId}/close`); + return await patchFetch(`${BASE_URL}/posts/${postId}/close`); }; diff --git a/frontend/src/api/postList.ts b/frontend/src/api/postList.ts index b5aaa1189..089623883 100644 --- a/frontend/src/api/postList.ts +++ b/frontend/src/api/postList.ts @@ -1,4 +1,4 @@ -import { PostInfo, PostListByOptionalOption, PostListByRequiredOption } from '@type/post'; +import { PostInfoResponse, PostListByOptionalOption, PostListByRequiredOption } from '@type/post'; import { REQUEST_STATUS_OPTION, @@ -10,7 +10,9 @@ import { import { getFetch } from '@utils/fetch'; -const BASE_URL = process.env.VOTOGETHER_MOCKING_URL; +import { transformPostResponse } from './post'; + +const BASE_URL = process.env.VOTOGETHER_BASE_URL; export const makePostListUrl = ( requiredOption: PostListByRequiredOption, @@ -44,10 +46,10 @@ export const getPostList = async ( const postListUrl = makePostListUrl(requiredOption, optionalOption); - const postList = await getFetch(postListUrl); + const postList = await getFetch(postListUrl); return { pageNumber, - postList, + postList: postList.map(post => transformPostResponse(post)), }; }; diff --git a/frontend/src/api/wus/userInfo.ts b/frontend/src/api/userInfo.ts similarity index 93% rename from frontend/src/api/wus/userInfo.ts rename to frontend/src/api/userInfo.ts index e712fc403..023ca2e83 100644 --- a/frontend/src/api/wus/userInfo.ts +++ b/frontend/src/api/userInfo.ts @@ -16,7 +16,7 @@ export const transformUserInfoResponse = (userInfo: UserInfoResponse): User => { const BASE_URL = process.env.VOTOGETHER_BASE_URL; -export const getUserInfo = async () => { +export const getUserInfo = async (): Promise => { const userInfo = await getFetch(`${BASE_URL}/members/me`); return transformUserInfoResponse(userInfo); diff --git a/frontend/src/api/voteResult.ts b/frontend/src/api/voteResult.ts index d6bce671d..614ba5e0f 100644 --- a/frontend/src/api/voteResult.ts +++ b/frontend/src/api/voteResult.ts @@ -2,8 +2,10 @@ import { VoteResult } from '@components/VoteStatistics/type'; import { getFetch } from '@utils/fetch'; +const BASE_URL = process.env.VOTOGETHER_BASE_URL; + export const getPostStatistics = async (postId: number): Promise => { - return await getFetch(`/posts/${postId}/options`); + return await getFetch(`${BASE_URL}/posts/${postId}/options`); }; export const getOptionStatistics = async ({ @@ -13,5 +15,5 @@ export const getOptionStatistics = async ({ postId: number; optionId: number; }): Promise => { - return await getFetch(`/posts/${postId}/options/${optionId}`); + return await getFetch(`${BASE_URL}/posts/${postId}/options/${optionId}`); }; diff --git a/frontend/src/components/PostForm/PostForm.stories.tsx b/frontend/src/components/PostForm/PostForm.stories.tsx index e9b255a38..13fe3863b 100644 --- a/frontend/src/components/PostForm/PostForm.stories.tsx +++ b/frontend/src/components/PostForm/PostForm.stories.tsx @@ -25,8 +25,8 @@ const MOCK_DATA: PostInfo = { { id: 13217, name: '게임' }, { id: 13219, name: '연예' }, ], - startTime: '2023-07-18 12:40', - endTime: '2023-08-15 12:40', + createTime: '2023-07-18 12:40', + deadline: '2023-08-15 12:40', voteInfo: { selectedOptionId: 1, allPeopleCount: 0, diff --git a/frontend/src/components/PostForm/index.tsx b/frontend/src/components/PostForm/index.tsx index c88ec73c5..2589ffb0a 100644 --- a/frontend/src/components/PostForm/index.tsx +++ b/frontend/src/components/PostForm/index.tsx @@ -1,10 +1,12 @@ import type { UseMutateFunction } from '@tanstack/react-query'; -import React, { HTMLAttributes, useState } from 'react'; +import React, { HTMLAttributes, useContext, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { PostInfo } from '@type/post'; +import { AuthContext } from '@hooks/context/auth'; +import { useCategoryList } from '@hooks/query/category/useCategoryList'; import { useContentImage } from '@hooks/useContentImage'; import { useMultiSelect } from '@hooks/useMultiSelect'; import { useText } from '@hooks/useText'; @@ -20,9 +22,9 @@ import WritingVoteOptionList from '@components/optionList/WritingVoteOptionList' import { POST_DESCRIPTION_MAX_LENGTH, POST_TITLE_MAX_LENGTH } from '@constants/post'; +import { changeCategoryToOption } from '@utils/post/changeCategoryToOption'; import { addTimeToDate, formatTimeWithOption } from '@utils/post/formatTime'; - -import { MOCK_CATEGORY_LIST } from '@mocks/mockData/categoryList'; +import { getDeadlineTime } from '@utils/post/getDeadlineTime'; import { DEADLINE_OPTION } from './constants'; import ContentImagePart from './ContentImageSection'; @@ -44,8 +46,8 @@ export default function PostForm({ data, mutate, isError, error }: PostFormProps title, content, category: categoryIds, - startTime, - endTime: deadline, + createTime, + deadline, voteInfo, imageUrl, } = data ?? {}; @@ -53,6 +55,8 @@ export default function PostForm({ data, mutate, isError, error }: PostFormProps const navigate = useNavigate(); const writingOptionHook = useWritingOption(voteInfo?.options); const contentImageHook = useContentImage(imageUrl); + const { isLogged } = useContext(AuthContext).loggedInfo; + const { data: categoryList } = useCategoryList(isLogged); const { isOpen, openComponent, closeComponent } = useToggle(); const [time, setTime] = useState({ @@ -60,7 +64,7 @@ export default function PostForm({ data, mutate, isError, error }: PostFormProps hour: 0, minute: 0, }); - const baseTime = startTime ? new Date(startTime) : new Date(); + const baseTime = createTime ? new Date(createTime) : new Date(); const { text: writingTitle, handleTextChange: handleTitleChange } = useText(title ?? ''); const { text: writingContent, handleTextChange: handleContentChange } = useText(content ?? ''); @@ -69,6 +73,8 @@ export default function PostForm({ data, mutate, isError, error }: PostFormProps CATEGORY_COUNT_LIMIT ); + const categoryOptionList = changeCategoryToOption(categoryList ?? []); + const handleDeadlineButtonClick = (option: string) => { setTime(formatTimeWithOption(option)); }; @@ -143,36 +149,6 @@ export default function PostForm({ data, mutate, isError, error }: PostFormProps } }; - const getDeadlineTime = ({ - day, - hour, - minute, - }: { - day: number; - hour: number; - minute: number; - }) => { - const timeMessage = []; - - if (day === 0 && hour === 0 && minute === 0) { - return '마감 시간을 선택해주세요'; - } - - if (day > 0) { - timeMessage.push(`${day}일`); - } - - if (hour > 0) { - timeMessage.push(`${hour}시간`); - } - - if (minute > 0) { - timeMessage.push(`${minute}분`); - } - - return `${timeMessage.join(' ')} 후에 마감됩니다.`; - }; - return ( <> @@ -188,7 +164,7 @@ export default function PostForm({ data, mutate, isError, error }: PostFormProps - 글 작성일({startTime})로부터 하루 이후 ( + 글 작성일({createTime})로부터 하루 이후 ( {addTimeToDate({ day: 1, hour: 0, minute: 0 }, baseTime)})까지만 선택 가능합니다. diff --git a/frontend/src/components/common/Layout/index.tsx b/frontend/src/components/common/Layout/index.tsx index 9438d9aa7..6cba03095 100644 --- a/frontend/src/components/common/Layout/index.tsx +++ b/frontend/src/components/common/Layout/index.tsx @@ -2,12 +2,11 @@ import { PropsWithChildren, useContext } from 'react'; import { useNavigate } from 'react-router-dom'; import { AuthContext } from '@hooks/context/auth'; +import { useCategoryList } from '@hooks/query/category/useCategoryList'; import Dashboard from '@components/common/Dashboard'; import WideHeader from '@components/common/WideHeader'; -import { MOCK_FAVORITE_CATEGORIES } from '@mocks/mockData/category'; - import * as S from './style'; interface LayoutProps extends PropsWithChildren { @@ -19,7 +18,7 @@ export default function Layout({ children, isSidebarVisible }: LayoutProps) { const { loggedInfo } = useContext(AuthContext); - const categoryList = MOCK_FAVORITE_CATEGORIES; + const { data: categoryList } = useCategoryList(loggedInfo.isLogged); const selectedCategory = undefined; const handleLogoutClick = () => {}; @@ -37,7 +36,7 @@ export default function Layout({ children, isSidebarVisible }: LayoutProps) { diff --git a/frontend/src/components/common/Post/index.tsx b/frontend/src/components/common/Post/index.tsx index 8ce8366bc..8e58aa984 100644 --- a/frontend/src/components/common/Post/index.tsx +++ b/frontend/src/components/common/Post/index.tsx @@ -15,7 +15,7 @@ interface PostProps { } export default function Post({ postInfo, isPreview }: PostProps) { - const { postId, category, title, writer, startTime, endTime, content, voteInfo } = postInfo; + const { postId, category, title, writer, createTime, deadline, content, voteInfo } = postInfo; const handleVoteClick = (newOptionId: number) => { if (voteInfo.selectedOptionId === newOptionId) return; @@ -34,13 +34,13 @@ export default function Post({ postInfo, isPreview }: PostProps) { return ( - {category.map(category => category.name).join(' | ')} + {category?.map(category => category.name).join(' | ')} {title} {writer.nickname} - {startTime} - {endTime} + {createTime} + {deadline} {content} diff --git a/frontend/src/components/common/Post/mockData.ts b/frontend/src/components/common/Post/mockData.ts index 45081314e..0395adeb1 100644 --- a/frontend/src/components/common/Post/mockData.ts +++ b/frontend/src/components/common/Post/mockData.ts @@ -25,8 +25,8 @@ export const MOCK_NOT_VOTE_POST: PostInfo = { name: '상담', }, ], - startTime: '2023-07-12 12:40', - endTime: '2023-07-20 18:40', + createTime: '2023-07-12 12:40', + deadline: '2023-07-20 18:40', voteInfo: { selectedOptionId: 0, allPeopleCount: 100, @@ -88,8 +88,8 @@ export const MOCK_VOTE_POST: PostInfo = { name: '상담', }, ], - startTime: '2023-07-12 12:40', - endTime: '2023-07-21 18:40', + createTime: '2023-07-12 12:40', + deadline: '2023-07-21 18:40', voteInfo: { selectedOptionId: 12312, allPeopleCount: 123, diff --git a/frontend/src/hooks/context/auth.tsx b/frontend/src/hooks/context/auth.tsx index f94924615..586d96c95 100644 --- a/frontend/src/hooks/context/auth.tsx +++ b/frontend/src/hooks/context/auth.tsx @@ -28,7 +28,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { useEffect(() => { const accessToken = getCookieToken().accessToken; - if (accessToken) setLoggedInfo(origin => ({ ...origin, accessToken })); + if (accessToken) setLoggedInfo(origin => ({ ...origin, accessToken, isLogged: true })); }, []); return ( diff --git a/frontend/src/hooks/query/category/useCategoryFavoriteToggle.ts b/frontend/src/hooks/query/category/useCategoryFavoriteToggle.ts index 63eca3657..6c45fd49a 100644 --- a/frontend/src/hooks/query/category/useCategoryFavoriteToggle.ts +++ b/frontend/src/hooks/query/category/useCategoryFavoriteToggle.ts @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Category } from '@type/category'; -import { addFavoriteCategory, removeFavoriteCategory } from '@api/wus/categoryList'; +import { addFavoriteCategory, removeFavoriteCategory } from '@api/categoryList'; import { QUERY_KEY } from '@constants/queryKey'; diff --git a/frontend/src/hooks/query/category/useCategoryList.ts b/frontend/src/hooks/query/category/useCategoryList.ts index 41fb6af62..475f1e835 100644 --- a/frontend/src/hooks/query/category/useCategoryList.ts +++ b/frontend/src/hooks/query/category/useCategoryList.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query'; import { Category } from '@type/category'; -import { getGuestCategoryList, getUserCategoryList } from '@api/wus/categoryList'; +import { getGuestCategoryList, getUserCategoryList } from '@api/categoryList'; import { QUERY_KEY } from '@constants/queryKey'; diff --git a/frontend/src/hooks/query/usePostList.tsx b/frontend/src/hooks/query/usePostList.tsx index e5a477381..bb68705db 100644 --- a/frontend/src/hooks/query/usePostList.tsx +++ b/frontend/src/hooks/query/usePostList.tsx @@ -24,6 +24,7 @@ export const usePostList = ( return lastPage.pageNumber + 1; }, + suspense: true, } ); diff --git a/frontend/src/hooks/query/user/useUserInfo.ts b/frontend/src/hooks/query/user/useUserInfo.ts index 27a2e22de..3a93eac67 100644 --- a/frontend/src/hooks/query/user/useUserInfo.ts +++ b/frontend/src/hooks/query/user/useUserInfo.ts @@ -1,13 +1,13 @@ import { useQuery } from '@tanstack/react-query'; -import { UserInfoResponse } from '@type/user'; +import { User } from '@type/user'; -import { getUserInfo } from '@api/wus/userInfo'; +import { getUserInfo } from '@api/userInfo'; import { QUERY_KEY } from '@constants/queryKey'; export const useUserInfo = (isLogged: boolean) => { - const { data, error, isLoading, isError } = useQuery( + const { data, error, isLoading, isError } = useQuery( [QUERY_KEY.USER_INFO, isLogged], getUserInfo ); diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 0e00ec7b4..e494a44a0 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -5,13 +5,13 @@ import ReactDOM from 'react-dom/client'; import App from './App'; import { worker } from './mocks/worker'; -// if (process.env.NODE_ENV === 'development') { -// worker.start(); -// } +if (process.env.NODE_ENV === 'development') { + worker.start(); +} const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); root.render( - // - - // + + + ); diff --git a/frontend/src/mocks/wus/categoryList.ts b/frontend/src/mocks/categoryList.ts similarity index 100% rename from frontend/src/mocks/wus/categoryList.ts rename to frontend/src/mocks/categoryList.ts diff --git a/frontend/src/mocks/handlers.ts b/frontend/src/mocks/handlers.ts index a0768687a..ef1df12a0 100644 --- a/frontend/src/mocks/handlers.ts +++ b/frontend/src/mocks/handlers.ts @@ -1,11 +1,11 @@ +import { mockCategoryHandlers } from './categoryList'; import { mockComment } from './comment'; import { example } from './example/get'; import { mockVoteResult } from './getVoteDetail'; import { mockPost } from './post'; +import { mockPostList } from './postList'; +import { mockUserInfo } from './userInfo'; import { mockVote } from './vote'; -import { mockCategoryHandlers } from './wus/categoryList'; -import { mockPostList } from './wus/post'; -import { mockUserInfo } from './wus/userInfo'; export const handlers = [ ...example, diff --git a/frontend/src/mocks/mockData/post.ts b/frontend/src/mocks/mockData/post.ts index e361baeec..839ae3a2f 100644 --- a/frontend/src/mocks/mockData/post.ts +++ b/frontend/src/mocks/mockData/post.ts @@ -1,4 +1,6 @@ -export const MOCK_POST_INFO = { +import { PostInfo } from '@type/post'; + +export const MOCK_POST_INFO: PostInfo = { postId: 1, title: '어느 곳에서 정보를 찾아야 할지도 막막한 사람들을 위한, 심심풀이로 나의 취향과 남의 취향을 비교해보고 싶은 사람들을 위한 프로젝트', @@ -6,6 +8,7 @@ export const MOCK_POST_INFO = { id: 12121221, nickname: '우아한 잔치국수', }, + imageUrl: 'https://source.unsplash.com/random', content: '이는 사람들에게 재미와 정보, 두 가지를 줄 수 있습니다. 사람들은 MBTI, 밸런스게임처럼 나와 같은 사람들을 찾고, 나와 다른 사람들과 비교하는 것을 즐깁니다. 이를 컨텐츠화하여 보다 빠르게 질문하고 답변하며, 사람들의 반응을 확인할 수 있다면 사람들은 충분한 즐거움을 느낄 것입니다. 또한 20대가 많은 대학가에 창업을 하고 싶지만 20대의 의견을 모르겠을 때, 확실한 답은 아닐지라도 어느 정도의 가이드를 줄 수 있을 것입니다. 질문자에게 제공되는 성별/나이대별 투표 결과 정보는 질문자가 하고자 하는 의사결정의 근거가 될 수 있을 것입니다.', category: [ @@ -22,8 +25,8 @@ export const MOCK_POST_INFO = { name: '상담', }, ], - startTime: '2023-07-12 12:40', - endTime: '2023-07-13 18:40', + createTime: '2023-07-12 12:40', + deadline: '2023-07-13 18:40', voteInfo: { selectedOptionId: 2, allPeopleCount: 123, @@ -33,18 +36,21 @@ export const MOCK_POST_INFO = { text: '당선', peopleCount: 30, percent: 30, + imageUrl: '', }, { id: 123, text: 'votogether', peopleCount: 40, percent: 40, + imageUrl: 'https://source.unsplash.com/random', }, { id: 1234, text: '인스타그램, 블라인드와 같은 SNS의 형식을 차용합니다. 누군가는 글을 쓰고, 누군가는 반응합니다. 다만, 댓글은 없습니다. 투표로 자신의 의견을 표현하고 이를 사람들에게 보여줍니다.', peopleCount: 20, percent: 20, + imageUrl: 'https://source.unsplash.com/random', }, { id: 2, diff --git a/frontend/src/mocks/mockData/postList.ts b/frontend/src/mocks/mockData/postList.ts index ba85cf666..8a1d8d142 100644 --- a/frontend/src/mocks/mockData/postList.ts +++ b/frontend/src/mocks/mockData/postList.ts @@ -1,8 +1,10 @@ -import { PostInfo } from '@type/post'; +import { PostInfo, PostInfoResponse } from '@type/post'; -export const MOCK_POST_LIST: PostInfo[] = []; +import { transformPostResponse } from '@api/post'; -const getMockPost = () => ({ +export const MOCK_POST_LIST: PostInfoResponse[] = []; + +const getMockPost = (): PostInfoResponse => ({ postId: Math.floor(Math.random() * 100000), title: '어느 곳에서 정보를 찾아야 할지도 막막한 사람들을 위한, 심심풀이로 나의 취향과 남의 취향을 비교해보고 싶은 사람들을 위한 프로젝트', @@ -13,7 +15,7 @@ const getMockPost = () => ({ content: '이는 사람들에게 재미와 정보, 두 가지를 줄 수 있습니다. 사람들은 MBTI, 밸런스게임처럼 나와 같은 사람들을 찾고, 나와 다른 사람들과 비교하는 것을 즐깁니다. 이를 컨텐츠화하여 보다 빠르게 질문하고 답변하며, 사람들의 반응을 확인할 수 있다면 사람들은 충분한 즐거움을 느낄 것입니다. 또한 20대가 많은 대학가에 창업을 하고 싶지만 20대의 의견을 모르겠을 때, 확실한 답은 아닐지라도 어느 정도의 가이드를 줄 수 있을 것입니다. 질문자에게 제공되는 성별/나이대별 투표 결과 정보는 질문자가 하고자 하는 의사결정의 근거가 될 수 있을 것입니다.', imageUrl: '', - category: [ + categories: [ { id: 1, name: '개발', @@ -27,39 +29,40 @@ const getMockPost = () => ({ name: '상담', }, ], - startTime: '2023-07-12 12:40', - endTime: '2023-07-13 18:40', + createdAt: '2023-07-12 12:40', + deadline: '2023-07-13 18:40', voteInfo: { selectedOptionId: 9, - allPeopleCount: 123, + totalVoteCount: 123, options: [ { - id: 6, - text: '당선', - peopleCount: 30, - percent: 30, + optionId: 6, + content: '당선', + voteCount: 30, + votePercent: 30, imageUrl: '', }, { - id: 7, - text: 'votogether', - peopleCount: 40, - percent: 40, + optionId: 7, + content: 'votogether', + voteCount: 40, + votePercent: 40, imageUrl: '', }, { - id: 8, - text: '인스타그램, 블라인드와 같은 SNS의 형식을 차용합니다. 누군가는 글을 쓰고, 누군가는 반응합니다. 다만, 댓글은 없습니다. 투표로 자신의 의견을 표현하고 이를 사람들에게 보여줍니다.', - peopleCount: 20, + optionId: 8, + content: + '인스타그램, 블라인드와 같은 SNS의 형식을 차용합니다. 누군가는 글을 쓰고, 누군가는 반응합니다. 다만, 댓글은 없습니다. 투표로 자신의 의견을 표현하고 이를 사람들에게 보여줍니다.', + voteCount: 20, imageUrl: '', - percent: 20, + votePercent: 20, }, { - id: 9, - text: 'fun from choice, 오늘도 즐거운 한 표 ', + optionId: 9, + content: 'fun from choice, 오늘도 즐거운 한 표 ', imageUrl: 'https://source.unsplash.com/random', - peopleCount: 10, - percent: 10, + voteCount: 10, + votePercent: 10, }, ], }, @@ -68,3 +71,7 @@ const getMockPost = () => ({ for (let index = 0; index < 10; index += 1) { MOCK_POST_LIST.push(getMockPost()); } + +export const MOCK_TRANSFORM_POST_LIST: PostInfo[] = MOCK_POST_LIST.map(POST => + transformPostResponse(POST) +); diff --git a/frontend/src/mocks/post.ts b/frontend/src/mocks/post.ts index 7b271e0ac..0ed9d50ce 100644 --- a/frontend/src/mocks/post.ts +++ b/frontend/src/mocks/post.ts @@ -1,6 +1,30 @@ import { rest } from 'msw'; +import { MOCK_POST_INFO } from './mockData/post'; + export const mockPost = [ + rest.get('/posts/:postId', (req, res, ctx) => { + return res(ctx.delay(1000), ctx.status(200), ctx.json(MOCK_POST_INFO)); + }), + + rest.delete('/posts/:postId', (req, res, ctx) => { + return res( + ctx.delay(1000), + ctx.status(200), + ctx.json({ message: '게시글이 성공적으로 삭제되었습니다' }) + ); + }), + + rest.patch('/posts/:postId/close', (req, res, ctx) => { + MOCK_POST_INFO.deadline = '2023-07-13 18:40'; + + return res( + ctx.delay(1000), + ctx.status(200), + ctx.json({ message: '게시글이 성공적으로 조기 마감 되었습니다' }) + ); + }), + //게시글 작성 rest.post('/posts', (req, res, ctx) => { window.console.log('게시글 작성 완료', req.body); @@ -8,13 +32,13 @@ export const mockPost = [ return res( ctx.delay(1000), ctx.status(201), - ctx.json({ message: '게시글이 성공적으로 생성되었습니다!!' }) + ctx.json({ message: '게시글이 성공적으로 생성되었습니다' }) ); }), //게시글 수정 rest.put('/posts/:postId', (req, res, ctx) => { - window.console.log('게시글 수정 완료', req.body); + window.console.log('게시글 수정 완료되었습니다', req.body); return res( ctx.delay(1000), diff --git a/frontend/src/mocks/wus/post.ts b/frontend/src/mocks/postList.ts similarity index 100% rename from frontend/src/mocks/wus/post.ts rename to frontend/src/mocks/postList.ts diff --git a/frontend/src/mocks/sua/post.ts b/frontend/src/mocks/sua/post.ts deleted file mode 100644 index 9462f4d84..000000000 --- a/frontend/src/mocks/sua/post.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { rest } from 'msw'; - -import { PostInfo } from '@type/post'; - -const examplePost: PostInfo = { - postId: 1, - title: - '어느 곳에서 정보를 찾아야 할지도 막막한 사람들을 위한, 심심풀이로 나의 취향과 남의 취향을 비교해보고 싶은 사람들을 위한 프로젝트', - writer: { - id: 12121221, - nickname: '우아한 잔치국수', - }, - content: - '이는 사람들에게 재미와 정보, 두 가지를 줄 수 있습니다. 사람들은 MBTI, 밸런스게임처럼 나와 같은 사람들을 찾고, 나와 다른 사람들과 비교하는 것을 즐깁니다. 이를 컨텐츠화하여 보다 빠르게 질문하고 답변하며, 사람들의 반응을 확인할 수 있다면 사람들은 충분한 즐거움을 느낄 것입니다. 또한 20대가 많은 대학가에 창업을 하고 싶지만 20대의 의견을 모르겠을 때, 확실한 답은 아닐지라도 어느 정도의 가이드를 줄 수 있을 것입니다. 질문자에게 제공되는 성별/나이대별 투표 결과 정보는 질문자가 하고자 하는 의사결정의 근거가 될 수 있을 것입니다.', - imageUrl: '', - category: [ - { - id: 76767, - name: '개발', - }, - { - id: 74632, - name: '연애', - }, - { - id: 71347, - name: '상담', - }, - ], - startTime: '2023-07-12 12:40', - endTime: '2023-07-21 18:40', - voteInfo: { - selectedOptionId: 2, - allPeopleCount: 123, - options: [ - { - id: 12, - text: '당선', - peopleCount: 30, - percent: 30, - imageUrl: '', - }, - { - id: 123, - text: 'votogether', - peopleCount: 40, - percent: 40, - imageUrl: '', - }, - { - id: 1234, - text: '인스타그램, 블라인드와 같은 SNS의 형식을 차용합니다. 누군가는 글을 쓰고, 누군가는 반응합니다. 다만, 댓글은 없습니다. 투표로 자신의 의견을 표현하고 이를 사람들에게 보여줍니다.', - peopleCount: 20, - percent: 20, - imageUrl: '', - }, - { - id: 2, - text: 'fun from choice, 오늘도 즐거운 한 표 ', - imageUrl: 'https://source.unsplash.com/random', - peopleCount: 10, - percent: 10, - }, - ], - }, -}; - -export const getPostTest = [ - rest.get('/posts/:postId', (req, res, ctx) => { - return res(ctx.delay(1000), ctx.status(200), ctx.json(examplePost)); - }), - - rest.delete('/posts/:postId', (req, res, ctx) => { - return res(ctx.delay(1000), ctx.status(200), ctx.json({ message: 'ok' })); - }), - - rest.patch('/posts/:postId/close', (req, res, ctx) => { - examplePost.endTime = '2023-07-13 18:40'; - - return res(ctx.delay(1000), ctx.status(200), ctx.json({ message: 'ok' })); - }), -]; diff --git a/frontend/src/mocks/wus/userInfo.ts b/frontend/src/mocks/userInfo.ts similarity index 100% rename from frontend/src/mocks/wus/userInfo.ts rename to frontend/src/mocks/userInfo.ts diff --git a/frontend/src/pages/MyInfo/index.tsx b/frontend/src/pages/MyInfo/index.tsx index ac2a49bf3..ecba39835 100644 --- a/frontend/src/pages/MyInfo/index.tsx +++ b/frontend/src/pages/MyInfo/index.tsx @@ -1,7 +1,7 @@ +import { useContext } from 'react'; import { useNavigate } from 'react-router-dom'; -import { User } from '@type/user'; - +import { AuthContext } from '@hooks/context/auth'; import { useToggle } from '@hooks/useToggle'; import Accordion from '@components/common/Accordion'; @@ -18,13 +18,12 @@ export default function MyInfo() { const navigate = useNavigate(); const { isOpen, openComponent, closeComponent } = useToggle(); - // const { data: userInfo, error, isLoading, isError } = useUserInfo(); // 유저 정보 조회 관련 pr merge 필요 - const MOCK_USER_INFO: User = { - nickname: '우아한 코끼리', - postCount: 4, - voteCount: 128, - userPoint: 200, - }; + const { userInfo } = useContext(AuthContext).loggedInfo; + + if (!userInfo) { + navigate('/'); + return; + } return ( @@ -40,7 +39,7 @@ export default function MyInfo() { - + diff --git a/frontend/src/pages/post/EditPost/index.tsx b/frontend/src/pages/post/EditPost/index.tsx index 69033420e..939899af0 100644 --- a/frontend/src/pages/post/EditPost/index.tsx +++ b/frontend/src/pages/post/EditPost/index.tsx @@ -25,8 +25,8 @@ export default function EditPost() { { id: 13217, name: '게임' }, { id: 13219, name: '연예' }, ], - startTime: '2023-07-18 12:40', - endTime: '2023-08-15 12:40', + createTime: '2023-07-18 12:40', + deadline: '2023-08-15 12:40', voteInfo: { selectedOptionId: 1, allPeopleCount: 0, diff --git a/frontend/src/pages/post/PostDetail/index.tsx b/frontend/src/pages/post/PostDetail/index.tsx index 8e604cb11..56cfdf662 100644 --- a/frontend/src/pages/post/PostDetail/index.tsx +++ b/frontend/src/pages/post/PostDetail/index.tsx @@ -46,7 +46,7 @@ export default function PostDetailPage() { } const isWriter = postData.writer.id === userId; - const isClosed = checkClosedPost(postData.endTime); + const isClosed = checkClosedPost(postData.deadline); const movePage = { moveWritePostPage: () => { diff --git a/frontend/src/types/post.ts b/frontend/src/types/post.ts index 98e638ba1..5d2dd9e10 100644 --- a/frontend/src/types/post.ts +++ b/frontend/src/types/post.ts @@ -8,6 +8,14 @@ export interface WrittenVoteOptionType { imageUrl: string; } +export interface WrittenVoteOptionTypeResponse { + optionId: number; + content: string; + voteCount: number; + votePercent: number; + imageUrl: string; +} + export interface PostInfo { postId: number; title: string; @@ -15,8 +23,8 @@ export interface PostInfo { content: string; imageUrl: string; category: { id: number; name: string }[]; - startTime: string; - endTime: string; + createTime: string; + deadline: string; voteInfo: { selectedOptionId: number; allPeopleCount: number; @@ -24,6 +32,22 @@ export interface PostInfo { }; } +export interface PostInfoResponse { + postId: number; + title: string; + writer: { id: number; nickname: string }; + content: string; + imageUrl: string; + categories: { id: number; name: string }[]; + createdAt: string; + deadline: string; + voteInfo: { + selectedOptionId: number; + totalVoteCount: number; + options: WrittenVoteOptionTypeResponse[]; + }; +} + export interface PostList { pageNumber: number; postList: PostInfo[]; diff --git a/frontend/src/types/user.ts b/frontend/src/types/user.ts index 2bc5ed5fe..a81a4cd03 100644 --- a/frontend/src/types/user.ts +++ b/frontend/src/types/user.ts @@ -18,9 +18,8 @@ export interface ModifyNicknameRequest { nickname: string; } - export interface LoggedInfo { accessToken: string; isLogged: boolean; - userInfo?: UserInfoResponse; + userInfo?: User; } diff --git a/frontend/src/utils/post/changeCategoryToOption.ts b/frontend/src/utils/post/changeCategoryToOption.ts new file mode 100644 index 000000000..54fd1cb00 --- /dev/null +++ b/frontend/src/utils/post/changeCategoryToOption.ts @@ -0,0 +1,7 @@ +import { Category } from '@type/category'; + +import { Option } from '@components/common/MultiSelect/types'; + +export const changeCategoryToOption = (categoryList: Category[]): Option[] => { + return categoryList.map(category => ({ id: category.id, name: category.name })); +}; diff --git a/frontend/src/utils/post/getDeadlineTime.ts b/frontend/src/utils/post/getDeadlineTime.ts new file mode 100644 index 000000000..4952300ff --- /dev/null +++ b/frontend/src/utils/post/getDeadlineTime.ts @@ -0,0 +1,33 @@ +export const getDeadlineTime = ({ + day, + hour, + minute, +}: { + day: number; + hour: number; + minute: number; +}) => { + const timeMessage = []; + + if (day < 0 || hour < 0 || minute < 0) { + return '마감 시간을 다시 설정해주세요'; + } + + if (day === 0 && hour === 0 && minute === 0) { + return '마감 시간을 선택해주세요'; + } + + if (day > 0) { + timeMessage.push(`${day}일`); + } + + if (hour > 0) { + timeMessage.push(`${hour}시간`); + } + + if (minute > 0) { + timeMessage.push(`${minute}분`); + } + + return `${timeMessage.join(' ')} 후에 마감됩니다.`; +}; diff --git a/frontend/src/utils/time.ts b/frontend/src/utils/time.ts index f15736a55..b33ba3728 100644 --- a/frontend/src/utils/time.ts +++ b/frontend/src/utils/time.ts @@ -17,8 +17,8 @@ const convertTimeFromStringToNumber = (date: string) => { return Number([...datePieces, ...timePieces].join('')); }; -export const checkClosedPost = (endTime: string) => { +export const checkClosedPost = (deadline: string) => { const nowTimeNumber = convertNowTimeToNumber(); - const endTimeNumber = convertTimeFromStringToNumber(endTime); + const endTimeNumber = convertTimeFromStringToNumber(deadline); return nowTimeNumber >= endTimeNumber; };