회원가입 api
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import ChangePasswordModal from "../ChangePasswordModal";
|
||||
import PasswordChangeDoneModal from "../PasswordChangeDoneModal";
|
||||
import AccountDeleteModal from "../AccountDeleteModal";
|
||||
@@ -8,11 +9,90 @@ import MenuAccountOption from "@/app/menu/account/MenuAccountOption";
|
||||
|
||||
type VerificationState = 'initial' | 'sent' | 'verified' | 'failed' | 'changed';
|
||||
|
||||
type UserInfo = {
|
||||
email?: string;
|
||||
name?: string;
|
||||
phone?: string;
|
||||
};
|
||||
|
||||
export default function AccountPage() {
|
||||
const router = useRouter();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [verificationState, setVerificationState] = useState<VerificationState>('initial');
|
||||
const [doneOpen, setDoneOpen] = useState(false);
|
||||
const [deleteOpen, setDeleteOpen] = useState(false);
|
||||
const [userInfo, setUserInfo] = useState<UserInfo>({});
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
// 페이지 로드 시 사용자 정보 가져오기
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
async function fetchUserInfo() {
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
if (isMounted) {
|
||||
router.push('/login');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch('https://hrdi.coconutmeet.net/auth/me', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token && { Authorization: `Bearer ${token}` }),
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
// 토큰이 만료되었거나 유효하지 않은 경우
|
||||
localStorage.removeItem('token');
|
||||
if (isMounted) {
|
||||
router.push('/login');
|
||||
}
|
||||
return;
|
||||
}
|
||||
let errorMessage = `사용자 정보 조회 실패 (${response.status})`;
|
||||
try {
|
||||
const errorData = await response.json();
|
||||
if (errorData.error) {
|
||||
errorMessage = errorData.error;
|
||||
} else if (errorData.message) {
|
||||
errorMessage = errorData.message;
|
||||
}
|
||||
} catch (parseError) {
|
||||
// ignore
|
||||
}
|
||||
console.error('사용자 정보 조회 실패:', errorMessage);
|
||||
if (isMounted) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (isMounted) {
|
||||
setUserInfo(data);
|
||||
setIsLoading(false);
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : '네트워크 오류가 발생했습니다.';
|
||||
console.error('사용자 정보 조회 오류:', errorMessage);
|
||||
if (isMounted) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetchUserInfo();
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 개발 옵션에서 'changed'로 전환하면 완료 모달 표시
|
||||
useEffect(() => {
|
||||
@@ -22,7 +102,7 @@ export default function AccountPage() {
|
||||
return (
|
||||
<main className="flex w-full flex-col">
|
||||
<div className="flex h-[100px] items-center px-8">
|
||||
<h1 className="text-[24px] font-bold leading-[1.5] text-[#1b2027]">내 정보 수정</h1>
|
||||
<h1 className="text-[24px] font-bold leading-normal text-[#1b2027]">내 정보 수정</h1>
|
||||
</div>
|
||||
<div className="px-8 pb-20">
|
||||
<div className="rounded-lg border border-[#dee1e6] bg-white p-8">
|
||||
@@ -31,7 +111,9 @@ export default function AccountPage() {
|
||||
아이디 (이메일)
|
||||
</label>
|
||||
<div className="h-10 rounded-lg border border-[#dee1e6] bg-neutral-50 px-3 py-2">
|
||||
<span className="text-[16px] leading-[1.5] text-[#333c47]">skyblue@edu.com</span>
|
||||
<span className="text-[16px] leading-normal text-[#333c47]">
|
||||
{isLoading ? '로딩 중...' : (userInfo.email || '이메일 정보 없음')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 flex flex-col gap-2">
|
||||
@@ -40,7 +122,7 @@ export default function AccountPage() {
|
||||
</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="h-10 flex-1 rounded-lg border border-[#dee1e6] bg-neutral-50 px-3 py-2">
|
||||
<span className="text-[16px] leading-[1.5] text-[#333c47]">●●●●●●●●●●</span>
|
||||
<span className="text-[16px] leading-normal text-[#333c47]">●●●●●●●●●●</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
@@ -89,9 +171,47 @@ export default function AccountPage() {
|
||||
<AccountDeleteModal
|
||||
open={deleteOpen}
|
||||
onClose={() => setDeleteOpen(false)}
|
||||
onConfirm={() => {
|
||||
// TODO: 탈퇴 API 연동
|
||||
setDeleteOpen(false);
|
||||
onConfirm={async () => {
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
const response = await fetch('https://hrdi.coconutmeet.net/auth/delete/me', {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token && { Authorization: `Bearer ${token}` }),
|
||||
},
|
||||
});
|
||||
|
||||
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);
|
||||
alert(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
// 성공 시 토큰 제거 및 로그인 페이지로 이동
|
||||
localStorage.removeItem('token');
|
||||
setDeleteOpen(false);
|
||||
router.push('/login');
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : '네트워크 오류가 발생했습니다.';
|
||||
console.error('회원 탈퇴 오류:', errorMessage);
|
||||
alert(errorMessage);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user