From 31f13a38876fca03c3f1bf7b47fc294613f622a4 Mon Sep 17 00:00:00 2001 From: Im-younique Date: Mon, 10 Jun 2024 20:41:53 +0900 Subject: [PATCH 01/18] =?UTF-8?q?[feat]=20=ED=8F=BC=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=8F=BC=EC=97=90=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 --- .../app/login/components/LoginForm/index.tsx | 94 ++++++------------- client/src/components/Form/CheckBox/index.tsx | 25 +++++ client/src/components/Form/Error/index.tsx | 27 +++--- .../components/Form/FieldWrapper/index.tsx | 5 + client/src/components/Form/Input/index.tsx | 45 +++++++-- client/src/components/Form/Label/index.tsx | 23 ++--- client/src/components/Form/index.tsx | 8 +- 7 files changed, 120 insertions(+), 107 deletions(-) create mode 100644 client/src/components/Form/CheckBox/index.tsx create mode 100644 client/src/components/Form/FieldWrapper/index.tsx diff --git a/client/src/app/login/components/LoginForm/index.tsx b/client/src/app/login/components/LoginForm/index.tsx index 24ea0c5a..8be7ca35 100644 --- a/client/src/app/login/components/LoginForm/index.tsx +++ b/client/src/app/login/components/LoginForm/index.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState, useCallback } from 'react'; +import { useCallback } from 'react'; import { useRouter } from 'next/navigation'; //redux @@ -8,16 +8,13 @@ import { useDispatch, useSelector } from 'react-redux'; import { logIn } from '@/lib/redux/features/auth/authSlice'; //components -import { Tooltip } from '@/components'; +import { Tooltip, Form as CustomForm } from '@/components'; //hooks import useModal from '@/hooks/modal/useModal'; -//icons -import { EyeOnIcon, EyeOffIcon } from '@/assets/Icon'; - //formik -import { Formik, Form, Field, ErrorMessage } from 'formik'; +import { Formik, Form } from 'formik'; import * as Yup from 'yup'; //services @@ -45,8 +42,6 @@ interface ILogin { } export default function LoginForm() { - const [viewPassword, setViewPassword] = useState(false); - const dispatch = useDispatch(); const router = useRouter(); @@ -56,6 +51,7 @@ export default function LoginForm() { const handleSubmit = useCallback( async (sendData: ILogin, setSubmitting: (value: boolean) => void) => { + console.log(sendData); if (modalState.type === ModalType.CLOSE) { setSubmitting(true); try { @@ -92,73 +88,45 @@ export default function LoginForm() { {({ errors, touched, isSubmitting }) => (
-
- - + - -
-
- -
- -
setViewPassword((prev) => !prev)} - > - {viewPassword ? : } -
-
- + -
+ +
-
- - -
+ + 로그인 상태유지 +
{ + children?: React.ReactNode; +} + +export default function FormCheckBox({ children, ...props }: IProps) { + return ( +
+ + +
+ ); +} diff --git a/client/src/components/Form/Error/index.tsx b/client/src/components/Form/Error/index.tsx index 3c2b4224..c3ea4f8b 100644 --- a/client/src/components/Form/Error/index.tsx +++ b/client/src/components/Form/Error/index.tsx @@ -1,16 +1,13 @@ -import React from 'react'; - -interface IProps { - isDisplay?: boolean; - name?: string; +'use client'; + +import { ErrorMessage, ErrorMessageProps } from 'formik'; + +export default function FormErrorMessage(props: ErrorMessageProps) { + return ( + + ); } - -function FormError({ isDisplay, name }: IProps) { - const style = isDisplay - ? 'absolute left-0 -bottom-5 text-xs text-red-500' - : 'hidden'; - - return {name}; -} - -export default FormError; diff --git a/client/src/components/Form/FieldWrapper/index.tsx b/client/src/components/Form/FieldWrapper/index.tsx new file mode 100644 index 00000000..e9d08392 --- /dev/null +++ b/client/src/components/Form/FieldWrapper/index.tsx @@ -0,0 +1,5 @@ +import { PropsWithChildren } from 'react'; + +export default function FieldWrapper({ children }: PropsWithChildren) { + return
{children}
; +} diff --git a/client/src/components/Form/Input/index.tsx b/client/src/components/Form/Input/index.tsx index 6283cafc..f067db73 100644 --- a/client/src/components/Form/Input/index.tsx +++ b/client/src/components/Form/Input/index.tsx @@ -1,20 +1,45 @@ 'use client'; // react -import React from 'react'; +import { useState } from 'react'; // formik import { Field, FieldAttributes } from 'formik'; -function FormInput({ children, ...props }: FieldAttributes) { +// icons +import { EyeOnIcon, EyeOffIcon } from '@/assets/Icon'; + +interface IProps extends FieldAttributes { + touchedTarget?: boolean; + errorsTarget?: string; +} + +export default function FormInput({ + touchedTarget = false, + errorsTarget = '', + ...props +}: IProps) { + const type = props.type; + + const [viewPassword, setViewPassword] = useState(false); + return ( - - {children} - +
+ + {type === 'password' && ( +
setViewPassword((prev) => !prev)} + > + {viewPassword ? : } +
+ )} +
); } - -export default FormInput; diff --git a/client/src/components/Form/Label/index.tsx b/client/src/components/Form/Label/index.tsx index 6f17b69c..7f951f9c 100644 --- a/client/src/components/Form/Label/index.tsx +++ b/client/src/components/Form/Label/index.tsx @@ -1,22 +1,11 @@ -import React from 'react'; - -interface IProps { - name: string; - isEssential?: boolean; -} - -function FormLabel({ name, isEssential = false }: IProps) { - const essentialStyle = isEssential - ? `after:content-["*"] after:text-red-500` - : ''; +import { LabelHTMLAttributes } from 'react'; +export default function FormLabel( + props: LabelHTMLAttributes +) { return ( -
-
- -
+ + 로그인 +
)} diff --git a/client/src/components/Form/Button/index.tsx b/client/src/components/Form/Button/index.tsx index aab3397b..9360d537 100644 --- a/client/src/components/Form/Button/index.tsx +++ b/client/src/components/Form/Button/index.tsx @@ -1,20 +1,16 @@ -import React from 'react'; +import { ButtonHTMLAttributes } from 'react'; -interface IProps extends React.ButtonHTMLAttributes { - type: 'button' | 'submit'; -} - -function FormButton({ type, onClick, disabled, children }: IProps) { +export default function FormButton( + props: ButtonHTMLAttributes +) { return ( - +
+ +
); } - -export default FormButton; From 755caa3ea039ec74d37496c80c59db098dec7f76 Mon Sep 17 00:00:00 2001 From: Im-younique Date: Mon, 10 Jun 2024 20:52:16 +0900 Subject: [PATCH 03/18] =?UTF-8?q?[chore]=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=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/app/signup/layout.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/client/src/app/signup/layout.tsx b/client/src/app/signup/layout.tsx index ca088b9d..8663019e 100644 --- a/client/src/app/signup/layout.tsx +++ b/client/src/app/signup/layout.tsx @@ -1,10 +1,18 @@ -import React from 'react'; -import { Layout } from '@/components'; +import Logo from '@/components/Navigator/Logo'; -export default function LayoutComponent({ +export default function SignUpLayout({ children, }: { children: React.ReactNode; }) { - return {children}; + return ( +
+
+
+ +
+ {children} +
+
+ ); } From 74dfe5e1db25487e8a5f1125300c15b57df74b71 Mon Sep 17 00:00:00 2001 From: Im-younique Date: Tue, 11 Jun 2024 13:38:45 +0900 Subject: [PATCH 04/18] =?UTF-8?q?[chore]=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=ED=8F=BC=20UI=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/GithubSignUpButton/index.tsx | 34 +++ .../components/GoogleSignUpButton/index.tsx | 34 +++ .../components/InitialSignUpForm/index.tsx | 220 ++++++++++++++++++ client/src/app/signup/layout.tsx | 2 +- client/src/app/signup/page.tsx | 200 +++++----------- .../components/Form/FieldWrapper/index.tsx | 2 +- client/src/constants/constant.ts | 4 - 7 files changed, 353 insertions(+), 143 deletions(-) create mode 100644 client/src/app/signup/components/GithubSignUpButton/index.tsx create mode 100644 client/src/app/signup/components/GoogleSignUpButton/index.tsx create mode 100644 client/src/app/signup/components/InitialSignUpForm/index.tsx diff --git a/client/src/app/signup/components/GithubSignUpButton/index.tsx b/client/src/app/signup/components/GithubSignUpButton/index.tsx new file mode 100644 index 00000000..28d62342 --- /dev/null +++ b/client/src/app/signup/components/GithubSignUpButton/index.tsx @@ -0,0 +1,34 @@ +'use client'; + +import { Icon } from '@iconify/react'; + +//hooks +import useModal from '@/hooks/modal/useModal'; + +//constant +import { errorMessage, ModalType } from '@/constants/constant'; + +export default function GithubSignUpButton() { + const { openModal } = useModal(); + + return ( +
+ +
+ ); +} diff --git a/client/src/app/signup/components/GoogleSignUpButton/index.tsx b/client/src/app/signup/components/GoogleSignUpButton/index.tsx new file mode 100644 index 00000000..347baff5 --- /dev/null +++ b/client/src/app/signup/components/GoogleSignUpButton/index.tsx @@ -0,0 +1,34 @@ +'use client'; + +import { Icon } from '@iconify/react'; + +//hooks +import useModal from '@/hooks/modal/useModal'; + +//constant +import { errorMessage, ModalType } from '@/constants/constant'; + +export default function GoogleSignUpButton() { + const { openModal } = useModal(); + + return ( +
+ +
+ ); +} diff --git a/client/src/app/signup/components/InitialSignUpForm/index.tsx b/client/src/app/signup/components/InitialSignUpForm/index.tsx new file mode 100644 index 00000000..3eaf80ec --- /dev/null +++ b/client/src/app/signup/components/InitialSignUpForm/index.tsx @@ -0,0 +1,220 @@ +'use client'; + +import { useState } from 'react'; + +//components +import { Button, Form as CustomForm } from '@/components'; + +//hooks +import useModal from '@/hooks/modal/useModal'; +import useEmail from '@/hooks/form/useEmail'; + +//formik +import { Formik, Form, Field } from 'formik'; +import * as Yup from 'yup'; + +//services +import { userManager } from '@/service/user'; + +//constants +import { + initialSignupValue, + ModalType, + successMessage, + errorMessage, + regex, +} from '@/constants/constant'; + +// types +import { EmailState, ISignupData } from '@/types'; + +const ValidationSchema = Yup.object().shape({ + userId: Yup.string() + .required(errorMessage.blankID) + .matches(regex.id, errorMessage.invalidFormatId), + password: Yup.string() + .required(errorMessage.blankPassword) + .matches(regex.password, errorMessage.invalidFormatPassword), + passwordConfirm: Yup.string() + .required(errorMessage.blankPassword) + .oneOf([Yup.ref('password')], errorMessage.mismatchPassword), + email: Yup.string() + .required(errorMessage.blankEmail) + .email(errorMessage.invalidFormatEmail), +}); + +export default function InitialSignUpForm() { + const [checkedId, setCheckedId] = useState(''); + + const { openModal } = useModal(); + + const { + certificateRef, + emailState, + emailAuthToken, + handleChangeCertifiactionNumber, + handleRequestEmail, + handleCheckEmail, + } = useEmail('SIGNUP'); + + const checkDuplicateID = async (userId: string) => { + try { + await userManager.checkDuplicateUser(userId); + setCheckedId(userId); + openModal({ + type: ModalType.SUCCESS, + message: successMessage.availableIdSuccess, + }); + } catch (error) { + setCheckedId(''); + openModal({ + type: ModalType.ERROR, + message: + error === 'duplicate' + ? errorMessage.duplicateId + : errorMessage.network, + }); + } + }; + + const handleSubmit = async ( + sendData: Pick, + setSubmitting: (value: boolean) => void + ) => { + // 아이디 / 이메일 인증확인 + if (checkedId !== sendData.userId || emailAuthToken === '') { + openModal({ + type: ModalType.ERROR, + message: + checkedId !== sendData.userId + ? errorMessage.checkDuplicateId + : errorMessage.checkCertificateEmail, + }); + return; + } + setSubmitting(true); + const data = { + signUpDto: { ...sendData, emailAuthToken }, + }; + }; + + return ( + handleSubmit(data, setSubmitting)} + > + {({ values, errors, touched, isSubmitting }) => ( +
+
+ + + 이메일 + +
+ + +
+ +
+ {emailState === EmailState.Submitted && ( +
+ + +
+ )} + + + 아이디 + +
+ + +
+ +
+ + + 비밀번호 + + + + + + + 비밀번호 확인 + + + + +
+
+ + 이용약관 및 개인정보 처리방침에 동의합니다. + +
+ + 다음 + +
+ )} +
+ ); +} diff --git a/client/src/app/signup/layout.tsx b/client/src/app/signup/layout.tsx index 8663019e..60351ce6 100644 --- a/client/src/app/signup/layout.tsx +++ b/client/src/app/signup/layout.tsx @@ -6,7 +6,7 @@ export default function SignUpLayout({ children: React.ReactNode; }) { return ( -
+
diff --git a/client/src/app/signup/page.tsx b/client/src/app/signup/page.tsx index 9644cf08..6706dc50 100644 --- a/client/src/app/signup/page.tsx +++ b/client/src/app/signup/page.tsx @@ -1,146 +1,72 @@ -'use client'; +import Link from 'next/link'; -// react, next -import React, { useState } from 'react'; -import { useRouter } from 'next/navigation'; - -// packages -import { Formik, Form } from 'formik'; -import * as Yup from 'yup'; - -// components -import { Divider, Avatar, LoadingIcon, Form as CustomForm } from '@/components'; - -// hooks -import useEmail from '@/hooks/form/useEmail'; -import useInputImage from '@/hooks/form/useInputImage'; - -// constant -import { - developExperience, - ModalType, - successMessage, - errorMessage, - initialSignupValue, - regex, -} from '@/constants/constant'; - -// types -import { EmailState, ISignupData } from '@/types'; - -// service -import { userManager } from '@/service/user'; -import useModal from '@/hooks/modal/useModal'; - -// hooks - -const ValidationSchema = Yup.object().shape({ - userId: Yup.string() - .required(errorMessage.blankID) - .matches(regex.id, errorMessage.invalidFormatId), - password: Yup.string() - .required(errorMessage.blankPassword) - .matches(regex.password, errorMessage.invalidFormatPassword), - passwordConfirm: Yup.string() - .required(errorMessage.blankPassword) - .oneOf([Yup.ref('password')], errorMessage.mismatchPassword), - name: Yup.string().required(errorMessage.blankName), - email: Yup.string() - .required(errorMessage.blankEmail) - .email(errorMessage.invalidFormatEmail), -}); +//components +import InitialSignUpForm from './components/InitialSignUpForm'; +import GoogleSignUpButton from './components/GoogleSignUpButton'; +import GithubSignUpButton from './components/GithubSignUpButton'; export default function SignUp() { - const router = useRouter(); - - // Modal - const { openModal, closeModal } = useModal(); - - const { - certificateRef, - emailState, - emailAuthToken, - handleChangeCertifiactionNumber, - handleRequestEmail, - handleCheckEmail, - } = useEmail('SIGNUP'); - - const { imgRef, profileImg, imgFile, handleChooseFile, handleImgInput } = - useInputImage(); - - // 아이디 중복 체크 여부 - const [checkedId, setCheckedId] = useState(''); - - const checkDuplicateID = async (userId: string) => { - try { - await userManager.checkDuplicateUser(userId); - setCheckedId(userId); - openModal({ - type: ModalType.SUCCESS, - message: successMessage.availableIdSuccess, - }); - } catch (error) { - setCheckedId(''); - openModal({ - type: ModalType.ERROR, - message: - error === 'duplicate' - ? errorMessage.duplicateId - : errorMessage.network, - }); - } - }; - - const handleSubmit = async ( - sendData: ISignupData, - setSubmitting: (value: boolean) => void - ) => { - // 아이디 / 이메일 인증확인 - if (checkedId !== sendData.userId || emailAuthToken === '') { - openModal({ - type: ModalType.ERROR, - message: - checkedId !== sendData.userId - ? errorMessage.checkDuplicateId - : errorMessage.checkCertificateEmail, - }); - return; - } - setSubmitting(true); - const data = { - signUpDto: { ...sendData, emailAuthToken }, - imgFile, - }; - try { - await userManager.createUser(data); - openModal({ - type: ModalType.SUCCESS, - message: successMessage.signUpSuccess, - callback: () => { - closeModal(); - router.push('/login'); - }, - }); - } catch { - openModal({ - type: ModalType.ERROR, - message: errorMessage.failedSignUp, - }); - } finally { - setSubmitting(false); - } - }; + // const handleSubmit = async ( + // sendData: ISignupData, + // setSubmitting: (value: boolean) => void + // ) => { + // // 아이디 / 이메일 인증확인 + // if (checkedId !== sendData.userId || emailAuthToken === '') { + // openModal({ + // type: ModalType.ERROR, + // message: + // checkedId !== sendData.userId + // ? errorMessage.checkDuplicateId + // : errorMessage.checkCertificateEmail, + // }); + // return; + // } + // setSubmitting(true); + // const data = { + // signUpDto: { ...sendData, emailAuthToken }, + // imgFile, + // }; + // try { + // await userManager.createUser(data); + // openModal({ + // type: ModalType.SUCCESS, + // message: successMessage.signUpSuccess, + // callback: () => { + // closeModal(); + // router.push('/login'); + // }, + // }); + // } catch { + // openModal({ + // type: ModalType.ERROR, + // message: errorMessage.failedSignUp, + // }); + // } finally { + // setSubmitting(false); + // } + // }; return (
-
-

회원가입

-

- * 필수입력사항 -

+

+ 회원가입 +

+ +
+ + +
+ + {"이미 '리덕' 회원이신가요?"} + + + 로그인 하기 +
- - @@ -317,7 +243,7 @@ export default function SignUp() {
)} - + */}
); } diff --git a/client/src/components/Form/FieldWrapper/index.tsx b/client/src/components/Form/FieldWrapper/index.tsx index e9d08392..d5ba86ed 100644 --- a/client/src/components/Form/FieldWrapper/index.tsx +++ b/client/src/components/Form/FieldWrapper/index.tsx @@ -1,5 +1,5 @@ import { PropsWithChildren } from 'react'; export default function FieldWrapper({ children }: PropsWithChildren) { - return
{children}
; + return
{children}
; } diff --git a/client/src/constants/constant.ts b/client/src/constants/constant.ts index 627b86a4..16d73d59 100644 --- a/client/src/constants/constant.ts +++ b/client/src/constants/constant.ts @@ -88,11 +88,7 @@ export const initialSignupValue = { userId: '', password: '', passwordConfirm: '', - name: '', email: '', - school: '', - company: '', - developYear: '', }; // 이미지 파일 최대용량 10MB From 9d4373e657f24c7c2e7a30ef8614cc1daa6237a7 Mon Sep 17 00:00:00 2001 From: Im-younique Date: Tue, 11 Jun 2024 13:39:06 +0900 Subject: [PATCH 05/18] =?UTF-8?q?[chore]=20Button=20blue=5Fgray=5Fline=20d?= =?UTF-8?q?iabled=20style=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/base/Button/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/base/Button/index.tsx b/client/src/components/base/Button/index.tsx index 607215d0..b6177d2a 100644 --- a/client/src/components/base/Button/index.tsx +++ b/client/src/components/base/Button/index.tsx @@ -21,7 +21,7 @@ export default function Button(props: ButtonProps) { yellow_line: 'bg-yellow-scale-50 border border-yellow-scale-500 text-black disabled:bg-gray-scale-50 disabled:border-gray-scale-800 disabled:text-gray-scale-600', blue_gray_line: - 'border border-gray-900 hover:bg-blue-gray-scale-100 active:bg-blue-gary-scale-100 disabled:bg-gray-scale-50 disabled:border-gray-800 disabled:text-blue-gray-600', + 'border border-gray-900 hover:bg-blue-gray-scale-100 active:bg-blue-gary-scale-100 disabled:bg-gray-scale-50 disabled:border-gray-800 disabled:text-blue-gray-600 disabled:opacity-50', blue_gray_line_disabled: 'bg-gray-scale-50 border border-gray-800 text-blue-gray-scale-600 opacity-40', red: 'bg-red-scale-600 text-white hover:bg-red-scale-700 active:bg-red-scale-700 disable:bg-red-scale-200', From e155cb34ee6c8e18d49983d21c9caa95ddfe82ff Mon Sep 17 00:00:00 2001 From: Im-younique Date: Tue, 11 Jun 2024 13:39:24 +0900 Subject: [PATCH 06/18] =?UTF-8?q?[fix]=20FormCheckbox=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Form/CheckBox/index.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/client/src/components/Form/CheckBox/index.tsx b/client/src/components/Form/CheckBox/index.tsx index 132d0dc8..17edb8ac 100644 --- a/client/src/components/Form/CheckBox/index.tsx +++ b/client/src/components/Form/CheckBox/index.tsx @@ -11,13 +11,10 @@ export default function FormCheckBox({ children, ...props }: IProps) {
-
From d3cfe4a156aebb1b62a4cfb43590ea03d8d80228 Mon Sep 17 00:00:00 2001 From: Im-younique Date: Tue, 11 Jun 2024 14:33:06 +0900 Subject: [PATCH 07/18] =?UTF-8?q?[chore]=20=ED=8C=A8=EC=8A=A4=EC=9B=8C?= =?UTF-8?q?=EB=93=9C=20=EB=B3=B4=EA=B8=B0=20=EC=95=88=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Form/Input/index.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/src/components/Form/Input/index.tsx b/client/src/components/Form/Input/index.tsx index f067db73..4af5a6a9 100644 --- a/client/src/components/Form/Input/index.tsx +++ b/client/src/components/Form/Input/index.tsx @@ -17,16 +17,15 @@ interface IProps extends FieldAttributes { export default function FormInput({ touchedTarget = false, errorsTarget = '', + type, ...props }: IProps) { - const type = props.type; - const [viewPassword, setViewPassword] = useState(false); return (
Date: Tue, 11 Jun 2024 15:05:24 +0900 Subject: [PATCH 08/18] =?UTF-8?q?[feat]=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EA=B8=B0=EB=B3=B8=EC=A0=95=EB=B3=B4=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/InitialSignUpForm/index.tsx | 43 +++++++++++++++---- client/src/constants/constant.ts | 1 + 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/client/src/app/signup/components/InitialSignUpForm/index.tsx b/client/src/app/signup/components/InitialSignUpForm/index.tsx index 3eaf80ec..ce7ce5a7 100644 --- a/client/src/app/signup/components/InitialSignUpForm/index.tsx +++ b/client/src/app/signup/components/InitialSignUpForm/index.tsx @@ -1,9 +1,10 @@ 'use client'; import { useState } from 'react'; +import { useRouter } from 'next/navigation'; //components -import { Button, Form as CustomForm } from '@/components'; +import { Button, LoadingIcon, Form as CustomForm } from '@/components'; //hooks import useModal from '@/hooks/modal/useModal'; @@ -43,7 +44,14 @@ const ValidationSchema = Yup.object().shape({ .email(errorMessage.invalidFormatEmail), }); +interface IFormData extends Pick { + passwordConfirm: string; + agreeTerm: boolean; +} + export default function InitialSignUpForm() { + const router = useRouter(); + const [checkedId, setCheckedId] = useState(''); const { openModal } = useModal(); @@ -77,11 +85,12 @@ export default function InitialSignUpForm() { } }; - const handleSubmit = async ( - sendData: Pick, + const handleSubmit = ( + sendData: IFormData, setSubmitting: (value: boolean) => void ) => { - // 아이디 / 이메일 인증확인 + const { passwordConfirm, agreeTerm, ...mainData } = sendData; + if (checkedId !== sendData.userId || emailAuthToken === '') { openModal({ type: ModalType.ERROR, @@ -90,12 +99,26 @@ export default function InitialSignUpForm() { ? errorMessage.checkDuplicateId : errorMessage.checkCertificateEmail, }); + setSubmitting(false); return; } - setSubmitting(true); + if (!agreeTerm) { + openModal({ + type: ModalType.ERROR, + message: '약관 동의는 필수 입니다.', + }); + setSubmitting(false); + return; + } + const data = { - signUpDto: { ...sendData, emailAuthToken }, + ...mainData, + emailAuthToken, }; + + sessionStorage.setItem('signupDto', JSON.stringify(data)); + setSubmitting(false); + router.push('/signup/addInfo'); }; return ( @@ -127,7 +150,11 @@ export default function InitialSignUpForm() { disabled={errors.email !== undefined || values.email === ''} onClick={() => handleRequestEmail(values.email)} > - 메일인증 + {emailState === EmailState.Submitting ? ( + + ) : ( + '메일인증' + )}
@@ -206,7 +233,7 @@ export default function InitialSignUpForm() {
- + 이용약관 및 개인정보 처리방침에 동의합니다.
diff --git a/client/src/constants/constant.ts b/client/src/constants/constant.ts index 16d73d59..126e2601 100644 --- a/client/src/constants/constant.ts +++ b/client/src/constants/constant.ts @@ -89,6 +89,7 @@ export const initialSignupValue = { password: '', passwordConfirm: '', email: '', + agreeTerm: false, }; // 이미지 파일 최대용량 10MB From 4fe4b2944f1fe1e620c32fab821314956e6bd678 Mon Sep 17 00:00:00 2001 From: Im-younique Date: Tue, 11 Jun 2024 17:35:50 +0900 Subject: [PATCH 09/18] =?UTF-8?q?[feat]=20SelectForm=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Form/Select/index.tsx | 42 +++++++++++++++++++++ client/src/components/Form/index.tsx | 2 + 2 files changed, 44 insertions(+) create mode 100644 client/src/components/Form/Select/index.tsx diff --git a/client/src/components/Form/Select/index.tsx b/client/src/components/Form/Select/index.tsx new file mode 100644 index 00000000..e841a25c --- /dev/null +++ b/client/src/components/Form/Select/index.tsx @@ -0,0 +1,42 @@ +'use client'; + +import { Field, FieldAttributes } from 'formik'; + +import { ArrowDownIcon } from '@/assets/Icon'; + +interface IProps extends FieldAttributes { + touchedTarget?: boolean; + errorsTarget?: string; + placeholder?: string; + options: Array; +} + +export default function FormSelect({ + touchedTarget = false, + errorsTarget = '', + placeholder, + options, + ...props +}: IProps) { + return ( +
+ + + {options.map((val) => ( + + ))} + + +
+ ); +} diff --git a/client/src/components/Form/index.tsx b/client/src/components/Form/index.tsx index cea79805..a552e854 100644 --- a/client/src/components/Form/index.tsx +++ b/client/src/components/Form/index.tsx @@ -7,6 +7,7 @@ import FormInput from './Input'; import FormLabel from './Label'; import FieldWrapper from './FieldWrapper'; import FormCheckBox from './CheckBox'; +import FormSelect from './Select'; const Form = { FormBox, @@ -18,6 +19,7 @@ const Form = { FormLabel, FieldWrapper, FormCheckBox, + FormSelect, }; export default Form; From 683faa8c248b12e04a353169062ca544c0331c17 Mon Sep 17 00:00:00 2001 From: Im-younique Date: Tue, 11 Jun 2024 17:36:44 +0900 Subject: [PATCH 10/18] =?UTF-8?q?[Add]=20WorkingForm=20UI=20=EC=A0=9C?= =?UTF-8?q?=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signup/components/WorkingForm/index.tsx | 89 +++++++++++++++++++ client/src/constants/constant.ts | 4 + 2 files changed, 93 insertions(+) create mode 100644 client/src/app/signup/components/WorkingForm/index.tsx diff --git a/client/src/app/signup/components/WorkingForm/index.tsx b/client/src/app/signup/components/WorkingForm/index.tsx new file mode 100644 index 00000000..e8d56ca7 --- /dev/null +++ b/client/src/app/signup/components/WorkingForm/index.tsx @@ -0,0 +1,89 @@ +//components +import { Form as CustomForm } from '@/components'; +import { errorMessage } from '@/constants/constant'; + +//formik +import { Formik, Form } from 'formik'; +import * as Yup from 'yup'; + +//constants +import { developExperience, ALLMONTH } from '@/constants/constant'; + +const ValidationSchema = Yup.object().shape({ + company: Yup.string().required(errorMessage.blankCompany), + developYear: Yup.number().required(errorMessage.blankDevlopYear), +}); + +const InitialWorkingValue = { + company: '', + developYear: '', + developMonth: '', +}; + +interface IWokring { + company: string; + developYear: string; + developMonth: string; +} + +export default function WorkingForm({ goNext }: { goNext: () => void }) { + const handleSubmit = (data: IWokring) => { + console.log(data); + }; + + return ( + handleSubmit(data)} + > + {({ errors, touched, isSubmitting }) => ( +
+
+

현재 재직중이신가요?

+
+ + + 회사 + + + + + + 개발 직무 시작일 +
+ + +
+ +
+
+ + {'아직 경력이 없어요. 개발 꿈나무 입니다 :)'} + +
+ + 다음 + +
+ )} +
+ ); +} diff --git a/client/src/constants/constant.ts b/client/src/constants/constant.ts index 126e2601..0e118bc2 100644 --- a/client/src/constants/constant.ts +++ b/client/src/constants/constant.ts @@ -13,6 +13,8 @@ export const errorMessage = Object.freeze({ blankPassword: '비밀번호는 필수 입력값 입니다.', blankName: '이름은 필수 입력값 입니다.', blankEmail: '이메일을 입력해주세요.', + blankCompany: '회사를 입력해주세요', + blankDevlopYear: '개발 시작연도는 필수입니다.', minIDLength: '아이디는 최소 6자 이상입니다.', maxIDLength: '아이디는 최대 12자 이하입니다.', invalidFormatId: '아이디는 6 ~ 12자 영어 소문자, 숫자로 이뤄집니다', @@ -25,6 +27,7 @@ export const errorMessage = Object.freeze({ network: '네트워크 오류 입니다.', checkDuplicateId: '아이디 중복확인을 진행해주세요', checkCertificateEmail: '이메일 인증을 진행해주세요', + necessaryAgreeTerm: '약관 동의는 필수 입니다.', needLogin: '로그인이 필요합니다.', blankComment: '댓글을 입력해주세요.', notComplete: '준비 중인 기능입니다.', @@ -101,6 +104,7 @@ export const developExperience = Array.from( { length: 60 }, (_, i) => thisYear - i ); +export const ALLMONTH = Array.from({ length: 12 }, (_, i) => i + 1); export const MODAL_TITLE = { success: '성공', From 0465d0df7f9d7b78fe16fbda8450026e929d6731 Mon Sep 17 00:00:00 2001 From: Im-younique Date: Tue, 11 Jun 2024 17:41:24 +0900 Subject: [PATCH 11/18] =?UTF-8?q?[chore]=20Field=20=EC=9A=94=EC=86=8C?= =?UTF-8?q?=EB=93=A4=20padding=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/InitialSignUpForm/index.tsx | 17 ++++++++++++----- client/src/components/Form/Input/index.tsx | 4 ++-- client/src/components/Form/Select/index.tsx | 4 ++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/client/src/app/signup/components/InitialSignUpForm/index.tsx b/client/src/app/signup/components/InitialSignUpForm/index.tsx index ce7ce5a7..a2e1ae9a 100644 --- a/client/src/app/signup/components/InitialSignUpForm/index.tsx +++ b/client/src/app/signup/components/InitialSignUpForm/index.tsx @@ -105,7 +105,7 @@ export default function InitialSignUpForm() { if (!agreeTerm) { openModal({ type: ModalType.ERROR, - message: '약관 동의는 필수 입니다.', + message: errorMessage.necessaryAgreeTerm, }); setSubmitting(false); return; @@ -142,7 +142,7 @@ export default function InitialSignUpForm() { placeholder="이메일 입력" className={`${ touched.email && errors.email && 'border-red-scale-600' - } flex-1 border border-blue-gray-scale-50 py-[7px] px-4 text-body3 placeholder:text-gray-scale-600 focus:outline-blue-gray-scale-500 disabled:bg-gray-scale-100 disabled:outline-blue-gray-scale-50`} + } flex-1 border border-blue-gray-scale-50 py-[14px] px-4 text-body3 placeholder:text-gray-scale-600 focus:outline-blue-gray-scale-500 disabled:bg-gray-scale-100 disabled:outline-blue-gray-scale-50`} />
From b4b027d430b6fba69c49294b9b9204c29a12cbfc Mon Sep 17 00:00:00 2001 From: Im-younique Date: Wed, 12 Jun 2024 10:12:17 +0900 Subject: [PATCH 15/18] =?UTF-8?q?[feat]=20InformationForm=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/InfomationForm/index.tsx | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 client/src/app/signup/components/InfomationForm/index.tsx diff --git a/client/src/app/signup/components/InfomationForm/index.tsx b/client/src/app/signup/components/InfomationForm/index.tsx new file mode 100644 index 00000000..93249f46 --- /dev/null +++ b/client/src/app/signup/components/InfomationForm/index.tsx @@ -0,0 +1,118 @@ +import { useRouter } from 'next/navigation'; + +//components +import { Form as CustomForm } from '@/components'; + +//hooks +import useModal from '@/hooks/modal/useModal'; + +//formik +import { Formik, Form } from 'formik'; +import * as Yup from 'yup'; + +//services +import { userManager } from '@/service/user'; + +//constants +import { ModalType, successMessage, errorMessage } from '@/constants/constant'; + +//types +import { ISignupData } from '@/types'; + +const ValidationSchema = Yup.object().shape({ + name: Yup.string().required(errorMessage.blankName), +}); + +const InitialInformationValue = { + name: '', + description: '', +}; + +interface IAddInfo { + name: string; + description: string; +} + +interface ISignupDto extends ISignupData { + emailAuthToken: string; +} + +export default function InformationForm() { + const router = useRouter(); + + const { openModal, closeModal } = useModal(); + + const initialData = JSON.parse(sessionStorage.getItem('signupDto') || ''); + + const handleSubmit = async ( + addData: IAddInfo, + setSubmitting: (value: boolean) => void + ) => { + const data = { + signUpDto: { ...initialData, ...addData } as ISignupDto, + imgFile: null, + }; + try { + await userManager.createUser(data); + openModal({ + type: ModalType.SUCCESS, + message: successMessage.signUpSuccess, + callback: () => { + closeModal(); + router.push('/login'); + }, + }); + sessionStorage.removeItem('signupDto'); + } catch { + openModal({ + type: ModalType.ERROR, + message: errorMessage.failedSignUp, + }); + } finally { + setSubmitting(false); + } + }; + + return ( + handleSubmit(data, setSubmitting)} + > + {({ errors, touched, isSubmitting }) => ( +
+
+ + + 프로필 이름 + + + + + + + 한줄소개(선택) + + + +
+ + 시작하기 + +
+ )} +
+ ); +} From fecf0a275094e4025f2807ce930a2719b4d47f78 Mon Sep 17 00:00:00 2001 From: Im-younique Date: Wed, 12 Jun 2024 10:12:34 +0900 Subject: [PATCH 16/18] =?UTF-8?q?[chore]=20ProfileButton=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Navigator/ProfileButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/Navigator/ProfileButton.tsx b/client/src/components/Navigator/ProfileButton.tsx index eccbf0a9..034262d5 100644 --- a/client/src/components/Navigator/ProfileButton.tsx +++ b/client/src/components/Navigator/ProfileButton.tsx @@ -50,7 +50,7 @@ export default function ProfileButton() { return (
); } From 12504f99d4f416e5ea9cc77626d7174dd4a82a01 Mon Sep 17 00:00:00 2001 From: Im-younique Date: Wed, 12 Jun 2024 10:13:37 +0900 Subject: [PATCH 18/18] =?UTF-8?q?[chore]=20Form=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EB=B3=80=EA=B2=BD=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=82=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EC=A3=BC=EC=84=9D=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/app/profile/components/EditProfile/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/app/profile/components/EditProfile/index.tsx b/client/src/app/profile/components/EditProfile/index.tsx index aa215fe8..236eb73b 100644 --- a/client/src/app/profile/components/EditProfile/index.tsx +++ b/client/src/app/profile/components/EditProfile/index.tsx @@ -203,7 +203,7 @@ export default function EditProfile({ > {({ values, errors, touched, isSubmitting }) => (
- + {/* {userId} @@ -457,7 +457,7 @@ export default function EditProfile({ 회원탈퇴 -
+ */} )}