회원가입폼 검사

This commit is contained in:
koreacomp5
2025-10-10 14:25:29 +09:00
parent 624276df08
commit 614c7bd992

View File

@@ -15,6 +15,7 @@ export default function RegisterPage() {
agreeTerms: false, agreeTerms: false,
}); });
const [loading, setLoading] = React.useState(false); const [loading, setLoading] = React.useState(false);
const [errors, setErrors] = React.useState<Record<string, string[]>>({});
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => { const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value, type, checked } = e.target; const { name, value, type, checked } = e.target;
setForm((f) => ({ ...f, [name]: type === "checkbox" ? checked : value })); setForm((f) => ({ ...f, [name]: type === "checkbox" ? checked : value }));
@@ -29,7 +30,13 @@ export default function RegisterPage() {
body: JSON.stringify(form), body: JSON.stringify(form),
}); });
const data = await res.json(); const data = await res.json();
if (!res.ok) throw new Error(data?.error || "회원가입 실패"); if (!res.ok) {
const fieldErrors = (data?.error?.fieldErrors ?? {}) as Record<string, string[]>;
setErrors(fieldErrors);
const msg = data?.error?.message || Object.values(fieldErrors)[0]?.[0] || "회원가입 실패";
throw new Error(msg);
}
setErrors({});
show("회원가입 성공! 로그인해주세요"); show("회원가입 성공! 로그인해주세요");
location.href = "/login"; location.href = "/login";
} catch (err: any) { } catch (err: any) {
@@ -42,12 +49,30 @@ export default function RegisterPage() {
<div style={{ maxWidth: 480, margin: "40px auto" }}> <div style={{ maxWidth: 480, margin: "40px auto" }}>
<h1></h1> <h1></h1>
<form onSubmit={onSubmit} style={{ display: "flex", flexDirection: "column", gap: 12 }}> <form onSubmit={onSubmit} style={{ display: "flex", flexDirection: "column", gap: 12 }}>
<input name="nickname" placeholder="닉네임" value={form.nickname} onChange={onChange} style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} /> <input name="nickname" placeholder="닉네임" value={form.nickname} onChange={onChange} aria-invalid={!!errors.nickname} aria-describedby="err-nickname" style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} />
<input name="name" placeholder="이름" value={form.name} onChange={onChange} style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} /> {errors.nickname?.length ? (
<input name="phone" placeholder="전화번호" value={form.phone} onChange={onChange} style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} /> <span id="err-nickname" style={{ color: "#c00", fontSize: 12 }}>{errors.nickname[0]}</span>
<input name="birth" placeholder="생년월일 (YYYY-MM-DD)" value={form.birth} onChange={onChange} style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} /> ) : null}
<input name="password" placeholder="비밀번호" type="password" value={form.password} onChange={onChange} style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} /> <input name="name" placeholder="이름" value={form.name} onChange={onChange} aria-invalid={!!errors.name} aria-describedby="err-name" style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} />
<input name="confirmPassword" placeholder="비밀번호 확인" type="password" value={form.confirmPassword} onChange={onChange} style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} /> {errors.name?.length ? (
<span id="err-name" style={{ color: "#c00", fontSize: 12 }}>{errors.name[0]}</span>
) : null}
<input name="phone" placeholder="전화번호" value={form.phone} onChange={onChange} aria-invalid={!!errors.phone} aria-describedby="err-phone" style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} />
{errors.phone?.length ? (
<span id="err-phone" style={{ color: "#c00", fontSize: 12 }}>{errors.phone[0]}</span>
) : null}
<input name="birth" placeholder="생년월일 (YYYY-MM-DD)" value={form.birth} onChange={onChange} aria-invalid={!!errors.birth} aria-describedby="err-birth" style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} />
{errors.birth?.length ? (
<span id="err-birth" style={{ color: "#c00", fontSize: 12 }}>{errors.birth[0]}</span>
) : null}
<input name="password" placeholder="비밀번호" type="password" value={form.password} onChange={onChange} aria-invalid={!!errors.password} aria-describedby="err-password" style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} />
{errors.password?.length ? (
<span id="err-password" style={{ color: "#c00", fontSize: 12 }}>{errors.password[0]}</span>
) : null}
<input name="confirmPassword" placeholder="비밀번호 확인" type="password" value={form.confirmPassword} onChange={onChange} aria-invalid={!!errors.confirmPassword} aria-describedby="err-confirmPassword" style={{ padding: 8, border: "1px solid #ddd", borderRadius: 6 }} />
{errors.confirmPassword?.length ? (
<span id="err-confirmPassword" style={{ color: "#c00", fontSize: 12 }}>{errors.confirmPassword[0]}</span>
) : null}
<label style={{ display: "flex", alignItems: "center", gap: 8 }}> <label style={{ display: "flex", alignItems: "center", gap: 8 }}>
<input name="agreeTerms" type="checkbox" checked={form.agreeTerms} onChange={onChange} /> <input name="agreeTerms" type="checkbox" checked={form.agreeTerms} onChange={onChange} />
</label> </label>