From 0af8be95ca184130c73bde2c1b565710cb458f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=91=ED=98=84?= Date: Tue, 19 Sep 2023 17:18:45 +0900 Subject: [PATCH] =?UTF-8?q?[Feat]=EA=B4=80=EC=8B=AC=EC=A2=85=EB=AA=A9=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20get/post/delete=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=ED=95=B4=EA=B2=B0=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EB=A0=8C=EB=8D=94=EB=A7=81=EC=9D=80=20=EB=AF=B8=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20Issues=20#19?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/HoldingList/Holdings.tsx | 263 ++++++++++++++++++ client/src/components/watchlist/StockItem.tsx | 2 + .../watchlist/StockSearchComponent.tsx | 10 + client/src/hooks/stars/useDeletestars.ts | 2 +- client/src/hooks/stars/usePoststars.ts | 5 +- 5 files changed, 278 insertions(+), 4 deletions(-) create mode 100644 client/src/components/HoldingList/Holdings.tsx diff --git a/client/src/components/HoldingList/Holdings.tsx b/client/src/components/HoldingList/Holdings.tsx new file mode 100644 index 00000000..e9c3ab78 --- /dev/null +++ b/client/src/components/HoldingList/Holdings.tsx @@ -0,0 +1,263 @@ +import React, { useState } from 'react'; +import styled from 'styled-components'; +import Samsung_logo from "../../asset/logos/Samsung_logo.svg" +import Menu_icon from "../../asset/images/menu.png" + +const Holdings: React.FC = ({ currentListType, onChangeListType }) => { + const [isMenuOpen, setMenuOpen] = useState(false); + + + const holdingsData = [ + { name: "삼성전자", code: "005930", price: "71,000원", change: "+6.13%", + profit: "수익", holding: "보유", profitAmount: "+10,000원", purchasePrice: "61,000원", + rateOfReturn: "+15%", stocksHeld: "100주", logo: Samsung_logo + }, + // ... (다른 종목들의 더미 데이터도 추가 가능) + ]; + + const [showChangePrice, setShowChangePrice] = useState(false); + + return ( + +
+ setMenuOpen(!isMenuOpen)} + /> + {currentListType} + {isMenuOpen && ( + + { onChangeListType('관심종목'); setMenuOpen(false); }}>관심종목 + { onChangeListType('보유종목'); setMenuOpen(false); }}>보유종목 + { onChangeListType('전체종목'); setMenuOpen(false); }}>전체종목 + + )} +
+ + 평가 수익금: +5,000,000원 {/* 임의의 평가 수익금 */} + + {holdingsData.map(stock => ( + <> + + + + {stock.name} + {stock.code} + + + {stock.price} + setShowChangePrice(true)} + onMouseLeave={() => setShowChangePrice(false)} + > + {showChangePrice ? stock.profitAmount : stock.change} + + + + + + {stock.profit} + {stock.holding} + + + {stock.profitAmount} + {stock.purchasePrice} + + + {stock.rateOfReturn} + {stock.stocksHeld} + + + + + ))} +
+ ); +}; + +type holdingsProps = { + currentListType: '전체종목' | '관심종목' | '보유종목'; + onChangeListType: (type: '전체종목' | '관심종목' | '보유종목') => void; +}; + +const getColorByChange = (change: string) => { + if (change.startsWith('+')) return 'red'; + if (change.startsWith('-')) return 'blue'; + return 'black'; + }; + + const HoldingsContainer = styled.div` + padding: 8px 0px; + `; + + const Header = styled.div` + padding:0px 16px; + display: flex; + align-items: center; + position: relative; + `; + + const Icon = styled.img` + width: 24px; + height: 24px; + cursor: pointer; + margin-right: 10px; + `; + + const HeaderText = styled.span` + 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; + + &:hover { + background-color: #e0e0e0; + } + `; + + const StockItem = styled.button` + display: flex; + justify-content: space-between; + align-items: flex-start; // 시작 위치 정렬 추가 + padding: 8px 0; + border-bottom: 1px solid #e0e0e0; + width: 100%; + background-color: transparent; + cursor: pointer; + border: none; + text-align: left; + `; + + 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; // 시작 위치 정렬 추가 + `; + + const StockPrice = styled.span.attrs<{ change: string }>(({ change }) => ({ + style: { + color: getColorByChange(change), + }, + }))``; + + const StockChange = styled.span.attrs<{ change: string }>(({ change }) => ({ + style: { + color: getColorByChange(change), + }, + }))` + cursor: pointer; // 마우스 포인터 변경 추가 + `; + + const Divider1 = styled.div` + margin:0px; + padding:0px; + width: 100%; + height: 11px; + 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 StockDetails = styled.div` + display: flex; + justify-content: space-between; + padding: 8px 0; + width: 100%; +`; + +const DetailSection = styled.div` + display: flex; + flex-direction: column; + align-items: center; +`; + +const DetailTitle = styled.span` + font-weight: light; + font-size : 14px; +`; + +const DetailData = styled.span` + font-size: 14px; // Setting standardized font size for all data +`; + +const getColorByValue = (value: string) => { + if (value.startsWith('+')) return 'red'; + if (value.startsWith('-')) return 'blue'; + return 'black'; +}; + +const ColoredDetailData = styled.span.attrs<{ value: string }>(({ value }) => ({ + style: { + color: getColorByValue(value), + }, +}))` + font-size: 14px; // Setting standardized font size for all data +`; + +const ThickDivider = styled.div` + height: 3px; + background-color: #aaa; + margin: 8px 0; +`; + +export default Holdings; diff --git a/client/src/components/watchlist/StockItem.tsx b/client/src/components/watchlist/StockItem.tsx index 089d23fc..d454ace9 100644 --- a/client/src/components/watchlist/StockItem.tsx +++ b/client/src/components/watchlist/StockItem.tsx @@ -6,6 +6,8 @@ import useDeleteStar from '../../hooks/stars/useDeletestars'; import { useDispatch } from 'react-redux'; import { changeCompanyId } from "../../reducer/CompanyId-Reducer"; + + import kia from '../../asset/logos/기아.svg'; import dy from '../../asset/logos/디와이.jpeg'; import logosamsung from '../../asset/logos/삼성전자.svg'; diff --git a/client/src/components/watchlist/StockSearchComponent.tsx b/client/src/components/watchlist/StockSearchComponent.tsx index c202b65d..8824314c 100644 --- a/client/src/components/watchlist/StockSearchComponent.tsx +++ b/client/src/components/watchlist/StockSearchComponent.tsx @@ -4,6 +4,7 @@ import styled from "styled-components"; import { changeCompanyId } from "../../reducer/CompanyId-Reducer"; import useGetCompanyList from "../../hooks/useGetCompanyList"; + const stockSearch = "종목 검색"; const search = "검색"; const noExistCompany = "noExistCompany"; @@ -20,13 +21,22 @@ const StockSearchComponent: React.FC = () => { const handleSearchCompany = () => { let searchResult: string = noExistCompany; + let foundCompanyId: number | null = null; companyList.forEach((company: CompanyProps) => { if (company.korName === searchWord) { searchResult = existCompany; dispatch(changeCompanyId(company.companyId)); + foundCompanyId = company.companyId; // companyId 저장 } }); + if (searchResult === existCompany && foundCompanyId !== null) { + dispatch(changeCompanyId(foundCompanyId)); + } else { + dispatch(changeCompanyId(-1)); + } + + if (searchResult === noExistCompany) { dispatch(changeCompanyId(-1)); diff --git a/client/src/hooks/stars/useDeletestars.ts b/client/src/hooks/stars/useDeletestars.ts index 5c3f9918..e18ad039 100644 --- a/client/src/hooks/stars/useDeletestars.ts +++ b/client/src/hooks/stars/useDeletestars.ts @@ -3,7 +3,7 @@ import { useMutation } from 'react-query'; // DELETE 요청을 수행하는 함수 const deleteStarData = async (companyId: number) => { const accessToken = localStorage.getItem('accessToken'); - const response = await fetch('http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com:8080/stars', { + const response = await fetch(`http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com:8080/stars/?companyId=${companyId}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json', diff --git a/client/src/hooks/stars/usePoststars.ts b/client/src/hooks/stars/usePoststars.ts index f3f56a09..637e4733 100644 --- a/client/src/hooks/stars/usePoststars.ts +++ b/client/src/hooks/stars/usePoststars.ts @@ -2,13 +2,12 @@ import { useMutation } from 'react-query'; const postStarData = async (companyId: number) => { const accessToken = localStorage.getItem('accessToken'); - const res = await fetch('http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com:8080/stars', { + const res = await fetch(`http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com:8080/stars/?companyId=${companyId}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `${accessToken}` - }, - body: JSON.stringify({ companyId }) + } }); if (!res.ok) {