Skip to content

Commit

Permalink
회원가입 폼 리팩토링 및 유효성 검사 추가
Browse files Browse the repository at this point in the history
- 회원가입 폼에서 서비스 코드 분리
- tanstack query(react-query)를 사용하여 회원가입 로직 통합
- 코드 전반에 걸쳐 가독성 및 유지 보수성 향상
  • Loading branch information
deipanema committed Oct 28, 2024
1 parent 60af140 commit b6390a7
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 43 deletions.
10 changes: 10 additions & 0 deletions src/api/authAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import api from "@/lib/api";

export const signup = async (data: { email: string; nickname: string; password: string }) => {
const response = await api.post("/user", {
email: data.email,
name: data.nickname,
password: data.password,
});
return response.data;
};
69 changes: 28 additions & 41 deletions src/app/(auth)/components/SignupForm.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"use client";

import { toast } from "react-toastify";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import axios from "axios";
import { z } from "zod";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

import { useSignup } from "@/hook/useSignup";

import SubmitButton from "./SubmitButton";
import InputField from "./InputField";

Expand All @@ -16,67 +16,54 @@ type FormFields = "nickname" | "email" | "password" | "passwordConfirm";
type FormData = z.infer<typeof signupSchema>;

export default function SignupForm() {
const router = useRouter();

const {
register,
handleSubmit,
formState: { errors, isSubmitting },
trigger,
setError,
clearErrors,
reset,
watch,
} = useForm<FormData>({
resolver: zodResolver(signupSchema),
mode: "onChange", // 실시간 유효성 검사를 위해 추가
});

useEffect(() => {
const firstInput = document.getElementById("nickname") as HTMLInputElement;
if (firstInput) {
firstInput.focus();
}
}, []);
const signupMutation = useSignup();

const onSubmit = async (data: FormData) => {
try {
const response = await axios.post(`${process.env.NEXT_PUBLIC_API_URL}/user`, {
email: data.email,
name: data.nickname,
password: data.password,
});

if (response.data) {
clearErrors();
reset();
toast.success("회원가입이 완료되었습니다.");
router.push("/login");
}
} catch (error) {
console.error("회원가입 서버 오류🚨", error);
signupMutation.mutate(data, {
onError: (error) => {
console.error("회원가입 서버 오류🚨", error);

if (axios.isAxiosError(error) && error.response) {
const errorCode = error.response.status;
const errorInfo = errorMessage[errorCode];
if (axios.isAxiosError(error) && error.response) {
const errorCode = error.response.status;
const errorInfo = errorMessage[errorCode];

if (errorCode) {
setError(errorInfo.field, {
type: "manual",
message: errorInfo.message,
});
if (errorInfo) {
setError(errorInfo.field, {
type: "manual",
message: errorInfo.message,
});
}
}
}
}
},
});
};

useEffect(() => {
const firstInput = document.getElementById("nickname") as HTMLInputElement;
if (firstInput) {
firstInput.focus();
}
}, []);

return (
<form className="flex flex-col justify-center" aria-label="회원가입 양식" onSubmit={handleSubmit(onSubmit)}>
<InputField
id="nickname"
label="닉네임"
type="text"
placeholder="닉네임을 입력해 주세요."
placeholder="별명(2~20자)"
register={register}
errors={errors}
trigger={trigger}
Expand All @@ -86,7 +73,7 @@ export default function SignupForm() {
id="email"
label="아이디"
type="email"
placeholder="이메일을 입력해 주세요."
placeholder="이메일"
register={register}
errors={errors}
trigger={trigger}
Expand All @@ -96,7 +83,7 @@ export default function SignupForm() {
id="password"
label="비밀번호"
type="password"
placeholder="비밀번호를 입력해 주세요."
placeholder="비밀번호"
register={register}
errors={errors}
trigger={trigger}
Expand All @@ -106,7 +93,7 @@ export default function SignupForm() {
id="passwordConfirm"
label="비밀번호 확인"
type="password"
placeholder="비밀번호를 입력해 주세요."
placeholder="비밀번호 확인"
register={register}
errors={errors}
trigger={trigger}
Expand Down
4 changes: 2 additions & 2 deletions src/app/(auth)/components/SignupFormContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ export default function SignupFormContainer() {
<section aria-labelledby="signup-heading" className="flex items-center justify-center">
<Image alt="브랜드" width={106} height={35} src="/brand.webp" className="absolute left-4 top-4" priority />
<div className="w-[343px] rounded-2xl bg-white px-8 py-6 sm:w-[510px] sm:rounded-3xl sm:px-14 sm:py-8 md:mx-[102px]">
<h2 id="signup-heading" className="pb-8 text-center text-[20px] font-bold text-black">
<h1 id="signup-heading" className="pb-8 text-center text-xl font-bold text-black">
회원가입
</h2>
</h1>
<SignupForm />
<LoginPrompt />
</div>
Expand Down
22 changes: 22 additions & 0 deletions src/hook/useSignup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useRouter } from "next/navigation";
import { toast } from "react-toastify";
import { useMutation } from "@tanstack/react-query";

import { signup } from "@/api/authAPI";
import { ErrorType } from "@/api/goalAPI";

export const useSignup = () => {
const router = useRouter();
console.log("1");

return useMutation({
mutationFn: signup,
onSuccess: () => {
toast.success("회원가입이 완료되었습니다.");
router.push("/login");
},
onError: (error: ErrorType) => {
throw error;
},
});
};

0 comments on commit b6390a7

Please sign in to comment.