diff --git a/src/Router.tsx b/src/Router.tsx index 9f746cc..8c15694 100644 --- a/src/Router.tsx +++ b/src/Router.tsx @@ -12,8 +12,8 @@ import { ROUTES } from "./constants/router"; import AuthLayout from "./layouts/AuthLayout"; import MainLayout from "./layouts/MainLayout"; -const SignupPage = lazy(() => import("@/pages/SignupPage")); -const SigninPage = lazy(() => import("@/pages/SigninPage")); +const SignupPage = lazy(() => import("@/pages/AuthPage/SignupPage")); +const SigninPage = lazy(() => import("@/pages/AuthPage/SigninPage")); const ProfilePage = lazy(() => import("@/pages/ProfilePage/ProfilePage")); const ProfileRegisterPage = lazy(() => import("@/pages/ProfileRegisterPage")); diff --git a/src/layouts/AuthLayout.tsx b/src/layouts/AuthLayout.tsx index 4769b3f..d68f41d 100644 --- a/src/layouts/AuthLayout.tsx +++ b/src/layouts/AuthLayout.tsx @@ -2,7 +2,7 @@ import { Outlet } from "react-router-dom"; export default function AuthLayout() { return ( -
+
diff --git a/src/pages/SigninPage.tsx b/src/pages/AuthPage/SigninPage.tsx similarity index 74% rename from src/pages/SigninPage.tsx rename to src/pages/AuthPage/SigninPage.tsx index 3085cc7..3e994bb 100644 --- a/src/pages/SigninPage.tsx +++ b/src/pages/AuthPage/SigninPage.tsx @@ -1,8 +1,12 @@ +import { useState, useEffect } from "react"; + import { AxiosError } from "axios"; import { useNavigate, Link } from "react-router-dom"; -import Logo from "../assets/logo/thejulge.svg?react"; -import { useAuthForm } from "../hooks/useAuthForm"; +import Logo from "../../assets/logo/thejulge.svg?react"; + +import Spinner from "./components/Spinner"; +import { useAuthForm } from "./hooks/useAuthForm"; import { postAuthentication } from "@/apis/services/authenticationService"; import Button from "@/components/Button"; @@ -13,13 +17,28 @@ import { useModalStore } from "@/store/useModalStore"; export default function SigninPage() { const navigate = useNavigate(); - const { setUserAndToken } = useUserStore(); + const { user, setUserAndToken } = useUserStore(); const { openModal, closeModal } = useModalStore(); const { formData, errors, isFormValid, handleChange, resetForm } = useAuthForm("signin"); + const [isSubmitting, setIsSubmitting] = useState(false); + + useEffect(() => { + if (user) { + if (user.type === "employer") { + navigate(ROUTES.SHOP.ROOT); + } else if (user.type === "employee") { + navigate(ROUTES.PROFILE.ROOT); + } + } + }, [user, navigate]); + const handleSubmit = async () => { + if (isSubmitting) return; + setIsSubmitting(true); + try { const res = await postAuthentication({ email: formData.email, @@ -72,13 +91,15 @@ export default function SigninPage() { }, ], }); + } finally { + setIsSubmitting(false); } }; return ( -
+
- +
- 로그인하기 + {isSubmitting && } + {isSubmitting ? "로그인 중..." : "로그인하기"} diff --git a/src/pages/SignupPage.tsx b/src/pages/AuthPage/SignupPage.tsx similarity index 84% rename from src/pages/SignupPage.tsx rename to src/pages/AuthPage/SignupPage.tsx index b3460b3..7c9f2dc 100644 --- a/src/pages/SignupPage.tsx +++ b/src/pages/AuthPage/SignupPage.tsx @@ -1,10 +1,14 @@ +import { useState, useEffect } from "react"; + import { AxiosError } from "axios"; import clsx from "clsx"; import { useNavigate, Link } from "react-router-dom"; -import IconCheck from "../assets/icon/check.svg?react"; -import Logo from "../assets/logo/thejulge.svg?react"; -import { useAuthForm } from "../hooks/useAuthForm"; +import IconCheck from "../../assets/icon/check.svg?react"; +import Logo from "../../assets/logo/thejulge.svg?react"; + +import Spinner from "./components/Spinner"; +import { useAuthForm } from "./hooks/useAuthForm"; import { postAuthentication } from "@/apis/services/authenticationService"; import { postUser } from "@/apis/services/userService"; @@ -16,7 +20,7 @@ import { useModalStore } from "@/store/useModalStore"; export default function SignupPage() { const navigate = useNavigate(); - const { setUserAndToken } = useUserStore(); + const { user, setUserAndToken } = useUserStore(); const { openModal, closeModal } = useModalStore(); const { @@ -28,7 +32,22 @@ export default function SignupPage() { resetForm, } = useAuthForm("signup"); + const [isSubmitting, setIsSubmitting] = useState(false); + + useEffect(() => { + if (user) { + if (user.type === "employer") { + navigate(ROUTES.SHOP.ROOT); + } else if (user.type === "employee") { + navigate(ROUTES.PROFILE.ROOT); + } + } + }, [user, navigate]); + const handleSubmit = async () => { + if (isSubmitting) return; + setIsSubmitting(true); + try { const response = await postUser({ email: formData.email, @@ -90,13 +109,15 @@ export default function SignupPage() { }, ], }); + } finally { + setIsSubmitting(false); } }; return ( -
+
- +
- 가입하기 + {isSubmitting && } + {isSubmitting ? "가입 중..." : "가입하기"} diff --git a/src/pages/AuthPage/components/Spinner.tsx b/src/pages/AuthPage/components/Spinner.tsx new file mode 100644 index 0000000..05120ab --- /dev/null +++ b/src/pages/AuthPage/components/Spinner.tsx @@ -0,0 +1,5 @@ +export default function Spinner() { + return ( +
+ ); +} diff --git a/src/hooks/useAuthForm.ts b/src/pages/AuthPage/hooks/useAuthForm.ts similarity index 76% rename from src/hooks/useAuthForm.ts rename to src/pages/AuthPage/hooks/useAuthForm.ts index 630e387..73dc105 100644 --- a/src/hooks/useAuthForm.ts +++ b/src/pages/AuthPage/hooks/useAuthForm.ts @@ -41,24 +41,34 @@ export function useAuthForm(mode: Mode) { (field: keyof FormData) => (e: React.ChangeEvent) => { const value = e.target.value; setFormData((prev) => ({ ...prev, [field]: value })); - if (field === "email") { - const isValidEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value); setErrors((prev) => ({ ...prev, - email: isValidEmail ? undefined : "올바른 이메일 형식이 아닙니다.", + email: + value.length === 0 + ? undefined + : value.includes("@") + ? /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) + ? undefined + : "올바른 이메일 형식이 아닙니다." + : undefined, })); } if (field === "password") { + const trimmed = value.trim(); setErrors((prev) => ({ ...prev, password: - value.length >= 8 ? undefined : "비밀번호는 8자 이상이어야 합니다.", + value.length > 0 && trimmed.length === 0 + ? "비밀번호에 공백만 입력할 수 없습니다." + : trimmed.length > 0 && trimmed.length < 8 + ? "비밀번호는 최소 8자 이상이어야 합니다." + : undefined, ...(mode === "signup" && formData.confirmPassword && { confirmPassword: - value !== formData.confirmPassword + trimmed !== formData.confirmPassword ? "비밀번호가 일치하지 않습니다." : undefined, }),