From 532ceb88c93c9940183c3dc09b467d163b25cd4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=91=ED=98=84?= Date: Fri, 15 Sep 2023 15:14:38 +0900 Subject: [PATCH] =?UTF-8?q?[Feat]=EA=B4=80=EC=8B=AC=EC=A2=85=EB=AA=A9=20?= =?UTF-8?q?=EC=9E=AC=EA=B5=AC=ED=98=84=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=EC=8B=9C=20=EA=B8=B0=EB=8A=A5=EB=B6=88=EA=B0=80=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=EC=B0=BD=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EC=82=BD=EC=9E=85=EC=8B=9C=EC=BC=9C?= =?UTF-8?q?=EC=84=9C=20=EA=B2=80=EC=83=89=ED=95=9C=20=EC=A2=85=EB=AA=A9?= =?UTF-8?q?=EC=9D=84=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EC=97=90=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=8A=A4?= =?UTF-8?q?=ED=83=9D=ED=98=95=ED=83=9C=EB=A1=9C=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EC=9D=B4=EB=AF=B8=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=ED=95=9C=20=EC=A2=85=EB=AA=A9=EC=9D=84=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=97=90=20=EC=A0=80=EC=9E=A5=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=ED=9B=84=20=EC=A4=91=EC=95=99=20=EC=B0=A8=ED=8A=B8=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20Issues=20#19?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/EntireList/EntireList.tsx | 10 +- client/src/components/EntireList/Header.tsx | 1 + .../src/components/HoldingList/Holdings.tsx | 2 +- .../watchlist/StockSearchComponent.tsx | 97 ++++++++++++++++++ client/src/components/watchlist/WatchList.tsx | 99 +++++++++++-------- client/src/page/MainPage.tsx | 17 ++-- 6 files changed, 172 insertions(+), 54 deletions(-) create mode 100644 client/src/components/watchlist/StockSearchComponent.tsx diff --git a/client/src/components/EntireList/EntireList.tsx b/client/src/components/EntireList/EntireList.tsx index c4bad0aa..57f10af8 100644 --- a/client/src/components/EntireList/EntireList.tsx +++ b/client/src/components/EntireList/EntireList.tsx @@ -4,7 +4,7 @@ import Header from './Header'; import StockItem from './StockItem'; import useCompanyData from '../../hooks/useCompanyData'; -const WatchList: React.FC = ({ currentListType, onChangeListType }) => { +const EntireList: React.FC = ({ currentListType, onChangeListType }) => { const [isMenuOpen, setMenuOpen] = useState(false); const [showChangePrice, setShowChangePrice] = useState(false); @@ -46,7 +46,7 @@ const WatchList: React.FC = ({ currentListType, onChangeListType }; // Props와 상태에 대한 타입 정의 -type WatchListProps = { +type EntireListProps = { currentListType: '전체종목' | '관심종목' | '보유종목'; onChangeListType: (type: '전체종목' | '관심종목' | '보유종목') => void; }; @@ -88,9 +88,9 @@ text-align: center; color: red; // 수익금이 플러스일 경우 초록색으로 표시 `; const StockList = styled.div` - width: 90%; - max-height: 800px; /* 스크롤이 발생할 최대 높이를 지정하세요 */ + width: 100%; + max-height: 740px; /* 스크롤이 발생할 최대 높이를 지정하세요 */ overflow-y: auto; /* 세로 스크롤을 활성화합니다 */ `; -export default WatchList; +export default EntireList; diff --git a/client/src/components/EntireList/Header.tsx b/client/src/components/EntireList/Header.tsx index 2f08c4dd..50ea82a7 100644 --- a/client/src/components/EntireList/Header.tsx +++ b/client/src/components/EntireList/Header.tsx @@ -42,6 +42,7 @@ const HeaderWrapper = styled.div` const Icon = styled.img` margin-top: 9.5px; + margin-left: 10px; width: 24px; height: 24px; cursor: pointer; diff --git a/client/src/components/HoldingList/Holdings.tsx b/client/src/components/HoldingList/Holdings.tsx index 5a03e2c8..e9c3ab78 100644 --- a/client/src/components/HoldingList/Holdings.tsx +++ b/client/src/components/HoldingList/Holdings.tsx @@ -29,7 +29,7 @@ const Holdings: React.FC = ({ currentListType, onChangeListType } {isMenuOpen && ( { onChangeListType('관심종목'); setMenuOpen(false); }}>관심종목 - { onChangeListType('보유종목'); setMenuOpen(false); }}>투자종목 + { onChangeListType('보유종목'); setMenuOpen(false); }}>보유종목 { onChangeListType('전체종목'); setMenuOpen(false); }}>전체종목 )} diff --git a/client/src/components/watchlist/StockSearchComponent.tsx b/client/src/components/watchlist/StockSearchComponent.tsx new file mode 100644 index 00000000..68339b9c --- /dev/null +++ b/client/src/components/watchlist/StockSearchComponent.tsx @@ -0,0 +1,97 @@ +import React, { useState } from 'react'; +import { useDispatch } from "react-redux"; +import styled from "styled-components"; +import { changeCompanyId } from "../../reducer/CompanyId-Reducer"; +import useGetCompanyList from "../../hooks/useGetCompanyList"; + +const stockSearch = "종목 검색"; +const search = "검색"; +const noExistCompany = "noExistCompany"; +const existCompany = "existCompany"; + +const StockSearchComponent: React.FC = () => { + const dispatch = useDispatch(); + const { companyList } = useGetCompanyList(); + const [searchWord, setSearchWord] = useState(""); + + const handleChangeSearchWord = (e: React.ChangeEvent) => { + setSearchWord(e.target.value); + }; + + const handleSearchCompany = () => { + let searchResult: string = noExistCompany; + + companyList.forEach((company: CompanyProps) => { + if (company.korName === searchWord) { + searchResult = existCompany; + dispatch(changeCompanyId(company.companyId)); + } + }); + + if (searchResult === noExistCompany) { + dispatch(changeCompanyId(-1)); + } + }; + + const handlePressEnterToSearch = (e: React.KeyboardEvent) => { + if (e.code === "Enter" && e.nativeEvent.isComposing === false) { + handleSearchCompany(); + setSearchWord(""); + } + }; + + return ( + + + {search} + + ); +}; + +export default StockSearchComponent; + +interface CompanyProps { + companyId: number; + code: string; + korName: string; + stockAsBiResponseDto: null; + stockInfResponseDto: null; +} + +// 스타일 정의 + +const SearchContainer = styled.div` + display: flex; + align-items: center; + flex-grow: 0.7; +`; + +const StyledSearchInput = styled.input.attrs({ + type: "text", + placeholder: "검색...", +})` + width: 100%; + padding: 0.5rem; + border: 1px solid #ccc; + border-radius: 4px; + flex: 1; +`; + +const StyledSearchButton = styled.button` + background-color: #fff; + color: #2f4f4f; + border: 1px solid #2f4f4f; + padding: 0.5rem 1rem; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s; + &:hover { + background-color: #f2f2f2; + } + margin-left: 0.5rem; +`; diff --git a/client/src/components/watchlist/WatchList.tsx b/client/src/components/watchlist/WatchList.tsx index c4bad0aa..4592a1af 100644 --- a/client/src/components/watchlist/WatchList.tsx +++ b/client/src/components/watchlist/WatchList.tsx @@ -1,19 +1,40 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import styled from 'styled-components'; +import StockSearchComponent from './StockSearchComponent'; import Header from './Header'; import StockItem from './StockItem'; import useCompanyData from '../../hooks/useCompanyData'; +import { useSelector } from 'react-redux'; +import { RootState } from '../../store/config.ts'; // Redux store의 RootState를 import해야 합니다. const WatchList: React.FC = ({ currentListType, onChangeListType }) => { const [isMenuOpen, setMenuOpen] = useState(false); const [showChangePrice, setShowChangePrice] = useState(false); + const loginStatus = useSelector((state: RootState) => state.login); + + // useCompanyData 훅 사용하여 데이터 가져오기 const { data: companies, isLoading, isError } = useCompanyData(1, 14); // 'companies'가 'undefined'인 경우를 처리하기 위해 빈 배열로 초기화 const companiesList = companies || []; + + // 이미 검색된 회사 ID들을 저장하는 스택 형태의 상태 + const [searchedCompanyIds, setSearchedCompanyIds] = useState([]); + + // Redux store에서 선택된 회사 ID 가져오기 + const selectedCompanyId = useSelector((state: RootState) => state.companyId); + + // 새로운 회사 ID가 검색될 때마다 스택에 추가 + useEffect(() => { + if (selectedCompanyId !== -1 && !searchedCompanyIds.includes(selectedCompanyId)) { + setSearchedCompanyIds(prevIds => [...prevIds, selectedCompanyId]); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedCompanyId]); + return (
= ({ currentListType, onChangeListType setMenuOpen={setMenuOpen} /> - 평가 수익금: +5,000,000원 {/* 임의의 평가 수익금 */} + - {isLoading ? ( -
Loading...
- ) : isError ? ( -
Error fetching data
- ) : ( - companiesList.map((company) => ( - - )) - )} -
+ {isLoading ? ( +
Loading...
+ ) : isError ? ( +
Error fetching data
+ ) : loginStatus === 1 ? ( + companiesList + .filter(company => searchedCompanyIds.includes(company.companyId)) + .map((company) => ( + + )) + ) : ( +
로그인이 필요합니다.
+ )} + + ); }; @@ -59,38 +85,29 @@ const WatchListContainer = styled.div` `; 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 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 EvaluationProfit = styled.div` -font-size: 16px; -font-weight: bold; -margin: 8px 0; -text-align: center; -color: red; // 수익금이 플러스일 경우 초록색으로 표시 -`; const StockList = styled.div` width: 90%; max-height: 800px; /* 스크롤이 발생할 최대 높이를 지정하세요 */ overflow-y: auto; /* 세로 스크롤을 활성화합니다 */ `; -export default WatchList; +export default WatchList; \ No newline at end of file diff --git a/client/src/page/MainPage.tsx b/client/src/page/MainPage.tsx index 120d9489..d322f1ac 100644 --- a/client/src/page/MainPage.tsx +++ b/client/src/page/MainPage.tsx @@ -10,8 +10,9 @@ import EmailSignupModal from "../components/Signups/EmailSignup"; import EmailVerificationModal from "../components/Signups/EmailCertify"; import PasswordSettingModal from "../components/Signups/Password"; import CentralChart from "../components/CentralChart/Index"; -import WatchList from "../components/EntireList/EntireList"; -import Holdings from "../components/HoldingList/Holdings"; // Assuming you have a Holdings component +import EntireList from "../components/EntireList/EntireList"; +import HoldingList from "../components/HoldingList/HoldingList"; +import WatchList from "../components/WatchList/WatchList"; // Assuming you have a Holdings component import CompareChartSection from "../components/CompareChartSection/Index"; import StockOrderSection from "../components/StockOrderSection/Index"; import Welcome from "../components/Signups/Welcome"; @@ -141,11 +142,13 @@ const MainPage = () => { {!expandScreen.left && ( - {selectedMenu === "전체종목" ? ( - - ) : ( - - )} + {selectedMenu === "전체종목" ? ( + + ) : selectedMenu === "보유종목" ? ( + + ) : ( + + )} )}