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

[FE] 로그인 문제 오류 해결Dev client#19/watch list #113

Merged
merged 7 commits into from
Sep 15, 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
96 changes: 96 additions & 0 deletions client/src/components/EntireList/EntireList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import Header from './Header';
import StockItem from './StockItem';
import useCompanyData from '../../hooks/useCompanyData';

const EntireList: React.FC<EntireListProps> = ({ currentListType, onChangeListType }) => {
const [isMenuOpen, setMenuOpen] = useState(false);
const [showChangePrice, setShowChangePrice] = useState(false);

// useCompanyData 훅 사용하여 데이터 가져오기
const { data: companies, isLoading, isError } = useCompanyData(1, 14);

// 'companies'가 'undefined'인 경우를 처리하기 위해 빈 배열로 초기화
const companiesList = companies || [];

return (
<WatchListContainer>
<Header
currentListType={currentListType}
onChangeListType={onChangeListType}
isMenuOpen={isMenuOpen}
setMenuOpen={setMenuOpen}
/>
<Divider1 />
<EvaluationProfit>평가 수익금: +5,000,000원</EvaluationProfit> {/* 임의의 평가 수익금 */}
<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}
/>
))
)}
</StockList>
</WatchListContainer>
);
};

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

// WatchList 컴포넌트에 대한 스타일드 컴포넌트 정의
const WatchListContainer = styled.div`
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;
`;

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



const EvaluationProfit = styled.div`
font-size: 16px;
font-weight: bold;
margin: 8px 0;
text-align: center;
color: red; // 수익금이 플러스일 경우 초록색으로 표시
`;
const StockList = styled.div`
width: 100%;
max-height: 740px; /* 스크롤이 발생할 최대 높이를 지정하세요 */
overflow-y: auto; /* 세로 스크롤을 활성화합니다 */
`;

export default EntireList;
76 changes: 76 additions & 0 deletions client/src/components/EntireList/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from 'react';
import styled from 'styled-components';
import Menu_icon from "../../asset/images/menu.png";

const ALL_LIST = "전체종목";
const INTEREST_LIST = "관심종목";
const HOLDING_LIST = "보유종목";

const Header: React.FC<HeaderProps> = ({ currentListType, onChangeListType, isMenuOpen, setMenuOpen }) => {
return (
<HeaderWrapper>
<Icon
src={Menu_icon}
alt="menu icon"
onClick={() => setMenuOpen(!isMenuOpen)}
/>
<HeaderText>{currentListType}</HeaderText>
{isMenuOpen && (
<SlideMenu>
<MenuItem onClick={() => { onChangeListType(ALL_LIST); setMenuOpen(false); }}>{ALL_LIST}</MenuItem>
<MenuItem onClick={() => { onChangeListType(INTEREST_LIST); setMenuOpen(false); }}>{INTEREST_LIST}</MenuItem>
<MenuItem onClick={() => { onChangeListType(HOLDING_LIST); setMenuOpen(false); }}>{HOLDING_LIST}</MenuItem>
</SlideMenu>
)}
</HeaderWrapper>
);
};

type HeaderProps = {
currentListType: string;
onChangeListType: (type: "전체종목" | "관심종목" | "보유종목") => void;
isMenuOpen: boolean;
setMenuOpen: React.Dispatch<React.SetStateAction<boolean>>;
};


const HeaderWrapper = styled.div`
display: flex;
align-items: center;
position: relative;
`;

const Icon = styled.img`
margin-top: 9.5px;
margin-left: 10px;
width: 24px;
height: 24px;
cursor: pointer;
margin-right: 10px;
`;

const HeaderText = styled.span`
margin-top: 9.5px;
font-size: 18px;
`;

const SlideMenu = styled.div`
position: absolute;
top: 100%;
left: 0;
width: 248px;
background-color: #f7f7f7;
border: 1px solid #e0e0e0; /* 밑에 가로줄 추가 */
display: flex;
flex-direction: column;
`;

const MenuItem = styled.button`
padding: 8px 16px;
border: none;
background-color: transparent;
cursor: pointer;
text-align: left;
`;

export default Header;
95 changes: 95 additions & 0 deletions client/src/components/EntireList/StockItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React from 'react';
import styled from 'styled-components';
import logo from '../../asset/logos/SK_logo.png';

const StockItem: React.FC<StockItemProps> = ({ company, setShowChangePrice, showChangePrice }) => {
const isPositiveChange = parseFloat(company.stockChangeRate) > 0;
const priceColor = isPositiveChange ? 'red' : 'blue';

return (
<StockItemWrapper>
<Logo src={logo} alt="stock logo" />
<StockInfo>
<StockName>{company.korName}</StockName>
<StockCode>{company.code}</StockCode>
</StockInfo>
<StockPriceSection>
<StockPrice change={priceColor}>{company.stockPrice}</StockPrice>
<StockChange
change={priceColor}
onMouseEnter={() => setShowChangePrice(true)}
onMouseLeave={() => setShowChangePrice(false)}
>
{showChangePrice ? `${company.stockChangeAmount}%` : `${company.stockChangeRate}%`}
</StockChange>
</StockPriceSection>
</StockItemWrapper>
);
};

type NewCompanyData = {
companyId: number;
code: string;
korName: string;
stockPrice: string;
stockChangeAmount: string;
stockChangeRate: string;
};

type StockItemProps = {
company: NewCompanyData;
setShowChangePrice: React.Dispatch<React.SetStateAction<boolean>>;
showChangePrice: boolean;
};

const StockItemWrapper = styled.div`
display: flex;
flex-direction: row; /* 수평으로 정렬 */
justify-content: flex-start; /* 왼쪽 정렬 */
align-items: flex-start; /* 위로 정렬 */
padding: 8px 0;
border-bottom: 1px solid #e0e0e0;
width: 100%;
background-color: transparent;
cursor: pointer;
`;

const Logo = styled.img`
border-radius: 50%;
width: 40px;
height: 40px;
margin-right: 12px;
`;

const StockInfo = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
margin-right: 16px;
`;

const StockName = styled.span`
font-weight: bold;
`;

const StockCode = styled.span`
color: gray;
`;

const StockPriceSection = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
margin-left: auto; /* 자동으로 왼쪽 여백 추가 */
`;

const StockPrice = styled.span<{ change: string }>`
color: ${(props) => props.change};
`;

const StockChange = styled.span<{ change: string }>`
color: ${(props) => props.change};
cursor: pointer;
`;

export default StockItem;
75 changes: 75 additions & 0 deletions client/src/components/HoldingList/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react';
import styled from 'styled-components';
import Menu_icon from "../../asset/images/menu.png";

const ALL_LIST = "전체종목";
const INTEREST_LIST = "관심종목";
const HOLDING_LIST = "보유종목";

const Header: React.FC<HeaderProps> = ({ currentListType, onChangeListType, isMenuOpen, setMenuOpen }) => {
return (
<HeaderWrapper>
<Icon
src={Menu_icon}
alt="menu icon"
onClick={() => setMenuOpen(!isMenuOpen)}
/>
<HeaderText>{currentListType}</HeaderText>
{isMenuOpen && (
<SlideMenu>
<MenuItem onClick={() => { onChangeListType(ALL_LIST); setMenuOpen(false); }}>{ALL_LIST}</MenuItem>
<MenuItem onClick={() => { onChangeListType(INTEREST_LIST); setMenuOpen(false); }}>{INTEREST_LIST}</MenuItem>
<MenuItem onClick={() => { onChangeListType(HOLDING_LIST); setMenuOpen(false); }}>{HOLDING_LIST}</MenuItem>
</SlideMenu>
)}
</HeaderWrapper>
);
};

type HeaderProps = {
currentListType: string;
onChangeListType: (type: "전체종목" | "관심종목" | "보유종목") => void;
isMenuOpen: boolean;
setMenuOpen: React.Dispatch<React.SetStateAction<boolean>>;
};


const HeaderWrapper = styled.div`
display: flex;
align-items: center;
position: relative;
`;

const Icon = styled.img`
margin-top: 9.5px;
width: 24px;
height: 24px;
cursor: pointer;
margin-right: 10px;
`;

const HeaderText = styled.span`
margin-top: 9.5px;
font-size: 18px;
`;

const SlideMenu = styled.div`
position: absolute;
top: 100%;
left: 0;
width: 248px;
background-color: #f7f7f7;
border: 1px solid #e0e0e0; /* 밑에 가로줄 추가 */
display: flex;
flex-direction: column;
`;

const MenuItem = styled.button`
padding: 8px 16px;
border: none;
background-color: transparent;
cursor: pointer;
text-align: left;
`;

export default Header;
Loading