From 0466ee963e4c2351ea36d9c0687e6d2fb7e9b68f Mon Sep 17 00:00:00 2001 From: JeonDoGyun Date: Sat, 11 Nov 2023 05:35:03 +0900 Subject: [PATCH 01/10] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EC=BA=90=EC=B9=AD=20=EA=B5=AC=EC=B2=B4=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 모달로 안내 문구가 나오도록 구현 --- .../signUp/components/SignupGuideModal.tsx | 23 +++ .../signUp/components/SignupInputForm.tsx | 173 +++++++++++------- .../signUp/components/VSignupInputForm.tsx | 162 ++++++++-------- src/pages/signUp/signupType.d.ts | 9 + 4 files changed, 229 insertions(+), 138 deletions(-) create mode 100644 src/pages/signUp/components/SignupGuideModal.tsx diff --git a/src/pages/signUp/components/SignupGuideModal.tsx b/src/pages/signUp/components/SignupGuideModal.tsx new file mode 100644 index 00000000..21a16ca7 --- /dev/null +++ b/src/pages/signUp/components/SignupGuideModal.tsx @@ -0,0 +1,23 @@ +import { SignupGuideModalProps } from '../signupType'; + +const SignupGuideModal = ({ text, open, onClose }: SignupGuideModalProps) => { + if (!open) { + return null; + } + + return ( + +
+
{text}
+ +
+
+ ); +}; + +export default SignupGuideModal; diff --git a/src/pages/signUp/components/SignupInputForm.tsx b/src/pages/signUp/components/SignupInputForm.tsx index bef45f8c..8996b274 100644 --- a/src/pages/signUp/components/SignupInputForm.tsx +++ b/src/pages/signUp/components/SignupInputForm.tsx @@ -9,6 +9,7 @@ import { LoadingProps, } from '../signupType'; import VSignupInputForm from './VSignupInputForm'; +import SignupGuideModal from './SignupGuideModal'; const SignupInputForm = () => { const [shelterInfo, setShelterInfo] = useRecoilState(shelterSignupState); @@ -16,18 +17,19 @@ const SignupInputForm = () => { isValid: false, checked: false, }); - const [passwordConfirm, setPasswordConfirm] = useState(true); - const [emailValidText, setEmailValidText] = useState(''); - const [emailInValidText, setEmailInValidText] = useState(''); - + const [passwordConfirm, setPasswordConfirm] = useState(true); + const [modalOpen, setModalOpen] = useState(false); + const [modalText, setModalText] = useState(''); + const [emailValidText, setEmailValidText] = useState(''); + const [emailInValidText, setEmailInValidText] = useState(''); + const navigate = useNavigate(); const [errors, setErrors] = useState>({}); const [isLoading, setIsLoading] = useState({ submitIsLoading: false, duplicateCheckIsLoading: false, }); - const navigate = useNavigate(); - + /** 프론트에서 유효성 검사 진행 */ const validationSchema = Yup.object().shape({ email: Yup.string() .email('이메일 형식에 맞게 입력해주세요.') @@ -77,64 +79,84 @@ const SignupInputForm = () => { setEmailConfirm(emailConfirmObj); }; - // 이메일 중복 검사 api + const handleModalClose = () => { + setModalOpen(false); + }; + + /** 이메일 중복 검사 api */ const duplicateCheck = async () => { setErrors({}); setIsLoading((prev) => ({ ...prev, duplicateCheckIsLoading: true })); - await fetch(`${process.env.REACT_APP_URI}/account/email`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - email: shelterInfo.email, - }), - }) - .then((res) => { - return res.json(); - }) - .then((data) => { - if (!data.success) { - getEmailValidText({ - validText: '', - inValidText: data.error.message, - emailConfirmObj: { - isValid: false, - checked: false, - }, - }); - } else if (!shelterInfo.email) { - getEmailValidText({ - validText: '', - inValidText: '', - // 안 넣으면 빈칸으로 공간 차지해서 이렇게 조건 넣어줌 - emailConfirmObj: { - isValid: false, - checked: true, - }, - }); - } else { - getEmailValidText({ - validText: '사용 가능한 이메일입니다.', - inValidText: '', - emailConfirmObj: { - isValid: true, - checked: true, - }, - }); - } - }); - setIsLoading((prev) => ({ ...prev, duplicateCheckIsLoading: false })); + try { + const response = await fetch( + `${process.env.REACT_APP_URI}/account/email`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + email: shelterInfo.email, + }), + }, + ); + + const data = await response.json(); + + if (!data.success) { + getEmailValidText({ + validText: '', + inValidText: data.error.message, + emailConfirmObj: { + isValid: false, + checked: false, + }, + }); + } else if (!shelterInfo.email) { + getEmailValidText({ + validText: '', + inValidText: '', + emailConfirmObj: { + isValid: false, + checked: true, + }, + }); + } else { + getEmailValidText({ + validText: '사용 가능한 이메일입니다.', + inValidText: '', + emailConfirmObj: { + isValid: true, + checked: true, + }, + }); + } + return data; + } finally { + setIsLoading((prev) => ({ ...prev, duplicateCheckIsLoading: false })); + } }; + /** 회원가입 api 요청 + * 이메일 중복 확인이 되었는지 확인 + * 필수 정보가 입력되었는지 확인 + * 정보가 제대로 입력되었을 때 api 요청 + */ const userFetch = () => { - // 중복 확인이 되지 않았을 때 + getEmailValidText({ + validText: '', + inValidText: '', + emailConfirmObj: { + isValid: false, + checked: false, + }, + }); if (!emailConfirm.checked) { - alert('이메일 중복을 확인해주세요'); + setErrors({}); + setModalText('이메일을 중복을 확인해주세요.'); setIsLoading((prev) => ({ ...prev, submitIsLoading: false })); - } - // 제대로 확인되었을 때 - if (emailConfirm.isValid && emailConfirm.checked) { + setModalOpen(true); + } else if (emailConfirm.isValid && emailConfirm.checked) { fetch(`${process.env.REACT_APP_URI}/account/shelter`, { method: 'POST', headers: { @@ -151,11 +173,31 @@ const SignupInputForm = () => { }), }) .then((res) => { + if (!res.ok) { + if (res.status === 400) { + setModalText('필수 정보를 확인해주세요.'); + setModalOpen(true); + } + if (res.status === 500) { + ; + } + } return res.json(); }) .then((data) => { if (!data.success) { - alert(data.error.message); + getEmailValidText({ + validText: '', + inValidText: '', + emailConfirmObj: { + isValid: false, + checked: false, + }, + }); } else { navigate('/login'); } @@ -164,9 +206,10 @@ const SignupInputForm = () => { } }; - // input에 들어가는 value에 따라 recoilState인 shelterInfo의 값 갱신 - // 비밀번호 일치하지 않는 경우 에러 텍스트 표시 - // 나머지 case의 경우, input value를 저장하는 용도로만 사용하기 때문에 default로 설정 + /** input에 들어가는 value에 따라 recoilState인 shelterInfo의 값 갱신 + * 비밀번호 일치하지 않는 경우 에러 텍스트 표시 + * 나머지 case의 경우, input value를 저장하는 용도로만 사용하기 때문에 default로 설정 + */ const getInputValue = (target: HTMLInputElement) => { const inputKey = target.dataset.inputType as string; switch (inputKey) { @@ -183,7 +226,7 @@ const SignupInputForm = () => { } }; - // yup을 통해 input value의 validation check 후 errorText를 errors state에 저장 + /** yup을 통해 input value의 validation check 후 errorText를 errors state에 저장 */ const validationCheck = () => { validationSchema .validate(shelterInfo, { abortEarly: false }) @@ -213,6 +256,7 @@ const SignupInputForm = () => { const handleChange = (event: React.ChangeEvent) => { const target = event.target as HTMLInputElement; + setErrors({}); getInputValue(target); }; @@ -222,20 +266,23 @@ const SignupInputForm = () => { */ const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - await validationCheck(); setIsLoading((prev) => ({ ...prev, submitIsLoading: true })); - await userFetch(); + validationCheck(); + userFetch(); }; const SignupInputFormProps = { handleChange, handleSubmit, + handleModalClose, duplicateCheck, emailValidText, emailInValidText, passwordConfirm, errors, isLoading, + modalOpen, + modalText, }; return ; diff --git a/src/pages/signUp/components/VSignupInputForm.tsx b/src/pages/signUp/components/VSignupInputForm.tsx index 26f2b69c..c670bf98 100644 --- a/src/pages/signUp/components/VSignupInputForm.tsx +++ b/src/pages/signUp/components/VSignupInputForm.tsx @@ -3,9 +3,11 @@ import InputGroup from 'commons/components/InputGroup'; import { ClipLoader } from 'react-spinners'; import { VSignupInputProps } from '../signupType'; import ValidateText from './ValidateText'; +import SignupGuideModal from './SignupGuideModal'; const VSignupInputForm = ({ handleChange, + handleModalClose, handleSubmit, duplicateCheck, emailValidText, @@ -13,96 +15,106 @@ const VSignupInputForm = ({ passwordConfirm, errors, isLoading, + modalOpen, + modalText, }: VSignupInputProps) => { return ( -
-
+ <> + +
+ + +
+ + + + + + {!passwordConfirm && ( +
비밀번호가 일치하지 않습니다.
+ )} + - -
- - - - - - - {!passwordConfirm && ( -
비밀번호가 일치하지 않습니다.
- )} - - - + + - - - - + ); }; diff --git a/src/pages/signUp/signupType.d.ts b/src/pages/signUp/signupType.d.ts index 239f8a88..a6ed5063 100644 --- a/src/pages/signUp/signupType.d.ts +++ b/src/pages/signUp/signupType.d.ts @@ -28,14 +28,23 @@ export interface ValidationProps { export interface VSignupInputProps { handleChange: (event: React.ChangeEvent) => void; handleSubmit: (e: React.FormEvent) => void; + handleModalClose: () => void; duplicateCheck: () => void; emailValidText: string; emailInValidText: string; passwordConfirm: boolean; errors: Partial; isLoading: LoadingProps; + modalOpen: boolean; + modalText: string; } export interface SignupPageProps { redirectLoginPage: () => void; } + +export interface SignupGuideModalProps { + open: boolean; + text: string; + onClose: () => void; +} From da0ccdd9410966b99c40cd6dda83e144dc60752d Mon Sep 17 00:00:00 2001 From: JeonDoGyun Date: Sat, 11 Nov 2023 05:37:31 +0900 Subject: [PATCH 02/10] =?UTF-8?q?refactor:=20=EC=95=88=EB=82=B4=EB=AC=B8?= =?UTF-8?q?=EA=B5=AC=20=EB=AA=A8=EB=8B=AC=20=EA=B3=B5=ED=86=B5=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modals/TextGuideModal.tsx} | 10 +++++++--- src/pages/signUp/components/SignupInputForm.tsx | 2 +- src/pages/signUp/components/VSignupInputForm.tsx | 2 +- src/pages/signUp/signupType.d.ts | 6 ------ 4 files changed, 9 insertions(+), 11 deletions(-) rename src/{pages/signUp/components/SignupGuideModal.tsx => commons/modals/TextGuideModal.tsx} (70%) diff --git a/src/pages/signUp/components/SignupGuideModal.tsx b/src/commons/modals/TextGuideModal.tsx similarity index 70% rename from src/pages/signUp/components/SignupGuideModal.tsx rename to src/commons/modals/TextGuideModal.tsx index 21a16ca7..ea624087 100644 --- a/src/pages/signUp/components/SignupGuideModal.tsx +++ b/src/commons/modals/TextGuideModal.tsx @@ -1,6 +1,10 @@ -import { SignupGuideModalProps } from '../signupType'; +interface TextGuideModalProps { + open: boolean; + text: string; + onClose: () => void; +} -const SignupGuideModal = ({ text, open, onClose }: SignupGuideModalProps) => { +const TextGuideModal = ({ text, open, onClose }: TextGuideModalProps) => { if (!open) { return null; } @@ -20,4 +24,4 @@ const SignupGuideModal = ({ text, open, onClose }: SignupGuideModalProps) => { ); }; -export default SignupGuideModal; +export default TextGuideModal; diff --git a/src/pages/signUp/components/SignupInputForm.tsx b/src/pages/signUp/components/SignupInputForm.tsx index 8996b274..1bb69307 100644 --- a/src/pages/signUp/components/SignupInputForm.tsx +++ b/src/pages/signUp/components/SignupInputForm.tsx @@ -9,7 +9,7 @@ import { LoadingProps, } from '../signupType'; import VSignupInputForm from './VSignupInputForm'; -import SignupGuideModal from './SignupGuideModal'; +import SignupGuideModal from '../../../commons/modals/TextGuideModal'; const SignupInputForm = () => { const [shelterInfo, setShelterInfo] = useRecoilState(shelterSignupState); diff --git a/src/pages/signUp/components/VSignupInputForm.tsx b/src/pages/signUp/components/VSignupInputForm.tsx index c670bf98..63a96a04 100644 --- a/src/pages/signUp/components/VSignupInputForm.tsx +++ b/src/pages/signUp/components/VSignupInputForm.tsx @@ -3,7 +3,7 @@ import InputGroup from 'commons/components/InputGroup'; import { ClipLoader } from 'react-spinners'; import { VSignupInputProps } from '../signupType'; import ValidateText from './ValidateText'; -import SignupGuideModal from './SignupGuideModal'; +import SignupGuideModal from '../../../commons/modals/TextGuideModal'; const VSignupInputForm = ({ handleChange, diff --git a/src/pages/signUp/signupType.d.ts b/src/pages/signUp/signupType.d.ts index a6ed5063..c6b181e4 100644 --- a/src/pages/signUp/signupType.d.ts +++ b/src/pages/signUp/signupType.d.ts @@ -42,9 +42,3 @@ export interface VSignupInputProps { export interface SignupPageProps { redirectLoginPage: () => void; } - -export interface SignupGuideModalProps { - open: boolean; - text: string; - onClose: () => void; -} From 26d7291b3859c2f33a45b84053144f6a1026a4b7 Mon Sep 17 00:00:00 2001 From: JeonDoGyun Date: Sat, 11 Nov 2023 05:51:07 +0900 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20status=20code=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=9D=BC=20=EC=97=90=EB=9F=AC=20=EC=BA=90=EC=B9=AD=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/login/components/LoginInputForm.tsx | 26 ++++++- .../login/components/VLoginInputForm.tsx | 78 +++++++++++-------- src/pages/login/loginType.d.ts | 3 + .../signUp/components/SignupInputForm.tsx | 7 +- .../signUp/components/VSignupInputForm.tsx | 4 +- 5 files changed, 74 insertions(+), 44 deletions(-) diff --git a/src/pages/login/components/LoginInputForm.tsx b/src/pages/login/components/LoginInputForm.tsx index 020eb858..953f3155 100644 --- a/src/pages/login/components/LoginInputForm.tsx +++ b/src/pages/login/components/LoginInputForm.tsx @@ -11,6 +11,8 @@ const LoginInputForm = () => { const [userInfo, setUserInfo] = useRecoilState(shelterLoginState); const [errors, setErrors] = useState>({}); const [isLoading, setIsLoading] = useState(false); + const [modalOpen, setModalOpen] = useState(false); + const [modalText, setModalText] = useState(''); const navigate = useNavigate(); const currentDate = new Date(); @@ -44,8 +46,14 @@ const LoginInputForm = () => { if (!res.ok) { // error 발생 시 처리는 status 값에 따라 하는 것으로 변경 필요 - const errorData = await res.json(); - console.error('userFetchError: ', errorData); + if (res.status === 400) { + setModalText('이메일, 비밀번호를 확인해주세요.'); + setModalOpen(true); + } + if (res.status === 500) { + setModalText('서버에 오류가 발생했습니다.'); + setModalOpen(true); + } } const response = await res.json(); @@ -102,8 +110,11 @@ const LoginInputForm = () => { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); setIsLoading(true); - validateCheck(); - mutation.mutate(); + try { + validateCheck(); + } finally { + mutation.mutate(); + } }; const handleChange = (event: React.ChangeEvent) => { @@ -115,11 +126,18 @@ const LoginInputForm = () => { } }; + const handleModalClose = () => { + setModalOpen(false); + }; + const LoginInputFormProps = { handleChange, handleSubmit, errors, isLoading, + modalOpen, + modalText, + handleModalClose, }; return ; diff --git a/src/pages/login/components/VLoginInputForm.tsx b/src/pages/login/components/VLoginInputForm.tsx index f221a9b8..df162b57 100644 --- a/src/pages/login/components/VLoginInputForm.tsx +++ b/src/pages/login/components/VLoginInputForm.tsx @@ -1,5 +1,6 @@ import InputGroup from 'commons/components/InputGroup'; import { ClipLoader } from 'react-spinners'; +import TextGuideModal from 'commons/modals/TextGuideModal'; import { LoginInputFormProps, ValidationTextProps } from '../loginType'; const ValidateText = ({ text }: ValidationTextProps) => { @@ -11,43 +12,54 @@ const VLoginInputForm = ({ isLoading, handleChange, handleSubmit, + modalOpen, + modalText, + handleModalClose, }: LoginInputFormProps) => { return ( -
- { - handleChange(e); - }} - autocomplete="off" - /> - + <> + + { + handleChange(e); + }} + autocomplete="off" + /> + + + { + handleChange(e); + }} + autocomplete="off" + /> + + + - { - handleChange(e); - }} - autocomplete="off" + - - - + ); }; diff --git a/src/pages/login/loginType.d.ts b/src/pages/login/loginType.d.ts index 387aa882..bead2d35 100644 --- a/src/pages/login/loginType.d.ts +++ b/src/pages/login/loginType.d.ts @@ -5,6 +5,9 @@ export interface LoginInputFormProps { isLoading: boolean; handleChange: (event: React.ChangeEvent) => void; handleSubmit: (e: React.FormEvent) => void; + modalOpen: boolean; + modalText: string; + handleModalClose: () => void; } export interface ValidationTextProps { diff --git a/src/pages/signUp/components/SignupInputForm.tsx b/src/pages/signUp/components/SignupInputForm.tsx index 1bb69307..fae15798 100644 --- a/src/pages/signUp/components/SignupInputForm.tsx +++ b/src/pages/signUp/components/SignupInputForm.tsx @@ -179,11 +179,8 @@ const SignupInputForm = () => { setModalOpen(true); } if (res.status === 500) { - ; + setModalText('서버에 오류가 발생했습니다.'); + setModalOpen(true); } } return res.json(); diff --git a/src/pages/signUp/components/VSignupInputForm.tsx b/src/pages/signUp/components/VSignupInputForm.tsx index 63a96a04..0dab9c71 100644 --- a/src/pages/signUp/components/VSignupInputForm.tsx +++ b/src/pages/signUp/components/VSignupInputForm.tsx @@ -3,7 +3,7 @@ import InputGroup from 'commons/components/InputGroup'; import { ClipLoader } from 'react-spinners'; import { VSignupInputProps } from '../signupType'; import ValidateText from './ValidateText'; -import SignupGuideModal from '../../../commons/modals/TextGuideModal'; +import TextGuideModal from '../../../commons/modals/TextGuideModal'; const VSignupInputForm = ({ handleChange, @@ -109,7 +109,7 @@ const VSignupInputForm = ({ - Date: Sat, 11 Nov 2023 06:04:42 +0900 Subject: [PATCH 04/10] =?UTF-8?q?fix:=20lazy=20loading=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EC=9D=B8=ED=95=9C=20=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 페이지 이동 시 발생하는 react-router-dom error page 문제 해결 --- src/App.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index eaa89da2..af44dba6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,6 +5,7 @@ import { RouteObject, RouterProvider, } from 'react-router-dom'; +import { Suspense } from 'react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import DetailPetPage from 'pages/detailPet/DetailPetPage'; import ProfileListPage from 'pages/profileList/ProfileListPage'; @@ -21,6 +22,7 @@ import GNB from 'layouts/GNB'; import NotFound from 'pages/notFound/NotFound'; import HomePage from 'pages/home/HomePage'; import UpdatePage from 'pages/update/UpdatePage'; +import { ClipLoader } from 'react-spinners'; const queryClient = new QueryClient({ defaultOptions: { @@ -112,7 +114,9 @@ function App() { return ( - + }> + + ); From ab3e551ec19dd6f5a51a3ab496be68b5897d89e8 Mon Sep 17 00:00:00 2001 From: JeonDoGyun Date: Sat, 11 Nov 2023 06:15:57 +0900 Subject: [PATCH 05/10] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=EC=97=90=20=EB=B3=B4=EC=9D=B4?= =?UTF-8?q?=EB=8A=94=20=EC=BB=A8=ED=85=90=EC=B8=A0=20=EC=A1=B0=EC=A0=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 등록하기가 로그인 되었을 때만 보이도록 수정했습니다. --- src/layouts/VGNB.tsx | 21 +++++++++++++-------- src/layouts/VLargeGNB.tsx | 22 +++++++++++++--------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/layouts/VGNB.tsx b/src/layouts/VGNB.tsx index fc2aa8cb..b0d44d27 100644 --- a/src/layouts/VGNB.tsx +++ b/src/layouts/VGNB.tsx @@ -1,5 +1,6 @@ import LogoButton from 'commons/components/LogoButton'; import UserToggleBox from 'commons/components/UserToggleBox'; +import { getCookie } from 'commons/cookie/cookie'; import { Link } from 'react-router-dom'; export interface VGNBProps { @@ -21,6 +22,8 @@ const VGNB = (props: VGNBProps) => { handleToggleClick, } = props; + const token = getCookie('loginToken'); + return ( <> {/* 좁은 화면 */} @@ -66,14 +69,16 @@ const VGNB = (props: VGNBProps) => { > 내 주변 보호소 찾기 -
  • - 등록하기 -
  • + {token && ( +
  • + 등록하기 +
  • + )} diff --git a/src/layouts/VLargeGNB.tsx b/src/layouts/VLargeGNB.tsx index 9bce525c..017102eb 100644 --- a/src/layouts/VLargeGNB.tsx +++ b/src/layouts/VLargeGNB.tsx @@ -1,6 +1,7 @@ import { Link } from 'react-router-dom'; import LogoButton from 'commons/components/LogoButton'; import UserSelectBox from 'commons/components/UserDropdownBox'; +import { getCookie } from 'commons/cookie/cookie'; export interface VLargeGNBProps { handleCategoryButtonClick: () => void; @@ -16,6 +17,7 @@ const VLargeGNB = (props: VLargeGNBProps) => { isFindShelterPage, isRegisterPage, } = props; + const token = getCookie('loginToken'); return (
    @@ -48,15 +50,17 @@ const VLargeGNB = (props: VLargeGNBProps) => { > 내 주변 보호소 찾기 -
  • - 등록하기 -
  • + {token && ( +
  • + 등록하기 +
  • + )}
    From af5f7a72880e93675ef388aecd69410246e49924 Mon Sep 17 00:00:00 2001 From: JeonDoGyun Date: Sat, 11 Nov 2023 06:51:13 +0900 Subject: [PATCH 06/10] =?UTF-8?q?style:=20=EC=A4=91=EB=B3=B5=EB=90=9C=20ta?= =?UTF-8?q?ilwind=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=AA=85=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layouts/ErrorBoundary.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layouts/ErrorBoundary.tsx b/src/layouts/ErrorBoundary.tsx index d23515b7..40c46778 100644 --- a/src/layouts/ErrorBoundary.tsx +++ b/src/layouts/ErrorBoundary.tsx @@ -47,7 +47,7 @@ class ErrorBoundary extends Component {

    {this.state.error.message}

    홈으로 @@ -64,7 +64,7 @@ class ErrorBoundary extends Component { 홈으로 From 598d8997598f386f89d1db4a47fbb10726802cea Mon Sep 17 00:00:00 2001 From: JeonDoGyun Date: Sat, 11 Nov 2023 06:52:15 +0900 Subject: [PATCH 07/10] =?UTF-8?q?feat:=20=EB=B3=B4=ED=98=B8=EC=86=8C=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=88=98=EC=A0=95=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=97=90=EB=9F=AC=20=EC=BA=90=EC=B9=AD=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get, put 방식 모두 적용 --- src/pages/editProfile/EditProfilePage.tsx | 71 ++--------- .../components/EditProfileTemplate.tsx | 115 ++++++++++++++++++ .../VEditProfileTemplate.tsx} | 25 +++- src/pages/editProfile/editProfileType.d.ts | 4 + 4 files changed, 146 insertions(+), 69 deletions(-) create mode 100644 src/pages/editProfile/components/EditProfileTemplate.tsx rename src/pages/editProfile/{VEditProfilePage.tsx => components/VEditProfileTemplate.tsx} (75%) diff --git a/src/pages/editProfile/EditProfilePage.tsx b/src/pages/editProfile/EditProfilePage.tsx index 4341c339..2673f938 100644 --- a/src/pages/editProfile/EditProfilePage.tsx +++ b/src/pages/editProfile/EditProfilePage.tsx @@ -1,70 +1,13 @@ -import { useMutation } from '@tanstack/react-query'; -import { useParams } from 'react-router-dom'; -import { useRecoilState } from 'recoil'; -import { shelterSignupState } from 'recoil/shelterState'; -import { getCookie } from 'commons/cookie/cookie'; -import usePostFetch from 'commons/apis/usePostFetch'; -import useGetFetch from 'commons/apis/useGetFetch'; -import { useEffect } from 'react'; -import VEditProfilePage from './VEditProfilePage'; +import React from 'react'; +import ErrorBoundary from 'layouts/ErrorBoundary'; +import EditProfileTemplate from './components/EditProfileTemplate'; const EditProfilePage = () => { - const params = useParams(); - const shelterId = params.id; - const token = getCookie('loginToken'); - const [shelterInfo, setShelterInfo] = useRecoilState(shelterSignupState); - - const { getStatusCode, getLoading, getData } = useGetFetch( - `${process.env.REACT_APP_URI}/shelter/${shelterId}?page=1`, + return ( + + + ); - - const { postStatusCode, postloading, postData } = usePostFetch( - `${process.env.REACT_APP_URI}/shelter/${shelterId}`, - { - method: 'PUT', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json', - }, - - body: JSON.stringify({ - name: shelterInfo.name, - contact: shelterInfo.contact, - shelterAddressUpdateDto: shelterInfo.address, - }), - }, - ); - - const mutation = useMutation(getData, { - onSuccess: (info) => { - setShelterInfo({ - ...shelterInfo, - name: info.response.shelter.name, - contact: info.response.shelter.contact, - address: { - ...info.response.shelter.address, - }, - }); - }, - }); - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - postData(); - }; - - useEffect(() => { - mutation.mutate(); - }, []); - - const EditProfileProps = { - getLoading, - postloading, - handleSubmit, - shelterInfo, - }; - - return ; }; export default EditProfilePage; diff --git a/src/pages/editProfile/components/EditProfileTemplate.tsx b/src/pages/editProfile/components/EditProfileTemplate.tsx new file mode 100644 index 00000000..dedc0bae --- /dev/null +++ b/src/pages/editProfile/components/EditProfileTemplate.tsx @@ -0,0 +1,115 @@ +import { useMutation } from '@tanstack/react-query'; +import { useParams } from 'react-router-dom'; +import { useRecoilState } from 'recoil'; +import { shelterSignupState } from 'recoil/shelterState'; +import { getCookie } from 'commons/cookie/cookie'; +import usePostFetch from 'commons/apis/usePostFetch'; +import useGetFetch from 'commons/apis/useGetFetch'; +import { useEffect, useState } from 'react'; +import VEditProfilePage from './VEditProfileTemplate'; + +const EditProfileTemplate = () => { + const params = useParams(); + const shelterId = params.id; + const token = getCookie('loginToken'); + const [shelterInfo, setShelterInfo] = useRecoilState(shelterSignupState); + const [modalOpen, setModalOpen] = useState(false); + const [modalText, setModalText] = useState(''); + + const { getStatusCode, getLoading, getData } = useGetFetch( + `${process.env.REACT_APP_URI}/shelter/${shelterId}?page=1`, + ); + + const { postStatusCode, postloading, postData } = usePostFetch( + `${process.env.REACT_APP_URI}/shelter/${shelterId}`, + { + method: 'PUT', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + + body: JSON.stringify({ + name: shelterInfo.name, + contact: shelterInfo.contact, + shelterAddressUpdateDto: shelterInfo.address, + }), + }, + ); + + const mutation = useMutation(getData, { + onSuccess: (info) => { + setShelterInfo({ + ...shelterInfo, + name: info.response.shelter.name, + contact: info.response.shelter.contact, + address: { + ...info.response.shelter.address, + }, + }); + }, + onError: () => { + if (getStatusCode === 404) { + setModalText('해당 보호소는 없는 보호소입니다.'); + setModalOpen(true); + } + if (getStatusCode === 404) { + setModalText('서버에 오류가 발생했습니다.'); + setModalOpen(true); + } + }, + }); + + const getInputValue = (target: HTMLInputElement) => { + const inputKey = target.dataset.inputType as string; + setShelterInfo((prev) => ({ ...prev, [inputKey]: target.value })); + }; + + const handleChange = (event: React.ChangeEvent) => { + const target = event.target as HTMLInputElement; + getInputValue(target); + }; + + const handleModalClose = () => { + setModalOpen(false); + }; + + const handlePutStatusCode = (status: number) => { + if (status === 403) { + setModalText('타 보호소 정보 수정에 대한 접근 권한이 없습니다.'); + setModalOpen(true); + } + if (status === 404) { + setModalText('존재하지 않는 보호소 계정입니다.'); + setModalOpen(true); + } + if (status === 500) { + setModalText('서버에 오류가 발생했습니다.'); + setModalOpen(true); + } + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + postData(); + handlePutStatusCode(postStatusCode); + }; + + useEffect(() => { + mutation.mutate(); + }, []); + + const EditProfileProps = { + getLoading, + postloading, + modalOpen, + modalText, + handleSubmit, + handleChange, + handleModalClose, + }; + + return ; +}; + +export default EditProfileTemplate; diff --git a/src/pages/editProfile/VEditProfilePage.tsx b/src/pages/editProfile/components/VEditProfileTemplate.tsx similarity index 75% rename from src/pages/editProfile/VEditProfilePage.tsx rename to src/pages/editProfile/components/VEditProfileTemplate.tsx index afffcede..6f0ab40f 100644 --- a/src/pages/editProfile/VEditProfilePage.tsx +++ b/src/pages/editProfile/components/VEditProfileTemplate.tsx @@ -3,14 +3,19 @@ import InputGroup from 'commons/components/InputGroup'; import { ClipLoader } from 'react-spinners'; import { shelterSignupState } from 'recoil/shelterState'; import { useRecoilValue } from 'recoil'; -import EditProfilePageSkeleton from './components/EditProfilePageSkeleton'; -import EditAddressInputGroup from './components/EditAddressInputGroup'; -import { VEditProfileProps } from './editProfileType'; +import TextGuideModal from 'commons/modals/TextGuideModal'; +import EditProfilePageSkeleton from './EditProfilePageSkeleton'; +import EditAddressInputGroup from './EditAddressInputGroup'; +import { VEditProfileProps } from '../editProfileType'; -const VEditProfilePage = ({ +const VEditProfileTemplate = ({ getLoading, postloading, + modalOpen, + modalText, + handleModalClose, handleSubmit, + handleChange, }: VEditProfileProps) => { const shelterInfo = useRecoilValue(shelterSignupState); @@ -37,19 +42,23 @@ const VEditProfilePage = ({ > + + )} ); }; -export default VEditProfilePage; +export default VEditProfileTemplate; diff --git a/src/pages/editProfile/editProfileType.d.ts b/src/pages/editProfile/editProfileType.d.ts index 0967c435..0f068284 100644 --- a/src/pages/editProfile/editProfileType.d.ts +++ b/src/pages/editProfile/editProfileType.d.ts @@ -1,5 +1,9 @@ export interface VEditProfileProps { getLoading: boolean; postloading: boolean; + modalOpen: boolean; + modalText: string; + handleModalClose: () => void; + handleChange: (event: React.ChangeEvent) => void; handleSubmit: (e: React.FormEvent) => void; } From 198947d52bfb367302abf39eb36528ba9f242fc7 Mon Sep 17 00:00:00 2001 From: JeonDoGyun Date: Sat, 11 Nov 2023 06:52:57 +0900 Subject: [PATCH 08/10] =?UTF-8?q?feat:=20=EC=95=88=EB=82=B4=EB=AC=B8?= =?UTF-8?q?=EA=B5=AC=20=EB=AA=A8=EB=8B=AC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commons/apis/usePostFetch.ts | 2 +- src/pages/signUp/components/SignupInputForm.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/commons/apis/usePostFetch.ts b/src/commons/apis/usePostFetch.ts index 4ae61309..050aaf10 100644 --- a/src/commons/apis/usePostFetch.ts +++ b/src/commons/apis/usePostFetch.ts @@ -3,7 +3,7 @@ import { useState } from 'react'; const usePostFetch = (url: string, options: object) => { const [data, setData] = useState>(); const [error, setError] = useState>(); - const [postStatusCode, setStatusCode] = useState(); + const [postStatusCode, setStatusCode] = useState(200); const [postloading, setLoading] = useState(false); const postData = async () => { diff --git a/src/pages/signUp/components/SignupInputForm.tsx b/src/pages/signUp/components/SignupInputForm.tsx index fae15798..24d3a10a 100644 --- a/src/pages/signUp/components/SignupInputForm.tsx +++ b/src/pages/signUp/components/SignupInputForm.tsx @@ -9,7 +9,6 @@ import { LoadingProps, } from '../signupType'; import VSignupInputForm from './VSignupInputForm'; -import SignupGuideModal from '../../../commons/modals/TextGuideModal'; const SignupInputForm = () => { const [shelterInfo, setShelterInfo] = useRecoilState(shelterSignupState); From 85293363e7094038b4539701d421f53d4969eac4 Mon Sep 17 00:00:00 2001 From: JeonDoGyun Date: Sat, 11 Nov 2023 06:54:51 +0900 Subject: [PATCH 09/10] =?UTF-8?q?fix:=20status=20code=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=20=EB=B6=80=EB=B6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 잘못 입력된 status code 부분 고쳤습니다. --- src/pages/editProfile/components/EditProfileTemplate.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/editProfile/components/EditProfileTemplate.tsx b/src/pages/editProfile/components/EditProfileTemplate.tsx index dedc0bae..0795ad0c 100644 --- a/src/pages/editProfile/components/EditProfileTemplate.tsx +++ b/src/pages/editProfile/components/EditProfileTemplate.tsx @@ -53,7 +53,7 @@ const EditProfileTemplate = () => { setModalText('해당 보호소는 없는 보호소입니다.'); setModalOpen(true); } - if (getStatusCode === 404) { + if (getStatusCode === 500) { setModalText('서버에 오류가 발생했습니다.'); setModalOpen(true); } From 6d428cbbf53ed43fd5115f0e47b11306bda038ca Mon Sep 17 00:00:00 2001 From: JeonDoGyun Date: Sat, 11 Nov 2023 07:03:26 +0900 Subject: [PATCH 10/10] =?UTF-8?q?fix:=20url=20=EC=A0=95=EB=B3=B4=EC=97=90?= =?UTF-8?q?=20=EC=9D=B4=EB=AF=B8=EC=A7=80=EA=B0=80=20=EB=82=98=EC=98=A4?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=B6=80=EB=B6=84=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 --- public/index.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/index.html b/public/index.html index 9991b105..d0fdcb02 100644 --- a/public/index.html +++ b/public/index.html @@ -17,7 +17,10 @@ /> - +