From a59dd0f7053d868dbb7d25af40cca1c793876730 Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Wed, 29 Nov 2023 15:45:39 +0900 Subject: [PATCH 01/14] =?UTF-8?q?[Add]=20Form=20=ED=95=A9=EC=84=B1=20?= =?UTF-8?q?=EC=BB=B4=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 --- client/src/components/Form/Box/index.tsx | 13 ++++++++++ client/src/components/Form/Button/index.tsx | 23 ++++++++++++++++++ .../src/components/Form/Container/index.tsx | 11 +++++++++ .../src/components/Form/Description/index.tsx | 11 +++++++++ client/src/components/Form/Error/index.tsx | 16 +++++++++++++ client/src/components/Form/Input/index.tsx | 24 +++++++++++++++++++ client/src/components/Form/Label/index.tsx | 16 +++++++++++++ client/src/components/Form/index.tsx | 19 +++++++++++++++ client/src/components/index.tsx | 1 + 9 files changed, 134 insertions(+) create mode 100644 client/src/components/Form/Box/index.tsx create mode 100644 client/src/components/Form/Button/index.tsx create mode 100644 client/src/components/Form/Container/index.tsx create mode 100644 client/src/components/Form/Description/index.tsx create mode 100644 client/src/components/Form/Error/index.tsx create mode 100644 client/src/components/Form/Input/index.tsx create mode 100644 client/src/components/Form/Label/index.tsx create mode 100644 client/src/components/Form/index.tsx diff --git a/client/src/components/Form/Box/index.tsx b/client/src/components/Form/Box/index.tsx new file mode 100644 index 00000000..71716965 --- /dev/null +++ b/client/src/components/Form/Box/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +interface IProps { + children: React.ReactNode; +} + +function FormBox({ children }: IProps) { + return ( +
{children}
+ ); +} + +export default FormBox; diff --git a/client/src/components/Form/Button/index.tsx b/client/src/components/Form/Button/index.tsx new file mode 100644 index 00000000..a0316f56 --- /dev/null +++ b/client/src/components/Form/Button/index.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +interface IProps { + type: 'button' | 'submit'; + onClick: () => void; + disabled: boolean; + name: string; +} + +function FormButton({ type, onClick, disabled, name }: IProps) { + return ( + + ); +} + +export default FormButton; diff --git a/client/src/components/Form/Container/index.tsx b/client/src/components/Form/Container/index.tsx new file mode 100644 index 00000000..75a4a29b --- /dev/null +++ b/client/src/components/Form/Container/index.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +interface IProps { + children: React.ReactNode; +} + +function FormContainer({ children }: IProps) { +
{children}
; +} + +export default FormContainer; diff --git a/client/src/components/Form/Description/index.tsx b/client/src/components/Form/Description/index.tsx new file mode 100644 index 00000000..e53c7a06 --- /dev/null +++ b/client/src/components/Form/Description/index.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +interface IProps { + name: string; +} + +function FormDiscription({ name }: IProps) { + return {name}; +} + +export default FormDiscription; diff --git a/client/src/components/Form/Error/index.tsx b/client/src/components/Form/Error/index.tsx new file mode 100644 index 00000000..8a3df75e --- /dev/null +++ b/client/src/components/Form/Error/index.tsx @@ -0,0 +1,16 @@ +import React from 'react'; + +interface IProps { + isDisplay: boolean; + name: string; +} + +function FormError({ isDisplay, name }: IProps) { + return ( + isDisplay && ( + {name} + ) + ); +} + +export default FormError; diff --git a/client/src/components/Form/Input/index.tsx b/client/src/components/Form/Input/index.tsx new file mode 100644 index 00000000..c727cb1d --- /dev/null +++ b/client/src/components/Form/Input/index.tsx @@ -0,0 +1,24 @@ +// react +import React from 'react'; + +// formik +import { Field } from 'formik'; + +interface IProps { + type: 'text' | 'password' | 'file'; + name: string; + placeholder: string; +} + +function FormInput({ type, name, placeholder }: IProps) { + return ( + + ); +} + +export default FormInput; diff --git a/client/src/components/Form/Label/index.tsx b/client/src/components/Form/Label/index.tsx new file mode 100644 index 00000000..f3e8aea2 --- /dev/null +++ b/client/src/components/Form/Label/index.tsx @@ -0,0 +1,16 @@ +import React from 'react'; + +interface IProps { + name: string; + isEssential?: boolean; +} + +function FormLabel({ name, isEssential = false }: IProps) { + const essentialStyle = isEssential + ? `after:content-['*'] after:color-red` + : ''; + + return ; +} + +export default FormLabel; diff --git a/client/src/components/Form/index.tsx b/client/src/components/Form/index.tsx new file mode 100644 index 00000000..59972ee4 --- /dev/null +++ b/client/src/components/Form/index.tsx @@ -0,0 +1,19 @@ +import FormBox from './Box'; +import FormButton from './Button'; +import FormContainer from './Container'; +import FormDiscription from './Description'; +import FormError from './Error'; +import FormInput from './Input'; +import FormLabel from './Label'; + +const Form = { + FormBox, + FormButton, + FormContainer, + FormDiscription, + FormError, + FormInput, + FormLabel, +}; + +export default Form; diff --git a/client/src/components/index.tsx b/client/src/components/index.tsx index ca0917fc..43c49a28 100644 --- a/client/src/components/index.tsx +++ b/client/src/components/index.tsx @@ -12,3 +12,4 @@ export { default as EditProfile } from '@/components/common/EditProfile'; export { default as UserInfo } from '@/components/common/UserInfo'; export { default as Gpt } from '@/components/mygpt/gpt'; export { default as Skeleton } from '@/components/common/Skeleton'; +export { default as Form } from '@/components/Form'; From d7dd51dfad90fabcc803067c3ea8c6aaf9a4680f Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Thu, 30 Nov 2023 11:36:28 +0900 Subject: [PATCH 02/14] =?UTF-8?q?[refact]=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=ED=8F=BC=20=ED=95=A9=EC=84=B1=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=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 --- client/src/components/Form/Box/index.tsx | 13 - client/src/components/Form/Input/index.tsx | 24 -- .../src/components/common/Form/Box/index.tsx | 17 ++ .../{ => common}/Form/Button/index.tsx | 8 +- .../{ => common}/Form/Container/index.tsx | 2 +- .../{ => common}/Form/Description/index.tsx | 2 +- .../{ => common}/Form/Error/index.tsx | 8 +- .../components/common/Form/Input/index.tsx | 18 ++ .../{ => common}/Form/Label/index.tsx | 10 +- .../components/{ => common}/Form/index.tsx | 0 client/src/components/index.tsx | 2 +- client/src/pages/signup/index.tsx | 283 ++++++++---------- 12 files changed, 179 insertions(+), 208 deletions(-) delete mode 100644 client/src/components/Form/Box/index.tsx delete mode 100644 client/src/components/Form/Input/index.tsx create mode 100644 client/src/components/common/Form/Box/index.tsx rename client/src/components/{ => common}/Form/Button/index.tsx (77%) rename client/src/components/{ => common}/Form/Container/index.tsx (67%) rename client/src/components/{ => common}/Form/Description/index.tsx (64%) rename client/src/components/{ => common}/Form/Error/index.tsx (54%) create mode 100644 client/src/components/common/Form/Input/index.tsx rename client/src/components/{ => common}/Form/Label/index.tsx (53%) rename client/src/components/{ => common}/Form/index.tsx (100%) diff --git a/client/src/components/Form/Box/index.tsx b/client/src/components/Form/Box/index.tsx deleted file mode 100644 index 71716965..00000000 --- a/client/src/components/Form/Box/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; - -interface IProps { - children: React.ReactNode; -} - -function FormBox({ children }: IProps) { - return ( -
{children}
- ); -} - -export default FormBox; diff --git a/client/src/components/Form/Input/index.tsx b/client/src/components/Form/Input/index.tsx deleted file mode 100644 index c727cb1d..00000000 --- a/client/src/components/Form/Input/index.tsx +++ /dev/null @@ -1,24 +0,0 @@ -// react -import React from 'react'; - -// formik -import { Field } from 'formik'; - -interface IProps { - type: 'text' | 'password' | 'file'; - name: string; - placeholder: string; -} - -function FormInput({ type, name, placeholder }: IProps) { - return ( - - ); -} - -export default FormInput; diff --git a/client/src/components/common/Form/Box/index.tsx b/client/src/components/common/Form/Box/index.tsx new file mode 100644 index 00000000..aed39050 --- /dev/null +++ b/client/src/components/common/Form/Box/index.tsx @@ -0,0 +1,17 @@ +import React from 'react'; + +interface IProps { + type?: 'row' | 'column'; + children: React.ReactNode; +} + +function FormBox({ type = 'row', children }: IProps) { + const style = + type === 'row' + ? 'relative flex grow shrink gap-x-2 items-baseline sm:gap-x-3' + : 'flex flex-col grow gap-y-2'; + + return
{children}
; +} + +export default FormBox; diff --git a/client/src/components/Form/Button/index.tsx b/client/src/components/common/Form/Button/index.tsx similarity index 77% rename from client/src/components/Form/Button/index.tsx rename to client/src/components/common/Form/Button/index.tsx index a0316f56..8486697e 100644 --- a/client/src/components/Form/Button/index.tsx +++ b/client/src/components/common/Form/Button/index.tsx @@ -2,9 +2,9 @@ import React from 'react'; interface IProps { type: 'button' | 'submit'; - onClick: () => void; - disabled: boolean; - name: string; + onClick?: () => void; + disabled?: boolean; + name: string | React.ReactNode; } function FormButton({ type, onClick, disabled, name }: IProps) { @@ -13,7 +13,7 @@ function FormButton({ type, onClick, disabled, name }: IProps) { type={type} disabled={disabled} onClick={onClick} - className="w-20 p-2 ml-2 text-sm font-semibold text-white bg-indigo-600 rounded-md hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 disabled:opacity-70 sm:w-24 sm:text-base" + className="min-w-fit p-2 text-sm font-semibold text-white bg-indigo-600 rounded-md hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 disabled:opacity-70 sm:w-24 sm:text-base" > {name} diff --git a/client/src/components/Form/Container/index.tsx b/client/src/components/common/Form/Container/index.tsx similarity index 67% rename from client/src/components/Form/Container/index.tsx rename to client/src/components/common/Form/Container/index.tsx index 75a4a29b..7470d742 100644 --- a/client/src/components/Form/Container/index.tsx +++ b/client/src/components/common/Form/Container/index.tsx @@ -5,7 +5,7 @@ interface IProps { } function FormContainer({ children }: IProps) { -
{children}
; + return
{children}
; } export default FormContainer; diff --git a/client/src/components/Form/Description/index.tsx b/client/src/components/common/Form/Description/index.tsx similarity index 64% rename from client/src/components/Form/Description/index.tsx rename to client/src/components/common/Form/Description/index.tsx index e53c7a06..04e3a397 100644 --- a/client/src/components/Form/Description/index.tsx +++ b/client/src/components/common/Form/Description/index.tsx @@ -5,7 +5,7 @@ interface IProps { } function FormDiscription({ name }: IProps) { - return {name}; + return {name}; } export default FormDiscription; diff --git a/client/src/components/Form/Error/index.tsx b/client/src/components/common/Form/Error/index.tsx similarity index 54% rename from client/src/components/Form/Error/index.tsx rename to client/src/components/common/Form/Error/index.tsx index 8a3df75e..cf7dc607 100644 --- a/client/src/components/Form/Error/index.tsx +++ b/client/src/components/common/Form/Error/index.tsx @@ -1,14 +1,16 @@ import React from 'react'; interface IProps { - isDisplay: boolean; - name: string; + isDisplay?: boolean; + name?: string; } function FormError({ isDisplay, name }: IProps) { return ( isDisplay && ( - {name} + + {name} + ) ); } diff --git a/client/src/components/common/Form/Input/index.tsx b/client/src/components/common/Form/Input/index.tsx new file mode 100644 index 00000000..303282ea --- /dev/null +++ b/client/src/components/common/Form/Input/index.tsx @@ -0,0 +1,18 @@ +// react +import React from 'react'; + +// formik +import { Field } from 'formik'; + +function FormInput({ ...props }) { + return ( + + {props!.children} + + ); +} + +export default FormInput; diff --git a/client/src/components/Form/Label/index.tsx b/client/src/components/common/Form/Label/index.tsx similarity index 53% rename from client/src/components/Form/Label/index.tsx rename to client/src/components/common/Form/Label/index.tsx index f3e8aea2..95509555 100644 --- a/client/src/components/Form/Label/index.tsx +++ b/client/src/components/common/Form/Label/index.tsx @@ -7,10 +7,16 @@ interface IProps { function FormLabel({ name, isEssential = false }: IProps) { const essentialStyle = isEssential - ? `after:content-['*'] after:color-red` + ? `after:content-["*"] after:text-red-500` : ''; - return ; + return ( + + ); } export default FormLabel; diff --git a/client/src/components/Form/index.tsx b/client/src/components/common/Form/index.tsx similarity index 100% rename from client/src/components/Form/index.tsx rename to client/src/components/common/Form/index.tsx diff --git a/client/src/components/index.tsx b/client/src/components/index.tsx index 43c49a28..32b106df 100644 --- a/client/src/components/index.tsx +++ b/client/src/components/index.tsx @@ -12,4 +12,4 @@ export { default as EditProfile } from '@/components/common/EditProfile'; export { default as UserInfo } from '@/components/common/UserInfo'; export { default as Gpt } from '@/components/mygpt/gpt'; export { default as Skeleton } from '@/components/common/Skeleton'; -export { default as Form } from '@/components/Form'; +export { default as Form } from '@/components/common/Form'; diff --git a/client/src/pages/signup/index.tsx b/client/src/pages/signup/index.tsx index 33f33595..b75642b4 100644 --- a/client/src/pages/signup/index.tsx +++ b/client/src/pages/signup/index.tsx @@ -3,11 +3,11 @@ import React, { useState, useRef } from 'react'; import { useRouter } from 'next/router'; // packages -import { Formik, Form, Field } from 'formik'; +import { Formik, Form } from 'formik'; import * as Yup from 'yup'; // components -import { Divider, Avatar, LoadingIcon } from '@/components'; +import { Divider, Avatar, LoadingIcon, Form as CustomForm } from '@/components'; // constant import { @@ -247,96 +247,81 @@ export default function SignUp() { > {({ values, errors, touched, isSubmitting }) => (
-
- -
- + + + - {errors.userId && touched.userId && ( - - {errors.userId} - - )} -
- -
-
- -
- + checkDuplicateID( + values.userId, + touched.userId, + errors.userId + ) + } + /> + + + + + + + - {errors.password && touched.password && ( - - {errors.password} - - )} -
-
-
- -
- + + + + + + - {errors.passwordConfirm && touched.passwordConfirm && ( - - {errors.passwordConfirm} - - )} -
-
-
- -
- + + + + + + - {errors.name && touched.name && ( - - {errors.name} - - )} -
-
-
- -
+ + + + + + - - - 이미지 크기의 최대용량은 10MB 입니다. - -
-
-
- -
-
- + + + + + + + + - -
+ name={ + sendingEmail ? ( + + ) : ( + '인증번호 발송' + ) + } + /> + {isSendEmail && ( -
+ - -
+ /> + )} -
-
-
- - -
-
- - -
-
- -
- + + + + + + + + + + + + + + + + + {developExperience.map((val) => ( ))} - - - 개발 시작연도는 실제 직장에 입사한 연도입니다. - -
-
+ + + +
- + name="회원가입" + />
)} From fc225eb9ab6df55fb8d433394f18f6dcdaf48cec Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Thu, 30 Nov 2023 15:47:48 +0900 Subject: [PATCH 03/14] =?UTF-8?q?[refact]=20useEmail=20=ED=9B=85=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EB=A1=9C=EC=A7=81=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/EditProfile/index.tsx | 219 ++++-------------- client/src/hooks/Form/useEmail.ts | 100 ++++++++ client/src/hooks/Form/useInputImage.ts | 0 client/src/pages/signup/index.tsx | 104 +++------ .../service/email/checkProfileEmailNumber.ts | 10 +- client/src/service/email/sendProfileEmail.ts | 6 +- client/src/types/index.ts | 2 +- 7 files changed, 187 insertions(+), 254 deletions(-) create mode 100644 client/src/hooks/Form/useEmail.ts create mode 100644 client/src/hooks/Form/useInputImage.ts diff --git a/client/src/components/common/EditProfile/index.tsx b/client/src/components/common/EditProfile/index.tsx index 168b8e2e..16effc79 100644 --- a/client/src/components/common/EditProfile/index.tsx +++ b/client/src/components/common/EditProfile/index.tsx @@ -14,10 +14,10 @@ import { Avatar, LoadingIcon } from '@/components'; // hooks import { useModal } from '@/hooks'; +import useEmail from '@/hooks/Form/useEmail'; // service import { BASE_URL } from '@/service/base/api'; -import { emailManager } from '@/service/email'; import { userManager } from '@/service/user'; // constant @@ -31,19 +31,7 @@ import { } from '@/constants/constant'; // types -import { IUserInfo, EmailState, UserInputData, EmailType } from '@/types'; - -interface ICheckEmailDto { - email: string; - number: number; - type: EmailType; -} - -interface IAuthToken { - emailAuthToken?: string; - schoolEmailAuthToken?: string; - companyEmailAuthToken?: string; -} +import { IUserInfo, EmailState, UserInputData } from '@/types'; const ValidationSchema = Yup.object().shape({ password: Yup.string().matches( @@ -83,6 +71,34 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { const { openModal } = useModal(); + // 이메일 + const { + certificateRef: userCertificateNumberRef, + emailState: userEmailState, + emailAuthToken, + handleChangeCertifiactionNumber: handleChangeUserCertificationNumber, + handleRequestEmail: handleRequestUserEmail, + handleCheckEmail: handleCheckUserEmail, + } = useEmail('USER'); + + const { + certificateRef: schoolCertificateNumberRef, + emailState: schoolEmailState, + emailAuthToken: schoolEmailAuthToken, + handleChangeCertifiactionNumber: handleChangeSchoolCertificationNumber, + handleRequestEmail: handleRequestSchoolEmail, + handleCheckEmail: handleCheckSchoolEmail, + } = useEmail('SCHOOL'); + + const { + certificateRef: companyCertificateNumberRef, + emailState: companyEmailState, + emailAuthToken: companyEmailAuthToken, + handleChangeCertifiactionNumber: handleChangeCompanyCertificationNumber, + handleRequestEmail: handleRequestCompanyEmail, + handleCheckEmail: handleCheckCompanyEmail, + } = useEmail('COMPANY'); + const handleLogout = async () => { try { await fetch('/api/deleteToken', { @@ -105,33 +121,6 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { ); const [imgFile, setImgFile] = useState(null); - // TODO 이메일 Custom Hook 만들기 - const [authToken, setAuthToken] = useState({}); - - // User 이메일 관련 - const userCertificateNumberRef = useRef(null); - const [userEmailState, setUserEmailState] = useState( - EmailState.None - ); - const [userCertificationNumber, setUserCertificationNumber] = - useState(''); - - // School 이메일 관련 - const schoolCertificateNumberRef = useRef(null); - const [schoolEmailState, setSchoolEmailState] = useState( - EmailState.None - ); - const [schoolCertificationNumber, setSchoolCertificationNumber] = - useState(''); - - // Comapny 이메일 관련 - const companyCertificateNumberRef = useRef(null); - const [companyEmailState, setCompanyEmailState] = useState( - EmailState.None - ); - const [companyCertificationNumber, setCompanyCertificationNumber] = - useState(''); - const handleChooseFile = () => { imgRef.current?.click(); }; @@ -166,98 +155,6 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { } }; - const handleSubmitEmail = async (type: EmailType, email: string) => { - switch (type) { - case 'USER': { - setUserEmailState(EmailState.Submitting); - break; - } - case 'SCHOOL': { - setSchoolEmailState(EmailState.Submitting); - break; - } - case 'COMPANY': { - setCompanyEmailState(EmailState.Submitting); - break; - } - } - try { - await emailManager.sendProfileEmail({ - data: { - email, - }, - }); - switch (type) { - case 'USER': { - setUserEmailState(EmailState.Submitted); - break; - } - case 'SCHOOL': { - setSchoolEmailState(EmailState.Submitted); - break; - } - case 'COMPANY': { - setCompanyEmailState(EmailState.Submitted); - break; - } - } - openModal({ - type: ModalType.SUCCESS, - message: successMessage.sendingEmailSuccess, - }); - } catch (e) { - openModal({ - type: ModalType.ERROR, - message: errorMessage.failedSendingEmail, - }); - switch (type) { - case 'USER': { - setUserEmailState(EmailState.None); - break; - } - case 'SCHOOL': { - setSchoolEmailState(EmailState.None); - break; - } - case 'COMPANY': { - setCompanyEmailState(EmailState.None); - break; - } - } - } - }; - - const handleCheckEmail = async (type: EmailType, email: string) => { - // 인증번호가 일치한다면 토큰 받아옴 - const number = { - USER: userCertificationNumber, - SCHOOL: schoolCertificationNumber, - COMPANY: companyCertificationNumber, - }; - const dto: ICheckEmailDto = { - email, - number: parseInt(number[type]), - type, - }; - try { - const emailAuthToken = await emailManager.checkProfileEmailNumber({ - data: dto, - }); - if (type === 'USER') { - setAuthToken({ ...authToken, emailAuthToken }); - } else if (type === 'COMPANY') { - setAuthToken({ ...authToken, companyEmailAuthToken: emailAuthToken }); - } else if (type === 'SCHOOL') { - setAuthToken({ ...authToken, schoolEmailAuthToken: emailAuthToken }); - } - } catch { - openModal({ - type: ModalType.ERROR, - message: errorMessage.checkCertificateEmail, - }); - } - }; - const initialValues = { name: name, password: '', @@ -280,18 +177,9 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { const data = { modifyUserDto: { ...modifyUserDto, - emailAuthToken: - userEmailState === EmailState.Submitted - ? authToken.emailAuthToken - : '', - schoolEmailAuthToken: - schoolEmailState === EmailState.Submitted - ? authToken.schoolEmailAuthToken - : '', - companyEmailAuthToken: - companyEmailState === EmailState.Submitted - ? authToken.companyEmailAuthToken - : '', + emailAuthToken, + schoolEmailAuthToken, + companyEmailAuthToken, }, imgFile, }; @@ -319,13 +207,14 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { setSubmitting(false); } }; + return ( handleSubmit(data, setSubmitting)} > - {({ values, errors, touched, isSubmitting }) => ( + {({ values, errors, isSubmitting }) => (
@@ -403,9 +292,9 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { {initialValues.email !== values.email && ( @@ -465,10 +354,11 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { /> @@ -530,10 +416,11 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { /> diff --git a/client/src/hooks/Form/useEmail.ts b/client/src/hooks/Form/useEmail.ts new file mode 100644 index 00000000..d5502a8d --- /dev/null +++ b/client/src/hooks/Form/useEmail.ts @@ -0,0 +1,100 @@ +// react, next +import React, { useState, useRef } from 'react'; + +// 전역 +import { useModal } from '../'; + +// types +import { EmailState, EmailType } from '@/types'; + +// constant +import { ModalType, successMessage, errorMessage } from '@/constants/constant'; + +// services +import { emailManager } from '@/service/email'; + +function useEmail(type: EmailType) { + const { openModal } = useModal(); + + const certificateRef = useRef(null); + const [certificateNumber, setCertificationNumber] = useState(''); + + const [emailState, setEmailState] = useState(EmailState.None); + const [emailAuthToken, setEmailAuthToken] = useState(''); + + const handleChangeCertifiactionNumber = ( + e: React.ChangeEvent + ) => { + setCertificationNumber(e.target.value); + }; + + const handleRequestEmail = async (email: string) => { + setEmailState(EmailState.Submitting); + try { + switch (type) { + case 'SIGNUP': { + await emailManager.sendSignUpEmail({ email }); + break; + } + default: { + await emailManager.sendProfileEmail({ email }); + } + } + setEmailState(EmailState.Submitted); + openModal({ + type: ModalType.SUCCESS, + message: successMessage.sendingEmailSuccess, + }); + } catch { + openModal({ + type: ModalType.ERROR, + message: errorMessage.failedSendingEmail, + }); + setEmailState(EmailState.None); + } + }; + + const handleCheckEmail = async (email: string) => { + let token = ''; + try { + switch (type) { + case 'SIGNUP': { + token = await emailManager.checkSignUpNumber({ + email, + number: parseInt(certificateNumber), + }); + break; + } + default: { + token = await emailManager.checkProfileEmailNumber({ + email, + number: parseInt(certificateNumber), + type, + }); + } + } + setEmailAuthToken(token); + openModal({ + type: ModalType.SUCCESS, + message: successMessage.confirmNumberSuccess, + }); + } catch { + setEmailAuthToken(''); + openModal({ + type: ModalType.ERROR, + message: errorMessage.notmatchConfirmNumber, + }); + } + }; + + return { + certificateRef, + emailState, + emailAuthToken, + handleChangeCertifiactionNumber, + handleRequestEmail, + handleCheckEmail, + }; +} + +export default useEmail; diff --git a/client/src/hooks/Form/useInputImage.ts b/client/src/hooks/Form/useInputImage.ts new file mode 100644 index 00000000..e69de29b diff --git a/client/src/pages/signup/index.tsx b/client/src/pages/signup/index.tsx index b75642b4..5394deb8 100644 --- a/client/src/pages/signup/index.tsx +++ b/client/src/pages/signup/index.tsx @@ -1,4 +1,4 @@ -import { Layout } from '@/components'; +// react, next import React, { useState, useRef } from 'react'; import { useRouter } from 'next/router'; @@ -7,7 +7,16 @@ import { Formik, Form } from 'formik'; import * as Yup from 'yup'; // components -import { Divider, Avatar, LoadingIcon, Form as CustomForm } from '@/components'; +import { + Layout, + Divider, + Avatar, + LoadingIcon, + Form as CustomForm, +} from '@/components'; + +// hooks +import useEmail from '@/hooks/Form/useEmail'; // constant import { @@ -21,11 +30,10 @@ import { } from '@/constants/constant'; // types -import { ISignupData } from '@/types'; +import { EmailState, ISignupData } from '@/types'; // service import { userManager } from '@/service/user'; -import { emailManager } from '@/service/email'; // hooks import { useModal } from '@/hooks'; @@ -50,22 +58,25 @@ export default function SignUp() { const router = useRouter(); const imgRef = useRef(null); - const certificateNumberRef = useRef(null); const [profileImg, setProfileImg] = useState(''); const [imgFile, setImgFile] = useState(null); - const [certificateNumber, setCertificateNumber] = useState(''); // Modal const { openModal, closeModal } = useModal(); + // email + const { + certificateRef, + emailState, + emailAuthToken, + handleChangeCertifiactionNumber, + handleRequestEmail, + handleCheckEmail, + } = useEmail('SIGNUP'); + // 아이디 중복 체크 여부 const [checkedId, setCheckedId] = useState(''); - // 이메일 전송/확인 여부 - const [isSendEmail, setIsSendEmail] = useState(false); - const [sendingEmail, setSendingEmail] = useState(false); - const [emailAuthToken, setEmailAuthToken] = useState(''); - const checkDuplicateID = async ( userId: string, isTouched: boolean | undefined, @@ -134,60 +145,6 @@ export default function SignUp() { } }; - const handleRequestEmail = async ( - email: string, - isTouched: boolean | undefined, - errorMsg: string | undefined - ) => { - if (!isTouched || errorMsg) { - openModal({ - type: ModalType.ERROR, - message: errorMsg ? errorMsg : errorMessage.blankEmail, - }); - } else { - setSendingEmail(true); - try { - await emailManager.sendSignUpEmail({ email }); - setIsSendEmail(true); - openModal({ - type: ModalType.SUCCESS, - message: successMessage.sendingEmailSuccess, - }); - } catch { - openModal({ - type: ModalType.ERROR, - message: errorMessage.failedSendingEmail, - }); - } finally { - setSendingEmail(false); - } - } - }; - - const handleCertificateNumber = (e: React.ChangeEvent) => { - setCertificateNumber(e.target.value); - }; - - const handleCheckEmail = async (email: string) => { - try { - const emailAuthToken = await emailManager.checkSignUpNumber({ - email, - number: parseInt(certificateNumber), - }); - setEmailAuthToken(emailAuthToken); - openModal({ - type: ModalType.SUCCESS, - message: successMessage.confirmNumberSuccess, - }); - } catch { - setEmailAuthToken(''); - openModal({ - type: ModalType.ERROR, - message: errorMessage.notmatchConfirmNumber, - }); - } - }; - const handleSubmit = async ( sendData: ISignupData, setSubmitting: (value: boolean) => void @@ -349,15 +306,12 @@ export default function SignUp() { /> - handleRequestEmail( - values.email, - touched.email, - errors.email - ) + disabled={ + errors.email !== undefined || values.email === '' } + onClick={() => handleRequestEmail(values.email)} name={ - sendingEmail ? ( + emailState === EmailState.Submitting ? ( ) : ( '인증번호 발송' @@ -365,13 +319,13 @@ export default function SignUp() { } /> - {isSendEmail && ( + {emailState === EmailState.Submitted && ( ({ suburl, data }); diff --git a/client/src/service/email/sendProfileEmail.ts b/client/src/service/email/sendProfileEmail.ts index a86879e1..fb4e2460 100644 --- a/client/src/service/email/sendProfileEmail.ts +++ b/client/src/service/email/sendProfileEmail.ts @@ -2,12 +2,10 @@ import { axios_post } from '../base/api'; interface PropType { - data: { - email: string; - }; + email: string; } -export default async function sendProfileEmail({ data }: PropType) { +export default async function sendProfileEmail(data: PropType) { const suburl = '/auth/email/profile/number'; const result = await axios_post({ suburl, data }); diff --git a/client/src/types/index.ts b/client/src/types/index.ts index 9e045b0b..151ddb1b 100644 --- a/client/src/types/index.ts +++ b/client/src/types/index.ts @@ -108,4 +108,4 @@ export interface IChatUserDto { unReadMessageCount: number; } -export type EmailType = 'USER' | 'COMPANY' | 'SCHOOL'; +export type EmailType = 'SIGNUP' | 'USER' | 'COMPANY' | 'SCHOOL'; From 3995e84639bd872f610c0f12d71e5d1fc9ee245c Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Thu, 30 Nov 2023 16:17:09 +0900 Subject: [PATCH 04/14] =?UTF-8?q?[refact]=20useInputImage=20=ED=9B=85=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EB=A1=9C=EC=A7=81=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/EditProfile/index.tsx | 57 ++--------- client/src/hooks/Form/useInputImage.ts | 55 +++++++++++ client/src/pages/signup/index.tsx | 99 +++++-------------- client/src/types/index.ts | 2 +- 4 files changed, 87 insertions(+), 126 deletions(-) diff --git a/client/src/components/common/EditProfile/index.tsx b/client/src/components/common/EditProfile/index.tsx index 16effc79..b56383cb 100644 --- a/client/src/components/common/EditProfile/index.tsx +++ b/client/src/components/common/EditProfile/index.tsx @@ -1,5 +1,5 @@ // react, next -import React, { useState, useRef } from 'react'; +import React from 'react'; import { useRouter } from 'next/router'; import { useDispatch } from 'react-redux'; import { update } from '@/lib/redux/slices/authSlice'; @@ -7,7 +7,6 @@ import { update } from '@/lib/redux/slices/authSlice'; // thrid-party import { Formik, Form, Field } from 'formik'; import * as Yup from 'yup'; -import { logOut } from '@/lib/redux/slices/authSlice'; // components import { Avatar, LoadingIcon } from '@/components'; @@ -15,14 +14,14 @@ import { Avatar, LoadingIcon } from '@/components'; // hooks import { useModal } from '@/hooks'; import useEmail from '@/hooks/Form/useEmail'; +import useInputImage from '@/hooks/Form/useInputImage'; // service -import { BASE_URL } from '@/service/base/api'; import { userManager } from '@/service/user'; +import { logOut } from '@/lib/redux/slices/authSlice'; // constant import { - IMAGE_FILE_MAX_SIZE, ModalType, developExperience, errorMessage, @@ -99,6 +98,9 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { handleCheckEmail: handleCheckCompanyEmail, } = useEmail('COMPANY'); + const { imgRef, profileImg, imgFile, handleChooseFile, handleImgInput } = + useInputImage(userProfileImgPath); + const handleLogout = async () => { try { await fetch('/api/deleteToken', { @@ -114,47 +116,6 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { } }; - // profileImg 관련 - const imgRef = useRef(null); - const [profileImg, setProfileImg] = useState( - `${BASE_URL}${userProfileImgPath === undefined ? '' : userProfileImgPath}` - ); - const [imgFile, setImgFile] = useState(null); - - const handleChooseFile = () => { - imgRef.current?.click(); - }; - - const handleImgInput = (e: React.ChangeEvent) => { - if (e.target.files && e.target.files.length !== 0) { - const file = e.target.files[0]; - const fileSize = file.size; - if (fileSize > IMAGE_FILE_MAX_SIZE) { - alert('이미지 파일 용량 초과'); - return; - } - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onloadend = () => { - // null 방지 - if (reader.result) { - if (typeof reader.result === 'string') { - setImgFile(file); - setProfileImg(reader.result); - } else { - // ArrayBuffer인 경우 string으로 변경 - setProfileImg( - String.fromCharCode.apply( - null, - Array.from(new Uint16Array(reader.result)) - ) - ); - } - } - }; - } - }; - const initialValues = { name: name, password: '', @@ -293,9 +254,7 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { diff --git a/client/src/hooks/Form/useInputImage.ts b/client/src/hooks/Form/useInputImage.ts index e69de29b..f48acbd3 100644 --- a/client/src/hooks/Form/useInputImage.ts +++ b/client/src/hooks/Form/useInputImage.ts @@ -0,0 +1,55 @@ +// react, next +import React, { useState, useRef } from 'react'; + +// constant +import { IMAGE_FILE_MAX_SIZE } from '@/constants/constant'; + +// services +import { BASE_URL } from '@/service/base/api'; + +function useInputImage(initialProfileImg?: string) { + const imgRef = useRef(null); + + const [profileImg, setProfileImg] = useState( + `${BASE_URL}${initialProfileImg || ''}` + ); + const [imgFile, setImgFile] = useState(null); + + const handleChooseFile = () => { + imgRef.current?.click(); + }; + + const handleImgInput = (e: React.ChangeEvent) => { + if (e.target.files && e.target.files.length !== 0) { + const file = e.target.files[0]; + const fileSize = file.size; + if (fileSize > IMAGE_FILE_MAX_SIZE) { + alert('이미지 파일 용량 초과'); + return; + } + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onloadend = () => { + // null 방지 + if (reader.result) { + if (typeof reader.result === 'string') { + setImgFile(file); + setProfileImg(reader.result); + } else { + // ArrayBuffer인 경우 string으로 변경 + setProfileImg( + String.fromCharCode.apply( + null, + Array.from(new Uint16Array(reader.result)) + ) + ); + } + } + }; + } + }; + + return { imgRef, profileImg, imgFile, handleChooseFile, handleImgInput }; +} + +export default useInputImage; diff --git a/client/src/pages/signup/index.tsx b/client/src/pages/signup/index.tsx index 5394deb8..f27c7388 100644 --- a/client/src/pages/signup/index.tsx +++ b/client/src/pages/signup/index.tsx @@ -1,5 +1,5 @@ // react, next -import React, { useState, useRef } from 'react'; +import React, { useState } from 'react'; import { useRouter } from 'next/router'; // packages @@ -17,10 +17,10 @@ import { // hooks import useEmail from '@/hooks/Form/useEmail'; +import useInputImage from '@/hooks/Form/useInputImage'; // constant import { - IMAGE_FILE_MAX_SIZE, developExperience, ModalType, successMessage, @@ -57,14 +57,9 @@ const ValidationSchema = Yup.object().shape({ export default function SignUp() { const router = useRouter(); - const imgRef = useRef(null); - const [profileImg, setProfileImg] = useState(''); - const [imgFile, setImgFile] = useState(null); - // Modal const { openModal, closeModal } = useModal(); - // email const { certificateRef, emailState, @@ -74,74 +69,29 @@ export default function SignUp() { handleCheckEmail, } = useEmail('SIGNUP'); + const { imgRef, profileImg, imgFile, handleChooseFile, handleImgInput } = + useInputImage(); + // 아이디 중복 체크 여부 const [checkedId, setCheckedId] = useState(''); - const checkDuplicateID = async ( - userId: string, - isTouched: boolean | undefined, - errorMsg: string | undefined - ) => { - if (!isTouched || errorMsg) { + 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: errorMsg || errorMessage.blankID, + message: + error === 'duplicate' + ? errorMessage.duplicateId + : errorMessage.network, }); - } else { - 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 handleChooseFile = () => { - imgRef.current?.click(); - }; - - const handleImgInput = (e: React.ChangeEvent) => { - if (e.target.files && e.target.files.length !== 0) { - const file = e.target.files[0]; - const fileSize = file.size; - if (fileSize > IMAGE_FILE_MAX_SIZE) { - openModal({ - type: ModalType.ERROR, - message: errorMessage.imageCapacityExceeded, - }); - return; - } - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onloadend = () => { - // null 방지 - if (reader.result) { - if (typeof reader.result === 'string') { - setImgFile(file); - setProfileImg(reader.result); - } else { - // ArrayBuffer인 경우 string으로 변경 - setProfileImg( - String.fromCharCode.apply( - null, - Array.from(new Uint16Array(reader.result)) - ) - ); - } - } - }; } }; @@ -215,16 +165,13 @@ export default function SignUp() { - checkDuplicateID( - values.userId, - touched.userId, - errors.userId - ) + disabled={ + values.userId === '' || errors.userId !== undefined } + onClick={() => checkDuplicateID(values.userId)} /> diff --git a/client/src/types/index.ts b/client/src/types/index.ts index 151ddb1b..cd2411a6 100644 --- a/client/src/types/index.ts +++ b/client/src/types/index.ts @@ -32,7 +32,7 @@ export interface IUserInfo { companyEmail?: string; companyEmailAuthentication?: boolean; developAnnual?: number; - email?: string; + email: string; name: string; post?: Array; school?: string; From 11577ea620de64b014969589e85d3f94d73f97ce Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Thu, 30 Nov 2023 18:35:18 +0900 Subject: [PATCH 05/14] =?UTF-8?q?[chore]=20=ED=8F=BC=20=ED=95=A9=EC=84=B1?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=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/common/Form/Error/index.tsx | 12 +++++------- client/src/components/common/Form/Label/index.tsx | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/client/src/components/common/Form/Error/index.tsx b/client/src/components/common/Form/Error/index.tsx index cf7dc607..3c2b4224 100644 --- a/client/src/components/common/Form/Error/index.tsx +++ b/client/src/components/common/Form/Error/index.tsx @@ -6,13 +6,11 @@ interface IProps { } function FormError({ isDisplay, name }: IProps) { - return ( - isDisplay && ( - - {name} - - ) - ); + 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/common/Form/Label/index.tsx b/client/src/components/common/Form/Label/index.tsx index 95509555..6f17b69c 100644 --- a/client/src/components/common/Form/Label/index.tsx +++ b/client/src/components/common/Form/Label/index.tsx @@ -12,7 +12,7 @@ function FormLabel({ name, isEssential = false }: IProps) { return ( From aa3015f476df02867439c9da09e52e20f3cbbed3 Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Thu, 30 Nov 2023 18:35:36 +0900 Subject: [PATCH 06/14] =?UTF-8?q?[refact]=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=88=98=EC=A0=95=20=ED=95=A9=EC=84=B1=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/EditProfile/index.tsx | 349 +++++++++--------- 1 file changed, 168 insertions(+), 181 deletions(-) diff --git a/client/src/components/common/EditProfile/index.tsx b/client/src/components/common/EditProfile/index.tsx index b56383cb..235713ed 100644 --- a/client/src/components/common/EditProfile/index.tsx +++ b/client/src/components/common/EditProfile/index.tsx @@ -9,7 +9,7 @@ import { Formik, Form, Field } from 'formik'; import * as Yup from 'yup'; // components -import { Avatar, LoadingIcon } from '@/components'; +import { Avatar, LoadingIcon, Form as CustomForm } from '@/components'; // hooks import { useModal } from '@/hooks'; @@ -33,6 +33,7 @@ import { import { IUserInfo, EmailState, UserInputData } from '@/types'; const ValidationSchema = Yup.object().shape({ + name: Yup.string().required(errorMessage.blankName), password: Yup.string().matches( regex.password, errorMessage.invalidFormatPassword @@ -117,22 +118,23 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { }; const initialValues = { - name: name, + name, + email, + school, + company, + developAnnual, password: '', newPassword: '', newPasswordConfirm: '', - email: email, - school: school, schoolEmail: schoolEmail || '', - company: company, companyEmail: companyEmail || '', - developAnnual: developAnnual, }; const handleSubmit = async ( inputData: UserInputData, setSubmitting: (value: boolean) => void ) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const { newPasswordConfirm, ...modifyUserDto } = inputData; const data = { @@ -175,52 +177,63 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { validationSchema={ValidationSchema} onSubmit={(data, { setSubmitting }) => handleSubmit(data, setSubmitting)} > - {({ values, errors, isSubmitting }) => ( - -
- + {({ values, errors, touched, isSubmitting }) => ( + + + {userId} -
-
- - -
-
- -
- + + + + + + + + + + + {` 현재 비밀번호는 필수 입력입니다.`} -
-
-
- - -
-
- - -
-
- -
+ + + + + + + + + + + + + + + + + + + + - - - 이미지 크기의 최대용량은 10MB 입니다. - -
-
-
- -
-
- - {initialValues.email !== values.email && ( - - )} - - * 변경시 재인증이 필요합니다. - -
- {userEmailState === EmailState.Submitted && ( + ) + } + disabled={ + errors.email !== undefined || + values.email === '' || + initialValues.email === values.email + } + onClick={() => handleRequestUserEmail(values.email)} + /> + + {userEmailState === EmailState.Submitted ? (
+ ) : ( + + * 변경시 재인증이 필요합니다. + )} -
-
-
- -
- + + + + + + {!schoolEmailAuthentication && ( 메일 인증이 필요합니다. )} -
-
-
- -
-
- - - - * 변경시 재인증이 필요합니다. - -
- {schoolEmailState === EmailState.Submitted && ( + /> + + {schoolEmailState === EmailState.Submitted ? (
+ ) : ( + + * 변경시 재인증이 필요합니다. + )} -
-
-
- -
- + + + + + + {!companyEmailAuthentication && ( 메일 인증이 필요합니다. )} -
-
-
- -
-
- - - - * 변경시 재인증이 필요합니다. - -
- {companyEmailState === EmailState.Submitted && ( + /> + + {companyEmailState === EmailState.Submitted ? (
+ ) : ( + + * 변경시 재인증이 필요합니다. + )} -
-
-
- -
- + + + + + {developExperience.map((val) => ( ))} - - - 개발 시작연도는 실제 직장에 입사한 연도입니다. - -
+ + + + +
+ +
- - )} From 5d16d26b026602bb6f8e96a7268b11bf40f41184 Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Mon, 4 Dec 2023 11:01:56 +0900 Subject: [PATCH 07/14] =?UTF-8?q?[chore]=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=AA=A8=EB=8B=AC=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=EB=AA=85=EC=8B=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/EditProfile/index.tsx | 9 +++++++-- client/src/constants/constant.ts | 1 + client/src/service/user/updateUser.ts | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/client/src/components/common/EditProfile/index.tsx b/client/src/components/common/EditProfile/index.tsx index 235713ed..6eeae4e3 100644 --- a/client/src/components/common/EditProfile/index.tsx +++ b/client/src/components/common/EditProfile/index.tsx @@ -24,6 +24,7 @@ import { logOut } from '@/lib/redux/slices/authSlice'; import { ModalType, developExperience, + errorCodeToMessage, errorMessage, regex, successMessage, @@ -162,9 +163,13 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { message: successMessage.profileUpdateSuccess, }); } catch (error) { + type Code = 'INVALID_PARAMETER' | 'INVALID_PASSWORD'; openModal({ type: ModalType.ERROR, - message: error instanceof Error ? error.message : errorMessage.error, + message: + error instanceof Error + ? errorCodeToMessage[error.message as Code] + : errorMessage.Unknown, }); } finally { setSubmitting(false); @@ -377,7 +382,7 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { } disabled={ errors.companyEmail !== undefined || - values.companyEmail !== '' + values.companyEmail === '' } onClick={() => handleRequestCompanyEmail(values.companyEmail)} /> diff --git a/client/src/constants/constant.ts b/client/src/constants/constant.ts index ea4e7bb0..f033d9fb 100644 --- a/client/src/constants/constant.ts +++ b/client/src/constants/constant.ts @@ -48,6 +48,7 @@ export const errorCodeToMessage = Object.freeze({ 'USER_NOT_EXIST': '유저가 존재하지 않습니다.', 'INVALID_PASSWORD': '비밀번호가 맞지 않습니다.', 'UNAUTHENTICATED_EMAIL': '이메일 인증이 필요합니다.', + 'INVALID_PARAMETER': '필수 입력 값을 채워주세요', '': '알 수 없는 오류입니다.', 'undefined': '알 수 없는 오류입니다.', }); diff --git a/client/src/service/user/updateUser.ts b/client/src/service/user/updateUser.ts index 261f1a8e..d6b7307a 100644 --- a/client/src/service/user/updateUser.ts +++ b/client/src/service/user/updateUser.ts @@ -37,6 +37,6 @@ export default async function updateUser({ if (result.isOkay) { return result.data as IUserInfo; } else { - throw new Error(result.error); + throw new Error(result.error.code); } } From bc70b1a4451d5e7234932ec4077becdad1ed230c Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Mon, 4 Dec 2023 11:11:57 +0900 Subject: [PATCH 08/14] =?UTF-8?q?[chore]=20=ED=9A=8C=EC=9B=90=ED=83=88?= =?UTF-8?q?=ED=87=B4=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/EditProfile/index.tsx | 40 ++++++++++++++- client/src/constants/constant.ts | 4 -- client/src/pages/profile/[id].tsx | 50 ++----------------- 3 files changed, 42 insertions(+), 52 deletions(-) diff --git a/client/src/components/common/EditProfile/index.tsx b/client/src/components/common/EditProfile/index.tsx index 6eeae4e3..9fe8b47c 100644 --- a/client/src/components/common/EditProfile/index.tsx +++ b/client/src/components/common/EditProfile/index.tsx @@ -5,7 +5,7 @@ import { useDispatch } from 'react-redux'; import { update } from '@/lib/redux/slices/authSlice'; // thrid-party -import { Formik, Form, Field } from 'formik'; +import { Formik, Form } from 'formik'; import * as Yup from 'yup'; // components @@ -26,6 +26,7 @@ import { developExperience, errorCodeToMessage, errorMessage, + warningMessage, regex, successMessage, } from '@/constants/constant'; @@ -70,7 +71,7 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { userProfileImgPath, }: IUserInfo = userData; - const { openModal } = useModal(); + const { openModal, closeModal } = useModal(); // 이메일 const { @@ -118,6 +119,36 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { } }; + const handleWithdrawal = () => { + openModal({ + type: ModalType.WARNING, + message: warningMessage.confirmWithdrawal, + callback: async () => { + closeModal(); + try { + await userManager.deleteUser(); + await fetch('/api/deleteToken', { + method: 'DELETE', + }); + dispatch(logOut()); + openModal({ + type: ModalType.SUCCESS, + message: successMessage.withdrawalSuccess, + callback: () => { + closeModal(); + router.replace('/'); + }, + }); + } catch { + openModal({ + type: ModalType.ERROR, + message: errorMessage.error, + }); + } + }, + }); + }; + const initialValues = { name, email, @@ -439,6 +470,11 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { name="로그아웃" onClick={handleLogout} /> +
)} diff --git a/client/src/constants/constant.ts b/client/src/constants/constant.ts index f033d9fb..2b41a124 100644 --- a/client/src/constants/constant.ts +++ b/client/src/constants/constant.ts @@ -121,10 +121,6 @@ export const sideBarList = [ content: '덕력치', iconName: 'bi:bar-chart-fill', }, - { - content: '회원탈퇴', - iconName: 'ic:outline-log-out', - }, ]; export enum ModalType { diff --git a/client/src/pages/profile/[id].tsx b/client/src/pages/profile/[id].tsx index 144098c5..47ee1a62 100644 --- a/client/src/pages/profile/[id].tsx +++ b/client/src/pages/profile/[id].tsx @@ -1,8 +1,6 @@ import React, { useState } from 'react'; import { useRouter } from 'next/router'; -import { useModal } from '@/hooks'; -import { useDispatch, useSelector } from 'react-redux'; -import { logOut } from '@/lib/redux/slices/authSlice'; +import { useSelector } from 'react-redux'; // components import { Layout, Avatar, Divider, UserInfo, EditProfile } from '@/components'; @@ -12,13 +10,7 @@ import { BASE_URL } from '@/service/base/api'; import { userManager } from '@/service/user'; // constant -import { - ModalType, - errorMessage, - sideBarList, - successMessage, - warningMessage, -} from '@/constants/constant'; +import { sideBarList } from '@/constants/constant'; // types import { IUserInfo } from '@/types'; @@ -36,11 +28,8 @@ export default function Profile({ }) { const router = useRouter(); - const dispatch = useDispatch(); const user = useSelector((state: IReduxState) => state.auth); - const { openModal, closeModal } = useModal(); - const isMyPage = router.query.id === user.userId; const [selectedMenu, setSelectedMenu] = useState('내 정보'); @@ -49,37 +38,7 @@ export default function Profile({ const { company, name, school, userProfileImgPath } = userData; const handleSelectMenu = (content: string) => { - if (content === '회원탈퇴') { - openModal({ - type: ModalType.WARNING, - message: warningMessage.confirmWithdrawal, - callback: async () => { - closeModal(); - try { - await userManager.deleteUser(); - await fetch('/api/deleteToken', { - method: 'DELETE', - }); - dispatch(logOut()); - openModal({ - type: ModalType.SUCCESS, - message: successMessage.withdrawalSuccess, - callback: () => { - closeModal(); - router.replace('/'); - }, - }); - } catch { - openModal({ - type: ModalType.ERROR, - message: errorMessage.error, - }); - } - }, - }); - } else { - setSelectedMenu(content); - } + setSelectedMenu(content); }; //TODO: 반응형 디자인 고려하기 (모바일 디자인) return ( @@ -106,8 +65,7 @@ export default function Profile({ className={`${ content === selectedMenu && 'before:block before:absolute before:w-1 before:h-8 before:translate-x-[-15px] before:bg-indigo-600 before:rounded-sm bg-gray-200' - } text-left rounded-md p-2 text-sm font-semibold text-black hover:bg-gray-200 flex items-center - ${content === '회원탈퇴' && !isMyPage && `hidden`}`} + } text-left rounded-md p-2 text-sm font-semibold text-black hover:bg-gray-200 flex items-center`} onClick={() => handleSelectMenu(content)} > Date: Mon, 4 Dec 2023 11:44:01 +0900 Subject: [PATCH 09/14] =?UTF-8?q?[chore]=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=B0=98=EC=9D=91=ED=98=95=20=EB=94=94?= =?UTF-8?q?=EC=9E=90=EC=9D=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/EditProfile/index.tsx | 2 +- client/src/pages/profile/[id].tsx | 30 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/client/src/components/common/EditProfile/index.tsx b/client/src/components/common/EditProfile/index.tsx index 9fe8b47c..ef5e5336 100644 --- a/client/src/components/common/EditProfile/index.tsx +++ b/client/src/components/common/EditProfile/index.tsx @@ -214,7 +214,7 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { onSubmit={(data, { setSubmitting }) => handleSubmit(data, setSubmitting)} > {({ values, errors, touched, isSubmitting }) => ( -
+ {userId} diff --git a/client/src/pages/profile/[id].tsx b/client/src/pages/profile/[id].tsx index 47ee1a62..650e4591 100644 --- a/client/src/pages/profile/[id].tsx +++ b/client/src/pages/profile/[id].tsx @@ -40,11 +40,11 @@ export default function Profile({ const handleSelectMenu = (content: string) => { setSelectedMenu(content); }; - //TODO: 반응형 디자인 고려하기 (모바일 디자인) + return ( -
-
+
+

{name}

-

@{company}

+

{company}

{school}

-
    +
      {sideBarList.map(({ content, iconName }) => (
+
    + {sideBarList.map(({ content, iconName }) => ( +
  • handleSelectMenu(content)} + > + + {content} +
  • + ))} +
{isMyPage ? ( From 3de0cc00a098230494dc41fc9c346a4bb8d9627e Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Mon, 4 Dec 2023 12:44:23 +0900 Subject: [PATCH 10/14] =?UTF-8?q?[chore]=20iconify=EB=A1=9C=20=EB=8C=80?= =?UTF-8?q?=EC=B2=B4=EA=B0=80=EB=8A=A5=ED=95=9C=20public=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/public/images/advertise.png | Bin 9963 -> 0 bytes client/public/images/google_logo.png | Bin 1247 -> 0 bytes client/public/images/user_icon.png | Bin 8383 -> 0 bytes .../components/common/Advertisement/index.tsx | 8 ++++-- client/src/components/common/Avatar/index.tsx | 26 ++++++++++++------ client/src/pages/login/index.tsx | 10 ++----- 6 files changed, 25 insertions(+), 19 deletions(-) delete mode 100644 client/public/images/advertise.png delete mode 100644 client/public/images/google_logo.png delete mode 100644 client/public/images/user_icon.png diff --git a/client/public/images/advertise.png b/client/public/images/advertise.png deleted file mode 100644 index 9732eb405b52237aa8cd2069062f72af9ecb10fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9963 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 S@_~hE0Q$VSVfk6NJO2h?OoM*_ diff --git a/client/public/images/google_logo.png b/client/public/images/google_logo.png deleted file mode 100644 index e7d106c4421e680481973b9d78dfbe4f0f09ed97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1247 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≺0*taMg~Bt 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 diff --git a/client/src/components/common/Advertisement/index.tsx b/client/src/components/common/Advertisement/index.tsx index 37928da8..e5ec74fa 100644 --- a/client/src/components/common/Advertisement/index.tsx +++ b/client/src/components/common/Advertisement/index.tsx @@ -1,9 +1,13 @@ -import Image from 'next/image'; +// react import React from 'react'; + +// thrid-party +import { Icon } from '@iconify/react'; + export default function Advertisement() { return (
- Ads +

준비중...

); diff --git a/client/src/components/common/Avatar/index.tsx b/client/src/components/common/Avatar/index.tsx index 86845ea0..fc9ed429 100644 --- a/client/src/components/common/Avatar/index.tsx +++ b/client/src/components/common/Avatar/index.tsx @@ -3,6 +3,9 @@ import Image from 'next/image'; import { positionStyle, avatarSizeStyle } from '@/styles/styleConstant'; +// thrid-party +import { Icon } from '@iconify/react'; + // service import { BASE_URL } from '@/service/base/api'; @@ -24,15 +27,20 @@ export default function Avatar({ const avatarStyle = `relative rounded-full border border-slate-200 ${avatarSizeStyle[size]} max-w-[200px] max-h-[200px] overflow-hidden`; return (
- {alt} + {src === BASE_URL || src === '' ? ( + + ) : ( + {alt} + )} {hasDot && (
- googleLogo + 구글 계정으로 로그인
From 2906d95c913f3c9f4dd18c3614b150ef26497e66 Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Mon, 4 Dec 2023 13:16:43 +0900 Subject: [PATCH 11/14] =?UTF-8?q?[chore]=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=ED=99=94=EB=A9=B4=20=EB=B0=98=EC=9D=91?= =?UTF-8?q?=ED=98=95=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/EditProfile/index.tsx | 2 +- client/src/components/common/UserInfo/index.tsx | 4 ++-- client/src/constants/constant.ts | 2 +- client/src/pages/profile/[id].tsx | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/components/common/EditProfile/index.tsx b/client/src/components/common/EditProfile/index.tsx index ef5e5336..a54afecb 100644 --- a/client/src/components/common/EditProfile/index.tsx +++ b/client/src/components/common/EditProfile/index.tsx @@ -214,7 +214,7 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { onSubmit={(data, { setSubmitting }) => handleSubmit(data, setSubmitting)} > {({ values, errors, touched, isSubmitting }) => ( - + {userId} diff --git a/client/src/components/common/UserInfo/index.tsx b/client/src/components/common/UserInfo/index.tsx index 483f405a..5d7927fa 100644 --- a/client/src/components/common/UserInfo/index.tsx +++ b/client/src/components/common/UserInfo/index.tsx @@ -112,12 +112,12 @@ export default function UserInfo({ userData }: { userData: IUserInfo }) { return ( <> -
+
{labelContent.map(({ label, content }) => ( ))}
-
+
+
) : ( @@ -349,19 +345,18 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { - ) : ( - '인증번호 전송' - ) - } disabled={ errors.schoolEmail !== undefined || values.schoolEmail === '' } onClick={() => handleRequestSchoolEmail(values.schoolEmail)} - /> + > + {schoolEmailState === EmailState.Submitting ? ( + + ) : ( + '인증번호 전송' + )} + {schoolEmailState === EmailState.Submitted ? (
@@ -371,13 +366,12 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { ref={schoolCertificateNumberRef} onChange={handleChangeSchoolCertificationNumber} /> - +
) : ( @@ -404,19 +398,18 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { - ) : ( - '인증번호 전송' - ) - } disabled={ errors.companyEmail !== undefined || values.companyEmail === '' } onClick={() => handleRequestCompanyEmail(values.companyEmail)} - /> + > + {companyEmailState === EmailState.Submitting ? ( + + ) : ( + '인증번호 전송' + )} + {companyEmailState === EmailState.Submitted ? (
@@ -426,13 +419,12 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) { ref={companyCertificateNumberRef} onChange={handleChangeCompanyCertificationNumber} /> - +
) : ( @@ -460,21 +452,15 @@ export default function EditProfile({ userData }: { userData: IUserInfo }) {
- - - + + 정보수정 + + + 로그아웃 + + + 회원탈퇴 +
)} diff --git a/client/src/components/common/Form/Box/index.tsx b/client/src/components/common/Form/Box/index.tsx index aed39050..c06d9091 100644 --- a/client/src/components/common/Form/Box/index.tsx +++ b/client/src/components/common/Form/Box/index.tsx @@ -1,8 +1,7 @@ import React from 'react'; -interface IProps { +interface IProps extends React.HTMLAttributes { type?: 'row' | 'column'; - children: React.ReactNode; } function FormBox({ type = 'row', children }: IProps) { diff --git a/client/src/components/common/Form/Button/index.tsx b/client/src/components/common/Form/Button/index.tsx index 8486697e..aab3397b 100644 --- a/client/src/components/common/Form/Button/index.tsx +++ b/client/src/components/common/Form/Button/index.tsx @@ -1,13 +1,10 @@ import React from 'react'; -interface IProps { +interface IProps extends React.ButtonHTMLAttributes { type: 'button' | 'submit'; - onClick?: () => void; - disabled?: boolean; - name: string | React.ReactNode; } -function FormButton({ type, onClick, disabled, name }: IProps) { +function FormButton({ type, onClick, disabled, children }: IProps) { return ( ); } diff --git a/client/src/pages/signup/index.tsx b/client/src/pages/signup/index.tsx index f27c7388..c12abb9f 100644 --- a/client/src/pages/signup/index.tsx +++ b/client/src/pages/signup/index.tsx @@ -164,12 +164,13 @@ export default function SignUp() { /> checkDuplicateID(values.userId)} - /> + > + 중복확인 + + > + 파일 업로드 + @@ -257,14 +259,13 @@ export default function SignUp() { errors.email !== undefined || values.email === '' } onClick={() => handleRequestEmail(values.email)} - name={ - emailState === EmailState.Submitting ? ( - - ) : ( - '인증번호 발송' - ) - } - /> + > + {emailState === EmailState.Submitting ? ( + + ) : ( + '인증번호 발송' + )} + {emailState === EmailState.Submitted && ( @@ -276,9 +277,10 @@ export default function SignUp() { /> handleCheckEmail(values.email)} - /> + > + 인증번호 확인 + )} @@ -323,11 +325,9 @@ export default function SignUp() {
- + + 회원가입 +
)} From e9280b1566aeb234ccba7c257e4e8d0d964d5f52 Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Mon, 4 Dec 2023 15:53:17 +0900 Subject: [PATCH 13/14] =?UTF-8?q?[chore]=20=EC=A0=9C=EB=84=A4=EB=A6=AD=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=B6=94=EB=A1=A0=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EB=AA=85=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/Form/Input/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/components/common/Form/Input/index.tsx b/client/src/components/common/Form/Input/index.tsx index 303282ea..ccd124ad 100644 --- a/client/src/components/common/Form/Input/index.tsx +++ b/client/src/components/common/Form/Input/index.tsx @@ -2,15 +2,15 @@ import React from 'react'; // formik -import { Field } from 'formik'; +import { Field, FieldAttributes } from 'formik'; -function FormInput({ ...props }) { +function FormInput({ children, ...props }: FieldAttributes) { return ( - {props!.children} + {children} ); } From 5c2f6830b44daa289d82055712c7cadfd5d16d05 Mon Sep 17 00:00:00 2001 From: DongYounYim Date: Mon, 4 Dec 2023 15:58:47 +0900 Subject: [PATCH 14/14] =?UTF-8?q?[chore]=20=ED=94=BC=EB=93=9C=EB=B0=B1=20?= =?UTF-8?q?=EB=B0=98=EC=98=81=20=ED=83=80=EC=9E=85=20=EB=AA=85=EC=8B=9C,?= =?UTF-8?q?=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/constants/constant.ts | 4 +++- client/src/pages/profile/[id].tsx | 10 ++++------ client/src/types/index.ts | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/client/src/constants/constant.ts b/client/src/constants/constant.ts index 34c94f46..6ab188a0 100644 --- a/client/src/constants/constant.ts +++ b/client/src/constants/constant.ts @@ -1,3 +1,5 @@ +import { MyPageTab } from '@/types'; + export const linkList = [ { name: '채팅방', href: '/chat' }, { name: 'GPT', href: '/mygpt' }, @@ -104,7 +106,7 @@ export const MODAL_TITLE = { error: '오류', }; -export const sideBarList = [ +export const sideBarList: { content: MyPageTab; iconName: string }[] = [ { content: '프로필', iconName: 'uil:user', diff --git a/client/src/pages/profile/[id].tsx b/client/src/pages/profile/[id].tsx index b53faed1..5b8367db 100644 --- a/client/src/pages/profile/[id].tsx +++ b/client/src/pages/profile/[id].tsx @@ -13,7 +13,7 @@ import { userManager } from '@/service/user'; import { sideBarList } from '@/constants/constant'; // types -import { IUserInfo } from '@/types'; +import { IUserInfo, MyPageTab } from '@/types'; import { IReduxState } from '@/types/redux/IReduxState'; // icons @@ -32,12 +32,12 @@ export default function Profile({ const isMyPage = router.query.id === user.userId; - const [selectedMenu, setSelectedMenu] = useState('프로필'); + const [selectedMenu, setSelectedMenu] = useState('프로필'); const { userData } = pageProps; const { company, name, school, userProfileImgPath } = userData; - const handleSelectMenu = (content: string) => { + const handleSelectMenu = (content: MyPageTab) => { setSelectedMenu(content); }; @@ -46,9 +46,7 @@ export default function Profile({
diff --git a/client/src/types/index.ts b/client/src/types/index.ts index cd2411a6..50d96e98 100644 --- a/client/src/types/index.ts +++ b/client/src/types/index.ts @@ -109,3 +109,5 @@ export interface IChatUserDto { } export type EmailType = 'SIGNUP' | 'USER' | 'COMPANY' | 'SCHOOL'; + +export type MyPageTab = '프로필' | '활동기록' | '친구목록' | '덕력치';