diff --git a/src/App.tsx b/src/App.tsx index 74e8365..b828728 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,7 +12,7 @@ function App() { - } /> + } /> } /> } /> diff --git a/src/components/join/Button.tsx b/src/components/join/Button.tsx index 55f70f8..edff9d2 100644 --- a/src/components/join/Button.tsx +++ b/src/components/join/Button.tsx @@ -7,11 +7,9 @@ const ButtonWrapStyle = styled.div` border-radius: 10px; height: 50px; - border: 3px solid skyblue; - display: flex; justify-content: center; - margin-top: 30px; + margin-top: 15px; `; const ButtonStyle = styled.button` @@ -23,10 +21,10 @@ const ButtonStyle = styled.button` border: none; `; -const Button = () => { +const Button = ({ handleSignup }: { handleSignup: () => void }) => { return ( - 회원가입 + 회원가입 ); }; diff --git a/src/components/join/GotoLogin.tsx b/src/components/join/GotoLogin.tsx index 0875bb6..322f8af 100644 --- a/src/components/join/GotoLogin.tsx +++ b/src/components/join/GotoLogin.tsx @@ -1,7 +1,36 @@ +/** @jsxImportSource @emotion/react */ +import styled from "@emotion/styled"; +import { useNavigate } from "react-router-dom"; + +const GotoLoginContainer = styled.div` + font-size: 16px; + color: gray; + display: flex; + justify-content: center; +`; + +const UnderlinedLink = styled.u` + color: gray; + cursor: pointer; + text-decoration: underline; + justify-content: center; + + &:hover { + color: black; + } +`; + const GotoLogin = () => { + const navigate = useNavigate(); + const handleGotoLogin = () => { + navigate("/login"); // 로그인 후 이동할 경로 + }; return (
- 이미 계정이 있으신가요? 로그인 + + 이미 계정이 있으신가요?     + 로그인 +
); }; diff --git a/src/components/join/Input.tsx b/src/components/join/Input.tsx index d2b0c21..2d4dff2 100644 --- a/src/components/join/Input.tsx +++ b/src/components/join/Input.tsx @@ -1,5 +1,17 @@ import InputItem from "./InputItem"; import styled from "@emotion/styled"; +import { useState } from "react"; + +interface InputProps { + newPw: string; + setNewPw: React.Dispatch>; + newId: string; + setNewId: React.Dispatch>; + newAlias: string; + setNewAlias: React.Dispatch>; + checkNewPw: string; + setCheckNewPw: React.Dispatch>; +} const InputWrapStyle = styled.div` display: flex; @@ -7,13 +19,92 @@ const InputWrapStyle = styled.div` gap: 10px; `; -const Input = () => { +const ErrorMessageStyle = styled.div` + color: #ef0000; + font-size: 12px; +`; + +const PwMismatchStyle = styled.div` + color: #ef0000; + font-size: 12px; +`; + +const Input = ({ + newId, + setNewId, + newPw, + setNewPw, + newAlias, + setNewAlias, + checkNewPw, + setCheckNewPw, +}: InputProps) => { + const [newPwValid, setNewPwValid] = useState(false); + + const handleNewPw = (e: React.ChangeEvent) => { + const value = e.target.value; + setNewPw(value); + const regex = + /^(?=.*[A-Za-z])(?=.*\d)(?=.*[!@#$%^&*])[A-Za-z\d!@#$%^&*]{8,}$/; + if (regex.test(newPw)) { + setNewPwValid(true); + } else { + setNewPwValid(false); + } + }; + + const handleNewId = (e: React.ChangeEvent) => { + const value = e.target.value; + setNewId(value); + }; + + const handleNewAlias = (e: React.ChangeEvent) => { + const value = e.target.value; + setNewAlias(value); + }; + + const handleCheckNewPw = (e: React.ChangeEvent) => { + const value = e.target.value; + setCheckNewPw(value); + }; + return ( - - - - + + + + + {!newPwValid && newPw.length > 0 && ( +
영문, 숫자, 특수문자 포함 8자 이상 입력해주세요.
+ )} +
+ + + + {newPw != checkNewPw && checkNewPw.length >= 1 && ( +
비밀번호가 일치하지 않습니다.
+ )} +
); }; diff --git a/src/components/join/InputItem.tsx b/src/components/join/InputItem.tsx index 2a08451..44187e4 100644 --- a/src/components/join/InputItem.tsx +++ b/src/components/join/InputItem.tsx @@ -2,6 +2,9 @@ import styled from "@emotion/styled"; interface InputItemProps { content: string; + value?: string; + type: string; + onChange?: (e: React.ChangeEvent) => void; } const InputItemStyle = styled.input` @@ -12,10 +15,15 @@ const InputItemStyle = styled.input` border: none; `; -const InputItem = ({ content }: InputItemProps) => { +const InputItem = ({ content, value, onChange, type }: InputItemProps) => { return (
- +
); }; diff --git a/src/components/login/Button.tsx b/src/components/login/Button.tsx index 7862b3e..cb2a6a7 100644 --- a/src/components/login/Button.tsx +++ b/src/components/login/Button.tsx @@ -1,6 +1,5 @@ /** @jsxImportSource @emotion/react */ import styled from "@emotion/styled"; -import { useNavigate } from "react-router-dom"; // navigate 훅 사용 const ButtonStyle = styled.button` cursor: pointer; @@ -15,12 +14,7 @@ const ButtonStyle = styled.button` margin-top: 30px; `; -const Button = () => { - const navigate = useNavigate(); - const handleContinueLogin = () => { - navigate("/home"); // 로그인 후 이동할 경로 - }; - return 로그인; +const Button = ({ handleLogin }: { handleLogin: () => void }) => { + return 로그인; }; - export default Button; diff --git a/src/components/login/GotoJoin.tsx b/src/components/login/GotoJoin.tsx new file mode 100644 index 0000000..9fea33a --- /dev/null +++ b/src/components/login/GotoJoin.tsx @@ -0,0 +1,36 @@ +/** @jsxImportSource @emotion/react */ +import styled from "@emotion/styled"; +import { useNavigate } from "react-router-dom"; + +const GotoJoinContainer = styled.div` + font-size: 16px; + color: gray; + display: flex; + justify-content: center; +`; + +const UnderlinedLink = styled.u` + color: gray; + cursor: pointer; + text-decoration: underline; + justify-content: center; + + &:hover { + color: black; + } +`; + +const GotoJoin = () => { + const navigate = useNavigate(); + const handleGotoJoin = () => { + navigate("/join"); // 로그인 후 이동할 경로 + }; + return ( + + 아직 계정이 없으신가요?   + 회원가입 + + ); +}; + +export default GotoJoin; diff --git a/src/components/login/Input.tsx b/src/components/login/Input.tsx index 5ced8da..b6a0792 100644 --- a/src/components/login/Input.tsx +++ b/src/components/login/Input.tsx @@ -2,14 +2,14 @@ /** @jsxImportSource @emotion/react */ import styled from "@emotion/styled"; import InputItem from "./InputItem"; -import { useState } from "react"; interface InputProps { id: string; setId: React.Dispatch>; pw: string; - setPw: React.Dispatch>; - handlePw?: (e: React.ChangeEvent) => void; + setPw?: React.Dispatch>; + handlePw: (e: React.ChangeEvent) => void; + pwValid: boolean; } const InputStyle = styled.div` @@ -29,20 +29,7 @@ const ErrorMessageStyle = styled.div` font-size: 12px; `; -const Input = ({ id, setId, pw, setPw }: InputProps) => { - const [pwValid, setPwValid] = useState(false); - - const handlePw = (e: React.ChangeEvent) => { - setPw(e.target.value); - const regex = - /^(?=.*[A-Za-z])(?=.*\d)(?=.*[!@#$%^&*])[A-Za-z\d!@#$%^&*]{8,}$/; - if (regex.test(pw)) { - setPwValid(true); - } else { - setPwValid(false); - } - }; - +const Input = ({ id, setId, pw, pwValid, handlePw }: InputProps) => { return ( diff --git a/src/components/pages/JoinPage.tsx b/src/components/pages/JoinPage.tsx index bedeb3d..aaf5f79 100644 --- a/src/components/pages/JoinPage.tsx +++ b/src/components/pages/JoinPage.tsx @@ -2,6 +2,8 @@ import Input from "../join/Input"; import Button from "../join/Button"; import styled from "@emotion/styled"; import GotoLogin from "../join/GotoLogin"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; const JoinContainerStyle = styled.div` display: flex; @@ -31,13 +33,63 @@ const JoinWperStyle = styled.div` `; const JoinPage = () => { + const [newId, setNewId] = useState(""); + const [newPw, setNewPw] = useState(""); + const [checkNewPw, setCheckNewPw] = useState(""); + const [newAlias, setNewAlias] = useState(""); + + const handleSignup = async () => { + const navigate = useNavigate(); + if (newPw !== checkNewPw) { + alert("비밀번호가 일치하지 않습니다."); + return; + } + const signupData = { + loginId: newId, + username: newAlias, + password: newPw, + }; + + try { + const response = await fetch( + "http://13.125.208.182:8080/v1/members/join", + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(signupData), + credentials: "include", + } + ); + if (response.ok) { + alert("회원가입에 성공했습니다!"); + navigate("/login"); + } else { + const errorData = await response.json(); + alert(`회원가입 실패: ${errorData.message}`); + console.log(`Error status : ${response.status}`); + } + } catch (error) { + console.log("회원가입 요청 중 오류 발생:", error); + alert("회원가입 요청 중 문제가 발생했습니다."); + } + }; + return ( <>

회원가입

- -