register api
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { useMemo, useState } from "react";
|
||||
import { useMemo, useState, useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
import LoginCheckboxActiveSvg from "@/app/svgs/logincheckboxactivesvg";
|
||||
import LoginCheckboxInactiveSvg from "@/app/svgs/logincheckboxinactivesvg";
|
||||
import LoginInputSvg from "@/app/svgs/inputformx";
|
||||
|
||||
type Gender = "male" | "female" | "";
|
||||
type Gender = "MALE" | "FEMALE" | "";
|
||||
|
||||
type RegisterFormProps = {
|
||||
onOpenDone: () => void;
|
||||
@@ -73,10 +73,129 @@ export default function RegisterForm({ onOpenDone, onOpenCodeError }: RegisterFo
|
||||
return Object.keys(nextErrors).length === 0;
|
||||
}
|
||||
|
||||
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
// 입력 필드가 유효해지면 해당 필드의 에러를 자동으로 지움
|
||||
useEffect(() => {
|
||||
setErrors((prev) => {
|
||||
const next = { ...prev };
|
||||
if (name.trim().length > 0 && prev.name) delete next.name;
|
||||
if (isPhoneValid && prev.phone) delete next.phone;
|
||||
if (isEmailValid && prev.email) delete next.email;
|
||||
if (isPasswordValid && prev.password) delete next.password;
|
||||
if (isPasswordConfirmValid && prev.passwordConfirm) delete next.passwordConfirm;
|
||||
if (gender !== "" && prev.gender) delete next.gender;
|
||||
if (birthdate.trim().length > 0 && prev.birthdate) delete next.birthdate;
|
||||
if (allAgree && prev.agreements) delete next.agreements;
|
||||
return next;
|
||||
});
|
||||
}, [name, isPhoneValid, isEmailValid, isPasswordValid, isPasswordConfirmValid, gender, birthdate, allAgree]);
|
||||
|
||||
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
console.log("handleSubmit");
|
||||
e.preventDefault();
|
||||
if (!validateAll()) return;
|
||||
onOpenDone();
|
||||
await RegisterUser();
|
||||
}
|
||||
|
||||
async function verifyEmailCode() {
|
||||
try{
|
||||
const response = await fetch(
|
||||
"https://hrdi.coconutmeet.net/auth/verify-email/confirm",
|
||||
{
|
||||
method: "POST", headers: {"Content-Type": "application/json",},
|
||||
body: JSON.stringify({email: email,emailCode: emailCode})
|
||||
});
|
||||
if (!response.ok) {
|
||||
console.error("이메일 인증번호 검증 실패:", response.statusText);
|
||||
onOpenCodeError();
|
||||
return;
|
||||
}
|
||||
// 인증 성공 시 상태 업데이트
|
||||
setEmailCodeVerified(true);
|
||||
}
|
||||
catch(error){
|
||||
console.error("이메일 인증번호 검증 오류:", error);
|
||||
onOpenCodeError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function sendEmailCode() {
|
||||
|
||||
if (!isEmailValid) return;
|
||||
// INSERT_YOUR_CODE
|
||||
try {
|
||||
const response = await fetch(
|
||||
"https://hrdi.coconutmeet.net/auth/verify-email/send",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json",},
|
||||
body: JSON.stringify({email: email})
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
console.error("이메일 인증번호 전송 실패:", response.statusText);
|
||||
alert("인증번호 전송실패");
|
||||
return;
|
||||
}
|
||||
// 성공 시에만 상태 업데이트
|
||||
setEmailCodeSent(true);
|
||||
setEmailCode("");
|
||||
setEmailCodeVerified(false);
|
||||
} catch (error) {
|
||||
console.error("이메일 인증번호 전송 오류:", error);
|
||||
alert("인증번호 전송실패");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function RegisterUser() {
|
||||
if (!emailCodeVerified) {
|
||||
onOpenCodeError("이메일 인증을 완료해주세요.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const response = await fetch("https://hrdi.coconutmeet.net/auth/signup", {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json",},
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
emailCode: emailCode,
|
||||
password: password,
|
||||
passwordConfirm: passwordConfirm,
|
||||
name: name,
|
||||
phone: phone,
|
||||
gender: gender,
|
||||
birthDate: birthdate
|
||||
})
|
||||
});
|
||||
if (!response.ok) {
|
||||
let errorMessage = `회원가입 실패 (${response.status})`;
|
||||
try {
|
||||
const errorData = await response.json();
|
||||
if (errorData.error) {
|
||||
errorMessage = errorData.error;
|
||||
} else if (errorData.message) {
|
||||
errorMessage = errorData.message;
|
||||
} else if (response.statusText) {
|
||||
errorMessage = `${response.statusText} (${response.status})`;
|
||||
}
|
||||
} catch (parseError) {
|
||||
if (response.statusText) {
|
||||
errorMessage = `${response.statusText} (${response.status})`;
|
||||
}
|
||||
}
|
||||
console.error("회원가입 실패:", errorMessage);
|
||||
onOpenCodeError(errorMessage);
|
||||
return false;
|
||||
}
|
||||
onOpenDone();
|
||||
return true;
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : "네트워크 오류가 발생했습니다.";
|
||||
console.error("회원가입 오류:", errorMessage);
|
||||
onOpenCodeError(errorMessage);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -87,7 +206,6 @@ export default function RegisterForm({ onOpenDone, onOpenCodeError }: RegisterFo
|
||||
회원가입
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
{/* 이름 */}
|
||||
<div className="space-y-2">
|
||||
@@ -161,9 +279,10 @@ export default function RegisterForm({ onOpenDone, onOpenCodeError }: RegisterFo
|
||||
onFocus={() => setFocused((p) => ({ ...p, email: true }))}
|
||||
onBlur={() => setFocused((p) => ({ ...p, email: false }))}
|
||||
placeholder="이메일을 입력해 주세요."
|
||||
className="h-[40px] px-[12px] py-[7px] w-full rounded-[8px] border border-neutral-40 focus:outline-none focus:border-neutral-700 text-[18px] text-neutral-700 placeholder:text-input-placeholder-text pr-[40px]"
|
||||
disabled={emailCodeVerified}
|
||||
className="h-[40px] px-[12px] py-[7px] w-full rounded-[8px] border border-neutral-40 focus:outline-none focus:border-neutral-700 text-[18px] text-neutral-700 placeholder:text-input-placeholder-text pr-[40px] disabled:bg-gray-100 disabled:cursor-not-allowed"
|
||||
/>
|
||||
{email.trim().length > 0 && focused.email && (
|
||||
{email.trim().length > 0 && focused.email && !emailCodeVerified && (
|
||||
<button
|
||||
type="button"
|
||||
onMouseDown={(e) => { e.preventDefault(); setEmail(""); }}
|
||||
@@ -176,15 +295,9 @@ export default function RegisterForm({ onOpenDone, onOpenCodeError }: RegisterFo
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!isEmailValid}
|
||||
className={`h-[40px] px-[12px] rounded-[8px] text-[16px] font-semibold ${isEmailValid ? "bg-inactive-button text-white" : "bg-gray-50 text-input-placeholder-text"}`}
|
||||
onClick={() => {
|
||||
if (!isEmailValid) return;
|
||||
alert("인증번호 전송 (가상 동작)");
|
||||
setEmailCodeSent(true);
|
||||
setEmailCode("");
|
||||
setEmailCodeVerified(false);
|
||||
}}
|
||||
disabled={!isEmailValid || emailCodeVerified}
|
||||
className={`h-[40px] px-[12px] rounded-[8px] text-[16px] font-semibold ${isEmailValid && !emailCodeVerified ? "bg-inactive-button text-white" : "bg-gray-50 text-input-placeholder-text"}`}
|
||||
onClick={sendEmailCode}
|
||||
>
|
||||
인증번호 전송
|
||||
</button>
|
||||
@@ -207,7 +320,8 @@ export default function RegisterForm({ onOpenDone, onOpenCodeError }: RegisterFo
|
||||
onFocus={() => setFocused((p) => ({ ...p, emailCode: true }))}
|
||||
onBlur={() => setFocused((p) => ({ ...p, emailCode: false }))}
|
||||
placeholder="인증번호 6자리"
|
||||
className="h-[40px] px-[12px] py-[7px] w-full rounded-[8px] border border-neutral-40 focus:outline-none focus:border-neutral-700 text-[18px] text-neutral-700 placeholder:text-input-placeholder-text pr-[40px]"
|
||||
disabled={emailCodeVerified}
|
||||
className="h-[40px] px-[12px] py-[7px] w-full rounded-[8px] border border-neutral-40 focus:outline-none focus:border-neutral-700 text-[18px] text-neutral-700 placeholder:text-input-placeholder-text pr-[40px] disabled:bg-gray-100 disabled:cursor-not-allowed"
|
||||
/>
|
||||
{emailCode.trim().length > 0 && focused.emailCode && !emailCodeVerified && (
|
||||
<button
|
||||
@@ -224,18 +338,22 @@ export default function RegisterForm({ onOpenDone, onOpenCodeError }: RegisterFo
|
||||
type="button"
|
||||
disabled={emailCodeVerified}
|
||||
className={`h-[40px] px-[12px] rounded-[8px] text-[16px] font-semibold ${!emailCodeVerified ? "bg-active-button text-white" : "bg-gray-50 text-input-placeholder-text"}`}
|
||||
onClick={() => {
|
||||
// 가상 검증: 6자리면 성공, 아니면 에러 모달
|
||||
if (emailCode.length !== 6) {
|
||||
onOpenCodeError();
|
||||
return;
|
||||
}
|
||||
setEmailCodeVerified(true);
|
||||
}}
|
||||
onClick={verifyEmailCode}
|
||||
>
|
||||
{emailCodeVerified ? "인증완료" : "인증하기"}
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-[13px] leading-[normal] text-[#384fbf]">
|
||||
{emailCodeVerified ? (
|
||||
"인증이 완료됐습니다"
|
||||
) : (
|
||||
<>
|
||||
인증 확인을 위해 작성한 이메일로 인증번호를 발송했습니다.
|
||||
<br />
|
||||
이메일을 확인해 주세요.
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -306,13 +424,13 @@ export default function RegisterForm({ onOpenDone, onOpenCodeError }: RegisterFo
|
||||
<input
|
||||
type="radio"
|
||||
name="gender"
|
||||
value="male"
|
||||
checked={gender === "male"}
|
||||
onChange={() => setGender("male")}
|
||||
value="MALE"
|
||||
checked={gender === "MALE"}
|
||||
onChange={() => setGender("MALE")}
|
||||
className="sr-only"
|
||||
/>
|
||||
<span className={`inline-block rounded-full size-[18px] border ${gender === "male" ? "border-active-button" : "border-[#8c95a1]"}`}>
|
||||
{gender === "male" && <span className="block size-[9px] rounded-full bg-active-button m-[4.5px]" />}
|
||||
<span className={`inline-block rounded-full size-[18px] border ${gender === "MALE" ? "border-active-button" : "border-[#8c95a1]"}`}>
|
||||
{gender === "MALE" && <span className="block size-[9px] rounded-full bg-active-button m-[4.5px]" />}
|
||||
</span>
|
||||
남성
|
||||
</label>
|
||||
@@ -320,13 +438,13 @@ export default function RegisterForm({ onOpenDone, onOpenCodeError }: RegisterFo
|
||||
<input
|
||||
type="radio"
|
||||
name="gender"
|
||||
value="female"
|
||||
checked={gender === "female"}
|
||||
onChange={() => setGender("female")}
|
||||
value="FEMALE"
|
||||
checked={gender === "FEMALE"}
|
||||
onChange={() => setGender("FEMALE")}
|
||||
className="sr-only"
|
||||
/>
|
||||
<span className={`inline-block rounded-full size-[18px] border ${gender === "female" ? "border-active-button" : "border-[#8c95a1]"}`}>
|
||||
{gender === "female" && <span className="block size-[9px] rounded-full bg-active-button m-[4.5px]" />}
|
||||
<span className={`inline-block rounded-full size-[18px] border ${gender === "FEMALE" ? "border-active-button" : "border-[#8c95a1]"}`}>
|
||||
{gender === "FEMALE" && <span className="block size-[9px] rounded-full bg-active-button m-[4.5px]" />}
|
||||
</span>
|
||||
여성
|
||||
</label>
|
||||
|
||||
@@ -14,6 +14,7 @@ export default function RegisterPage() {
|
||||
return (
|
||||
<>
|
||||
<div className="min-h-screen w-full flex flex-col items-center justify-between">
|
||||
|
||||
<RegisterForm
|
||||
onOpenDone={() => setDoneOpen(true)}
|
||||
onOpenCodeError={(msg) => {
|
||||
@@ -21,6 +22,7 @@ export default function RegisterPage() {
|
||||
setCodeErrorOpen(true);
|
||||
}}
|
||||
/>
|
||||
|
||||
<RegisterOption
|
||||
doneOpen={doneOpen}
|
||||
setDoneOpen={setDoneOpen}
|
||||
|
||||
Reference in New Issue
Block a user