From bbdb7d2520de57316c3dbb9af3630c39e6fece96 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sat, 3 Aug 2024 17:20:41 +0900 Subject: [PATCH 01/18] =?UTF-8?q?chore:=20LandingPage=EC=9D=98=20styles=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LandingPage/components/FormBody/index.tsx | 2 +- .../LandingPage/components/FormBody/styles.ts | 7 ++++ .../components/FormLayout/index.tsx | 3 +- .../components/FormLayout/styles.ts | 14 +++++++ .../components/ReviewAccessForm/index.tsx | 5 ++- .../components/ReviewAccessForm/styles.ts | 23 +++++++++++ frontend/src/pages/LandingPage/styles.ts | 41 ------------------- 7 files changed, 50 insertions(+), 45 deletions(-) create mode 100644 frontend/src/pages/LandingPage/components/FormBody/styles.ts create mode 100644 frontend/src/pages/LandingPage/components/FormLayout/styles.ts create mode 100644 frontend/src/pages/LandingPage/components/ReviewAccessForm/styles.ts diff --git a/frontend/src/pages/LandingPage/components/FormBody/index.tsx b/frontend/src/pages/LandingPage/components/FormBody/index.tsx index ba647f06a..bb43455b1 100644 --- a/frontend/src/pages/LandingPage/components/FormBody/index.tsx +++ b/frontend/src/pages/LandingPage/components/FormBody/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { EssentialPropsWithChildren } from '@/types'; -import * as S from '../../styles'; +import * as S from './styles'; interface FormBodyProps { direction: React.CSSProperties['flexDirection']; diff --git a/frontend/src/pages/LandingPage/components/FormBody/styles.ts b/frontend/src/pages/LandingPage/components/FormBody/styles.ts new file mode 100644 index 000000000..d80533e34 --- /dev/null +++ b/frontend/src/pages/LandingPage/components/FormBody/styles.ts @@ -0,0 +1,7 @@ +import styled from '@emotion/styled'; + +export const FormBody = styled.div<{ direction: React.CSSProperties['flexDirection'] }>` + display: flex; + flex-direction: ${({ direction }) => direction}; + gap: 1.6em; +`; diff --git a/frontend/src/pages/LandingPage/components/FormLayout/index.tsx b/frontend/src/pages/LandingPage/components/FormLayout/index.tsx index 343ed3bde..881b31931 100644 --- a/frontend/src/pages/LandingPage/components/FormLayout/index.tsx +++ b/frontend/src/pages/LandingPage/components/FormLayout/index.tsx @@ -2,9 +2,10 @@ import React from 'react'; import { EssentialPropsWithChildren } from '@/types'; -import * as S from '../../styles'; import FormBody from '../FormBody'; +import * as S from './styles'; + interface FormProps { title: string; direction: React.CSSProperties['flexDirection']; diff --git a/frontend/src/pages/LandingPage/components/FormLayout/styles.ts b/frontend/src/pages/LandingPage/components/FormLayout/styles.ts new file mode 100644 index 000000000..eea9210cd --- /dev/null +++ b/frontend/src/pages/LandingPage/components/FormLayout/styles.ts @@ -0,0 +1,14 @@ +import styled from '@emotion/styled'; + +export const FormLayout = styled.form` + display: flex; + flex-direction: column; + + width: 40rem; +`; + +export const Title = styled.h2` + font-size: ${({ theme }) => theme.fontSize.basic}; + + margin-bottom: 2.2rem; +`; diff --git a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx index 4e2690fe5..e508fa17a 100644 --- a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx @@ -6,9 +6,10 @@ import { Input, Button } from '@/components'; import { useGroupAccessCode } from '@/hooks'; import { debounce } from '@/utils/debounce'; -import * as S from '../../styles'; import FormLayout from '../FormLayout'; +import * as S from './styles'; + const DEBOUNCE_TIME = 300; const ReviewAccessForm = () => { @@ -36,7 +37,7 @@ const ReviewAccessForm = () => { if (isValid) { updateGroupAccessCode(groupAccessCode); setErrorMessage(''); - + navigate('/user/review-preview-list'); } else { setErrorMessage('유효하지 않은 그룹 접근 코드입니다.'); diff --git a/frontend/src/pages/LandingPage/components/ReviewAccessForm/styles.ts b/frontend/src/pages/LandingPage/components/ReviewAccessForm/styles.ts new file mode 100644 index 000000000..88d472e8f --- /dev/null +++ b/frontend/src/pages/LandingPage/components/ReviewAccessForm/styles.ts @@ -0,0 +1,23 @@ +import styled from '@emotion/styled'; + +export const ReviewAccessFormContent = styled.div` + display: flex; + flex-direction: column; + + width: 100%; +`; + +export const ReviewAccessFormBody = styled.div` + display: flex; + justify-content: space-between; + + width: 100%; +`; + +export const ErrorMessage = styled.p` + font-size: 1.3rem; + + color: ${({ theme }) => theme.colors.red}; + + padding-left: 0.7rem; +`; diff --git a/frontend/src/pages/LandingPage/styles.ts b/frontend/src/pages/LandingPage/styles.ts index eb85951f2..942e32173 100644 --- a/frontend/src/pages/LandingPage/styles.ts +++ b/frontend/src/pages/LandingPage/styles.ts @@ -7,44 +7,3 @@ export const LandingPage = styled.div` margin-top: 4rem; `; - -export const FormLayout = styled.form` - display: flex; - flex-direction: column; - - width: 40rem; -`; - -export const Title = styled.h2` - font-size: ${({ theme }) => theme.fontSize.basic}; - - margin-bottom: 2.2rem; -`; - -export const ReviewAccessFormContent = styled.div` - display: flex; - flex-direction: column; - - width: 100%; -`; - -export const ReviewAccessFormBody = styled.div` - display: flex; - justify-content: space-between; - - width: 100%; -`; - -export const FormBody = styled.div<{ direction: React.CSSProperties['flexDirection'] }>` - display: flex; - flex-direction: ${({ direction }) => direction}; - gap: 1.6em; -`; - -export const ErrorMessage = styled.p` - font-size: 1.3rem; - - color: ${({ theme }) => theme.colors.red}; - - padding-left: 0.7rem; -`; From bf4f592c134f881e72fb42420fe0d11daf63d276 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sat, 3 Aug 2024 19:53:03 +0900 Subject: [PATCH 02/18] =?UTF-8?q?fix:=20POST=20=EC=9A=94=EC=B2=AD=EC=9D=84?= =?UTF-8?q?=20=ED=95=98=EB=8A=94=20=ED=95=A8=EC=88=98=EC=9D=98=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=EC=9D=84=20post~=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/endpoints.ts | 2 +- frontend/src/apis/group.ts | 4 ++-- frontend/src/mocks/handlers/group.ts | 23 +++++++++++++++++++ .../components/URLGeneratorForm/index.tsx | 4 ++-- 4 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 frontend/src/mocks/handlers/group.ts diff --git a/frontend/src/apis/endpoints.ts b/frontend/src/apis/endpoints.ts index ab5e0ebb4..4d32438cc 100644 --- a/frontend/src/apis/endpoints.ts +++ b/frontend/src/apis/endpoints.ts @@ -18,7 +18,7 @@ const endPoint = { gettingDataToWriteReview: (reviewRequestCode: string) => `${process.env.API_BASE_URL}/reviews/write?${REVIEW_WRITING_API_PARAMS.queryString.reviewRequestCode}=${reviewRequestCode}`, gettingReviewList: `${process.env.API_BASE_URL}/reviews`, - gettingCreatedGroupData: `${process.env.API_BASE_URL}/groups`, + postingCreatedGroupData: `${process.env.API_BASE_URL}/groups`, }; export default endPoint; diff --git a/frontend/src/apis/group.ts b/frontend/src/apis/group.ts index d276dbce1..51c8e0681 100644 --- a/frontend/src/apis/group.ts +++ b/frontend/src/apis/group.ts @@ -6,8 +6,8 @@ interface DataForURL { projectName: string; } -export const getCreatedGroupDataApi = async (dataForURL: DataForURL) => { - const response = await fetch(endPoint.gettingCreatedGroupData, { +export const postCreatedGroupDataApi = async (dataForURL: DataForURL) => { + const response = await fetch(endPoint.postingCreatedGroupData, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/frontend/src/mocks/handlers/group.ts b/frontend/src/mocks/handlers/group.ts new file mode 100644 index 000000000..e10c1a6f0 --- /dev/null +++ b/frontend/src/mocks/handlers/group.ts @@ -0,0 +1,23 @@ +import { http, HttpResponse } from 'msw'; + +import endPoint from '@/apis/endpoints'; + +import { CREATED_GROUP_DATA } from '../mockData/createdGroupData'; + +const postCreatedGroupData = () => { + return http.post( + endPoint.postingCreatedGroupData, + async () => { + return HttpResponse.json(CREATED_GROUP_DATA, { status: 200 }); + }, + ); +}; + +// const postCreatedGroupData = () => +// http.post(endPoint.postingCreatedGroupData, async (req, res, ctx) => { +// return HttpResponse.json(CREATED_GROUP_DATA, { status: 200 }); +// }); + +const groupHandler = [postCreatedGroupData()]; + +export default groupHandler; diff --git a/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx b/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx index fa2aab0d8..90ca3fb4f 100644 --- a/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; -import { getCreatedGroupDataApi } from '@/apis/group'; +import { postCreatedGroupDataApi } from '@/apis/group'; import { Button, Input } from '@/components'; import { useGroupAccessCode } from '@/hooks'; import { debounce } from '@/utils/debounce'; @@ -28,7 +28,7 @@ const URLGeneratorForm = () => { projectName: projectName, }; - const data = await getCreatedGroupDataApi(dataForURL); + const data = await postCreatedGroupDataApi(dataForURL); if (data) { const completeURL = getCompleteURL(data.reviewRequestCode); From d9fef2964074f34cac09070394b8293617c7aaf1 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sat, 3 Aug 2024 19:53:38 +0900 Subject: [PATCH 03/18] =?UTF-8?q?feat:=20=EA=B7=B8=EB=A3=B9=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=83=9D=EC=84=B1=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=9C=20MSW=20=ED=95=B8=EB=93=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/mocks/handlers/index.ts | 3 ++- frontend/src/mocks/mockData/createdGroupData.ts | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 frontend/src/mocks/mockData/createdGroupData.ts diff --git a/frontend/src/mocks/handlers/index.ts b/frontend/src/mocks/handlers/index.ts index 8bb8e8612..52f58c559 100644 --- a/frontend/src/mocks/handlers/index.ts +++ b/frontend/src/mocks/handlers/index.ts @@ -1,5 +1,6 @@ +import groupHandler from './group'; import reviewHandler from './review'; -const handlers = [...reviewHandler]; +const handlers = [...reviewHandler, ...groupHandler]; export default handlers; diff --git a/frontend/src/mocks/mockData/createdGroupData.ts b/frontend/src/mocks/mockData/createdGroupData.ts new file mode 100644 index 000000000..f1f6da5c9 --- /dev/null +++ b/frontend/src/mocks/mockData/createdGroupData.ts @@ -0,0 +1,4 @@ +export const CREATED_GROUP_DATA = { + reviewRequestCode: 'AbCdE', + groupAccessCode: 'a1b2c3', +}; From 8df4ef3354556cca9b030476590e5bdefa61c498 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sat, 3 Aug 2024 19:56:15 +0900 Subject: [PATCH 04/18] =?UTF-8?q?refactor:=20=EB=AA=A8=ED=82=B9=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EA=B0=92=EC=9D=84=20=EB=8D=94=20?= =?UTF-8?q?=EC=A7=81=EA=B4=80=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/mocks/mockData/createdGroupData.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/mocks/mockData/createdGroupData.ts b/frontend/src/mocks/mockData/createdGroupData.ts index f1f6da5c9..445d60d34 100644 --- a/frontend/src/mocks/mockData/createdGroupData.ts +++ b/frontend/src/mocks/mockData/createdGroupData.ts @@ -1,4 +1,4 @@ export const CREATED_GROUP_DATA = { - reviewRequestCode: 'AbCdE', - groupAccessCode: 'a1b2c3', + reviewRequestCode: 'mocked-reviewRequestCode', + groupAccessCode: 'mocked-groupAccessCode', }; From fec364e77ef3c90e28a39ade7353f1b0980bf9e1 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sun, 4 Aug 2024 14:12:57 +0900 Subject: [PATCH 05/18] =?UTF-8?q?refactor:=20LandingPage=EB=A5=BC=20ErrorS?= =?UTF-8?q?uspenseContainer=EA=B0=80=20=EA=B0=90=EC=8B=B8=EB=8F=84?= =?UTF-8?q?=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/src/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 7b2ca4511..36c73391e 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -7,6 +7,7 @@ import { RecoilRoot } from 'recoil'; import App from '@/App'; +import ErrorSuspenseContainer from './components/error/ErrorSuspenseContainer/index'; import DetailedReviewPage from './pages/DetailedReviewPage'; import ErrorPage from './pages/ErrorPage'; import LandingPage from './pages/LandingPage'; @@ -52,7 +53,11 @@ const router = createBrowserRouter([ }, { path: 'home', - element: , + element: ( + + + + ), }, ], }, From 269655ebf6bdf4a85918b61fba6f054e401b5103 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sun, 4 Aug 2024 14:16:29 +0900 Subject: [PATCH 06/18] =?UTF-8?q?refactor:=20URL=EC=9D=84=20=EC=96=BB?= =?UTF-8?q?=EC=96=B4=EC=98=A4=EB=8A=94=20API=EC=97=90=20react-query=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=20=EB=B0=8F=20API=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=9D=B4=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/endpoints.ts | 2 +- frontend/src/apis/group.ts | 6 +-- frontend/src/constants/queryKeys.ts | 5 +++ frontend/src/mocks/handlers/group.ts | 21 +++++---- .../components/URLGeneratorForm/index.tsx | 45 +++++++++---------- .../LandingPage/queries/usePostDataForURL.ts | 22 +++++++++ 6 files changed, 61 insertions(+), 40 deletions(-) create mode 100644 frontend/src/pages/LandingPage/queries/usePostDataForURL.ts diff --git a/frontend/src/apis/endpoints.ts b/frontend/src/apis/endpoints.ts index 4d32438cc..8403060d9 100644 --- a/frontend/src/apis/endpoints.ts +++ b/frontend/src/apis/endpoints.ts @@ -18,7 +18,7 @@ const endPoint = { gettingDataToWriteReview: (reviewRequestCode: string) => `${process.env.API_BASE_URL}/reviews/write?${REVIEW_WRITING_API_PARAMS.queryString.reviewRequestCode}=${reviewRequestCode}`, gettingReviewList: `${process.env.API_BASE_URL}/reviews`, - postingCreatedGroupData: `${process.env.API_BASE_URL}/groups`, + postingDataForURL: `${process.env.API_BASE_URL}/groups`, }; export default endPoint; diff --git a/frontend/src/apis/group.ts b/frontend/src/apis/group.ts index 51c8e0681..30071bfff 100644 --- a/frontend/src/apis/group.ts +++ b/frontend/src/apis/group.ts @@ -1,13 +1,13 @@ import createApiErrorMessage from './apiErrorMessageCreator'; import endPoint from './endpoints'; -interface DataForURL { +export interface DataForURL { revieweeName: string; projectName: string; } -export const postCreatedGroupDataApi = async (dataForURL: DataForURL) => { - const response = await fetch(endPoint.postingCreatedGroupData, { +export const postDataForURL = async (dataForURL: DataForURL) => { + const response = await fetch(endPoint.postingDataForURL, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/frontend/src/constants/queryKeys.ts b/frontend/src/constants/queryKeys.ts index 7df3e5730..6c6ba4756 100644 --- a/frontend/src/constants/queryKeys.ts +++ b/frontend/src/constants/queryKeys.ts @@ -1,4 +1,9 @@ +// TODO: 내용이 배열이 아니므로 단수형으로 수정하기 export const REVIEW_QUERY_KEYS = { detailedReview: 'detailedReview', reviews: 'reviews', }; + +export const GROUP_QUERY_KEY = { + dataForURL: 'dataForURL', +}; diff --git a/frontend/src/mocks/handlers/group.ts b/frontend/src/mocks/handlers/group.ts index e10c1a6f0..59548fb88 100644 --- a/frontend/src/mocks/handlers/group.ts +++ b/frontend/src/mocks/handlers/group.ts @@ -4,20 +4,19 @@ import endPoint from '@/apis/endpoints'; import { CREATED_GROUP_DATA } from '../mockData/createdGroupData'; -const postCreatedGroupData = () => { - return http.post( - endPoint.postingCreatedGroupData, - async () => { - return HttpResponse.json(CREATED_GROUP_DATA, { status: 200 }); - }, - ); +const postDataForUrl = () => { + return http.post(endPoint.postingDataForURL, async () => { + return HttpResponse.json(CREATED_GROUP_DATA, { status: 200 }); + }); }; -// const postCreatedGroupData = () => -// http.post(endPoint.postingCreatedGroupData, async (req, res, ctx) => { -// return HttpResponse.json(CREATED_GROUP_DATA, { status: 200 }); +// NOTE: 에러 테스트용 핸들러 +// const postDataForUrl = () => { +// return http.post(endPoint.postingDataForURL, async () => { +// return HttpResponse.json({ error: '서버 에러 테스트' }, { status: 500 }); // }); +// }; -const groupHandler = [postCreatedGroupData()]; +const groupHandler = [postDataForUrl()]; export default groupHandler; diff --git a/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx b/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx index 90ca3fb4f..ce42842e8 100644 --- a/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx @@ -1,45 +1,32 @@ import { useState } from 'react'; -import { postCreatedGroupDataApi } from '@/apis/group'; +import { DataForURL } from '@/apis/group'; import { Button, Input } from '@/components'; import { useGroupAccessCode } from '@/hooks'; import { debounce } from '@/utils/debounce'; +import usePostDataForURL from '../../queries/usePostDataForURL'; import FormLayout from '../FormLayout'; import ReviewGroupDataModal from '../ReviewGroupDataModal'; +// TODO: 디바운스 시간을 모든 경우에 0.3초로 고정할 것인지(전역 상수로 사용) 논의하기 const DEBOUNCE_TIME = 300; const URLGeneratorForm = () => { - const [name, setName] = useState(''); + const [revieweeName, setRevieweeName] = useState(''); const [projectName, setProjectName] = useState(''); const [reviewRequestCode, setReviewRequestCode] = useState(''); const [isModalOpen, setIsModalOpen] = useState(false); + const mutation = usePostDataForURL(); const { updateGroupAccessCode } = useGroupAccessCode(); const getCompleteURL = (reviewRequestCode: string) => { return `${window.location.origin}/user/review-writing/${reviewRequestCode}`; }; - const getCreatedGroupData = async (name: string, projectName: string) => { - const dataForURL = { - revieweeName: name, - projectName: projectName, - }; - - const data = await postCreatedGroupDataApi(dataForURL); - - if (data) { - const completeURL = getCompleteURL(data.reviewRequestCode); - - setReviewRequestCode(completeURL); - updateGroupAccessCode(data.groupAccessCode); - } - }; - const handleNameInputChange = (value: string) => { - setName(value); + setRevieweeName(value); }; const handleProjectNameInputChange = (value: string) => { @@ -49,15 +36,23 @@ const URLGeneratorForm = () => { const handleUrlCreationButtonClick = debounce((event: React.MouseEvent) => { event.preventDefault(); - if (name && projectName) { - getCreatedGroupData(name, projectName); - setIsModalOpen(true); + if (revieweeName && projectName) { + const dataForURL: DataForURL = { revieweeName, projectName }; + + mutation.mutate(dataForURL, { + onSuccess: (data) => { + const completeURL = getCompleteURL(data.reviewRequestCode); + setReviewRequestCode(completeURL); + updateGroupAccessCode(data.groupAccessCode); + setIsModalOpen(true); + }, + }); } }, DEBOUNCE_TIME); return ( - + { /> diff --git a/frontend/src/pages/LandingPage/queries/usePostDataForURL.ts b/frontend/src/pages/LandingPage/queries/usePostDataForURL.ts new file mode 100644 index 000000000..99df4f964 --- /dev/null +++ b/frontend/src/pages/LandingPage/queries/usePostDataForURL.ts @@ -0,0 +1,22 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { DataForURL, postDataForURL } from '@/apis/group'; +import { GROUP_QUERY_KEY } from '@/constants'; + +const usePostDataForURL = () => { + const queryClient = useQueryClient(); + + const data = useMutation({ + mutationFn: (dataForURL: DataForURL) => postDataForURL(dataForURL), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: [GROUP_QUERY_KEY.dataForURL] }); + }, + onError: (error) => { + console.error(error.message); + }, + }); + + return data; +}; + +export default usePostDataForURL; From bc2efd82994d2e7b9c6631094d4142912532a299 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sun, 4 Aug 2024 14:27:31 +0900 Subject: [PATCH 07/18] =?UTF-8?q?chore:=20LandingPage=20=ED=95=98=EC=9C=84?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=93=A4=EC=9D=98=20ind?= =?UTF-8?q?ex=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/FormLayout/index.tsx | 2 +- .../components/ReviewAccessForm/index.tsx | 2 +- .../components/URLGeneratorForm/index.tsx | 30 +++++++++---------- .../src/pages/LandingPage/components/index.ts | 5 ++++ 4 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 frontend/src/pages/LandingPage/components/index.ts diff --git a/frontend/src/pages/LandingPage/components/FormLayout/index.tsx b/frontend/src/pages/LandingPage/components/FormLayout/index.tsx index 881b31931..2bcd60e75 100644 --- a/frontend/src/pages/LandingPage/components/FormLayout/index.tsx +++ b/frontend/src/pages/LandingPage/components/FormLayout/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { EssentialPropsWithChildren } from '@/types'; -import FormBody from '../FormBody'; +import { FormBody } from '../index'; import * as S from './styles'; diff --git a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx index e508fa17a..067004507 100644 --- a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx @@ -6,7 +6,7 @@ import { Input, Button } from '@/components'; import { useGroupAccessCode } from '@/hooks'; import { debounce } from '@/utils/debounce'; -import FormLayout from '../FormLayout'; +import { FormLayout } from '../index'; import * as S from './styles'; diff --git a/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx b/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx index ce42842e8..02ce282a8 100644 --- a/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx @@ -6,8 +6,7 @@ import { useGroupAccessCode } from '@/hooks'; import { debounce } from '@/utils/debounce'; import usePostDataForURL from '../../queries/usePostDataForURL'; -import FormLayout from '../FormLayout'; -import ReviewGroupDataModal from '../ReviewGroupDataModal'; +import { FormLayout, ReviewGroupDataModal } from '../index'; // TODO: 디바운스 시간을 모든 경우에 0.3초로 고정할 것인지(전역 상수로 사용) 논의하기 const DEBOUNCE_TIME = 300; @@ -21,6 +20,18 @@ const URLGeneratorForm = () => { const mutation = usePostDataForURL(); const { updateGroupAccessCode } = useGroupAccessCode(); + const postDataForURL = () => { + const dataForURL: DataForURL = { revieweeName, projectName }; + + mutation.mutate(dataForURL, { + onSuccess: (data) => { + const completeURL = getCompleteURL(data.reviewRequestCode); + setReviewRequestCode(completeURL); + updateGroupAccessCode(data.groupAccessCode); + }, + }); + }; + const getCompleteURL = (reviewRequestCode: string) => { return `${window.location.origin}/user/review-writing/${reviewRequestCode}`; }; @@ -35,19 +46,8 @@ const URLGeneratorForm = () => { const handleUrlCreationButtonClick = debounce((event: React.MouseEvent) => { event.preventDefault(); - - if (revieweeName && projectName) { - const dataForURL: DataForURL = { revieweeName, projectName }; - - mutation.mutate(dataForURL, { - onSuccess: (data) => { - const completeURL = getCompleteURL(data.reviewRequestCode); - setReviewRequestCode(completeURL); - updateGroupAccessCode(data.groupAccessCode); - setIsModalOpen(true); - }, - }); - } + postDataForURL(); + setIsModalOpen(true); }, DEBOUNCE_TIME); return ( diff --git a/frontend/src/pages/LandingPage/components/index.ts b/frontend/src/pages/LandingPage/components/index.ts new file mode 100644 index 000000000..fcc70af96 --- /dev/null +++ b/frontend/src/pages/LandingPage/components/index.ts @@ -0,0 +1,5 @@ +export { default as FormBody } from './FormBody'; +export { default as FormLayout } from './FormLayout'; +export { default as ReviewAccessForm } from './ReviewAccessForm'; +export { default as ReviewGroupDataModal } from './ReviewGroupDataModal'; +export { default as URLGeneratorForm } from './URLGeneratorForm'; From 117cb0e5664bc4ecbd8e62ec0d6e6f7e2c7d828e Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sun, 4 Aug 2024 17:50:22 +0900 Subject: [PATCH 08/18] =?UTF-8?q?refactor:=20groupAccessCode=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20msw=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20=EC=97=90=EB=9F=AC=20=EC=83=81=ED=83=9C?= =?UTF-8?q?(=EC=97=86=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=9E=85=EB=A0=A5,?= =?UTF-8?q?=20=EC=84=9C=EB=B2=84=20=EC=97=90=EB=9F=AC)=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=20=EC=97=90=EB=9F=AC=20=EB=A9=94=EC=84=B8?= =?UTF-8?q?=EC=A7=80=EB=A5=BC=20=EC=B6=9C=EB=A0=A5=ED=95=98=EB=8F=84?= =?UTF-8?q?=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/src/apis/group.ts | 20 ++++++++++++++++ frontend/src/apis/review.ts | 12 ---------- frontend/src/constants/errorMessage.ts | 2 ++ frontend/src/mocks/handlers/group.ts | 23 ++++++++++++++++--- .../src/mocks/mockData/createdGroupData.ts | 4 ---- frontend/src/mocks/mockData/group.ts | 12 ++++++++++ .../components/ReviewAccessForm/index.tsx | 18 +++++---------- 7 files changed, 60 insertions(+), 31 deletions(-) delete mode 100644 frontend/src/mocks/mockData/createdGroupData.ts create mode 100644 frontend/src/mocks/mockData/group.ts diff --git a/frontend/src/apis/group.ts b/frontend/src/apis/group.ts index 30071bfff..0cf83cba7 100644 --- a/frontend/src/apis/group.ts +++ b/frontend/src/apis/group.ts @@ -1,3 +1,5 @@ +import { API_ERROR_MESSAGE, INVALID_GROUP_ACCESS_CODE_MESSAGE } from '@/constants'; + import createApiErrorMessage from './apiErrorMessageCreator'; import endPoint from './endpoints'; @@ -22,3 +24,21 @@ export const postDataForURL = async (dataForURL: DataForURL) => { const data = await response.json(); return data; }; + +// NOTE: 리뷰 목록 엔드포인트(gettingReviewList)에 요청을 보내고 있지만, +// 요청 성격이 목록을 얻어오는 것이 아닌 유효한 groupAccessCode인지 확인하는 것이므로 group 파일에 작성함 +// 단, 해당 엔드포인트에 대한 정상 요청 핸들러가 동작한다면 아래 에러 핸들러는 동작하지 않음 +export const getIsValidGroupAccessCodeApi = async (groupAccessCode: string) => { + const response = await fetch(endPoint.gettingReviewList, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + GroupAccessCode: groupAccessCode, + }, + }); + + if (response.status === 400) throw new Error(INVALID_GROUP_ACCESS_CODE_MESSAGE); + if (response.status === 500) throw new Error(API_ERROR_MESSAGE.serverError); + + return response.ok; +}; diff --git a/frontend/src/apis/review.ts b/frontend/src/apis/review.ts index ed489997d..2b17d64ad 100644 --- a/frontend/src/apis/review.ts +++ b/frontend/src/apis/review.ts @@ -74,15 +74,3 @@ export const getReviewListApi = async (groupAccessCode: string) => { const data = await response.json(); return data as ReviewPreviewList; }; - -export const checkGroupAccessCodeApi = async (groupAccessCode: string) => { - const response = await fetch(endPoint.gettingReviewList, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - GroupAccessCode: groupAccessCode, - }, - }); - - return response.ok; -}; diff --git a/frontend/src/constants/errorMessage.ts b/frontend/src/constants/errorMessage.ts index 49d15e6df..aa61fcf09 100644 --- a/frontend/src/constants/errorMessage.ts +++ b/frontend/src/constants/errorMessage.ts @@ -15,3 +15,5 @@ export const API_ERROR_MESSAGE: ApiErrorMessages = { export const SERVER_ERROR_REGEX = /^5\d{2}$/; export const ROUTE_ERROR_MESSAGE = '찾으시는 페이지가 없어요.'; + +export const INVALID_GROUP_ACCESS_CODE_MESSAGE = '올바르지 않은 확인 코드예요.'; diff --git a/frontend/src/mocks/handlers/group.ts b/frontend/src/mocks/handlers/group.ts index 59548fb88..120253b3d 100644 --- a/frontend/src/mocks/handlers/group.ts +++ b/frontend/src/mocks/handlers/group.ts @@ -2,7 +2,7 @@ import { http, HttpResponse } from 'msw'; import endPoint from '@/apis/endpoints'; -import { CREATED_GROUP_DATA } from '../mockData/createdGroupData'; +import { CREATED_GROUP_DATA, INVALID_GROUP_ACCESS_CODE } from '../mockData/group'; const postDataForUrl = () => { return http.post(endPoint.postingDataForURL, async () => { @@ -10,13 +10,30 @@ const postDataForUrl = () => { }); }; -// NOTE: 에러 테스트용 핸들러 // const postDataForUrl = () => { // return http.post(endPoint.postingDataForURL, async () => { // return HttpResponse.json({ error: '서버 에러 테스트' }, { status: 500 }); // }); // }; -const groupHandler = [postDataForUrl()]; +const getIsValidGroupAccessCode = () => { + return http.get(endPoint.gettingReviewList, async () => { + return HttpResponse.json({ status: 200 }); + }); +}; + +// const getIsValidGroupAccessCode = () => { +// return http.get(endPoint.gettingReviewList, async () => { +// return HttpResponse.json(INVALID_GROUP_ACCESS_CODE, { status: 400 }); +// }); +// }; + +// const getIsValidGroupAccessCode = () => { +// return http.get(endPoint.gettingReviewList, async () => { +// return HttpResponse.json({ error: '서버 에러 테스트' }, { status: 500 }); +// }); +// }; + +const groupHandler = [postDataForUrl(), getIsValidGroupAccessCode()]; export default groupHandler; diff --git a/frontend/src/mocks/mockData/createdGroupData.ts b/frontend/src/mocks/mockData/createdGroupData.ts deleted file mode 100644 index 445d60d34..000000000 --- a/frontend/src/mocks/mockData/createdGroupData.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const CREATED_GROUP_DATA = { - reviewRequestCode: 'mocked-reviewRequestCode', - groupAccessCode: 'mocked-groupAccessCode', -}; diff --git a/frontend/src/mocks/mockData/group.ts b/frontend/src/mocks/mockData/group.ts new file mode 100644 index 000000000..cb7d0f55d --- /dev/null +++ b/frontend/src/mocks/mockData/group.ts @@ -0,0 +1,12 @@ +export const CREATED_GROUP_DATA = { + reviewRequestCode: 'mocked-reviewRequestCode', + groupAccessCode: 'mocked-groupAccessCode', +}; + +export const INVALID_GROUP_ACCESS_CODE = { + type: 'about:blank', + title: 'Bad Request', + status: 400, + detail: '올바르지 않은 확인 코드입니다.', + instance: '/reviews', +}; diff --git a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx index 067004507..e5917e966 100644 --- a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { useNavigate } from 'react-router'; -import { checkGroupAccessCodeApi } from '@/apis/review'; +import { getIsValidGroupAccessCodeApi } from '@/apis/group'; import { Input, Button } from '@/components'; import { useGroupAccessCode } from '@/hooks'; import { debounce } from '@/utils/debounce'; @@ -20,7 +20,7 @@ const ReviewAccessForm = () => { const [errorMessage, setErrorMessage] = useState(''); const isValidGroupAccessCode = async () => { - const isValid = await checkGroupAccessCodeApi(groupAccessCode); + const isValid = await getIsValidGroupAccessCodeApi(groupAccessCode); return isValid; }; @@ -32,18 +32,12 @@ const ReviewAccessForm = () => { event.preventDefault(); try { - const isValid = await isValidGroupAccessCode(); + await isValidGroupAccessCode(); - if (isValid) { - updateGroupAccessCode(groupAccessCode); - setErrorMessage(''); - - navigate('/user/review-preview-list'); - } else { - setErrorMessage('유효하지 않은 그룹 접근 코드입니다.'); - } + updateGroupAccessCode(groupAccessCode); + setErrorMessage(''); } catch (error) { - setErrorMessage('오류가 발생했습니다. 다시 시도해주세요.'); + if (error instanceof Error) setErrorMessage(error.message); } }, DEBOUNCE_TIME); From b118388609b52a33c982e89240d969359e255e8e Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sun, 4 Aug 2024 18:04:39 +0900 Subject: [PATCH 09/18] =?UTF-8?q?refactor:=20groupAccessCode=EC=97=90=20?= =?UTF-8?q?=EC=95=8C=ED=8C=8C=EB=B2=B3=20=EB=8C=80=EC=86=8C=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=EC=99=80=20=EC=88=AB=EC=9E=90=EB=A7=8C=20=EC=98=AC=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=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 --- .../LandingPage/components/ReviewAccessForm/index.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx index e5917e966..cb3a09795 100644 --- a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx @@ -24,6 +24,11 @@ const ReviewAccessForm = () => { return isValid; }; + const isAlphanumeric = (groupAccessCode: string) => { + const alphanumericRegex = /^[A-Za-z0-9]*$/; + return alphanumericRegex.test(groupAccessCode); + }; + const handleGroupAccessCodeInputChange = (value: string) => { setGroupAccessCode(value); }; @@ -32,10 +37,16 @@ const ReviewAccessForm = () => { event.preventDefault(); try { + if (!isAlphanumeric(groupAccessCode)) { + setErrorMessage('알파벳 대소문자와 숫자만 입력 가능합니다.'); + return; + } + await isValidGroupAccessCode(); updateGroupAccessCode(groupAccessCode); setErrorMessage(''); + navigate('/user/review-preview-list'); } catch (error) { if (error instanceof Error) setErrorMessage(error.message); } From 4ade792b569df96cd54c77867bfd876c1a93b117 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Mon, 5 Aug 2024 19:39:15 +0900 Subject: [PATCH 10/18] =?UTF-8?q?refactor:=20LandingPage=EC=97=90=EC=84=9C?= =?UTF-8?q?=20ErrorSuspenseContainer=EB=A5=BC=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=ED=95=98=EA=B3=A0=20=EB=8C=80=EC=8B=A0=20URLGeneratorForm?= =?UTF-8?q?=EB=A7=8C=EC=9D=84=20=EA=B0=90=EC=8B=B8=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/index.tsx | 51 ++++++++++++++++-------- frontend/src/pages/LandingPage/index.tsx | 6 ++- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 36c73391e..db4df174e 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -53,11 +53,7 @@ const router = createBrowserRouter([ }, { path: 'home', - element: ( - - - - ), + element: , }, ], }, @@ -65,15 +61,36 @@ const router = createBrowserRouter([ const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); -root.render( - - - - - - - - - - , -); +async function enableMocking() { + if (process.env.MSW) { + const { worker } = await import('./mocks/browser'); + return worker.start(); + } +} + +enableMocking().then(() => { + root.render( + + + + + + + + + + , + ); +}); +// root.render( +// +// +// +// +// +// +// +// +// +// , +// ); diff --git a/frontend/src/pages/LandingPage/index.tsx b/frontend/src/pages/LandingPage/index.tsx index 7a5c7ceda..313f095f0 100644 --- a/frontend/src/pages/LandingPage/index.tsx +++ b/frontend/src/pages/LandingPage/index.tsx @@ -1,3 +1,5 @@ +import { ErrorSuspenseContainer } from '@/components'; + import ReviewAccessForm from './components/ReviewAccessForm'; import URLGeneratorForm from './components/URLGeneratorForm'; import * as S from './styles'; @@ -5,7 +7,9 @@ import * as S from './styles'; const LandingPage = () => { return ( - + + + ); From cca5eb70df376072435542d589f65634ab5ace87 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Mon, 5 Aug 2024 19:40:41 +0900 Subject: [PATCH 11/18] =?UTF-8?q?refactor:=20Input=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=9D=98=20onChange=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/common/Input/index.tsx | 10 ++-------- .../LandingPage/components/ReviewAccessForm/index.tsx | 11 ++++++----- .../LandingPage/components/URLGeneratorForm/index.tsx | 8 ++++---- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/frontend/src/components/common/Input/index.tsx b/frontend/src/components/common/Input/index.tsx index beb373275..9773f92f2 100644 --- a/frontend/src/components/common/Input/index.tsx +++ b/frontend/src/components/common/Input/index.tsx @@ -5,20 +5,14 @@ export interface InputStyleProps { } interface InputProps extends InputStyleProps { value: string; - onChange: (value: string) => void; + onChange: (event: React.ChangeEvent) => void; type: string; id?: string; placeholder?: string; } const Input = ({ id, value, onChange, type, placeholder, $style }: InputProps) => { - const handleChange = (event: React.ChangeEvent) => { - onChange(event.target.value); - }; - - return ( - - ); + return ; }; export default Input; diff --git a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx index cb3a09795..b5d8b4fc3 100644 --- a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx @@ -13,12 +13,12 @@ import * as S from './styles'; const DEBOUNCE_TIME = 300; const ReviewAccessForm = () => { - const navigate = useNavigate(); - const { updateGroupAccessCode } = useGroupAccessCode(); - const [groupAccessCode, setGroupAccessCode] = useState(''); const [errorMessage, setErrorMessage] = useState(''); + const navigate = useNavigate(); + const { updateGroupAccessCode } = useGroupAccessCode(); + const isValidGroupAccessCode = async () => { const isValid = await getIsValidGroupAccessCodeApi(groupAccessCode); return isValid; @@ -29,8 +29,8 @@ const ReviewAccessForm = () => { return alphanumericRegex.test(groupAccessCode); }; - const handleGroupAccessCodeInputChange = (value: string) => { - setGroupAccessCode(value); + const handleGroupAccessCodeInputChange = (event: React.ChangeEvent) => { + setGroupAccessCode(event.target.value); }; const handleAccessReviewButtonClick = debounce(async (event: React.MouseEvent) => { @@ -46,6 +46,7 @@ const ReviewAccessForm = () => { updateGroupAccessCode(groupAccessCode); setErrorMessage(''); + navigate('/user/review-preview-list'); } catch (error) { if (error instanceof Error) setErrorMessage(error.message); diff --git a/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx b/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx index 02ce282a8..0f39a03de 100644 --- a/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx @@ -36,12 +36,12 @@ const URLGeneratorForm = () => { return `${window.location.origin}/user/review-writing/${reviewRequestCode}`; }; - const handleNameInputChange = (value: string) => { - setRevieweeName(value); + const handleNameInputChange = (event: React.ChangeEvent) => { + setRevieweeName(event.target.value); }; - const handleProjectNameInputChange = (value: string) => { - setProjectName(value); + const handleProjectNameInputChange = (event: React.ChangeEvent) => { + setProjectName(event.target.value); }; const handleUrlCreationButtonClick = debounce((event: React.MouseEvent) => { From 3ef4d310efa4a7c840dc4e190b626cde1fd8e804 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Mon, 5 Aug 2024 19:41:57 +0900 Subject: [PATCH 12/18] =?UTF-8?q?refactor:=20Input=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=20name=20=EC=86=8D=EC=84=B1=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/common/Input/index.tsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/common/Input/index.tsx b/frontend/src/components/common/Input/index.tsx index 9773f92f2..38456a9b5 100644 --- a/frontend/src/components/common/Input/index.tsx +++ b/frontend/src/components/common/Input/index.tsx @@ -8,11 +8,22 @@ interface InputProps extends InputStyleProps { onChange: (event: React.ChangeEvent) => void; type: string; id?: string; + name?: string; placeholder?: string; } -const Input = ({ id, value, onChange, type, placeholder, $style }: InputProps) => { - return ; +const Input = ({ id, value, name, onChange, type, placeholder, $style }: InputProps) => { + return ( + + ); }; export default Input; From ed8f888b3443b0a087a50f1b0c8e9ed69f3e5ef1 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Tue, 6 Aug 2024 13:10:49 +0900 Subject: [PATCH 13/18] =?UTF-8?q?refactor:=20=EC=88=98=EC=A0=95=EB=90=9C?= =?UTF-8?q?=20=EA=B2=BD=EB=A1=9C=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/LandingPage/components/ReviewAccessForm/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx index b5d8b4fc3..80f1901fa 100644 --- a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx @@ -47,7 +47,7 @@ const ReviewAccessForm = () => { updateGroupAccessCode(groupAccessCode); setErrorMessage(''); - navigate('/user/review-preview-list'); + navigate('/user/review-list'); } catch (error) { if (error instanceof Error) setErrorMessage(error.message); } From 79c6cc60d78ea46ebb0a03f7ee1c7f766c7045e9 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Tue, 6 Aug 2024 20:41:31 +0900 Subject: [PATCH 14/18] =?UTF-8?q?refactor:=20usePostDataForUrl=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=EC=97=90=EC=84=9C=20mutation=EC=9D=84=20=EB=A6=AC?= =?UTF-8?q?=ED=84=B4=ED=95=98=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/src/pages/LandingPage/queries/usePostDataForURL.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/LandingPage/queries/usePostDataForURL.ts b/frontend/src/pages/LandingPage/queries/usePostDataForURL.ts index 99df4f964..d841eee77 100644 --- a/frontend/src/pages/LandingPage/queries/usePostDataForURL.ts +++ b/frontend/src/pages/LandingPage/queries/usePostDataForURL.ts @@ -6,7 +6,7 @@ import { GROUP_QUERY_KEY } from '@/constants'; const usePostDataForURL = () => { const queryClient = useQueryClient(); - const data = useMutation({ + const { mutate } = useMutation({ mutationFn: (dataForURL: DataForURL) => postDataForURL(dataForURL), onSuccess: () => { queryClient.invalidateQueries({ queryKey: [GROUP_QUERY_KEY.dataForURL] }); @@ -16,7 +16,9 @@ const usePostDataForURL = () => { }, }); - return data; + return { + mutate, + }; }; export default usePostDataForURL; From 21df3c44276f18b28e7c68eaa40d1433e04d1466 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Tue, 6 Aug 2024 20:42:29 +0900 Subject: [PATCH 15/18] =?UTF-8?q?refactor:=20URL=EC=9D=84=20=EC=84=B1?= =?UTF-8?q?=EA=B3=B5=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=ED=95=9C=20=EC=9D=B4=ED=9B=84=20Input=EC=9D=84=20=EB=A6=AC?= =?UTF-8?q?=EC=85=8B=ED=95=98=EB=8A=94=20=ED=95=A8=EC=88=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LandingPage/components/URLGeneratorForm/index.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx b/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx index 0f39a03de..1249b43c3 100644 --- a/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/URLGeneratorForm/index.tsx @@ -26,12 +26,20 @@ const URLGeneratorForm = () => { mutation.mutate(dataForURL, { onSuccess: (data) => { const completeURL = getCompleteURL(data.reviewRequestCode); + setReviewRequestCode(completeURL); updateGroupAccessCode(data.groupAccessCode); + + resetInputs(); }, }); }; + const resetInputs = () => { + setRevieweeName(''); + setProjectName(''); + }; + const getCompleteURL = (reviewRequestCode: string) => { return `${window.location.origin}/user/review-writing/${reviewRequestCode}`; }; From dbd335a3b33439f019ab20c8b51e20c0b0b82ac3 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Tue, 6 Aug 2024 20:43:06 +0900 Subject: [PATCH 16/18] =?UTF-8?q?chore:=20NOTE=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/mocks/handlers/group.ts | 4 ++++ .../pages/LandingPage/components/ReviewAccessForm/index.tsx | 5 +++++ frontend/src/pages/LandingPage/index.tsx | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/frontend/src/mocks/handlers/group.ts b/frontend/src/mocks/handlers/group.ts index 120253b3d..333322888 100644 --- a/frontend/src/mocks/handlers/group.ts +++ b/frontend/src/mocks/handlers/group.ts @@ -4,24 +4,28 @@ import endPoint from '@/apis/endpoints'; import { CREATED_GROUP_DATA, INVALID_GROUP_ACCESS_CODE } from '../mockData/group'; +// NOTE: URL 생성 정상 응답 const postDataForUrl = () => { return http.post(endPoint.postingDataForURL, async () => { return HttpResponse.json(CREATED_GROUP_DATA, { status: 200 }); }); }; +// NOTE: URL 생성 에러 응답 // const postDataForUrl = () => { // return http.post(endPoint.postingDataForURL, async () => { // return HttpResponse.json({ error: '서버 에러 테스트' }, { status: 500 }); // }); // }; +// NOTE: 확인 코드 정상 응답 const getIsValidGroupAccessCode = () => { return http.get(endPoint.gettingReviewList, async () => { return HttpResponse.json({ status: 200 }); }); }; +// NOTE: 확인 코드 에러 응답 // const getIsValidGroupAccessCode = () => { // return http.get(endPoint.gettingReviewList, async () => { // return HttpResponse.json(INVALID_GROUP_ACCESS_CODE, { status: 400 }); diff --git a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx index 80f1901fa..ce7cd035d 100644 --- a/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx +++ b/frontend/src/pages/LandingPage/components/ReviewAccessForm/index.tsx @@ -12,6 +12,11 @@ import * as S from './styles'; const DEBOUNCE_TIME = 300; +// NOTE: groupAccessCode가 유효한지를 확인하는 API 호출은 fetch로 고정! +// 1. 요청을 통해 단순히 true, false 정도의 데이터를 단발적으로 가져오는 API이므로 +// 리액트 쿼리를 사용할 만큼 서버 상태를 정교하게 가지고 있을 필요 없음 +// 2. 리액트 쿼리를 도입했을 때 Errorboundary로 Form을 감싸지 않았고, useQuery를 사용했음에도 불구하고 +// error fallback이 뜨는 버그 존재 const ReviewAccessForm = () => { const [groupAccessCode, setGroupAccessCode] = useState(''); const [errorMessage, setErrorMessage] = useState(''); diff --git a/frontend/src/pages/LandingPage/index.tsx b/frontend/src/pages/LandingPage/index.tsx index 313f095f0..37dd6630b 100644 --- a/frontend/src/pages/LandingPage/index.tsx +++ b/frontend/src/pages/LandingPage/index.tsx @@ -5,12 +5,14 @@ import URLGeneratorForm from './components/URLGeneratorForm'; import * as S from './styles'; const LandingPage = () => { + // NOTE: ReviewAccessForm에서는 Errorboundary를 사용하지 않지만 감싸지 않으면 + // Error fallback에서 ReviewAccessForm 컴포넌트가 노출되므로 둘 다 감쌌음 return ( + - ); }; From 8fe641488131c992959fb5d4e933d85f17eb219a Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Tue, 6 Aug 2024 21:14:56 +0900 Subject: [PATCH 17/18] =?UTF-8?q?refactor:=20getIsValidGroupAccessCodeApi?= =?UTF-8?q?=EC=97=90=EC=84=9C=20400=20=EC=99=B8=EC=9D=98=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=B2=98=EB=A6=AC=EB=A5=BC=20=EA=B8=B0=EC=A1=B4?= =?UTF-8?q?=EC=9D=98=20createApiErrorMessage=EB=A5=BC=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=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/src/apis/group.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/apis/group.ts b/frontend/src/apis/group.ts index 0cf83cba7..e8516152e 100644 --- a/frontend/src/apis/group.ts +++ b/frontend/src/apis/group.ts @@ -1,4 +1,4 @@ -import { API_ERROR_MESSAGE, INVALID_GROUP_ACCESS_CODE_MESSAGE } from '@/constants'; +import { INVALID_GROUP_ACCESS_CODE_MESSAGE } from '@/constants'; import createApiErrorMessage from './apiErrorMessageCreator'; import endPoint from './endpoints'; @@ -38,7 +38,7 @@ export const getIsValidGroupAccessCodeApi = async (groupAccessCode: string) => { }); if (response.status === 400) throw new Error(INVALID_GROUP_ACCESS_CODE_MESSAGE); - if (response.status === 500) throw new Error(API_ERROR_MESSAGE.serverError); + if (!response.ok) throw new Error(createApiErrorMessage(response.status)); return response.ok; }; From 552cc6fbae014e70a76b30cb06afcd36eaa6f8d0 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Wed, 7 Aug 2024 11:13:02 +0900 Subject: [PATCH 18/18] =?UTF-8?q?chore:=20=EB=88=84=EB=9D=BD=EB=90=90?= =?UTF-8?q?=EB=8D=98=20-Api=20suffix=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/apis/group.ts | 2 +- frontend/src/pages/LandingPage/queries/usePostDataForURL.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/apis/group.ts b/frontend/src/apis/group.ts index e8516152e..d504ff1d6 100644 --- a/frontend/src/apis/group.ts +++ b/frontend/src/apis/group.ts @@ -8,7 +8,7 @@ export interface DataForURL { projectName: string; } -export const postDataForURL = async (dataForURL: DataForURL) => { +export const postDataForURLApi = async (dataForURL: DataForURL) => { const response = await fetch(endPoint.postingDataForURL, { method: 'POST', headers: { diff --git a/frontend/src/pages/LandingPage/queries/usePostDataForURL.ts b/frontend/src/pages/LandingPage/queries/usePostDataForURL.ts index d841eee77..ed27daec9 100644 --- a/frontend/src/pages/LandingPage/queries/usePostDataForURL.ts +++ b/frontend/src/pages/LandingPage/queries/usePostDataForURL.ts @@ -1,13 +1,13 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { DataForURL, postDataForURL } from '@/apis/group'; +import { DataForURL, postDataForURLApi } from '@/apis/group'; import { GROUP_QUERY_KEY } from '@/constants'; const usePostDataForURL = () => { const queryClient = useQueryClient(); const { mutate } = useMutation({ - mutationFn: (dataForURL: DataForURL) => postDataForURL(dataForURL), + mutationFn: (dataForURL: DataForURL) => postDataForURLApi(dataForURL), onSuccess: () => { queryClient.invalidateQueries({ queryKey: [GROUP_QUERY_KEY.dataForURL] }); },