Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat]회원가입 로그인 develop #115

Merged
merged 5 commits into from
Sep 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 36 additions & 50 deletions client/src/components/EntireList/EntireList.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import Header from './Header';
import StockItem from './StockItem';
import useCompanyData from '../../hooks/useCompanyData';
import { useGetCash } from '../../hooks/useCash'; // 훅 가져오기
import React, { useState } from "react";
import styled from "styled-components";
import Header from "./Header";
import StockItem from "./StockItem";
import useCompanyData from "../../hooks/useCompanyData";
import { useGetCash } from "../../hooks/useCash"; // 훅 가져오기

const EntireList: React.FC<EntireListProps> = ({ currentListType, onChangeListType }) => {
const [isMenuOpen, setMenuOpen] = useState(false);
Expand All @@ -15,88 +15,74 @@ const EntireList: React.FC<EntireListProps> = ({ currentListType, onChangeListTy
// 'companies'가 'undefined'인 경우를 처리하기 위해 빈 배열로 초기화
const companiesList = companies || [];

// 현금 보유량 가져오기
const moneyId = localStorage.getItem('moneyId');
const { data: cashData } = useGetCash(moneyId);
const holdingsAmount = cashData?.data?.money || "0";
// 현금 보유량 가져오기
const moneyId = localStorage.getItem("moneyId");
const { data: cashData } = useGetCash(moneyId);
const holdingsAmount = cashData?.data?.money || "0";

return (
<WatchListContainer>
<Header
currentListType={currentListType}
onChangeListType={onChangeListType}
isMenuOpen={isMenuOpen}
setMenuOpen={setMenuOpen}
/>
<Header currentListType={currentListType} onChangeListType={onChangeListType} isMenuOpen={isMenuOpen} setMenuOpen={setMenuOpen} />
<Divider1 />
<HoldingsAmount>현금 보유량: {holdingsAmount}원</HoldingsAmount> {/* 현금 보유량 표시 */}
<Divider2 />
<StockList>
{isLoading ? (
<div>Loading...</div>
) : isError ? (
<div>Error fetching data</div>
) : (
companiesList.map((company) => (
<StockItem
key={company.companyId}
company={company}
setShowChangePrice={setShowChangePrice}
showChangePrice={showChangePrice}
/>
))
)}
{isLoading ? <div>Loading...</div> : isError ? <div>Error fetching data</div> : companiesList.map((company) => <StockItem key={company.companyId} company={company} setShowChangePrice={setShowChangePrice} showChangePrice={showChangePrice} />)}
</StockList>
</WatchListContainer>
);
};

// Props와 상태에 대한 타입 정의
type EntireListProps = {
currentListType: '전체종목' | '관심종목' | '보유종목';
onChangeListType: (type: '전체종목' | '관심종목' | '보유종목') => void;
currentListType: "전체종목" | "관심종목" | "보유종목";
onChangeListType: (type: "전체종목" | "관심종목" | "보유종목") => void;
};

// WatchList 컴포넌트에 대한 스타일드 컴포넌트 정의
const WatchListContainer = styled.div`
height: calc(100vh - 53px);
display: flex;
flex-direction: column;
align-items: flex-start;
`;

const Divider1 = styled.div`
margin:0px;
padding:0px;
width: 100%;
height: 10px;
display: flex;
flex-direction: row;
border-bottom: 1px solid #2f4f4f;
margin: 0px;
padding: 0px;
width: 100%;
height: 10px;
display: flex;
flex-direction: row;
border-bottom: 1px solid #2f4f4f;
`;

const HoldingsAmount = styled.div`
font-size: 16px;
font-weight: bold;
margin: 8px 12px ;
margin: 8px 12px;
text-align: center;
color: darkslategray // 현금 보유량을 파란색으로 표시
color: darkslategray; // 현금 보유량을 파란색으로 표시
`;


const Divider2 = styled.div`
margin:0px;
padding:0px;
width: 100%;
height: 4.5px;
display: flex;
flex-direction: row;
border-bottom: 1px solid #2f4f4f;
margin: 0px;
padding: 0px;
width: 100%;
height: 4.5px;
display: flex;
flex-direction: row;
border-bottom: 1px solid #2f4f4f;
`;

const StockList = styled.div`
width: 100%;
max-height: 740px; /* 스크롤이 발생할 최대 높이를 지정하세요 */
height: 100%;
overflow-y: auto; /* 세로 스크롤을 활성화합니다 */

&::-webkit-scrollbar {
display: none;
}
`;

export default EntireList;
40 changes: 21 additions & 19 deletions client/src/components/Logins/EmailLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import React, { useState } from "react";
import { setLoginState } from "../../reducer/member/loginSlice";
import { useDispatch } from "react-redux";

// 이메일 로그인 모달 컴포넌트
const EmailLoginModal: React.FC<EmailLoginModalProps> = ({ onClose, onLogin }) => {
// 상수 문자열 정의
const titleText = "이메일로 로그인";
const emailLabelText = "이메일";
const passwordLabelText = "비밀번호";
Expand All @@ -15,55 +13,51 @@ const EmailLoginModal: React.FC<EmailLoginModalProps> = ({ onClose, onLogin }) =
const noAccountText = "계정이 없습니까?";
const registerButtonText = "회원가입하기";

//디스패치 함수 가져오기
const dispatch = useDispatch();

// 상태 변수 정의
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [generalError, setGeneralError] = useState<string | null>(null);

// 이메일 변경 핸들러
const handleEmailChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setEmail(event.target.value);
};

// 비밀번호 변경 핸들러
const handlePasswordChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setPassword(event.target.value);
};

// 로그인 버튼 클릭 핸들러
const handleLoginClick = async () => {
try {
const response = await axios.post("http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com:8080/members/login", {
email,
password,
});
const response = await axios.post(
"http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com:8080/members/login",
{ email, password },
{ validateStatus: (status) => status >= 200 && status < 600 }
);

if (response.status === 200) {
const accessToken = response.headers["authorization"];
console.log(accessToken);

const refreshToken = response.headers["refresh"];

// 로그인 상태로 만들기
dispatch(setLoginState());

// 토큰들을 로컬 스토리지에 저장
if (accessToken) localStorage.setItem("accessToken", accessToken);
if (refreshToken) localStorage.setItem("refreshToken", refreshToken);

onLogin();
onClose();
} else {
console.error("로그인 중 오류 발생");
setGeneralError(response.data.message || JSON.stringify(response.data));
}
} catch (error) {
console.error("로그인 중 오류:", error);
if (axios.isAxiosError(error) && error.response) {
setGeneralError(error.response.data.message || JSON.stringify(error.response.data));
} else {
console.error("로그인 중 오류:", error);
}
}
};

return (
// 모달 레이아웃
<ModalBackground>
<ModalContainer>
<CloseButton onClick={onClose}>&times;</CloseButton>
Expand All @@ -72,6 +66,7 @@ const EmailLoginModal: React.FC<EmailLoginModalProps> = ({ onClose, onLogin }) =
<Input type="email" placeholder="이메일을 입력하세요" value={email} onChange={handleEmailChange} />
<Label>{passwordLabelText}</Label>
<Input type="password" placeholder="비밀번호를 입력하세요" value={password} onChange={handlePasswordChange} />
{generalError && <ErrorMessage>{generalError}</ErrorMessage>}
<RightAlignedButton>{findPasswordText}</RightAlignedButton>
<LoginButton onClick={handleLoginClick}>{loginButtonText}</LoginButton>
<BottomText>
Expand Down Expand Up @@ -104,6 +99,7 @@ const ModalBackground = styled.div`
`;

const ModalContainer = styled.div`
z-index:4000;
position: relative;
background-color: white;
padding: 20px;
Expand Down Expand Up @@ -174,3 +170,9 @@ const RegisterButton = styled.button`
color: slategray;
cursor: pointer;
`;
const ErrorMessage = styled.p`
color: red;
margin-top: 5px;
margin-bottom: 10px;
font-size: 0.8rem;
`;
38 changes: 33 additions & 5 deletions client/src/components/Logins/GoogleLoginButton.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,49 @@
// GoogleLoginButton.tsx

import React from 'react';
import styled from 'styled-components';
import { useDispatch } from 'react-redux';
import { setLoginState } from '../../reducer/member/loginSlice';
import googleLogo from '../../asset/images/GoogleLogo.svg';

interface Props {
backendURL: string;
}

const GoogleLoginButton: React.FC<Props> = ({ backendURL }) => {
const dispatch = useDispatch();

const buttonText = "Login with Google";

const handleLoginClick = () => {
window.location.href = `${backendURL}`;
dispatch(setLoginState()); // 로그인 상태를 변경합니다.
};

return (
<button onClick={handleLoginClick}>
Login with Google
</button>
<GoogleButton onClick={handleLoginClick}>
<LogoImage src={googleLogo} alt="Google Logo" />
{buttonText}
</GoogleButton>
);
}

// Styled Components
const GoogleButton = 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 LogoImage = styled.img`
margin-right: 30px;
width: 60px;
height: auto;
`;

export default GoogleLoginButton;
36 changes: 33 additions & 3 deletions client/src/components/Logins/KakaoLoginButton.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,51 @@
// KakaoLoginButton.tsx

import React from 'react';
import styled from 'styled-components';
import { useDispatch } from 'react-redux';
import { setLoginState } from '../../reducer/member/loginSlice';
import kakaoLogo from '../../asset/images/KakaoLogo.svg';

interface Props {
backendURL: string;
}

const KakaoLoginButton: React.FC<Props> = ({ backendURL }) => {
const dispatch = useDispatch();

const buttonText = "Login with Kakao";

const handleLoginClick = () => {
window.location.href = `${backendURL}`;
dispatch(setLoginState()); // 로그인 상태를 변경합니다.
};

return (
<button onClick={handleLoginClick}>
Login with Kakao
</button>
<KakaoButton onClick={handleLoginClick}>
<LogoImage src={kakaoLogo} alt="Kakao Logo" />
{buttonText}
</KakaoButton>
);
}

// Styled Components
const KakaoButton = 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 LogoImage = styled.img`
margin-right: 30px;
width: 60px;
height: auto;
`;

export default KakaoLoginButton;
6 changes: 4 additions & 2 deletions client/src/components/Logins/LoginConfirmatationModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import styled from 'styled-components';

import TokenHandler from './TokenHandler';

const LoginConfirmationModal: React.FC<LoginConfirmationProps> = ({ onClose }) => {
const messageText = "로그인이 성공적으로 완료되었습니다!";
Expand All @@ -9,7 +9,8 @@ const LoginConfirmationModal: React.FC<LoginConfirmationProps> = ({ onClose }) =
return (
<ModalBackground>
<ModalContainer>
<Message>{messageText}</Message>
<TokenHandler />
<Message>{messageText}</Message>
<ConfirmButton onClick={onClose}>{confirmText}</ConfirmButton>
</ModalContainer>
</ModalBackground>
Expand All @@ -36,6 +37,7 @@ const ModalBackground = styled.div`
`;

const ModalContainer = styled.div`
z-index:4000;
position: relative;
background-color: white;
padding: 20px;
Expand Down
Loading