"use client"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { signup } from "@/features/auth/actions"; import { signupSchema, type SignupFormData, } from "@/features/auth/schemas/auth-schema"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { InlineSpinner } from "@/components/ui/loading-spinner"; import { useState } from "react"; /** * [회원가입 폼 클라이언트 컴포넌트 - React Hook Form 버전] * * React Hook Form과 Zod를 사용한 회원가입 폼입니다. * - 타입 안전한 폼 검증 * - 자동 에러 메시지 관리 * - 비밀번호/비밀번호 확인 일치 검증 * - 로딩 상태 표시 * * @see app/signup/page.tsx - 이 컴포넌트를 사용하는 페이지 */ export default function SignupForm() { // ========== 로딩 상태 ========== const [isLoading, setIsLoading] = useState(false); const [serverError, setServerError] = useState(""); // ========== React Hook Form 설정 ========== const { register, handleSubmit, formState: { errors }, watch, } = useForm({ resolver: zodResolver(signupSchema), mode: "onBlur", // 포커스 아웃 시 검증 }); // 비밀번호 실시간 감시 (일치 여부 표시용) const password = watch("password"); const confirmPassword = watch("confirmPassword"); // ========== 폼 제출 핸들러 ========== const onSubmit = async (data: SignupFormData) => { setServerError(""); setIsLoading(true); try { const formData = new FormData(); formData.append("email", data.email); formData.append("password", data.password); await signup(formData); } catch (error) { console.error("Signup error:", error); setServerError("회원가입 중 오류가 발생했습니다."); } finally { setIsLoading(false); } }; return (
{/* ========== 서버 에러 메시지 표시 ========== */} {serverError && (
{serverError}
)} {/* ========== 이메일 입력 필드 ========== */}
{errors.email && (

{errors.email.message}

)}
{/* ========== 비밀번호 입력 필드 ========== */}

최소 8자 이상, 대문자, 소문자, 숫자, 특수문자 포함

{errors.password && (

{errors.password.message}

)}
{/* ========== 비밀번호 확인 필드 ========== */}
{/* 비밀번호 불일치 시 실시간 피드백 */} {confirmPassword && password !== confirmPassword && !errors.confirmPassword && (

비밀번호가 일치하지 않습니다

)} {/* 비밀번호 일치 시 확인 메시지 */} {confirmPassword && password === confirmPassword && !errors.confirmPassword && (

비밀번호가 일치합니다 ✓

)} {/* Zod 검증 에러 */} {errors.confirmPassword && (

{errors.confirmPassword.message}

)}
{/* ========== 회원가입 버튼 ========== */}
); }