From bb6786785f2041423ce9b0a5e28a2d8db6c8f438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=91=ED=98=84?= Date: Thu, 31 Aug 2023 16:39:35 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[Feat]=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=201=EB=8B=A8=EA=B3=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/asset/images/GoogleLogo.svg | 2 + client/src/asset/images/KakaoLogo.svg | 21 +++ .../src/components/Headers/LogoutHeader.tsx | 9 +- client/src/components/Logins/EmailLogin.tsx | 115 +++++++++++++++ client/src/components/Logins/OAuthLogin.tsx | 137 ++++++++++++++++++ client/src/components/Signups/EmailSignup.tsx | 84 +++++++++++ client/src/page/MainPage.tsx | 49 ++++++- 7 files changed, 411 insertions(+), 6 deletions(-) create mode 100644 client/src/asset/images/GoogleLogo.svg create mode 100644 client/src/asset/images/KakaoLogo.svg create mode 100644 client/src/components/Logins/EmailLogin.tsx create mode 100644 client/src/components/Logins/OAuthLogin.tsx create mode 100644 client/src/components/Signups/EmailSignup.tsx diff --git a/client/src/asset/images/GoogleLogo.svg b/client/src/asset/images/GoogleLogo.svg new file mode 100644 index 00000000..3790851d --- /dev/null +++ b/client/src/asset/images/GoogleLogo.svg @@ -0,0 +1,2 @@ + + diff --git a/client/src/asset/images/KakaoLogo.svg b/client/src/asset/images/KakaoLogo.svg new file mode 100644 index 00000000..e5f5d11b --- /dev/null +++ b/client/src/asset/images/KakaoLogo.svg @@ -0,0 +1,21 @@ + +image/svg+xml diff --git a/client/src/components/Headers/LogoutHeader.tsx b/client/src/components/Headers/LogoutHeader.tsx index 04418fba..fe554e23 100644 --- a/client/src/components/Headers/LogoutHeader.tsx +++ b/client/src/components/Headers/LogoutHeader.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import styled from 'styled-components'; import StockHolmLogo from "../../asset/images/StockHolmLogo.png" -const LogoutHeader: React.FC = () => { +const LogoutHeader: React.FC = ({ onLoginClick })=> { const [searchValue, setSearchValue] = useState(''); const handleSearchChange = (event: React.ChangeEvent) => { @@ -16,13 +16,15 @@ const LogoutHeader: React.FC = () => { console.log("Logo clicked"); }; + + return ( - {loginText} + {loginText} ); }; @@ -78,5 +80,8 @@ const LoginButton = styled.button` background-color: #f2f2f2; // 호버 시 약간 어두운 흰색으로 변경 } `; +interface LogoutHeaderProps { + onLoginClick: () => void; +} export default LogoutHeader; diff --git a/client/src/components/Logins/EmailLogin.tsx b/client/src/components/Logins/EmailLogin.tsx new file mode 100644 index 00000000..d7fe5a26 --- /dev/null +++ b/client/src/components/Logins/EmailLogin.tsx @@ -0,0 +1,115 @@ +import styled from 'styled-components'; + +const EmailLoginModal = ({ onClose }: { onClose: () => void }) => { + // 문자열 변수 정의 + const titleText = "이메일로 로그인"; + const emailLabelText = "이메일"; + const passwordLabelText = "비밀번호"; + const findPasswordText = "비밀번호 찾기"; + const loginButtonText = "로그인"; + const noAccountText = "계정이 없습니까?"; + const registerButtonText = "회원가입하기"; + + return ( + + + × {/* 닫기 버튼 추가 */} + {titleText} + + + + + {findPasswordText} + {loginButtonText} + + {noAccountText} {registerButtonText} + + + + ); +}; + +export default EmailLoginModal; + +const ModalBackground = styled.div` + display: flex; + justify-content: center; + align-items: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); +`; + +const ModalContainer = styled.div` + background-color: white; + padding: 20px; + width: 400px; + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; +`; + +const CloseButton = styled.button` + position: absolute; + top: 10px; + right: 10px; + background: #FFFFFF; + border: 1px solid lightgray; + font-size: 1.5rem; + cursor: pointer; +`; + +const Title = styled.h2` + margin-bottom: 20px; + font-size: 1.6rem; // 크기를 줄입니다. + font-weight: 400; // 굵기를 줄입니다. +`; + +const Label = styled.label` + align-self: flex-start; + margin-top: 10px; +`; + +const Input = styled.input` + width: 100%; + padding: 10px; + margin-top: 5px; + border: 1px solid lightgray; + border-radius: 5px; +`; + +const RightAlignedButton = styled.button` + align-self: flex-end; + margin-top: 5px; + background: none; + border: none; + color: slategray; // 글자색을 변경합니다. + cursor: pointer; +`; + +const LoginButton = styled.button` + width: 100%; + padding: 10px; + margin-top: 10px; + background-color: darkslategray; // 배경색을 변경합니다. + color: white; + border: none; + border-radius: 5px; + cursor: pointer; +`; + +const BottomText = styled.div` + margin-top: 10px; + font-size: 0.9rem; // 크기를 줄입니다. +`; + +const RegisterButton = styled.button` + background: none; + border: none; + color: slategray; // 글자색을 변경합니다. + cursor: pointer; +`; \ No newline at end of file diff --git a/client/src/components/Logins/OAuthLogin.tsx b/client/src/components/Logins/OAuthLogin.tsx new file mode 100644 index 00000000..ec33e81b --- /dev/null +++ b/client/src/components/Logins/OAuthLogin.tsx @@ -0,0 +1,137 @@ +import styled from 'styled-components'; +import googleLogo from '../../asset/images/GoogleLogo.svg'; +import kakaoLogo from '../../asset/images/KakaoLogo.svg'; + + + +const OAuthLoginModal: React.FC = ({ onClose, onEmailLoginClick, onEmailSignupClick }) => { + const titleText = "로그인"; + const googleLoginText = "구글로 로그인"; + const kakaoLoginText = "카카오로 로그인"; + const orText = "또는"; + const emailLoginText = "이메일로 로그인"; + const emailSignupText = "이메일로 회원가입"; + + return ( + + + × + {titleText} + + + {googleLoginText} + + + + {kakaoLoginText} + + {orText} + + {emailLoginText} + {emailSignupText} + + + + ); +}; + +export default OAuthLoginModal; + +interface LoginModalProps { + onClose: () => void; + onEmailLoginClick: () => void; + onEmailSignupClick: () => void; // 추가 +} + +const OrText = styled.span` + margin: 20px 0; + color: grey; +`; + + +const Title = styled.h2` + margin-bottom: 20px; + font-size: 1.6rem; // 크기를 줄입니다. + font-weight: 400; // 굵기를 줄입니다. +`; + + +const ModalBackground = styled.div` + display: flex; + justify-content: center; + align-items: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); +`; + +const ModalContainer = styled.div` + background-color: white; + padding: 20px; + width: 400px; + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; +`; + +const CloseButton = styled.button` + position: absolute; + top: 10px; + right: 10px; + background: #FFFFFF; + border: 1px solid lightgray; + font-size: 1.5rem; + cursor: pointer; +`; + +const OAuthButton = styled.button` + margin: 10px 0; + padding: 10px 20px; + background-color: #FFFFFF; + border: 1px solid lightgray; + border-radius: 5px; + cursor: pointer; + width: 300px; // 버튼의 가로 너비를 동일하게 설정합니다. + display: flex; + align-items: center; + justify-content: center; +`; +const GoogleButton = styled(OAuthButton)` + display: flex; + align-items: center; + justify-content: center; +`; + +const KakaoButton = styled(OAuthButton)` + display: flex; + align-items: center; + justify-content: center; +`; + +const EmailButtonsContainer = styled.div` + display: flex; + justify-content: space-around; + width: 100%; + margin: 5px 0; +`; + + +const EmailButton = styled.button` + margin: 5px 0; + padding: 10px 20px; + background-color: #FFFFFF; + border: 1px solid lightgray; + border-radius: 5px; + cursor: pointer; +`; + + +const LogoImage = styled.img` + margin-right: 30px; + width: 60px; // 로고의 가로 크기를 조정합니다. 필요에 따라 값을 조절할 수 있습니다. + height: auto; // 가로 크기에 맞춰 세로 크기를 자동으로 조절합니다. +`; \ No newline at end of file diff --git a/client/src/components/Signups/EmailSignup.tsx b/client/src/components/Signups/EmailSignup.tsx new file mode 100644 index 00000000..0e34b9a3 --- /dev/null +++ b/client/src/components/Signups/EmailSignup.tsx @@ -0,0 +1,84 @@ +import styled from 'styled-components'; + +const EmailSignupModal = ({ onClose }: { onClose: () => void }) => { + // 문자열 변수 정의 + const titleText = "이메일로 회원가입"; + const emailLabelText = "이메일"; + const requestVerificationText = "이메일 인증요청"; + + return ( + + + × + {titleText} + + + {requestVerificationText} + + + ); +}; + +export default EmailSignupModal; + +const ModalBackground = styled.div` + display: flex; + justify-content: center; + align-items: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); +`; + +const ModalContainer = styled.div` + background-color: white; + padding: 20px; + width: 400px; + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; +`; + +const CloseButton = styled.button` + position: absolute; + top: 10px; + right: 10px; + background: #FFFFFF; + border: 1px solid lightgray; + font-size: 1.5rem; + cursor: pointer; +`; + +const Title = styled.h2` + margin-bottom: 20px; + font-size: 1.6rem; // 크기를 줄입니다. + font-weight: 400; // 굵기를 줄입니다. +`; + +const Label = styled.label` + align-self: flex-start; + margin-top: 10px; +`; + +const Input = styled.input` + width: 100%; + padding: 10px; + margin-top: 5px; + border: 1px solid lightgray; + border-radius: 5px; +`; + +const SignupButton = styled.button` + width: 100%; + padding: 10px; + margin-top: 10px; + background-color: darkslategray; // 배경색을 변경합니다. + color: white; + border: none; + border-radius: 5px; + cursor: pointer; +`; diff --git a/client/src/page/MainPage.tsx b/client/src/page/MainPage.tsx index cc799abc..42f0670d 100644 --- a/client/src/page/MainPage.tsx +++ b/client/src/page/MainPage.tsx @@ -1,17 +1,58 @@ -import { styled } from "styled-components"; -import LogoutHeader from "../components/Headers/LogoutHeader" -import LoginHeader from "../components/Headers/LoginHeader" +import { useState, useCallback } from 'react'; +import styled from "styled-components"; +import LogoutHeader from "../components/Headers/LogoutHeader"; +import LoginHeader from "../components/Headers/LoginHeader"; +import OAuthLoginModal from "../components/Logins/OAuthLogin"; +import EmailLoginModal from "../components/Logins/EmailLogin"; +import EmailSignupModal from "../components/Signups/EmailSignup"; const MainPage = () => { + const [isOAuthModalOpen, setOAuthModalOpen] = useState(false); + const [isEmailLoginModalOpen, setEmailLoginModalOpen] = useState(false); + const [isEmailSignupModalOpen, setEmailSignupModalOpen] = useState(false); + + const openOAuthModal = useCallback(() => { + setOAuthModalOpen(true); + }, []); + + const closeOAuthModal = useCallback(() => { + setOAuthModalOpen(false); + }, []); + + const openEmailLoginModal = useCallback(() => { + setOAuthModalOpen(false); + setEmailLoginModalOpen(true); + }, []); + + const closeEmailLoginModal = useCallback(() => { + setEmailLoginModalOpen(false); + }, []); + + const openEmailSignupModal = useCallback(() => { + setOAuthModalOpen(false); + setEmailSignupModalOpen(true); + }, []); + + const closeEmailSignupModal = useCallback(() => { + setEmailSignupModalOpen(false); + }, []); + return ( - +
+ {isOAuthModalOpen && } + {isEmailLoginModalOpen && } + {isEmailSignupModalOpen && }
); }; From 7b0034a2cfc5c7f636b5c01671fb6d438b35e5e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=91=ED=98=84?= Date: Fri, 1 Sep 2023 10:20:44 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84=20=EC=9D=B4?= =?UTF-8?q?=EB=A9=94=EC=9D=BC=20=EC=9D=B8=EC=A6=9D=ED=95=98=EA=B8=B0=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84=20=EB=B9=84?= =?UTF-8?q?=EB=B0=80=EB=B2=88=ED=98=B8=20=EC=84=A4=EC=A0=95=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?Issues=20#8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Signups/EmailCertify.tsx | 123 ++++++++++++++++++ client/src/components/Signups/EmailSignup.tsx | 25 ++-- client/src/components/Signups/Password.tsx | 93 +++++++++++++ client/src/page/MainPage.tsx | 43 +++++- 4 files changed, 275 insertions(+), 9 deletions(-) create mode 100644 client/src/components/Signups/EmailCertify.tsx create mode 100644 client/src/components/Signups/Password.tsx diff --git a/client/src/components/Signups/EmailCertify.tsx b/client/src/components/Signups/EmailCertify.tsx new file mode 100644 index 00000000..d3ff9a7e --- /dev/null +++ b/client/src/components/Signups/EmailCertify.tsx @@ -0,0 +1,123 @@ +import styled from 'styled-components'; + +const strings = { + titleText: "이메일 인증요청", + emailLabelText: "인증할 이메일", + codeLabelText: "인증코드", + nextStepText: "인증 후 다음단계", + codeHintText: "이메일로 전송된 코드를 입력하세요", + termsText: "개인정보 처리방침 및 서비스 이용약관에 동의합니다" + }; + + const EmailVerificationModal: React.FC = ({ onClose, onNextStep }) => { + return ( + + + × + {strings.titleText} + + + + + {strings.codeHintText} + + + + + + {strings.nextStepText} + + + + ); + }; + + +export default EmailVerificationModal; + +type EmailVerificationModalProps = { + onClose: () => void; + onNextStep: () => void; + }; + +const ModalBackground = styled.div` + display: flex; + justify-content: center; + align-items: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); +`; + +const ModalContainer = styled.div` + background-color: white; + padding: 20px; + width: 400px; + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; +`; + +const CloseButton = styled.button` + position: absolute; + top: 10px; + right: 10px; + background: #FFFFFF; + border: 1px solid lightgray; + font-size: 1.5rem; + cursor: pointer; +`; + +const Title = styled.h2` + margin-bottom: 20px; + font-size: 1.6rem; // 크기를 줄입니다. + font-weight: 400; // 굵기를 줄입니다. +`; + +const Label = styled.label` + align-self: flex-start; + margin-top: 10px; +`; + +const Input = styled.input` + width: 100%; + padding: 10px; + margin-top: 5px; + border: 1px solid lightgray; + border-radius: 5px; +`; + +const SignupButton = styled.button` + width: 100%; + padding: 10px; + margin-top: 10px; + background-color: darkslategray; // 배경색을 변경합니다. + color: white; + border: none; + border-radius: 5px; + cursor: pointer; +`; + +const HintText = styled.p` + color: red; + font-size: 0.8rem; + margin-top: 5px; +`; + +const TermsCheckbox = styled.div` + margin-top: 10px; + display: flex; + align-items: center; + + input[type="checkbox"] { + margin-right: 5px; + } + + label { + font-size: 0.9rem; + } +`; \ No newline at end of file diff --git a/client/src/components/Signups/EmailSignup.tsx b/client/src/components/Signups/EmailSignup.tsx index 0e34b9a3..24c136b0 100644 --- a/client/src/components/Signups/EmailSignup.tsx +++ b/client/src/components/Signups/EmailSignup.tsx @@ -1,19 +1,22 @@ import styled from 'styled-components'; -const EmailSignupModal = ({ onClose }: { onClose: () => void }) => { - // 문자열 변수 정의 - const titleText = "이메일로 회원가입"; - const emailLabelText = "이메일"; - const requestVerificationText = "이메일 인증요청"; +const strings = { + titleText: "이메일로 회원가입", + emailLabelText: "이메일", + requestVerificationText: "이메일 인증요청" +}; +const EmailSignupModal: React.FC = ({ onClose, onRequestVerification }) => { return ( × - {titleText} - + {strings.titleText} + - {requestVerificationText} + + {strings.requestVerificationText} + ); @@ -21,6 +24,12 @@ const EmailSignupModal = ({ onClose }: { onClose: () => void }) => { export default EmailSignupModal; + +type EmailSignupModalProps = { + onClose: () => void; + onRequestVerification: () => void; +}; + const ModalBackground = styled.div` display: flex; justify-content: center; diff --git a/client/src/components/Signups/Password.tsx b/client/src/components/Signups/Password.tsx new file mode 100644 index 00000000..1f7aad4f --- /dev/null +++ b/client/src/components/Signups/Password.tsx @@ -0,0 +1,93 @@ +import styled from 'styled-components'; + +const strings = { + titleText: "비밀번호 설정", + passwordLabelText: "비밀번호", + confirmPasswordLabelText: "비밀번호 확인", + nicknameLabelText: "닉네임", + confirmButtonText: "확인" + }; + + const PasswordSettingModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { + return ( + + + × + {strings.titleText} + + + + + + + {strings.confirmButtonText} + + + ); + }; + + export default PasswordSettingModal; + +const ModalBackground = styled.div` + display: flex; + justify-content: center; + align-items: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); +`; + +const ModalContainer = styled.div` + background-color: white; + padding: 20px; + width: 400px; + border-radius: 10px; + display: flex; + flex-direction: column; + align-items: center; +`; + +const Title = styled.h2` + margin-bottom: 20px; + font-size: 1.6rem; + font-weight: 400; +`; + + +const CloseButton = styled.button` + position: absolute; + top: 10px; + right: 10px; + background: #FFFFFF; + border: 1px solid lightgray; + font-size: 1.5rem; + cursor: pointer; +`; + +const Label = styled.label` + align-self: flex-start; + margin-top: 10px; +`; + +const Input = styled.input` + width: 100%; + padding: 10px; + margin-top: 5px; + border: 1px solid lightgray; + border-radius: 5px; +`; + + +const ConfirmButton = styled.button` + width: 100%; + padding: 10px; + margin-top: 10px; + background-color: darkslategray; + color: white; + border: none; + border-radius: 5px; + cursor: pointer; +`; \ No newline at end of file diff --git a/client/src/page/MainPage.tsx b/client/src/page/MainPage.tsx index 42f0670d..c3eb834a 100644 --- a/client/src/page/MainPage.tsx +++ b/client/src/page/MainPage.tsx @@ -5,6 +5,8 @@ import LoginHeader from "../components/Headers/LoginHeader"; import OAuthLoginModal from "../components/Logins/OAuthLogin"; import EmailLoginModal from "../components/Logins/EmailLogin"; import EmailSignupModal from "../components/Signups/EmailSignup"; +import EmailVerificationModal from '../components/Signups/EmailCertify'; +import PasswordSettingModal from '../components/Signups/Password'; const MainPage = () => { const [isOAuthModalOpen, setOAuthModalOpen] = useState(false); @@ -37,6 +39,28 @@ const MainPage = () => { setEmailSignupModalOpen(false); }, []); + const [isEmailVerificationModalOpen, setEmailVerificationModalOpen] = useState(false); + + const openEmailVerificationModal = useCallback(() => { + setEmailSignupModalOpen(false); // 이메일 회원가입 모달 닫기 + setEmailVerificationModalOpen(true); // 이메일 인증 모달 열기 + }, []); + + const closeEmailVerificationModal = useCallback(() => { + setEmailVerificationModalOpen(false); + }, []); + + const [isPasswordSettingModalOpen, setPasswordSettingModalOpen] = useState(false); + + const openPasswordSettingModal = useCallback(() => { + setEmailVerificationModalOpen(false); // 이메일 인증 모달 닫기 + setPasswordSettingModalOpen(true); // 비밀번호 설정 모달 열기 + }, []); + + const closePasswordSettingModal = useCallback(() => { + setPasswordSettingModalOpen(false); + }, []); + return ( @@ -52,7 +76,24 @@ const MainPage = () => { onEmailSignupClick={openEmailSignupModal} />} {isEmailLoginModalOpen && } - {isEmailSignupModalOpen && } + + {isEmailSignupModalOpen && + + } + + {isEmailVerificationModalOpen && + + } + + {isPasswordSettingModalOpen && + + } ); }; From 4b7452753dc787f5454557097ea84087064a5793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=91=ED=98=84?= Date: Fri, 1 Sep 2023 10:46:11 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[Feat]=20=EB=A1=9C=EA=B7=B8=EC=9D=B8,?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85,=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=B3=80?= =?UTF-8?q?=ED=99=98=20=EB=AA=A8=EB=8B=AC=EC=9D=98=20=EB=8B=AB=EA=B8=B0=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=EC=9D=84=20=EB=AA=A8=EB=8B=AC=EC=B0=BD=20?= =?UTF-8?q?=EC=95=88=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=ED=81=B4=EB=A6=AD=EC=8B=9C=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=EB=B6=80=ED=84=B0=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=ED=9B=84=20=EB=A1=9C=EA=B7=B8=EC=95=84=EC=9B=83?= =?UTF-8?q?=ED=95=A0=20=EB=95=8C=EA=B9=8C=EC=A7=80=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=9D=B4=EB=8F=99=20=EA=B5=AC=ED=98=84=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=97=AC=EB=B6=80=EB=A5=BC=20=ED=8C=90?= =?UTF-8?q?=EB=8B=A8=ED=95=98=EC=97=AC=20=ED=97=A4=EB=8D=94=EB=A5=BC=20?= =?UTF-8?q?=EA=B5=90=EC=B2=B4=20Issues#8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Headers/LoginHeader.tsx | 11 ++++++++--- client/src/components/Logins/EmailLogin.tsx | 1 + client/src/components/Logins/OAuthLogin.tsx | 1 + .../src/components/Signups/EmailCertify.tsx | 1 + client/src/components/Signups/EmailSignup.tsx | 1 + client/src/components/Signups/Password.tsx | 7 ++++++- client/src/page/MainPage.tsx | 19 ++++++++++++++++--- 7 files changed, 34 insertions(+), 7 deletions(-) diff --git a/client/src/components/Headers/LoginHeader.tsx b/client/src/components/Headers/LoginHeader.tsx index af416b2e..4ddd3947 100644 --- a/client/src/components/Headers/LoginHeader.tsx +++ b/client/src/components/Headers/LoginHeader.tsx @@ -4,7 +4,7 @@ import StockHolmLogo from "../../asset/images/StockHolmLogo.png"; import SampleProfile from "../../asset/images/ProfileSample.png"; import AlarmImage from "../../asset/images/alarm.png"; -const LoginHeader: React.FC = () => { +const LoginHeader: React.FC = ({ onLogoutClick }) => { const [searchValue, setSearchValue] = useState(''); const handleSearchChange = (event: React.ChangeEvent) => { @@ -30,12 +30,18 @@ const LoginHeader: React.FC = () => { - {logoutText} + {logoutText} {/* 로그아웃 버튼 클릭 시 onLogoutClick 실행 */} ); }; +export default LoginHeader; + +interface LoginHeaderProps { + onLogoutClick: () => void; // 로그아웃 클릭 핸들러 타입 정의 +} + const HeaderContainer = styled.div` display: flex; justify-content: space-between; @@ -124,4 +130,3 @@ const LogoutButton = styled.button` -export default LoginHeader; diff --git a/client/src/components/Logins/EmailLogin.tsx b/client/src/components/Logins/EmailLogin.tsx index d7fe5a26..dae78f03 100644 --- a/client/src/components/Logins/EmailLogin.tsx +++ b/client/src/components/Logins/EmailLogin.tsx @@ -44,6 +44,7 @@ const ModalBackground = styled.div` `; const ModalContainer = styled.div` + position: relative; background-color: white; padding: 20px; width: 400px; diff --git a/client/src/components/Logins/OAuthLogin.tsx b/client/src/components/Logins/OAuthLogin.tsx index ec33e81b..e1deb4d0 100644 --- a/client/src/components/Logins/OAuthLogin.tsx +++ b/client/src/components/Logins/OAuthLogin.tsx @@ -69,6 +69,7 @@ const ModalBackground = styled.div` `; const ModalContainer = styled.div` + position: relative; background-color: white; padding: 20px; width: 400px; diff --git a/client/src/components/Signups/EmailCertify.tsx b/client/src/components/Signups/EmailCertify.tsx index d3ff9a7e..54a6cc78 100644 --- a/client/src/components/Signups/EmailCertify.tsx +++ b/client/src/components/Signups/EmailCertify.tsx @@ -53,6 +53,7 @@ const ModalBackground = styled.div` `; const ModalContainer = styled.div` + position: relative; background-color: white; padding: 20px; width: 400px; diff --git a/client/src/components/Signups/EmailSignup.tsx b/client/src/components/Signups/EmailSignup.tsx index 24c136b0..b210705a 100644 --- a/client/src/components/Signups/EmailSignup.tsx +++ b/client/src/components/Signups/EmailSignup.tsx @@ -43,6 +43,7 @@ const ModalBackground = styled.div` `; const ModalContainer = styled.div` + position: relative; background-color: white; padding: 20px; width: 400px; diff --git a/client/src/components/Signups/Password.tsx b/client/src/components/Signups/Password.tsx index 1f7aad4f..3504804f 100644 --- a/client/src/components/Signups/Password.tsx +++ b/client/src/components/Signups/Password.tsx @@ -9,6 +9,10 @@ const strings = { }; const PasswordSettingModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { + const handleConfirmClick = () => { + console.log("Confirm button clicked!"); // 로그 추가 + onClose(); // 모달을 닫습니다. + }; return ( @@ -20,7 +24,7 @@ const strings = { - {strings.confirmButtonText} + {strings.confirmButtonText} ); @@ -41,6 +45,7 @@ const ModalBackground = styled.div` `; const ModalContainer = styled.div` + position: relative; background-color: white; padding: 20px; width: 400px; diff --git a/client/src/page/MainPage.tsx b/client/src/page/MainPage.tsx index c3eb834a..f726d6e3 100644 --- a/client/src/page/MainPage.tsx +++ b/client/src/page/MainPage.tsx @@ -61,10 +61,22 @@ const MainPage = () => { setPasswordSettingModalOpen(false); }, []); + const [isLoggedIn, setIsLoggedIn] = useState(false); // 로그인 상태 관리 + + const handleLogin = () => { + setIsLoggedIn(true); + }; + + const handleLogout = () => { + setIsLoggedIn(false); + }; + return ( - - + {isLoggedIn ? + : // 로그아웃 버튼 클릭 핸들러 추가 + + }
@@ -92,8 +104,9 @@ const MainPage = () => { } {isPasswordSettingModalOpen && - + { handleLogin(); closePasswordSettingModal(); }} /> } + ); }; From 0490b6b028dca6b84e0cef9b2fbb1e93f5fdbfd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=91=ED=98=84?= Date: Fri, 1 Sep 2023 11:37:22 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[Feat]=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20=EB=B0=B1=EC=97=94?= =?UTF-8?q?=EB=93=9C=EB=A1=9C=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=84?= =?UTF-8?q?=EC=86=A1=20axios=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC?= =?UTF-8?q?=EB=A6=AC=20=EC=84=A4=EC=B9=98=20=EB=B0=B1=EC=97=94=EB=93=9C=20?= =?UTF-8?q?=EB=A1=9C=EC=BB=AC=20=EC=A3=BC=EC=86=8C=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=A9=94=EC=9D=BC,=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8,=20?= =?UTF-8?q?=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20=ED=99=95=EC=9D=B8,=20?= =?UTF-8?q?=EB=8B=89=EB=84=A4=EC=9E=84,=20=EC=9D=B8=EC=A6=9D=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=A0=84=EC=86=A1=20=EA=B5=AC=EA=B8=80,=EC=B9=B4?= =?UTF-8?q?=EC=B9=B4=EC=98=A4=20OAuth=20=EC=9A=94=EC=B2=AD=20Issues#8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/package-lock.json | 91 +++++++++++++++++++ client/package.json | 1 + client/src/components/Logins/EmailLogin.tsx | 37 +++++++- client/src/components/Logins/OAuthLogin.tsx | 37 +++++++- .../src/components/Signups/EmailCertify.tsx | 75 ++++++++++----- client/src/components/Signups/EmailSignup.tsx | 25 ++++- client/src/components/Signups/Password.tsx | 67 ++++++++++---- client/src/page/MainPage.tsx | 7 +- 8 files changed, 288 insertions(+), 52 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 4a719d1c..3e42972c 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -8,6 +8,7 @@ "name": "vite-project", "version": "0.0.0", "dependencies": { + "axios": "^1.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", "styled-components": "^6.0.7" @@ -2833,6 +2834,21 @@ "node": ">=8" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", @@ -3052,6 +3068,17 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -3141,6 +3168,14 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -3608,6 +3643,38 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs-readdir-recursive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", @@ -3990,6 +4057,25 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4216,6 +4302,11 @@ "node": ">= 0.8.0" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", diff --git a/client/package.json b/client/package.json index 7745298f..4c717370 100644 --- a/client/package.json +++ b/client/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "axios": "^1.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", "styled-components": "^6.0.7" diff --git a/client/src/components/Logins/EmailLogin.tsx b/client/src/components/Logins/EmailLogin.tsx index dae78f03..02cae2ea 100644 --- a/client/src/components/Logins/EmailLogin.tsx +++ b/client/src/components/Logins/EmailLogin.tsx @@ -1,6 +1,8 @@ +import axios from 'axios'; import styled from 'styled-components'; +import React, { useState } from 'react'; -const EmailLoginModal = ({ onClose }: { onClose: () => void }) => { +const EmailLoginModal = ({ onClose, onLogin }: { onClose: () => void, onLogin: () => void }) => { // 문자열 변수 정의 const titleText = "이메일로 로그인"; const emailLabelText = "이메일"; @@ -10,17 +12,42 @@ const EmailLoginModal = ({ onClose }: { onClose: () => void }) => { const noAccountText = "계정이 없습니까?"; const registerButtonText = "회원가입하기"; + const [email, setEmail] = useState(''); // 입력된 이메일 상태 + const [password, setPassword] = useState(''); // 입력된 비밀번호 상태 + + const handleEmailChange = (event: React.ChangeEvent) => { + setEmail(event.target.value); + }; + + const handlePasswordChange = (event: React.ChangeEvent) => { + setPassword(event.target.value); + }; + + const handleLoginClick = async () => { + try { + const response = await axios.post('http://localhost:8080/login', { email, password }); + if (response.status === 200) { + onLogin(); + onClose(); + } else { + console.error('Error during login'); + } + } catch (error) { + console.error('Error during login:', error); + } + }; + return ( - × {/* 닫기 버튼 추가 */} + × {titleText} - + - + {findPasswordText} - {loginButtonText} + {loginButtonText} {noAccountText} {registerButtonText} diff --git a/client/src/components/Logins/OAuthLogin.tsx b/client/src/components/Logins/OAuthLogin.tsx index e1deb4d0..665385ee 100644 --- a/client/src/components/Logins/OAuthLogin.tsx +++ b/client/src/components/Logins/OAuthLogin.tsx @@ -1,6 +1,7 @@ import styled from 'styled-components'; import googleLogo from '../../asset/images/GoogleLogo.svg'; import kakaoLogo from '../../asset/images/KakaoLogo.svg'; +import axios from 'axios'; @@ -12,16 +13,48 @@ const OAuthLoginModal: React.FC = ({ onClose, onEmailLoginClick const emailLoginText = "이메일로 로그인"; const emailSignupText = "이메일로 회원가입"; + + const handleGoogleLogin = async () => { + try { + const response = await axios.post('http://localhost:8080/auth/google'); + if (response.status === 200) { + // 로그인 처리 + console.log("Successfully logged in with Google!"); + onClose(); + } else { + console.error("Error logging in with Google"); + } + } catch (error) { + console.error("Error logging in with Google:", error); + } + }; + + const handleKakaoLogin = async () => { + try { + const response = await axios.post('http://localhost:8080/auth/kakao'); + if (response.status === 200) { + // 로그인 처리 + console.log("Successfully logged in with Kakao!"); + onClose(); + } else { + console.error("Error logging in with Kakao"); + } + } catch (error) { + console.error("Error logging in with Kakao:", error); + } + }; + return ( × {titleText} - + {googleLoginText} - + + {kakaoLoginText} diff --git a/client/src/components/Signups/EmailCertify.tsx b/client/src/components/Signups/EmailCertify.tsx index 54a6cc78..722cd87d 100644 --- a/client/src/components/Signups/EmailCertify.tsx +++ b/client/src/components/Signups/EmailCertify.tsx @@ -1,3 +1,5 @@ +import axios from 'axios'; +import React, { useState } from 'react'; import styled from 'styled-components'; const strings = { @@ -7,38 +9,61 @@ const strings = { nextStepText: "인증 후 다음단계", codeHintText: "이메일로 전송된 코드를 입력하세요", termsText: "개인정보 처리방침 및 서비스 이용약관에 동의합니다" - }; - - const EmailVerificationModal: React.FC = ({ onClose, onNextStep }) => { +}; + +const EmailVerificationModal: React.FC = ({ onClose, onNextStep }) => { + const [email, setEmail] = useState('sample@example.com'); // 이메일 상태 + const [verificationCode, setVerificationCode] = useState(''); // 인증코드 상태 + + const handleEmailChange = (event: React.ChangeEvent) => { + setEmail(event.target.value); + }; + + const handleVerificationCodeChange = (event: React.ChangeEvent) => { + setVerificationCode(event.target.value); + }; + + const handleNextStepClick = async () => { + try { + const response = await axios.post('http://localhost:8080/email/confirm', { email, code: verificationCode }); + if (response.status === 200) { + onNextStep(); + } else { + console.error('Error during email confirmation'); + } + } catch (error) { + console.error('Error during email confirmation:', error); + } + }; + return ( - - - × - {strings.titleText} - - - - - {strings.codeHintText} - - - - - - {strings.nextStepText} - - - + + + × + {strings.titleText} + + + + + {strings.codeHintText} + + + + + + {strings.nextStepText} + + + ); - }; - +}; export default EmailVerificationModal; type EmailVerificationModalProps = { onClose: () => void; onNextStep: () => void; - }; +}; const ModalBackground = styled.div` display: flex; @@ -53,7 +78,7 @@ const ModalBackground = styled.div` `; const ModalContainer = styled.div` - position: relative; +position: relative; background-color: white; padding: 20px; width: 400px; diff --git a/client/src/components/Signups/EmailSignup.tsx b/client/src/components/Signups/EmailSignup.tsx index b210705a..c5483f73 100644 --- a/client/src/components/Signups/EmailSignup.tsx +++ b/client/src/components/Signups/EmailSignup.tsx @@ -1,4 +1,6 @@ +import axios from 'axios'; import styled from 'styled-components'; +import React, { useState } from 'react'; const strings = { titleText: "이메일로 회원가입", @@ -7,14 +9,33 @@ const strings = { }; const EmailSignupModal: React.FC = ({ onClose, onRequestVerification }) => { + const [email, setEmail] = useState(''); // 입력된 이메일을 관리하는 상태 + + const handleEmailChange = (event: React.ChangeEvent) => { + setEmail(event.target.value); + }; + + const handleVerificationRequest = async () => { + try { + const response = await axios.post('http://localhost:8080/email/send', { email }); + if (response.status === 200) { + onRequestVerification(); + } else { + console.error('Error sending verification email'); + } + } catch (error) { + console.error('Error sending verification email:', error); + } + }; + return ( × {strings.titleText} - - + + {strings.requestVerificationText} diff --git a/client/src/components/Signups/Password.tsx b/client/src/components/Signups/Password.tsx index 3504804f..1a135960 100644 --- a/client/src/components/Signups/Password.tsx +++ b/client/src/components/Signups/Password.tsx @@ -1,3 +1,5 @@ +import axios from 'axios'; +import React, { useState } from 'react'; import styled from 'styled-components'; const strings = { @@ -9,26 +11,57 @@ const strings = { }; const PasswordSettingModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { - const handleConfirmClick = () => { - console.log("Confirm button clicked!"); // 로그 추가 - onClose(); // 모달을 닫습니다. + const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [nickname, setNickname] = useState(''); + + const handlePasswordChange = (e: React.ChangeEvent) => { + setPassword(e.target.value); + }; + + const handleConfirmPasswordChange = (e: React.ChangeEvent) => { + setConfirmPassword(e.target.value); + }; + + const handleNicknameChange = (e: React.ChangeEvent) => { + setNickname(e.target.value); }; + + const handleConfirmClick = async () => { + try { + const response = await axios.post('http://localhost:8080/members', { + password, + confirmPassword, + nickname + }); + + if (response.status === 200) { + console.log('Data sent successfully'); + onClose(); + } else { + console.error('Error sending data'); + } + } catch (error) { + console.error('Error sending data:', error); + } + }; + return ( - - - × - {strings.titleText} - - - - - - - {strings.confirmButtonText} - - + + + × + {strings.titleText} + + + + + + + {strings.confirmButtonText} + + ); - }; +}; export default PasswordSettingModal; diff --git a/client/src/page/MainPage.tsx b/client/src/page/MainPage.tsx index f726d6e3..65d20768 100644 --- a/client/src/page/MainPage.tsx +++ b/client/src/page/MainPage.tsx @@ -87,7 +87,12 @@ const MainPage = () => { onEmailLoginClick={openEmailLoginModal} onEmailSignupClick={openEmailSignupModal} />} - {isEmailLoginModalOpen && } + {isEmailLoginModalOpen && + + } {isEmailSignupModalOpen &&