From 540b6a0269100964096d263918dfa10b6175d76e Mon Sep 17 00:00:00 2001 From: wuzoo Date: Tue, 5 Nov 2024 21:40:59 +0900 Subject: [PATCH 1/6] =?UTF-8?q?chore:=20gui=20style=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/asset/svg/logo_tiki_md.svg | 16 ++++++++-------- src/page/login/index/LoginPage.style.ts | 7 ++----- src/page/login/index/LoginPage.tsx | 11 ++++++++--- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/common/asset/svg/logo_tiki_md.svg b/src/common/asset/svg/logo_tiki_md.svg index 9a647729..4dfc01a0 100644 --- a/src/common/asset/svg/logo_tiki_md.svg +++ b/src/common/asset/svg/logo_tiki_md.svg @@ -1,14 +1,14 @@ - - - - - - - + + + + + + + - + diff --git a/src/page/login/index/LoginPage.style.ts b/src/page/login/index/LoginPage.style.ts index 1547237e..42e67904 100644 --- a/src/page/login/index/LoginPage.style.ts +++ b/src/page/login/index/LoginPage.style.ts @@ -17,14 +17,11 @@ export const formStyle = css({ display: 'flex', flexDirection: 'column', - width: '51.1rem', - height: '53rem', + width: '60rem', - padding: '6rem', + padding: '6rem 10.5rem', alignItems: 'center', justifyContent: 'center', - - gap: '3.2rem', }); export const findPasswordButtonStyle = css({ diff --git a/src/page/login/index/LoginPage.tsx b/src/page/login/index/LoginPage.tsx index 4c127e22..04358ff7 100644 --- a/src/page/login/index/LoginPage.tsx +++ b/src/page/login/index/LoginPage.tsx @@ -35,7 +35,7 @@ const LoginPage = () => { return (
- +
- From 49c9876a5f4a53f8734870d16367d9cdfe6cec79 Mon Sep 17 00:00:00 2001 From: wuzoo Date: Tue, 5 Nov 2024 23:21:15 +0900 Subject: [PATCH 2/6] feat: term page gui --- src/common/component/Modal/Modal.style.ts | 6 +- src/page/signUp/index/TermPage.tsx | 113 ++++++++---------- .../component/TermArea/TermArea.style.ts | 20 ---- .../index/component/TermArea/TermArea.tsx | 31 ----- .../component/TermItem/TermItem.style.ts | 48 ++++++++ .../index/component/TermItem/TermItem.tsx | 72 +++++++++++ .../TermsAgreeButton.style.ts | 11 +- .../TermsAgreeButton/TermsAgreeButton.tsx | 5 +- .../info/component/InfoForm/InfoForm.style.ts | 7 +- 9 files changed, 187 insertions(+), 126 deletions(-) delete mode 100644 src/page/signUp/index/component/TermArea/TermArea.style.ts delete mode 100644 src/page/signUp/index/component/TermArea/TermArea.tsx create mode 100644 src/page/signUp/index/component/TermItem/TermItem.style.ts create mode 100644 src/page/signUp/index/component/TermItem/TermItem.tsx diff --git a/src/common/component/Modal/Modal.style.ts b/src/common/component/Modal/Modal.style.ts index 136a84cb..21f62b74 100644 --- a/src/common/component/Modal/Modal.style.ts +++ b/src/common/component/Modal/Modal.style.ts @@ -22,11 +22,11 @@ export const dialogStyle = css({ position: 'fixed', top: '50%', left: '50%', - width: '51.1rem', zIndex: theme.zIndex.overlayTop, - paddingTop: '4.8rem', - paddingBottom: '4.8rem', + + padding: '3.2rem 2rem', + borderRadius: '16px', border: 'none', outline: 'none', diff --git a/src/page/signUp/index/TermPage.tsx b/src/page/signUp/index/TermPage.tsx index 17a4035e..e265ecf5 100644 --- a/src/page/signUp/index/TermPage.tsx +++ b/src/page/signUp/index/TermPage.tsx @@ -1,14 +1,11 @@ -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import Button from '@/common/component/Button/Button'; import Flex from '@/common/component/Flex/Flex'; import Heading from '@/common/component/Heading/Heading'; -import Text from '@/common/component/Text/Text'; -import { scrollStyle } from '@/common/style/scroll'; -import { detailStyle } from '@/page/signUp/index/TermPage.style'; -import TermArea from '@/page/signUp/index/component/TermArea/TermArea'; +import TermItem from '@/page/signUp/index/component/TermItem/TermItem'; import TermsAgreeButton from '@/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton'; import { pageStyle } from '@/page/signUp/info/InfoFormPage.style'; import { formStyle } from '@/page/signUp/info/component/InfoForm/InfoForm.style'; @@ -17,37 +14,39 @@ import { PATH } from '@/shared/constant/path'; import { PERSONAL, TERM } from '@/mock/data/term'; +type TermItem = { + serviceTerm: boolean; + privatePolicy: boolean; + personalInfo: boolean; +}; + const TermPage = () => { const [totalAgreeClicked, setTotalAgreeClicked] = useState(false); - const [requiredTermsStatus, setRequiredTermsStatus] = useState({ + const [termStatus, setTermStatus] = useState({ serviceTerm: false, privatePolicy: false, + personalInfo: false, }); - const [optionalTermsStatus, setOptionalTermsStatus] = useState({ collectionAgree: false }); const navigate = useNavigate(); - const isConfirmed = Object.values(requiredTermsStatus).every((item) => item === true); - - useEffect(() => { - if ( - !requiredTermsStatus.serviceTerm || - !requiredTermsStatus.privatePolicy || - !optionalTermsStatus.collectionAgree - ) { - setTotalAgreeClicked(false); - } - }, [optionalTermsStatus, requiredTermsStatus, totalAgreeClicked]); + const isConfirmed = termStatus.serviceTerm && termStatus.privatePolicy; const 약관전체동의클릭 = () => { setTotalAgreeClicked((prev) => !prev); - setRequiredTermsStatus({ + setTermStatus({ serviceTerm: totalAgreeClicked ? false : true, privatePolicy: totalAgreeClicked ? false : true, + personalInfo: totalAgreeClicked ? false : true, }); + }; - setOptionalTermsStatus({ collectionAgree: !optionalTermsStatus.collectionAgree }); + const handleItemClick = (key: keyof TermItem) => { + setTermStatus((prev) => ({ + ...prev, + [key]: !prev[key], + })); }; const handleNextStep = () => { @@ -56,47 +55,39 @@ const TermPage = () => { return ( - - - 이용 약관 동의 - -
- - - - setRequiredTermsStatus((prev) => ({ ...prev, serviceTerm: !prev.serviceTerm }))} - isChecked={requiredTermsStatus.serviceTerm}> - - {TERM} - - - - setRequiredTermsStatus((prev) => ({ ...prev, privatePolicy: !prev.privatePolicy }))} - isChecked={requiredTermsStatus.privatePolicy}> - - {PERSONAL} - - - - setOptionalTermsStatus((prev) => ({ ...prev, collectionAgree: !prev.collectionAgree }))} - isChecked={optionalTermsStatus.collectionAgree} - isRequired={false}> - - 이벤트 혜택 정보 수신 - - - - -
-
+
+ 이용 약관 동의 + + + + handleItemClick('serviceTerm')} + /> + handleItemClick('privatePolicy')} + /> + handleItemClick('personalInfo')} + /> + + +
); }; diff --git a/src/page/signUp/index/component/TermArea/TermArea.style.ts b/src/page/signUp/index/component/TermArea/TermArea.style.ts deleted file mode 100644 index c265cf83..00000000 --- a/src/page/signUp/index/component/TermArea/TermArea.style.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { css } from '@emotion/react'; - -export const wrapperStyle = css({ - display: 'flex', - flexDirection: 'column', - gap: '1.2rem', - - '& svg': { - width: '2.4rem', - height: '2.4rem', - - cursor: 'pointer', - }, -}); - -export const termStyle = css({ - display: 'flex', - alignItems: 'center', - gap: '0.8rem', -}); diff --git a/src/page/signUp/index/component/TermArea/TermArea.tsx b/src/page/signUp/index/component/TermArea/TermArea.tsx deleted file mode 100644 index df4eb2e9..00000000 --- a/src/page/signUp/index/component/TermArea/TermArea.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { HTMLAttributes } from 'react'; - -import Check from '@/common/asset/svg/ic_gray_check.svg?react'; -import CheckActive from '@/common/asset/svg/ic_key_check.svg?react'; -import Text from '@/common/component/Text/Text'; -import { theme } from '@/common/style/theme/theme'; - -import { termStyle, wrapperStyle } from '@/page/signUp/index/component/TermArea/TermArea.style'; - -interface TermAreaProps extends HTMLAttributes { - term: string; - isChecked: boolean; - onCheck: () => void; - isRequired?: boolean; -} - -const TermArea = ({ term, onCheck, isChecked, isRequired = true, children, ...props }: TermAreaProps) => { - return ( -
- - {isChecked ? : } - {term} - {isRequired ? '[필수]' : '[선택]'} - - - {children} -
- ); -}; - -export default TermArea; diff --git a/src/page/signUp/index/component/TermItem/TermItem.style.ts b/src/page/signUp/index/component/TermItem/TermItem.style.ts new file mode 100644 index 00000000..09db44cd --- /dev/null +++ b/src/page/signUp/index/component/TermItem/TermItem.style.ts @@ -0,0 +1,48 @@ +import { css } from '@emotion/react'; + +import { theme } from '@/common/style/theme/theme'; + +export const containerStyle = (isSelected: boolean) => + css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + + width: '100%', + height: '4rem', + + padding: '1.2rem', + + backgroundColor: 'transparent', + borderRadius: '8px', + border: `1px solid ${isSelected ? theme.colors.key_500 : theme.colors.gray_300}`, + + cursor: 'pointer', + }); + +export const iconStyle = (isSelected: boolean) => + css({ + '& > path': { + fill: isSelected ? theme.colors.key_500 : theme.colors.gray_800, + }, + }); + +export const termTextStyle = css({ + ...theme.text.body08, + fontWeight: 500, + + color: theme.colors.gray_800, +}); + +export const contentStyle = css({ + height: '37.8rem', + + overflowY: 'scroll', +}); + +export const expandButtonStyle = css({ + ...theme.text.body10, + fontWeight: 500, + + borderRadius: '4px', +}); diff --git a/src/page/signUp/index/component/TermItem/TermItem.tsx b/src/page/signUp/index/component/TermItem/TermItem.tsx new file mode 100644 index 00000000..45b85895 --- /dev/null +++ b/src/page/signUp/index/component/TermItem/TermItem.tsx @@ -0,0 +1,72 @@ +import { useState } from 'react'; + +import IcCheck from '@/common/asset/svg/ic_check.svg?react'; +import Button from '@/common/component/Button/Button'; +import Flex from '@/common/component/Flex/Flex'; +import Modal from '@/common/component/Modal/Modal'; +import Text from '@/common/component/Text/Text'; +import { scrollStyle } from '@/common/style/scroll'; +import { theme } from '@/common/style/theme/theme'; + +import { + containerStyle, + contentStyle, + expandButtonStyle, + iconStyle, + termTextStyle, +} from '@/page/signUp/index/component/TermItem/TermItem.style'; + +interface TermItemProps { + term: string; + content: string; + description: string; + onSelect?: () => void; + isRequired?: boolean; + isSelected?: boolean; +} + +const TermItem = ({ term, content, onSelect, description, isSelected = false, isRequired = false }: TermItemProps) => { + const [isExpanded, setIsExpanded] = useState(false); + + const title = `${isRequired ? '[필수]' : '[선택]'} ${term}`; + + return ( +
e.key === 'Enter' && onSelect?.()} + onClick={onSelect}> + + +

{title}

+
+ + + + setIsExpanded(false)}> + + + {title} + + {description} + + + +
+ + {content} + +
+ +
+
+
+ ); +}; + +export default TermItem; diff --git a/src/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton.style.ts b/src/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton.style.ts index 7b1f26ee..47a715e2 100644 --- a/src/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton.style.ts +++ b/src/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton.style.ts @@ -10,20 +10,21 @@ export const buttonStyle = (isClicked: boolean) => width: '100%', - padding: '1.2rem 1rem', + padding: '1.2rem', border: 'none', borderRadius: '8px', backgroundColor: isClicked ? theme.colors.blue_100 : theme.colors.gray_100, color: isClicked ? theme.colors.key_500 : theme.colors.black, - fontSize: theme.text.body04.fontSize, - lineHeight: theme.text.body04.lineHeight, + ...theme.text.body08, + fontWeight: 500, cursor: 'pointer', '& > svg': { - width: '2.4rem', - height: '2.4rem', + '& > path': { + fill: isClicked ? theme.colors.key_500 : theme.colors.gray_800, + }, }, }); diff --git a/src/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton.tsx b/src/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton.tsx index 6369839a..2371be58 100644 --- a/src/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton.tsx +++ b/src/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton.tsx @@ -1,7 +1,6 @@ import { ComponentPropsWithoutRef } from 'react'; -import Check from '@/common/asset/svg/ic_gray_check.svg?react'; -import CheckActive from '@/common/asset/svg/ic_key_check.svg?react'; +import IcCheck from '@/common/asset/svg/ic_check.svg?react'; import { buttonStyle } from '@/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton.style'; @@ -12,7 +11,7 @@ interface TermsAgreeButtonProps extends ComponentPropsWithoutRef<'button'> { const TermsAgreeButton = ({ isClicked = false, ...props }: TermsAgreeButtonProps) => { return ( ); diff --git a/src/page/signUp/info/component/InfoForm/InfoForm.style.ts b/src/page/signUp/info/component/InfoForm/InfoForm.style.ts index c3e71e1e..be7ea4c2 100644 --- a/src/page/signUp/info/component/InfoForm/InfoForm.style.ts +++ b/src/page/signUp/info/component/InfoForm/InfoForm.style.ts @@ -6,10 +6,11 @@ export const formStyle = css({ display: 'flex', flexDirection: 'column', justifyContent: 'space-between', - gap: '3.2rem', + gap: '6rem', - width: '100%', - minHeight: '70dvh', + width: '60rem', + + padding: '6rem 10.5rem', '& > div': { width: '100%', From be819dcd04d744776e550c32433a8726c8a4dba4 Mon Sep 17 00:00:00 2001 From: wuzoo Date: Wed, 6 Nov 2024 00:24:44 +0900 Subject: [PATCH 3/6] feat: univ form publishing --- .../SupportingText/SupportingText.style.ts | 2 +- src/common/router/Router.tsx | 2 +- src/page/signUp/index/TermPage.tsx | 2 +- src/page/signUp/info/InfoFormPage.tsx | 24 ++++++--- .../component/PasswordForm/PasswordForm.tsx | 46 ----------------- .../info/component/UnivForm/UnivForm.tsx | 51 +++++++++++++++++++ .../signUp/info/hook/common/useInfoForm.ts | 2 +- .../signUp/info/hook/common/useUnivForm.ts | 35 +++++++++++++ src/shared/constant/path.ts | 2 +- 9 files changed, 107 insertions(+), 59 deletions(-) delete mode 100644 src/page/signUp/info/component/PasswordForm/PasswordForm.tsx create mode 100644 src/page/signUp/info/component/UnivForm/UnivForm.tsx create mode 100644 src/page/signUp/info/hook/common/useUnivForm.ts diff --git a/src/common/component/SupportingText/SupportingText.style.ts b/src/common/component/SupportingText/SupportingText.style.ts index a2e520d2..7f494e5d 100644 --- a/src/common/component/SupportingText/SupportingText.style.ts +++ b/src/common/component/SupportingText/SupportingText.style.ts @@ -7,7 +7,7 @@ export const textStyle = (isError: boolean, isNotice: boolean) => { ? theme.colors.sementic_red : isNotice ? theme.colors.sementic_success - : theme.colors.gray_400; + : theme.colors.gray_500; return css({ color: textColor, paddingLeft: '0.8rem', wordBreak: 'break-word', ...theme.text.body09 }); }; diff --git a/src/common/router/Router.tsx b/src/common/router/Router.tsx index 94d30c41..fbe8ed8d 100644 --- a/src/common/router/Router.tsx +++ b/src/common/router/Router.tsx @@ -75,7 +75,7 @@ const router = createBrowserRouter([ ), }, { - path: PATH.SIGNUP_PASSWORD, + path: PATH.SIGNUP_UNIV, element: ( diff --git a/src/page/signUp/index/TermPage.tsx b/src/page/signUp/index/TermPage.tsx index e265ecf5..bd5a356d 100644 --- a/src/page/signUp/index/TermPage.tsx +++ b/src/page/signUp/index/TermPage.tsx @@ -50,7 +50,7 @@ const TermPage = () => { }; const handleNextStep = () => { - navigate(PATH.SIGNUP_INFO); + navigate(PATH.SIGNUP_UNIV); }; return ( diff --git a/src/page/signUp/info/InfoFormPage.tsx b/src/page/signUp/info/InfoFormPage.tsx index 383dec28..de6a1b00 100644 --- a/src/page/signUp/info/InfoFormPage.tsx +++ b/src/page/signUp/info/InfoFormPage.tsx @@ -1,26 +1,34 @@ -import { useMatch } from 'react-router-dom'; +import { useMatch, useNavigate } from 'react-router-dom'; +import Button from '@/common/component/Button/Button'; import Flex from '@/common/component/Flex/Flex'; import Heading from '@/common/component/Heading/Heading'; import { pageStyle } from '@/page/signUp/info/InfoFormPage.style'; import InfoForm from '@/page/signUp/info/component/InfoForm/InfoForm'; -import PasswordForm from '@/page/signUp/info/component/PasswordForm/PasswordForm'; +import UnivForm from '@/page/signUp/info/component/UnivForm/UnivForm'; import { PATH } from '@/shared/constant/path'; const InfoFormPage = () => { - const isInfoMatched = useMatch(PATH.SIGNUP_INFO); - const isPasswordMatched = useMatch(PATH.SIGNUP_PASSWORD); + const isUnivPage = useMatch(PATH.SIGNUP_UNIV); + const isInfoPage = useMatch(PATH.SIGNUP_INFO); + + const navigate = useNavigate(); return ( - - 회원가입 + + 회원가입 - {isInfoMatched && } +
+ {isUnivPage && } + {isInfoPage && } + - {isPasswordMatched && } +
); diff --git a/src/page/signUp/info/component/PasswordForm/PasswordForm.tsx b/src/page/signUp/info/component/PasswordForm/PasswordForm.tsx deleted file mode 100644 index 4015ec28..00000000 --- a/src/page/signUp/info/component/PasswordForm/PasswordForm.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { useLocation } from 'react-router-dom'; - -import Button from '@/common/component/Button/Button'; -import Flex from '@/common/component/Flex/Flex'; -import Input from '@/common/component/Input/Input'; - -import { formStyle } from '@/page/signUp/info/component/InfoForm/InfoForm.style'; -import { usePasswordForm } from '@/page/signUp/info/hook/common/usePasswordForm'; - -import { PLACEHOLDER } from '@/shared/constant/form'; - -const PasswordForm = () => { - const { - state: { formData }, - } = useLocation(); - - const { info, handleInfoChange, handleSubmit, error } = usePasswordForm(formData); - - return ( -
- - - - - -
- ); -}; - -export default PasswordForm; diff --git a/src/page/signUp/info/component/UnivForm/UnivForm.tsx b/src/page/signUp/info/component/UnivForm/UnivForm.tsx new file mode 100644 index 00000000..87212cdb --- /dev/null +++ b/src/page/signUp/info/component/UnivForm/UnivForm.tsx @@ -0,0 +1,51 @@ +import Button from '@/common/component/Button/Button'; +import Flex from '@/common/component/Flex/Flex'; +import Input from '@/common/component/Input/Input'; + +import { useUnivForm } from '@/page/signUp/info/hook/common/useUnivForm'; + +import { PLACEHOLDER } from '@/shared/constant/form'; + +const UnivForm = () => { + const { inputs, isVerfied, setIsVerified, handleChange } = useUnivForm(); + + return ( + + + + + handleChange(e, 'email')} + label="학교 인증" + placeholder={PLACEHOLDER.SCHOOL_EMAIL} + supportingText="메일함에서 인증 번호를 확인해주세요" + /> + + + {isVerfied ? ( + + handleChange(e, 'code')} + placeholder={PLACEHOLDER.AUTH_CODE} + /> + + + ) : ( +
+ )} + + ); +}; + +export default UnivForm; diff --git a/src/page/signUp/info/hook/common/useInfoForm.ts b/src/page/signUp/info/hook/common/useInfoForm.ts index ca0cc999..ceba39b4 100644 --- a/src/page/signUp/info/hook/common/useInfoForm.ts +++ b/src/page/signUp/info/hook/common/useInfoForm.ts @@ -153,7 +153,7 @@ export const useInfoForm = () => { email: info.email, }; - navigate(PATH.SIGNUP_PASSWORD, { + navigate(PATH.SIGNUP_UNIV, { state: { formData, }, diff --git a/src/page/signUp/info/hook/common/useUnivForm.ts b/src/page/signUp/info/hook/common/useUnivForm.ts new file mode 100644 index 00000000..d7c6bfcc --- /dev/null +++ b/src/page/signUp/info/hook/common/useUnivForm.ts @@ -0,0 +1,35 @@ +import { ChangeEvent, useState } from 'react'; + +import { useOverlay } from '@/common/hook'; + +type UnivForm = { + email: string; + code: string; +}; + +export const useUnivForm = () => { + const { isOpen: isSelectOpen, open: selectOpen, close: selectClose, toggle: selectToggle } = useOverlay(); + + const [inputs, setInputs] = useState({} as UnivForm); + + /** TODO: 추후 인증 api 결과값으로 대체 */ + const [isVerfied, setIsVerified] = useState(false); + + const handleChange = (e: ChangeEvent, key: keyof UnivForm) => { + setInputs((prev) => ({ + ...prev, + [key]: e.target.value, + })); + }; + + return { + inputs, + isVerfied, + setIsVerified, + handleChange, + isSelectOpen, + selectClose, + selectOpen, + selectToggle, + }; +}; diff --git a/src/shared/constant/path.ts b/src/shared/constant/path.ts index 3624d198..4670f788 100644 --- a/src/shared/constant/path.ts +++ b/src/shared/constant/path.ts @@ -6,7 +6,7 @@ export const PATH = { SIGNUP: '/signup', SIGNUP_INFO: '/signup-info', - SIGNUP_PASSWORD: '/signup-password', + SIGNUP_UNIV: '/signup-univ', PASSWORD_AUTH: '/password-auth', PASSWORD_RESET: '/password-reset', From c061eca13e72413f5ecfd6d734808586abc3db6c Mon Sep 17 00:00:00 2001 From: wuzoo Date: Wed, 6 Nov 2024 14:25:36 +0900 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20useTermForm=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/page/signUp/index/TermPage.tsx | 48 ++++------------------- src/page/signUp/index/hook/useTermForm.ts | 43 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 40 deletions(-) create mode 100644 src/page/signUp/index/hook/useTermForm.ts diff --git a/src/page/signUp/index/TermPage.tsx b/src/page/signUp/index/TermPage.tsx index bd5a356d..9dd733ac 100644 --- a/src/page/signUp/index/TermPage.tsx +++ b/src/page/signUp/index/TermPage.tsx @@ -1,4 +1,3 @@ -import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import Button from '@/common/component/Button/Button'; @@ -7,6 +6,7 @@ import Heading from '@/common/component/Heading/Heading'; import TermItem from '@/page/signUp/index/component/TermItem/TermItem'; import TermsAgreeButton from '@/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton'; +import { useTermForm } from '@/page/signUp/index/hook/useTermForm'; import { pageStyle } from '@/page/signUp/info/InfoFormPage.style'; import { formStyle } from '@/page/signUp/info/component/InfoForm/InfoForm.style'; @@ -14,51 +14,19 @@ import { PATH } from '@/shared/constant/path'; import { PERSONAL, TERM } from '@/mock/data/term'; -type TermItem = { - serviceTerm: boolean; - privatePolicy: boolean; - personalInfo: boolean; -}; - const TermPage = () => { - const [totalAgreeClicked, setTotalAgreeClicked] = useState(false); - const [termStatus, setTermStatus] = useState({ - serviceTerm: false, - privatePolicy: false, - personalInfo: false, - }); + const { totalAgreeClicked, termStatus, isConfirmed, handleAllTermsAgree, handleTermAgree } = useTermForm(); const navigate = useNavigate(); - const isConfirmed = termStatus.serviceTerm && termStatus.privatePolicy; - - const 약관전체동의클릭 = () => { - setTotalAgreeClicked((prev) => !prev); - - setTermStatus({ - serviceTerm: totalAgreeClicked ? false : true, - privatePolicy: totalAgreeClicked ? false : true, - personalInfo: totalAgreeClicked ? false : true, - }); - }; - - const handleItemClick = (key: keyof TermItem) => { - setTermStatus((prev) => ({ - ...prev, - [key]: !prev[key], - })); - }; - - const handleNextStep = () => { - navigate(PATH.SIGNUP_UNIV); - }; + const handleNextStep = () => navigate(PATH.SIGNUP_UNIV); return (
이용 약관 동의 - + { description="티키 서비스 이용약관은 다음과 같은 내용을 담고 있습니다." isRequired isSelected={termStatus.serviceTerm} - onSelect={() => handleItemClick('serviceTerm')} + onSelect={() => handleTermAgree('serviceTerm')} /> { description="티키 서비스 이용약관은 다음과 같은 내용을 담고 있습니다." isRequired isSelected={termStatus.privatePolicy} - onSelect={() => handleItemClick('privatePolicy')} + onSelect={() => handleTermAgree('privatePolicy')} /> handleItemClick('personalInfo')} + onSelect={() => handleTermAgree('personalInfo')} /> -
diff --git a/src/page/signUp/index/hook/useTermForm.ts b/src/page/signUp/index/hook/useTermForm.ts new file mode 100644 index 00000000..49013af6 --- /dev/null +++ b/src/page/signUp/index/hook/useTermForm.ts @@ -0,0 +1,43 @@ +import { useState } from 'react'; + +type TermItem = { + serviceTerm: boolean; + privatePolicy: boolean; + personalInfo: boolean; +}; + +export const useTermForm = () => { + const [totalAgreeClicked, setTotalAgreeClicked] = useState(false); + const [termStatus, setTermStatus] = useState({ + serviceTerm: false, + privatePolicy: false, + personalInfo: false, + }); + + const isConfirmed = termStatus.serviceTerm && termStatus.privatePolicy; + + const handleAllTermsAgree = () => { + setTotalAgreeClicked((prev) => !prev); + + setTermStatus({ + serviceTerm: totalAgreeClicked ? false : true, + privatePolicy: totalAgreeClicked ? false : true, + personalInfo: totalAgreeClicked ? false : true, + }); + }; + + const handleTermAgree = (key: keyof TermItem) => { + setTermStatus((prev) => ({ + ...prev, + [key]: !prev[key], + })); + }; + + return { + totalAgreeClicked, + termStatus, + isConfirmed, + handleAllTermsAgree, + handleTermAgree, + }; +}; From c69a898ca558b98d1d48836789ae24cf09cc2948 Mon Sep 17 00:00:00 2001 From: wuzoo Date: Wed, 6 Nov 2024 15:26:10 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20page=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/router/Router.tsx | 8 +- src/page/signUp/index/TermPage.tsx | 3 +- src/page/signUp/info/InfoFormPage.style.ts | 47 +----- src/page/signUp/info/InfoFormPage.tsx | 59 ++++--- src/page/signUp/info/UnivFormPage.tsx | 62 +++++++ .../info/component/InfoForm/InfoForm.style.ts | 63 ------- .../info/component/InfoForm/InfoForm.tsx | 155 ------------------ .../info/component/UnivForm/UnivForm.tsx | 51 ------ .../UnivSelectTriggerButton/Button.tsx | 33 ---- .../signUp/info/hook/common/useInfoForm.ts | 151 ++++++++--------- .../signUp/info/hook/common/useUnivForm.ts | 16 +- 11 files changed, 195 insertions(+), 453 deletions(-) create mode 100644 src/page/signUp/info/UnivFormPage.tsx delete mode 100644 src/page/signUp/info/component/InfoForm/InfoForm.style.ts delete mode 100644 src/page/signUp/info/component/InfoForm/InfoForm.tsx delete mode 100644 src/page/signUp/info/component/UnivForm/UnivForm.tsx delete mode 100644 src/page/signUp/info/component/UnivSelectTriggerButton/Button.tsx diff --git a/src/common/router/Router.tsx b/src/common/router/Router.tsx index fbe8ed8d..68c52887 100644 --- a/src/common/router/Router.tsx +++ b/src/common/router/Router.tsx @@ -18,6 +18,8 @@ import { TermPage, } from '@/common/router/lazy'; +import UnivFormPage from '@/page/signUp/info/UnivFormPage'; + import { PATH } from '@/shared/constant/path'; const Public = () => { @@ -67,15 +69,15 @@ const router = createBrowserRouter([ ), }, { - path: PATH.SIGNUP_INFO, + path: PATH.SIGNUP_UNIV, element: ( - + ), }, { - path: PATH.SIGNUP_UNIV, + path: PATH.SIGNUP_INFO, element: ( diff --git a/src/page/signUp/index/TermPage.tsx b/src/page/signUp/index/TermPage.tsx index 9dd733ac..f957f25e 100644 --- a/src/page/signUp/index/TermPage.tsx +++ b/src/page/signUp/index/TermPage.tsx @@ -7,8 +7,7 @@ import Heading from '@/common/component/Heading/Heading'; import TermItem from '@/page/signUp/index/component/TermItem/TermItem'; import TermsAgreeButton from '@/page/signUp/index/component/TermsAgreeButton/TermsAgreeButton'; import { useTermForm } from '@/page/signUp/index/hook/useTermForm'; -import { pageStyle } from '@/page/signUp/info/InfoFormPage.style'; -import { formStyle } from '@/page/signUp/info/component/InfoForm/InfoForm.style'; +import { formStyle, pageStyle } from '@/page/signUp/info/InfoFormPage.style'; import { PATH } from '@/shared/constant/path'; diff --git a/src/page/signUp/info/InfoFormPage.style.ts b/src/page/signUp/info/InfoFormPage.style.ts index 6a2919ac..623906b9 100644 --- a/src/page/signUp/info/InfoFormPage.style.ts +++ b/src/page/signUp/info/InfoFormPage.style.ts @@ -1,7 +1,5 @@ import { css } from '@emotion/react'; -import { theme } from '@/common/style/theme/theme'; - export const pageStyle = css({ justifyContent: 'center', alignItems: 'center', @@ -10,48 +8,17 @@ export const pageStyle = css({ height: '100dvh', }); -export const selectTriggerStyle = css({ +export const formStyle = css({ display: 'flex', + flexDirection: 'column', justifyContent: 'space-between', - alignItems: 'center', - - width: '100%', - padding: '1.2rem', + width: '60rem', + height: '60rem', - border: 'none', - borderBottom: `1px solid ${theme.colors.gray_400}`, - backgroundColor: 'transparent', - color: theme.colors.gray_500, + padding: '6rem 10.5rem', - fontSize: theme.text.body04.fontSize, - lineHeight: theme.text.body04.lineHeight, - - '& > svg': { - width: 10, - height: 10, - }, - - '&:focus': { - borderColor: theme.colors.key_500, + '& > div': { + width: '100%', }, }); - -export const identifyStyle = css({ - alignItems: 'end', - justifyContent: 'space-between', - gap: '0.8rem', - - position: 'relative', - - width: '100%', -}); - -export const timeStyle = css({ - position: 'absolute', - bottom: '1.5rem', - right: '20rem', - - color: theme.colors.key_500, - ...theme.text.body04, -}); diff --git a/src/page/signUp/info/InfoFormPage.tsx b/src/page/signUp/info/InfoFormPage.tsx index de6a1b00..e40edee1 100644 --- a/src/page/signUp/info/InfoFormPage.tsx +++ b/src/page/signUp/info/InfoFormPage.tsx @@ -1,35 +1,56 @@ -import { useMatch, useNavigate } from 'react-router-dom'; - import Button from '@/common/component/Button/Button'; import Flex from '@/common/component/Flex/Flex'; import Heading from '@/common/component/Heading/Heading'; +import Input from '@/common/component/Input/Input'; -import { pageStyle } from '@/page/signUp/info/InfoFormPage.style'; -import InfoForm from '@/page/signUp/info/component/InfoForm/InfoForm'; -import UnivForm from '@/page/signUp/info/component/UnivForm/UnivForm'; +import { formStyle, pageStyle } from '@/page/signUp/info/InfoFormPage.style'; +import { useInfoForm } from '@/page/signUp/info/hook/common/useInfoForm'; -import { PATH } from '@/shared/constant/path'; +import { PLACEHOLDER } from '@/shared/constant/form'; const InfoFormPage = () => { - const isUnivPage = useMatch(PATH.SIGNUP_UNIV); - const isInfoPage = useMatch(PATH.SIGNUP_INFO); - - const navigate = useNavigate(); + const { info, handleInfoChange, handleBirthChange, handleSubmit } = useInfoForm(); return ( - +
회원가입 - - - {isUnivPage && } - {isInfoPage && } - - - -
+
); }; diff --git a/src/page/signUp/info/UnivFormPage.tsx b/src/page/signUp/info/UnivFormPage.tsx new file mode 100644 index 00000000..41718865 --- /dev/null +++ b/src/page/signUp/info/UnivFormPage.tsx @@ -0,0 +1,62 @@ +import Button from '@/common/component/Button/Button'; +import Flex from '@/common/component/Flex/Flex'; +import Heading from '@/common/component/Heading/Heading'; +import Input from '@/common/component/Input/Input'; + +import { formStyle, pageStyle } from '@/page/signUp/info/InfoFormPage.style'; +import { useUnivForm } from '@/page/signUp/info/hook/common/useUnivForm'; + +import { PLACEHOLDER } from '@/shared/constant/form'; + +const UnivFormPage = () => { + const { inputs, isVerfied, setIsVerified, handleChange, handleSubmit } = useUnivForm(); + + return ( + +
+ 회원가입 + + + + + + handleChange(e, 'email')} + label="학교 인증" + placeholder={PLACEHOLDER.SCHOOL_EMAIL} + supportingText="메일함에서 인증 번호를 확인해주세요" + /> + + + {isVerfied ? ( + + handleChange(e, 'code')} + placeholder={PLACEHOLDER.AUTH_CODE} + /> + + + ) : ( +
+ )} + + + + + ); +}; + +export default UnivFormPage; diff --git a/src/page/signUp/info/component/InfoForm/InfoForm.style.ts b/src/page/signUp/info/component/InfoForm/InfoForm.style.ts deleted file mode 100644 index be7ea4c2..00000000 --- a/src/page/signUp/info/component/InfoForm/InfoForm.style.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { css } from '@emotion/react'; - -import { theme } from '@/common/style/theme/theme'; - -export const formStyle = css({ - display: 'flex', - flexDirection: 'column', - justifyContent: 'space-between', - gap: '6rem', - - width: '60rem', - - padding: '6rem 10.5rem', - - '& > div': { - width: '100%', - }, -}); - -export const selectTriggerStyle = (isError: boolean) => - css({ - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - - width: '100%', - - padding: '1.2rem', - - border: 'none', - borderBottom: `1px solid ${isError ? theme.colors.sementic_red : theme.colors.gray_400}`, - backgroundColor: 'transparent', - color: theme.colors.gray_500, - - fontSize: theme.text.body04.fontSize, - lineHeight: theme.text.body04.lineHeight, - - '& > svg': { - width: 10, - height: 10, - }, - - '&:focus': { - outline: 'none', - - borderColor: theme.colors.key_600, - }, - }); - -export const identifyStyle = css({ - position: 'relative', - - width: '100%', -}); - -export const timeStyle = css({ - position: 'absolute', - bottom: '1rem', - right: '12.5rem', - - color: theme.colors.key_600, - ...theme.text.body04, -}); diff --git a/src/page/signUp/info/component/InfoForm/InfoForm.tsx b/src/page/signUp/info/component/InfoForm/InfoForm.tsx deleted file mode 100644 index e23d8c82..00000000 --- a/src/page/signUp/info/component/InfoForm/InfoForm.tsx +++ /dev/null @@ -1,155 +0,0 @@ -import Button from '@/common/component/Button/Button'; -import Flex from '@/common/component/Flex/Flex'; -import Input from '@/common/component/Input/Input'; -import Select from '@/common/component/Select/Select'; -import { useOutsideClick } from '@/common/hook'; - -import { formStyle, identifyStyle, timeStyle } from '@/page/signUp/info/component/InfoForm/InfoForm.style'; -import { useSendMailMutation } from '@/page/signUp/info/hook/api/useSendMailMutation'; -import { useInfoForm } from '@/page/signUp/info/hook/common/useInfoForm'; -import { useTimer } from '@/page/signUp/info/hook/common/useTimer'; -import { formatTime } from '@/page/signUp/info/util/formatTime'; - -import { - AUTHCODE_MAXLENGTH, - EMAIL_REMAIN_TIME, - PLACEHOLDER, - SUPPORTING_TEXT, - UNIV_EMAIL_FORMAT, -} from '@/shared/constant/form'; -import { useToastAction } from '@/shared/store/toast'; -import { validateCode, validateEmail } from '@/shared/util/validate'; - -const InfoForm = () => { - const { - info, - handleInfoChange, - handleBirthChange, - handleUnivSelect, - handleSubmit, - verityCodeMutate, - isVerified, - isSelectOpen, - onSelectClose, - onSelectToggle, - error, - } = useInfoForm(); - - const ref = useOutsideClick(onSelectClose); - - console.log(info); - - const { - remainTime, - isTriggered: isMailSent, - handleTrigger: onSend, - handleReset: onTimerReset, - handleFail: onFail, - handleStop: onStop, - } = useTimer(EMAIL_REMAIN_TIME, SUPPORTING_TEXT.EMAIL_EXPIRED); - - const { mutate: sendMailMutate } = useSendMailMutation(info.email, onFail); - - if (isVerified) onStop(); - - const { createToast } = useToastAction(); - - const handleMailSend = () => { - if (!UNIV_EMAIL_FORMAT.test(info.email)) { - createToast(SUPPORTING_TEXT.EMAIL_INVALID, 'error'); - - return; - } - if (isMailSent) { - onTimerReset(); - } - - onSend(); - - sendMailMutate(); - }; - - const univOptions = [ - { value: '인하대학교' }, - { value: '건국대학교' }, - { value: '숙명여자대학교' }, - { value: '시립대학교' }, - { value: '중앙대학교' }, - ]; - - return ( -
- - - - - - - - {isMailSent && ( - - - {formatTime(remainTime)} - - - )} - - -
- ); -}; - -export default InfoForm; diff --git a/src/page/signUp/info/component/UnivForm/UnivForm.tsx b/src/page/signUp/info/component/UnivForm/UnivForm.tsx deleted file mode 100644 index 87212cdb..00000000 --- a/src/page/signUp/info/component/UnivForm/UnivForm.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import Button from '@/common/component/Button/Button'; -import Flex from '@/common/component/Flex/Flex'; -import Input from '@/common/component/Input/Input'; - -import { useUnivForm } from '@/page/signUp/info/hook/common/useUnivForm'; - -import { PLACEHOLDER } from '@/shared/constant/form'; - -const UnivForm = () => { - const { inputs, isVerfied, setIsVerified, handleChange } = useUnivForm(); - - return ( - - - - - handleChange(e, 'email')} - label="학교 인증" - placeholder={PLACEHOLDER.SCHOOL_EMAIL} - supportingText="메일함에서 인증 번호를 확인해주세요" - /> - - - {isVerfied ? ( - - handleChange(e, 'code')} - placeholder={PLACEHOLDER.AUTH_CODE} - /> - - - ) : ( -
- )} - - ); -}; - -export default UnivForm; diff --git a/src/page/signUp/info/component/UnivSelectTriggerButton/Button.tsx b/src/page/signUp/info/component/UnivSelectTriggerButton/Button.tsx deleted file mode 100644 index d2f019db..00000000 --- a/src/page/signUp/info/component/UnivSelectTriggerButton/Button.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { PropsWithChildren } from 'react'; - -import { selectTriggerStyle } from '@/page/signUp/info/component/InfoForm/InfoForm.style'; - -interface UnivSelectTriggerButtonProps extends PropsWithChildren { - isError?: boolean; - onOpen?: () => void; - onSelectClick?: () => void; -} - -const UnivSelectTriggerButton = ({ - isError = false, - onOpen, - onSelectClick, - children, -}: UnivSelectTriggerButtonProps) => { - return ( -
{ - if (e.key === 'Enter') { - onOpen?.(); - } - }} - onClick={onSelectClick}> - {children} -
- ); -}; - -export default UnivSelectTriggerButton; diff --git a/src/page/signUp/info/hook/common/useInfoForm.ts b/src/page/signUp/info/hook/common/useInfoForm.ts index ceba39b4..8a2983fa 100644 --- a/src/page/signUp/info/hook/common/useInfoForm.ts +++ b/src/page/signUp/info/hook/common/useInfoForm.ts @@ -1,55 +1,41 @@ -import { ChangeEvent, FormEvent, useCallback, useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { ChangeEvent, FormEvent, useCallback, useState } from 'react'; -import { useError, useOverlay } from '@/common/hook'; +import { useError } from '@/common/hook'; import { getFormatDateString, getFormatNumberString, isValidDate } from '@/page/signUp/info/util/date'; import { UserInfo } from '@/shared/api/signup/info/type'; -import { DATE_MAXLENGTH, FORMATTED_DATE_MAXLENGTH, SUPPORTING_TEXT } from '@/shared/constant/form'; -import { PATH } from '@/shared/constant/path'; -import { useVerifyCodeMutation } from '@/shared/hook/api/useVerifyCodeMutation'; -import { useToastAction } from '@/shared/store/toast'; +import { + DATE_MAXLENGTH, + FORMATTED_DATE_MAXLENGTH, + PASSWORD_VALID_FORMAT, + SUPPORTING_TEXT, +} from '@/shared/constant/form'; import { hasKeyInObject } from '@/shared/util/typeGuard'; -export type InfoFormData = Omit; - -type InfoFormUserInput = InfoFormData & { - authCode: string; -}; +export type InfoFormData = Omit; const IS_EMPTY_STRING = { name: SUPPORTING_TEXT.NAME, birth: SUPPORTING_TEXT.BIRTH, - univ: SUPPORTING_TEXT.UNIV, - email: SUPPORTING_TEXT.EMAIL, - authCode: SUPPORTING_TEXT.EMAIL_NOAUTH, + password: SUPPORTING_TEXT.PASSWORD, + passwordChecker: SUPPORTING_TEXT.PASSWORD_CHECKER, } as const; export const useInfoForm = () => { - const [info, setInfo] = useState({ name: '', birth: '', univ: '', email: '', authCode: '' }); + const [info, setInfo] = useState({ name: '', birth: '', password: '', passwordChecker: '' }); - const { error, updateFieldError, clearFieldError } = useError({ + const { error, updateFieldError, clearFieldError, setErrors } = useError({ name: '', birth: '', - univ: '', - email: '', - authCode: '', + password: '', + passwordChecker: '', }); - const { isOpen: isSelectOpen, open: onSelectOpen, close: onSelectClose, toggle: onSelectToggle } = useOverlay(); - - const { mutate: verityCodeMutate, isSuccess: isVerified } = useVerifyCodeMutation(info.email, info.authCode); - - const { createToast } = useToastAction(); - - const navigate = useNavigate(); - - useEffect(() => { - clearFieldError('univ'); - - onSelectClose(); - }, [onSelectClose, clearFieldError]); + /** + * TODD: 추후 UnivForm 로직에서 재사용 + * const { mutate: verityCodeMutate, isSuccess: isVerified } = useVerifyCodeMutation(info.email, info.authCode); + */ const handleInfoChange = useCallback( (e: ChangeEvent) => { @@ -88,18 +74,6 @@ export const useInfoForm = () => { [info.birth, clearFieldError] ); - const handleUnivSelect = useCallback( - (item: string) => { - setInfo((prev) => ({ - ...prev, - univ: item, - })); - - onSelectClose(); - }, - [onSelectClose] - ); - const validateDate = useCallback(() => { if (info.birth === '' || !isValidDate(info.birth)) { updateFieldError('birth', 'error'); @@ -109,10 +83,49 @@ export const useInfoForm = () => { return true; }, [info.birth, updateFieldError]); + const validatePassword = useCallback(() => { + if (info.password === '') { + updateFieldError('password', SUPPORTING_TEXT.PASSWORD); + + return false; + } + + if (info.passwordChecker === '') { + updateFieldError('passwordChecker', SUPPORTING_TEXT.PASSWORD_CHECKER); + + return false; + } + + if (info.password !== info.passwordChecker) { + setErrors({ + ...error, + password: SUPPORTING_TEXT.PASSWORD_NO_EQUAL, + passwordChecker: SUPPORTING_TEXT.PASSWORD_NO_EQUAL, + }); + + return false; + } + + if (!PASSWORD_VALID_FORMAT.test(info.password)) { + updateFieldError('password', SUPPORTING_TEXT.PASSWORD_INVALID); + + return false; + } + + return true; + }, [error, info, setErrors, updateFieldError]); + const validateForm = useCallback(() => { let isFormError = false; Object.entries(info).some(([key, value]) => { + /** 이름 유효성 검사 */ + if (key === 'name') { + if (value === '') { + updateFieldError(key, IS_EMPTY_STRING.name); + } + } + /** 생일 유효성 검사 */ if (key === 'birth') { if (!validateDate()) { @@ -120,60 +133,28 @@ export const useInfoForm = () => { return true; } } - /** 선택된 대학교 검사 */ - if (key === 'univ' && value === '') { - updateFieldError('univ', 'error'); - isFormError = true; - return true; - } - /** 나머지 info 유효성 검사 */ - if (value === '' && hasKeyInObject(error, key)) { - updateFieldError(key, IS_EMPTY_STRING[key]); - if (key === 'authCode') { - createToast(SUPPORTING_TEXT.EMAIL_NOAUTH, 'error'); - } + /** 비밀번호 유효성 검사 */ + + if (!validatePassword()) { isFormError = true; return true; } }); return !isFormError; - }, [createToast, info, validateDate, updateFieldError, error]); - - const handleSubmit = useCallback( - (e: FormEvent) => { - e.preventDefault(); + }, [info, validateDate, updateFieldError, validatePassword]); - if (!validateForm() || !isVerified) return; + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); - const formData: InfoFormData = { - name: info.name, - birth: info.birth, - univ: info.univ, - email: info.email, - }; - - navigate(PATH.SIGNUP_UNIV, { - state: { - formData, - }, - }); - }, - [info, isVerified, navigate, validateForm] - ); + if (!validateForm()) return; + }; return { info, handleInfoChange, handleBirthChange, - handleUnivSelect, handleSubmit, - verityCodeMutate, - isVerified, - isSelectOpen, - onSelectOpen, - onSelectClose, - onSelectToggle, error, }; }; diff --git a/src/page/signUp/info/hook/common/useUnivForm.ts b/src/page/signUp/info/hook/common/useUnivForm.ts index d7c6bfcc..06ac0c1d 100644 --- a/src/page/signUp/info/hook/common/useUnivForm.ts +++ b/src/page/signUp/info/hook/common/useUnivForm.ts @@ -1,7 +1,10 @@ -import { ChangeEvent, useState } from 'react'; +import { ChangeEvent, FormEvent, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; import { useOverlay } from '@/common/hook'; +import { PATH } from '@/shared/constant/path'; + type UnivForm = { email: string; code: string; @@ -15,6 +18,8 @@ export const useUnivForm = () => { /** TODO: 추후 인증 api 결과값으로 대체 */ const [isVerfied, setIsVerified] = useState(false); + const navigate = useNavigate(); + const handleChange = (e: ChangeEvent, key: keyof UnivForm) => { setInputs((prev) => ({ ...prev, @@ -22,11 +27,18 @@ export const useUnivForm = () => { })); }; + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + + navigate(PATH.SIGNUP_INFO); + }; + return { inputs, isVerfied, - setIsVerified, + setIsVerified, // 추후 삭제 handleChange, + handleSubmit, isSelectOpen, selectClose, selectOpen, From 1df571f77d50c748e19e47f49f7d8628182a4395 Mon Sep 17 00:00:00 2001 From: wuzoo Date: Wed, 6 Nov 2024 15:47:03 +0900 Subject: [PATCH 6/6] =?UTF-8?q?chore:=20=EB=B6=88=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../info/hook/common/usePasswordForm.ts | 90 ------------------- 1 file changed, 90 deletions(-) delete mode 100644 src/page/signUp/info/hook/common/usePasswordForm.ts diff --git a/src/page/signUp/info/hook/common/usePasswordForm.ts b/src/page/signUp/info/hook/common/usePasswordForm.ts deleted file mode 100644 index f0619d31..00000000 --- a/src/page/signUp/info/hook/common/usePasswordForm.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { ChangeEvent, FormEvent, useCallback, useState } from 'react'; - -import { useError } from '@/common/hook'; - -import { useSignupMutation } from '@/page/signUp/info/hook/api/useSignupMutation'; -import { InfoFormData } from '@/page/signUp/info/hook/common/useInfoForm'; - -import { UserInfo } from '@/shared/api/signup/info/type'; -import { PASSWORD_VALID_FORMAT, SUPPORTING_TEXT } from '@/shared/constant/form'; -import { hasKeyInObject } from '@/shared/util/typeGuard'; - -type PasswordFormData = Omit; - -export const usePasswordForm = (prevData: InfoFormData) => { - const [info, setInfo] = useState({ password: '', passwordChecker: '' }); - - const { error, setErrors, updateFieldError, clearFieldError } = useError({ password: '', passwordChecker: '' }); - - const { mutate: signUpMutate } = useSignupMutation(); - - const handleInfoChange = useCallback( - (key: keyof PasswordFormData) => (e: ChangeEvent) => { - const { value } = e.target; - - setInfo((prev) => ({ - ...prev, - [key]: value, - })); - if (value !== '' && hasKeyInObject(error, key)) { - clearFieldError(key); - } - }, - [error, clearFieldError] - ); - - const validateForm = useCallback(() => { - if (info.password === '') { - updateFieldError('password', SUPPORTING_TEXT.PASSWORD); - - return false; - } - - if (info.passwordChecker === '') { - updateFieldError('passwordChecker', SUPPORTING_TEXT.PASSWORD_CHECKER); - - return false; - } - - if (info.password !== info.passwordChecker) { - setErrors({ - password: SUPPORTING_TEXT.PASSWORD_NO_EQUAL, - passwordChecker: SUPPORTING_TEXT.PASSWORD_NO_EQUAL, - }); - - return false; - } - - if (!PASSWORD_VALID_FORMAT.test(info.password)) { - updateFieldError('password', SUPPORTING_TEXT.PASSWORD_INVALID); - - return false; - } - - return true; - }, [info, updateFieldError, setErrors]); - - const handleSubmit = useCallback( - (e: FormEvent) => { - e.preventDefault(); - - if (!validateForm()) return; - - const formData: UserInfo = { - ...prevData, - password: info.password, - passwordChecker: info.passwordChecker, - }; - - signUpMutate(formData); - }, - [validateForm, info, signUpMutate, prevData] - ); - - return { - info, - handleInfoChange, - handleSubmit, - error, - }; -};