From 8f17e128e27e9725f12c2ae31b06eb225debacb9 Mon Sep 17 00:00:00 2001 From: kiyeong Date: Sat, 30 Nov 2024 00:38:57 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20api=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MainPage/{MainPage.tsx => GuestPage.tsx} | 5 +- src/pages/MainPage/IntroModal.tsx | 1 + src/pages/MainPage/UserPage | 1 + src/pages/SignupPage/SignupPage.tsx | 165 ++++++++++++++++-- src/routes/index.tsx | 4 +- src/routes/path.ts | 2 +- 6 files changed, 155 insertions(+), 23 deletions(-) rename src/pages/MainPage/{MainPage.tsx => GuestPage.tsx} (96%) create mode 100644 src/pages/MainPage/UserPage diff --git a/src/pages/MainPage/MainPage.tsx b/src/pages/MainPage/GuestPage.tsx similarity index 96% rename from src/pages/MainPage/MainPage.tsx rename to src/pages/MainPage/GuestPage.tsx index a5b1fd2..e374610 100644 --- a/src/pages/MainPage/MainPage.tsx +++ b/src/pages/MainPage/GuestPage.tsx @@ -1,3 +1,4 @@ +// 로그인 하지 않은 사용자의 메인 페이지 컴포넌트 import { useState, useEffect, useRef } from "react"; import { MessageInput } from "./MessageInput/MessageInput"; import { MessageList } from "./messageList/MessageList"; @@ -10,7 +11,7 @@ import tutorial3 from "@/assets/tutorial3.svg"; import tutorial4 from "@/assets/tutorial4.svg"; import tutorial5 from "@/assets/tutorial5.svg"; -const MainPage = () => { +const GuestPage = () => { const [messages, setMessages] = useState([]); const [inputMessage, setInputMessage] = useState(""); const [isSidebarOpen, setSidebarOpen] = useState(false); @@ -330,4 +331,4 @@ const MainPage = () => { ); }; -export default MainPage; +export default GuestPage; diff --git a/src/pages/MainPage/IntroModal.tsx b/src/pages/MainPage/IntroModal.tsx index b9cb51a..c800c47 100644 --- a/src/pages/MainPage/IntroModal.tsx +++ b/src/pages/MainPage/IntroModal.tsx @@ -1,3 +1,4 @@ +// 서비스의 사용 설명서를 보여주는 모달 컴포넌트 import React from "react"; import { Modal, diff --git a/src/pages/MainPage/UserPage b/src/pages/MainPage/UserPage new file mode 100644 index 0000000..12e708e --- /dev/null +++ b/src/pages/MainPage/UserPage @@ -0,0 +1 @@ +// 로그인을 한 사용자의 메인 페이지 컴포넌트 diff --git a/src/pages/SignupPage/SignupPage.tsx b/src/pages/SignupPage/SignupPage.tsx index 98ea1d5..b38164e 100644 --- a/src/pages/SignupPage/SignupPage.tsx +++ b/src/pages/SignupPage/SignupPage.tsx @@ -8,28 +8,130 @@ import { Text, Image, IconButton, + useToast, + InputGroup, + InputRightElement, } from "@chakra-ui/react"; -import { ArrowBackIcon } from "@chakra-ui/icons"; -import { useNavigate } from "react-router-dom"; // React Router 사용 +import { ArrowBackIcon, ViewIcon, ViewOffIcon } from "@chakra-ui/icons"; +import { useNavigate } from "react-router-dom"; import welcomeHobanu from "./assets/signupHobanu.svg"; // 이미지 경로를 맞게 설정하세요 +const baseURL = import.meta.env.VITE_BASE_URL; // 환경 변수에서 baseURL 가져오기 + const SignupPage: React.FC = () => { const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [nickname, setNickname] = useState(""); + const [showPassword, setShowPassword] = useState(false); // 비밀번호 보이기/숨기기 상태 const [emailCheckMessage, setEmailCheckMessage] = useState(""); + const [emailCheckDone, setEmailCheckDone] = useState(false); // 이메일 중복 검사 완료 여부 + const toast = useToast(); // Toast 인스턴스 const navigate = useNavigate(); - const handleEmailCheck = () => { - // 이메일 중복 확인 로직 - if (email === "example@test.com") { - setEmailCheckMessage("이미 사용 중인 이메일입니다."); - } else { - setEmailCheckMessage("가입 가능한 이메일입니다."); + // 이메일 중복 확인 + const handleEmailCheck = async () => { + try { + const response = await fetch( + `${baseURL}/api/member/check-email?email=${email}`, + { + method: "GET", + } + ); + + if (response.status === 200) { + const data = await response.json(); + if (data.email_check) { + setEmailCheckDone(false); + setEmailCheckMessage("이미 사용 중인 이메일입니다."); + } else { + setEmailCheckDone(true); // 이메일 중복 검사 성공 + setEmailCheckMessage("가입 가능한 이메일입니다."); + } + } else if (response.status === 400) { + setEmailCheckDone(false); + setEmailCheckMessage("이메일에 공란이 있습니다."); + } else { + setEmailCheckDone(false); + setEmailCheckMessage("오류가 발생했습니다. 다시 시도해주세요."); + } + } catch (error) { + console.error("Error checking email:", error); + setEmailCheckDone(false); + setEmailCheckMessage( + "서버와 연결할 수 없습니다. 나중에 다시 시도해주세요." + ); + } + }; + + // 회원가입 요청 + const handleSignup = async () => { + // 이메일 중복 검사 완료 여부 확인 + if (!emailCheckDone) { + toast({ + title: "이메일 중복 검사를 먼저 해주세요.", + status: "warning", + position: "top", + duration: 1500, + isClosable: true, + }); + return; + } + + try { + const response = await fetch(`${baseURL}/api/member/signup`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email, + password, + nickname, + }), + }); + + if (response.status === 201) { + toast({ + title: "회원가입에 성공했습니다.", + status: "success", + position: "top", + duration: 1500, + isClosable: true, + }); + navigate("/login"); // 회원가입 성공 후 로그인 페이지로 이동 + } else if (response.status === 500) { + toast({ + title: "내부 서버 오류가 발생했습니다.", + status: "error", + position: "top", + duration: 1500, + isClosable: true, + }); + } else { + toast({ + title: "회원가입에 실패했습니다. 다시 시도해주세요.", + status: "error", + position: "top", + duration: 1500, + isClosable: true, + }); + } + } catch (error) { + console.error("Error during signup:", error); + toast({ + title: "서버와 연결할 수 없습니다. 나중에 다시 시도해주세요.", + status: "error", + position: "top", + duration: 1500, + isClosable: true, + }); } }; + // 이전 페이지로 이동 const handleBack = () => { - navigate(-1); // 이전 페이지로 이동 + navigate(-1); }; return ( @@ -59,7 +161,13 @@ const SignupPage: React.FC = () => { fontSize={"xl"} focusBorderColor="#DCD8C8" value={email} - onChange={(e) => setEmail(e.target.value)} + onChange={(e) => { + setEmail(e.target.value); + setEmailCheckDone(false); // 이메일 변경 시 중복 검사 초기화 + setEmailCheckMessage( + "이메일이 변경되었습니다. 중복 검사를 다시 수행해주세요." + ); + }} /> diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 4446ad9..e0e142d 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,5 +1,5 @@ import { createBrowserRouter, RouterProvider } from "react-router-dom"; -import MainPage from "@/pages/MainPage/MainPage"; +import GuestPage from "@/pages/MainPage/GuestPage"; import LoginPage from "@/pages/LoginPage/LoginPage"; import SignupPage from "@/pages/SignupPage/SignupPage"; import { RouterPath } from "./path"; // 경로 상수 가져오기 @@ -8,7 +8,7 @@ import { RouterPath } from "./path"; // 경로 상수 가져오기 const router = createBrowserRouter([ { path: RouterPath.root, - element: , // 메인 페이지를 직접 렌더링 + element: , // 메인 페이지를 직접 렌더링 }, { path: RouterPath.login, diff --git a/src/routes/path.ts b/src/routes/path.ts index 7d215d6..301a02f 100644 --- a/src/routes/path.ts +++ b/src/routes/path.ts @@ -1,6 +1,6 @@ export const RouterPath = { root: "/", - main: "/", + user: "/user", login: "/login", signup: "/signup", };