-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
7 changed files
with
710 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { useState, useEffect } from "react"; | ||
import styled from "styled-components"; | ||
import StockItem from "./StockItem"; | ||
import useCompanyData from "../../hooks/useCompanyData"; | ||
import { useSelector } from "react-redux"; // 👈 추가 | ||
import { StateProps } from "../../models/stateProps"; // 👈 추가 | ||
import useGetCash from "../../hooks/useGetCash"; | ||
|
||
const holdingAmountText = "보유 현금"; | ||
const amountUnit = "원"; | ||
|
||
const EntireList = () => { | ||
const { data: companies, isLoading, isError } = useCompanyData(1, 14); | ||
const { cashData: holdingsAmount } = useGetCash(); | ||
const companiesList = companies || []; | ||
|
||
const [showChangePrice, setShowChangePrice] = useState(false); | ||
const [holdingCash, setHoldingCash] = useState(""); | ||
const isLogin = useSelector((state: StateProps) => state.login); | ||
|
||
useEffect(() => { | ||
if (holdingsAmount) { | ||
const holdingCash = holdingsAmount.toLocaleString(); | ||
setHoldingCash(holdingCash); | ||
} | ||
}, [holdingsAmount]); | ||
|
||
return ( | ||
<Container> | ||
{isLogin === 1 && ( | ||
<Header2Container isLogin={isLogin}> | ||
<HoldingsAmount isLogin={isLogin}> | ||
<div className="amountText">{holdingAmountText}</div> | ||
<div className="amount"> | ||
{holdingCash} {amountUnit} | ||
</div> | ||
</HoldingsAmount> | ||
</Header2Container> | ||
)} | ||
<StockList> | ||
{isLoading ? <div></div> : isError ? <div>Error fetching data</div> : companiesList.map((company) => <StockItem key={company.companyId} company={company} setShowChangePrice={setShowChangePrice} showChangePrice={showChangePrice} />)} | ||
</StockList> | ||
</Container> | ||
); | ||
}; | ||
|
||
export default EntireList; | ||
|
||
const Container = styled.div` | ||
height: calc(100vh - 95px); | ||
display: flex; | ||
flex-direction: column; | ||
align-items: flex-start; | ||
`; | ||
|
||
const Header2Container = styled.div<{ isLogin: number }>` | ||
width: 100%; | ||
height: ${(props) => (props.isLogin === 0 ? "0px" : "43.5px")}; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
border-bottom: ${(props) => (props.isLogin === 0 ? "" : "1px solid black")}; | ||
`; | ||
|
||
const HoldingsAmount = styled.div<{ isLogin: number }>` | ||
width: 100%; | ||
height: 100%; | ||
display: ${(props) => (props.isLogin === 0 ? "none" : "flex")}; | ||
flex-direction: row; | ||
padding-left: 14px; | ||
align-items: center; | ||
gap: 6.5px; | ||
font-size: 0.95em; | ||
font-weight: 570; | ||
color: black; | ||
.amount { | ||
color: #2f4f4f; | ||
} | ||
`; | ||
|
||
const StockList = styled.div` | ||
height: 100%; | ||
width: 100%; | ||
overflow-y: auto; /* 세로 스크롤을 활성화합니다 */ | ||
&::-webkit-scrollbar { | ||
display: none; | ||
} | ||
`; |
139 changes: 139 additions & 0 deletions
139
client/src/components/LeftStockListSection/HoldingList.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import React, { useState } from "react"; | ||
import styled from "styled-components"; | ||
import StockItem from "./StockItem"; | ||
import useGetStockHolds from "../../hooks/useGetStockholds"; | ||
// import { StockItemProps } from "./StockItem"; | ||
import useCompanyData from "../../hooks/useCompanyData"; | ||
import LoginRequestIndicator from "./LoginRequestIndicator"; | ||
import { RootState } from "../../store/config"; | ||
import { useSelector } from "react-redux"; | ||
|
||
// 🔴 | ||
const evalutationProfitText = "평가 수익금"; | ||
const profitUnit = "원"; | ||
|
||
const HoldingList = () => { | ||
const [showChangePrice, setShowChangePrice] = useState(false); | ||
|
||
const { stockHolds, stockHoldsLoading: isLoading, stockHoldsError: isError } = useGetStockHolds(); | ||
const { data: companyData, isLoading: isCompanyDataLoading, isError: isCompanyDataError } = useCompanyData(1, 14); | ||
|
||
// 모든 stockReturn의 합을 계산합니다. | ||
let totalEvaluationProfit = 0; | ||
|
||
if (Array.isArray(stockHolds) && stockHolds.length > 0) { | ||
totalEvaluationProfit = stockHolds.reduce((sum: number, stockHold: StockItemProps["stockData"]) => sum + stockHold.stockReturn, 0); | ||
} | ||
|
||
const isLogin = useSelector((state: RootState) => state.login); // 로그인 상태 가져오기 | ||
|
||
// OAuth 모달을 열기 위한 함수 | ||
const openOAuthModal = () => { | ||
// OAuth 로그인 모달을 열기 위한 로직 | ||
}; | ||
|
||
return ( | ||
<WatchListContainer> | ||
<Header2Container> | ||
<EvaluationProfit profit={totalEvaluationProfit}> | ||
<div className="profitText">{evalutationProfitText}</div> | ||
<div className="profit"> | ||
{totalEvaluationProfit.toLocaleString()} {profitUnit} | ||
</div> | ||
</EvaluationProfit> | ||
</Header2Container> | ||
<StockList> | ||
{isLogin === 0 ? ( | ||
<LoginRequestIndicator openOAuthModal={openOAuthModal} /> | ||
) : isLoading || isCompanyDataLoading ? ( | ||
<div></div> | ||
) : isError || isCompanyDataError ? ( | ||
<div>Error fetching data</div> | ||
) : ( | ||
Array.isArray(stockHolds) && | ||
stockHolds.length > 0 && | ||
stockHolds.map((stockHold: StockItemProps["stockData"]) => { | ||
const matchedCompany = companyData ? companyData.find((company) => company.companyId === stockHold.companyId) : undefined; | ||
|
||
return matchedCompany ? <StockItem key={stockHold.companyId} stockData={stockHold} companyData={matchedCompany} setShowChangePrice={setShowChangePrice} showChangePrice={showChangePrice} /> : null; | ||
}) | ||
)} | ||
</StockList> | ||
</WatchListContainer> | ||
); | ||
}; | ||
|
||
export default HoldingList; | ||
|
||
type StockItemProps = { | ||
stockData: { | ||
stockHoldId: number; | ||
memberId: number; | ||
companyId: number; | ||
companyKorName: string; | ||
stockCount: number; | ||
totalPrice: number; | ||
percentage: number; | ||
stockReturn: number; | ||
reserveSellStockCount: number; | ||
}; | ||
companyData?: { | ||
companyId: number; | ||
code: string; | ||
korName: string; | ||
stockPrice: string; | ||
stockChangeAmount: string; | ||
stockChangeRate: string; | ||
}; | ||
setShowChangePrice: (value: boolean) => void; | ||
showChangePrice: boolean; | ||
}; | ||
|
||
const WatchListContainer = styled.div` | ||
width: 100%; | ||
height: calc(100vh - 53px); | ||
display: flex; | ||
flex-direction: column; | ||
align-items: flex-start; | ||
`; | ||
|
||
const Header2Container = styled.div` | ||
width: 100%; | ||
height: 43.5px; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
`; | ||
|
||
const EvaluationProfit = styled.div<{ profit: number }>` | ||
width: 100%; | ||
height: 100%; | ||
display: flex; | ||
flex-direction: row; | ||
align-items: center; | ||
font-size: 0.95em; | ||
font-weight: 570; | ||
gap: 6.5px; | ||
padding-left: 14px; | ||
text-align: "center"; | ||
color: ${(props) => (props.profit === 0 ? "#000" : props.profit > 0 ? "#e22926" : "#2679ed")}; | ||
border-bottom: 1px solid black; | ||
.profitText { | ||
color: black; | ||
} | ||
.profit { | ||
color: #2f4f4f; | ||
} | ||
`; | ||
|
||
const StockList = styled.div` | ||
height: 100%; | ||
width: 100%; | ||
overflow-y: auto; /* 세로 스크롤을 활성화합니다 */ | ||
&::-webkit-scrollbar { | ||
display: none; | ||
} | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
client/src/components/LeftStockListSection/LoginRequestIndicator.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// LoginRequestIndicator.tsx | ||
|
||
import React from "react"; | ||
import styled from "styled-components"; | ||
|
||
|
||
interface LoginRequestIndicatorProps { | ||
openOAuthModal: () => void; | ||
} | ||
|
||
const LoginRequestIndicator: React.FC<LoginRequestIndicatorProps> = ({ openOAuthModal }) => { | ||
return ( | ||
<LoginRequestContainer> | ||
<div className="Notification">로그인이 필요한 서비스입니다.</div> | ||
<button className="LoginButton" onClick={openOAuthModal}>StockHolm 로그인</button> | ||
</LoginRequestContainer> | ||
); | ||
}; | ||
|
||
const LoginRequestContainer = styled.div` | ||
width: 100%; | ||
height: 100%; | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-items: center; | ||
gap: 8px; | ||
.Notification { | ||
color: #999999; | ||
} | ||
.LoginButton { | ||
width: 170px; | ||
height: 32px; | ||
font-size: 15px; | ||
font-weight: 400; | ||
color: white; | ||
background-color: #2f4f4f; | ||
border: none; | ||
border-radius: 0.3rem; | ||
cursor: pointer; | ||
} | ||
`; | ||
|
||
export default LoginRequestIndicator; |
Oops, something went wrong.