diff --git a/client/src/app/login/components/LoginForm/index.tsx b/client/src/app/login/components/LoginForm/index.tsx
index 24ea0c5a..d094c90d 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();
@@ -92,73 +87,45 @@ export default function LoginForm() {
{({ errors, touched, isSubmitting }) => (
)}
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 }) => (
)}
diff --git a/client/src/app/signup/addInfo/page.tsx b/client/src/app/signup/addInfo/page.tsx
new file mode 100644
index 00000000..954a4aa2
--- /dev/null
+++ b/client/src/app/signup/addInfo/page.tsx
@@ -0,0 +1,22 @@
+'use client';
+
+import { useState } from 'react';
+
+// components
+import AddFormProgress from '../components/AddFormProgress';
+import WorkingForm from '../components/WorkingForm';
+import InformationForm from '../components/InfomationForm';
+
+export default function AddInfo() {
+ const [isLast, setIsLast] = useState(false);
+ return (
+ <>
+
+ {isLast ? (
+
+ ) : (
+ setIsLast(true)} />
+ )}
+ >
+ );
+}
diff --git a/client/src/app/signup/components/AddFormProgress/index.tsx b/client/src/app/signup/components/AddFormProgress/index.tsx
new file mode 100644
index 00000000..54b42c1f
--- /dev/null
+++ b/client/src/app/signup/components/AddFormProgress/index.tsx
@@ -0,0 +1,14 @@
+export default function AddFormProgress({
+ widthPercent,
+}: {
+ widthPercent: string;
+}) {
+ return (
+
+ );
+}
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/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 }) => (
+
+ )}
+
+ );
+}
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..a2e1ae9a
--- /dev/null
+++ b/client/src/app/signup/components/InitialSignUpForm/index.tsx
@@ -0,0 +1,254 @@
+'use client';
+
+import { useState } from 'react';
+import { useRouter } from 'next/navigation';
+
+//components
+import { Button, LoadingIcon, 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),
+});
+
+interface IFormData extends Pick {
+ passwordConfirm: string;
+ agreeTerm: boolean;
+}
+
+export default function InitialSignUpForm() {
+ const router = useRouter();
+
+ 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 = (
+ sendData: IFormData,
+ setSubmitting: (value: boolean) => void
+ ) => {
+ const { passwordConfirm, agreeTerm, ...mainData } = sendData;
+
+ if (checkedId !== sendData.userId || emailAuthToken === '') {
+ openModal({
+ type: ModalType.ERROR,
+ message:
+ checkedId !== sendData.userId
+ ? errorMessage.checkDuplicateId
+ : errorMessage.checkCertificateEmail,
+ });
+ setSubmitting(false);
+ return;
+ }
+ if (!agreeTerm) {
+ openModal({
+ type: ModalType.ERROR,
+ message: errorMessage.necessaryAgreeTerm,
+ });
+ setSubmitting(false);
+ return;
+ }
+
+ const data = {
+ ...mainData,
+ emailAuthToken,
+ };
+
+ sessionStorage.setItem('signupDto', JSON.stringify(data));
+ setSubmitting(false);
+ router.push('/signup/addInfo');
+ };
+
+ return (
+ handleSubmit(data, setSubmitting)}
+ >
+ {({ values, errors, touched, isSubmitting }) => (
+
+ )}
+
+ );
+}
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..5fe87410
--- /dev/null
+++ b/client/src/app/signup/components/WorkingForm/index.tsx
@@ -0,0 +1,113 @@
+//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 initialData = JSON.parse(sessionStorage.getItem('signupDto') || '');
+
+ const handleSubmit = (data: IWokring) => {
+ const { developMonth, ...addData } = data;
+
+ const bindData = {
+ ...initialData,
+ ...addData,
+ };
+
+ sessionStorage.setItem('signupDto', JSON.stringify(bindData));
+ goNext();
+ };
+
+ const handleClickCheckBox = () => {
+ const bindData = {
+ ...initialData,
+ company: '',
+ developYear: 0,
+ };
+
+ sessionStorage.setItem('signupDto', JSON.stringify(bindData));
+ goNext();
+ };
+
+ return (
+ handleSubmit(data)}
+ >
+ {({ errors, touched, isSubmitting }) => (
+
+ )}
+
+ );
+}
diff --git a/client/src/app/signup/layout.tsx b/client/src/app/signup/layout.tsx
index ca088b9d..60351ce6 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 (
+
+ );
}
diff --git a/client/src/app/signup/page.tsx b/client/src/app/signup/page.tsx
index 9644cf08..28d28ae2 100644
--- a/client/src/app/signup/page.tsx
+++ b/client/src/app/signup/page.tsx
@@ -1,323 +1,31 @@
-'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);
- }
- };
-
return (
-
-
회원가입
-
- * 필수입력사항
-
+
+ 회원가입
+
+
+
+
+
+
+
+ {"이미 '리덕' 회원이신가요?"}
+
+
+ 로그인 하기
+
-
-
- handleSubmit(data, setSubmitting)
- }
- >
- {({ values, errors, touched, isSubmitting }) => (
-
- )}
-
);
}
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;
diff --git a/client/src/components/Form/CheckBox/index.tsx b/client/src/components/Form/CheckBox/index.tsx
new file mode 100644
index 00000000..17edb8ac
--- /dev/null
+++ b/client/src/components/Form/CheckBox/index.tsx
@@ -0,0 +1,22 @@
+'use client';
+
+import { Field, FieldAttributes } from 'formik';
+
+interface IProps extends FieldAttributes {
+ 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..d5ba86ed
--- /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..3537347a 100644
--- a/client/src/components/Form/Input/index.tsx
+++ b/client/src/components/Form/Input/index.tsx
@@ -1,20 +1,44 @@
'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 = '',
+ type,
+ ...props
+}: IProps) {
+ 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 (
-