"use client"; import { FormEvent, useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import Link from "next/link"; type PasswordStrengthLabel = "약함" | "보통" | "강함"; function getPasswordStrengthLabel(password: string): PasswordStrengthLabel | null { if (!password || password.length < 4) { return null; } let score = 0; if (/[a-z]/.test(password)) score += 1; if (/[A-Z]/.test(password)) score += 1; if (/[0-9]/.test(password)) score += 1; if (/[^a-zA-Z0-9]/.test(password)) score += 1; if (password.length >= 12) score += 1; if (password.length < 8 || score <= 2) { return "약함"; } if (score === 3) { return "보통"; } return "강함"; } export default function SignupPage() { const router = useRouter(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [passwordConfirm, setPasswordConfirm] = useState(""); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); useEffect(() => { let cancelled = false; const checkAuth = async () => { try { const res = await fetch("/api/auth/me"); if (!cancelled && res.ok) { router.push("/dashboard"); } } catch { // ignore } }; void checkAuth(); return () => { cancelled = true; }; }, [router]); const handleSubmit = async (e: FormEvent) => { e.preventDefault(); setError(null); if (password !== passwordConfirm) { setError("비밀번호와 비밀번호 확인이 일치하지 않습니다."); return; } setLoading(true); try { const res = await fetch("/api/auth/signup", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, password }), }); if (!res.ok) { try { const data = await res.json(); setError(data?.message ?? "회원가입에 실패했습니다. 다시 시도해 주세요."); } catch { setError("회원가입에 실패했습니다. 다시 시도해 주세요."); } setLoading(false); return; } router.push("/dashboard"); } catch { setError("네트워크 오류가 발생했습니다. 잠시 후 다시 시도해 주세요."); } finally { setLoading(false); } }; const strengthLabel = getPasswordStrengthLabel(password); return (

회원가입

새 계정을 생성한 뒤 프로젝트를 저장하고 관리할 수 있습니다.

{error &&

{error}

}
setEmail(e.target.value)} className="w-full rounded border border-slate-300 bg-white px-2 py-1 text-xs text-slate-900 focus:outline-none focus:ring-1 focus:ring-sky-500 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-50" required />
setPassword(e.target.value)} className="w-full rounded border border-slate-300 bg-white px-2 py-1 text-xs text-slate-900 focus:outline-none focus:ring-1 focus:ring-sky-500 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-50" required minLength={8} />
{strengthLabel && (

비밀번호 난이도: {strengthLabel}

)}
setPasswordConfirm(e.target.value)} className="w-full rounded border border-slate-300 bg-white px-2 py-1 text-xs text-slate-900 focus:outline-none focus:ring-1 focus:ring-sky-500 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-50" required minLength={8} />

이미 계정이 있다면 {" "} 로그인 으로 이동해 주세요.

); }