Skip to content

Commit

Permalink
Merge pull request #115 from codestates-seb/dev-client#19/watchList
Browse files Browse the repository at this point in the history
[Feat]회원가입 로그인 develop
  • Loading branch information
sirloinbh authored Sep 16, 2023
2 parents 0fe0f3a + ee6e6f1 commit e04e570
Show file tree
Hide file tree
Showing 15 changed files with 359 additions and 204 deletions.
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

0 comments on commit e04e570

Please sign in to comment.