From e42380a3ec795dff75e68792ab8d31593af65fc4 Mon Sep 17 00:00:00 2001 From: Jungu Lee <100949102+jobkaeHenry@users.noreply.github.com> Date: Tue, 5 Dec 2023 00:51:25 +0900 Subject: [PATCH] =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85-=EB=A9=80?= =?UTF-8?q?=ED=8B=B0=EC=8A=A4=ED=83=AD=ED=8F=BC-=EC=A0=9C=EC=9E=91=20(#71)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactor : 회원가입 실패 이유 표출 * Refactor : 앱바 기본동작 추가 * Minor : Disable 버튼 스타일 추가 * New : FixedBottomCTA 버튼 추가 * Refactor : 회원가입 Multi-step-form 적용 --- .../app/(logoutOnly)/auth/signup/layout.tsx | 38 +++ .../src/app/(logoutOnly)/auth/signup/page.tsx | 289 ++++++++++-------- client/src/components/CustomAppbar.tsx | 8 +- client/src/components/FixedBottomCTA.tsx | 33 ++ .../src/components/auth/signup/SignupStep.tsx | 50 +++ client/src/const/theme.ts | 8 + client/src/hooks/useMultistepForm.ts | 62 ++++ client/src/queries/auth/useSignupMutation.tsx | 6 + client/src/store/auth/SignupPageContext.ts | 23 ++ 9 files changed, 389 insertions(+), 128 deletions(-) create mode 100644 client/src/app/(logoutOnly)/auth/signup/layout.tsx create mode 100644 client/src/components/FixedBottomCTA.tsx create mode 100644 client/src/components/auth/signup/SignupStep.tsx create mode 100644 client/src/hooks/useMultistepForm.ts create mode 100644 client/src/store/auth/SignupPageContext.ts diff --git a/client/src/app/(logoutOnly)/auth/signup/layout.tsx b/client/src/app/(logoutOnly)/auth/signup/layout.tsx new file mode 100644 index 0000000..5dfd381 --- /dev/null +++ b/client/src/app/(logoutOnly)/auth/signup/layout.tsx @@ -0,0 +1,38 @@ +"use client"; + +import SignupPageContext from "@/store/auth/SignupPageContext"; +import { SignupRequirement } from "@/types/auth/signupRequirement"; +import { Container, Paper } from "@mui/material"; +import { ReactNode, useState } from "react"; + +type layoutProps = { + children: ReactNode; +}; + +const layout = ({ children }: layoutProps) => { + const [disableBtn, setDisableBtn] = useState(false); + const [formData, setFormData] = useState({ + id: "", + email: "", + password: "", + nickname: "", + }); + return ( + + + + {children} + + + + ); +}; + +export default layout; diff --git a/client/src/app/(logoutOnly)/auth/signup/page.tsx b/client/src/app/(logoutOnly)/auth/signup/page.tsx index 42881d4..e8545f4 100644 --- a/client/src/app/(logoutOnly)/auth/signup/page.tsx +++ b/client/src/app/(logoutOnly)/auth/signup/page.tsx @@ -1,137 +1,174 @@ "use client"; -import Avatar from "@mui/material/Avatar"; -import Button from "@mui/material/Button"; -import CssBaseline from "@mui/material/CssBaseline"; -import TextField from "@mui/material/TextField"; -import FormControlLabel from "@mui/material/FormControlLabel"; -import Checkbox from "@mui/material/Checkbox"; -import Grid from "@mui/material/Grid"; -import Box from "@mui/material/Box"; -import LockOutlinedIcon from "@mui/icons-material/LockOutlined"; -import Typography from "@mui/material/Typography"; -import Container from "@mui/material/Container"; -import { SIGNIN } from "@/const/clientPath"; -import Link from "next/link"; -import { ChangeEvent, useState } from "react"; -import { SignupRequirement } from "@/types/auth/signupRequirement"; +import { ChangeEvent, useContext, useCallback, useState } from "react"; import useSignupMutation from "@/queries/auth/useSignupMutation"; +import SignupPageContext from "@/store/auth/SignupPageContext"; +import useMultistepForm from "@/hooks/useMultistepForm"; +import SignupStep from "@/components/auth/signup/SignupStep"; +import { TextField, LinearProgress } from "@mui/material"; +import CustomAppbar from "@/components/CustomAppbar"; +import { useRouter } from "next/navigation"; +import HOME from "@/const/clientPath"; +import { HomeOutlined } from "@mui/icons-material"; +import { SignupRequirement } from "@/types/auth/signupRequirement"; +import FixedBottomCTA from "@/components/FixedBottomCTA"; export default function SignUpPage() { - const [formData, setFormData] = useState({ - id: "", - email: "", - password: "", - nickname: "", - }); - const changeHandler = ({ - target, - }: ChangeEvent) => { - setFormData((prev) => ({ ...prev, [target.name]: target.value })); - }; - const { mutate: submitHandler } = useSignupMutation(); + const { formData, setFormData, disableBtn } = useContext(SignupPageContext); + const router = useRouter(); + + const changeHandler = useCallback( + ({ target }: ChangeEvent) => { + setFormData((prev) => ({ ...prev, [target.name]: target.value })); + }, + [] + ); + const [doubleCheckPassword, setDoubleCheckPassword] = useState(""); + + const { mutateAsync: signupHandler } = useSignupMutation(); + const submitHandler = useCallback(async (data: SignupRequirement) => { + try { + await signupHandler(data); + } catch (err) { + goTo(0); + } + }, []); + + const { + next, + MultistepForm, + isFirstStep, + isLastStep, + goTo, + totalPageNum, + currentIndex, + } = useMultistepForm( + [ + + + , + + + + , + + + setDoubleCheckPassword(target.value)} + /> + , + + 2) : undefined + } + > + + , + + 2) + : undefined + } + > + + , + ], + 0 + ); return ( - - - + : undefined} + onClickPrepend={() => (isFirstStep ? router.push(HOME) : router.back())} + onClickAppend={() => router.push(HOME)} + /> + + {MultistepForm} + { + !isLastStep ? next() : submitHandler(formData); }} + size="large" + disabled={disableBtn} > - - - - 회원가입 - { - e.preventDefault(); - submitHandler(formData); - }} - noValidate - sx={{ mt: 3 }} - > - - - changeHandler(e)} - /> - - - changeHandler(e)} - autoComplete="new-password" - /> - - - changeHandler(e)} - label="유저 아이디" - /> - - - changeHandler(e)} - name="nickname" - /> - - - } - label="유용한 정보를 받아볼게요." - /> - - - - - - - - Already have an account?{" "} - - 로그인 하러가기 - - - - - - - - + {!isLastStep ? "다음" : "투파이아 시작하기"} + + ); } diff --git a/client/src/components/CustomAppbar.tsx b/client/src/components/CustomAppbar.tsx index 8a1fb5c..9c353ee 100644 --- a/client/src/components/CustomAppbar.tsx +++ b/client/src/components/CustomAppbar.tsx @@ -40,7 +40,11 @@ const CustomAppbar = ({ {prependButton} ) : ( - router.back()}> + + onClickPrepend ? onClickPrepend(e) : router.back() + } + > )} @@ -67,7 +71,7 @@ const CustomAppbar = ({ const AppbarButton = styled(Button)(() => ({ minWidth: 40, fontWeight: "medium", - fontSize:'18px' + fontSize: "18px", })); export default memo(CustomAppbar); diff --git a/client/src/components/FixedBottomCTA.tsx b/client/src/components/FixedBottomCTA.tsx new file mode 100644 index 0000000..bc0044c --- /dev/null +++ b/client/src/components/FixedBottomCTA.tsx @@ -0,0 +1,33 @@ +import { Button, ButtonProps, Paper } from "@mui/material"; + +const FixedBottomCTA = ({ ...props }: ButtonProps) => { + return ( + <> +