diff --git a/src/Component/Chart/PieChart.tsx b/src/Component/Chart/PieChart.tsx index b65f3d0..13e2cfe 100644 --- a/src/Component/Chart/PieChart.tsx +++ b/src/Component/Chart/PieChart.tsx @@ -4,38 +4,41 @@ import { ApexOptions } from "apexcharts"; import { StockProps } from "../../constants/interface"; interface PieChartProps { - stockData: StockProps[]; + stockData: StockProps[]; } const PieChart: React.FC = ({ stockData }) => { - const series = stockData.map((item) => item.quantity); - const labels = stockData.map((item) => item.name); + console.log(stockData); + const series = stockData.map( + (item) => item.average * item.quantity * item.profitRate * 0.01 + ); + const labels = stockData.map((item) => item.name); - const options: ApexOptions = { - chart: { - type: "donut", - }, - labels: labels, - legend: { - position: "bottom", - }, - responsive: [ - { - breakpoint: 480, - options: { - chart: { - width: 450, - }, + const options: ApexOptions = { + chart: { + type: "donut", }, - }, - ], - }; + labels: labels, + legend: { + position: "bottom", + }, + responsive: [ + { + breakpoint: 480, + options: { + chart: { + width: 450, + }, + }, + }, + ], + }; - return ( -
- -
- ); + return ( +
+ +
+ ); }; export default PieChart; diff --git a/src/Component/Game/GameTradeSwipe.tsx b/src/Component/Game/GameTradeSwipe.tsx index 7166f86..63fbfe6 100644 --- a/src/Component/Game/GameTradeSwipe.tsx +++ b/src/Component/Game/GameTradeSwipe.tsx @@ -4,249 +4,298 @@ import TradeConfirmModal from "./TradeConfirmModal"; import axios from "axios"; import swal from "sweetalert"; import { usePortfolioStore } from "../../store/usePortfolioStore"; -import { StocksStore, useStock } from "../../store/stockContext"; +import { useStock } from "../../store/stockContext"; import { formatPrice } from "../../util/gameUtil"; import styled from "styled-components"; import { useSwipeStore } from "../../store/useSwipeStore"; interface GameTradeSwipeProps { - onClose: () => void; - isVisible: boolean; - year: string; - budget: number; + onClose: () => void; + isVisible: boolean; + year: string; + budget: number; } const GameTradeSwipe = ({ - onClose, - isVisible, - year, - budget, + onClose, + isVisible, + year, + budget, }: GameTradeSwipeProps) => { - const { stockData } = StocksStore(); - const [selectedStock, setSelectedStock] = useState<{ - stockId: number; - name: string; - } | null>(null); - const [quantity, setQuantity] = useState(0); - const [acting, setActing] = useState<"BUY" | "SELL">(); - const [isModalOpen, setIsModalOpen] = useState(false); - const [stockOptions, setStockOptions] = useState< - { stockId: number; name: string }[] - >([]); - const [currentPrice, setCurrentPrice] = useState(null); + const { stockData } = useStock(); + const [selectedStock, setSelectedStock] = useState<{ + stockId: number; + name: string; + } | null>(null); + const [quantity, setQuantity] = useState(0); + const [acting, setActing] = useState<"BUY" | "SELL">(); + const [isModalOpen, setIsModalOpen] = useState(false); + const [stockOptions, setStockOptions] = useState< + { stockId: number; name: string }[] + >([]); + const [currentPrice, setCurrentPrice] = useState(null); - const check = usePortfolioStore((state) => state.check); - const setCheck = usePortfolioStore((state) => state.setCheck); - const { holdingList } = useSwipeStore(); + const check = usePortfolioStore((state) => state.check); + const setCheck = usePortfolioStore((state) => state.setCheck); + const { holdingList } = useSwipeStore(); + // console.log(holdingList); - // 모달 외부 클릭 감지하기 위해 ref 생성 - const modalRef = useRef(null); + // 모달 외부 클릭 감지하기 위해 ref 생성 + const modalRef = useRef(null); - // 모달 외부 클릭 시 닫기 처리 - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if ( - modalRef.current && - !modalRef.current.contains(event.target as Node) - ) { - onClose(); - } + // 모달 외부 클릭 시 닫기 처리 + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + modalRef.current && + !modalRef.current.contains(event.target as Node) + ) { + onClose(); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, [onClose]); + + const handleStockChange = (direction: "left" | "right") => { + if (!selectedStock || stockOptions.length === 0) return; + const currentIndex = stockOptions.findIndex( + (stock) => stock.name === selectedStock.name + ); + const newIndex = + direction === "left" + ? (currentIndex - 1 + stockOptions.length) % stockOptions.length + : (currentIndex + 1) % stockOptions.length; + setSelectedStock(stockOptions[newIndex]); + + // 내가 가지고 있는 주식이면, 수량 업데이트 + const holdingStock = holdingList.find( + (holding) => holding.stockId === stockOptions[newIndex].stockId + ); + if (holdingStock) { + setQuantity(holdingStock.quantity); + } else { + setQuantity(0); + } }; - document.addEventListener("mousedown", handleClickOutside); - return () => { - document.removeEventListener("mousedown", handleClickOutside); + const handleQuantityChange = (direction: "left" | "right") => { + setQuantity((prev) => { + if (direction === "left" && prev > 1) { + return prev - 1; + } else if (direction === "right") { + return prev + 1; + } + return prev; + }); }; - }, [onClose]); - const handleStockChange = (direction: "left" | "right") => { - if (!selectedStock || stockOptions.length === 0) return; - const currentIndex = stockOptions.findIndex( - (stock) => stock.name === selectedStock.name - ); - const newIndex = - direction === "left" - ? (currentIndex - 1 + stockOptions.length) % stockOptions.length - : (currentIndex + 1) % stockOptions.length; - setSelectedStock(stockOptions[newIndex]); + const handleTradeConfirm = async () => { + if (currentPrice === 0) { + swal({ + title: "거래 실패", + text: "상장폐지된 주식은 거래할 수 없습니다.", + icon: "error", + }).then(() => { + setIsModalOpen(false); + }); + return; + } - // 내가 가지고 있는 주식이면, 수량 업데이트 - const holdingStock = holdingList.find( - (holding) => holding.stockId === stockOptions[newIndex].stockId - ); - if (holdingStock) { - setQuantity(holdingStock.quantity); - } else { - setQuantity(0); - } - }; + const data = { + stockId: selectedStock?.stockId || 0, + quantity, + acting, + }; + + try { + const res = await axios.post( + `${process.env.REACT_APP_API_URL}/v1/game/stock`, + data, + { withCredentials: true } + ); + if (res.status === 200) { + setCheck(!check); + swal({ title: "거래 성공", icon: "success" }); + setIsModalOpen(false); + setSelectedStock(stockOptions[0]); + setQuantity(0); + onClose(); + } + } catch (error: any) { + const errorMessage = + error.response?.data.message || "서버 오류가 발생했습니다."; + swal({ + title: "거래 실패", + text: errorMessage, + icon: "error", + }).then(() => { + setIsModalOpen(false); + }); + } + }; + + const openTradeConfirmModal = (action: "BUY" | "SELL") => { + setActing(action); + setIsModalOpen(true); + }; - const handleQuantityChange = (direction: "left" | "right") => { - setQuantity((prev) => { - if (direction === "left" && prev > 1) { - return prev - 1; - } else if (direction === "right") { - return prev + 1; - } - return prev; - }); - }; + const handleQuantityInputChange = (value: number) => { + setQuantity(value); + }; - const handleTradeConfirm = async () => { - const data = { - stockId: selectedStock?.stockId || 0, - quantity, - acting, + // 최대구매수량 계산 함수 + const handleMaxPurchaseQuantity = () => { + if (currentPrice && budget) { + const maxQuantity = Math.floor(budget / currentPrice); + setQuantity(maxQuantity > 0 ? maxQuantity : 0); + } }; - try { - const res = await axios.post( - `${process.env.REACT_APP_API_URL}/v1/game/stock`, - data, - { withCredentials: true } - ); - if (res.status === 200) { - setCheck(!check); - swal({ title: "거래 성공", icon: "success" }); - setIsModalOpen(false); - setSelectedStock(stockOptions[0]); - setQuantity(0); - onClose(); - } - } catch (error: any) { - const errorMessage = - error.response?.data.message || "서버 오류가 발생했습니다."; - swal({ - title: "거래 실패", - text: errorMessage, - icon: "error", - }).then(() => { - setIsModalOpen(false); - // 모달을 닫지 않음, 에러 후 닫지 않는 로직 유지 - }); - } - }; + // useEffect(() => { + // if (stockData) { + // const options = stockData.map((stock) => ({ + // stockId: stock.stockId, + // name: stock.name, + // })); + // setStockOptions(options); + // if (!selectedStock && options.length > 0) { + // setSelectedStock(options[0]); + // setCurrentPrice(stockData[0].current); + // } + // } + // if (selectedStock && stockData) { + // const selectedStockData = stockData.find( + // (stock) => stock.stockId === selectedStock.stockId + // ); + // setCurrentPrice(selectedStockData?.current || null); + // } + // }, [stockData, selectedStock]); + useEffect(() => { + if (stockData && stockData.length > 0) { + const options = stockData.map((stock) => ({ + stockId: stock.stockId, + name: stock.name, + })); + setStockOptions(options); - const openTradeConfirmModal = (action: "BUY" | "SELL") => { - setActing(action); - setIsModalOpen(true); - }; + // selectedStock이 없으면 첫 번째 종목을 선택 + if (!selectedStock && options.length > 0) { + setSelectedStock(options[0]); + setCurrentPrice(stockData[0].current || 0); // 초기값을 0으로 설정 + } else if (selectedStock) { + // 선택한 종목에 맞는 가격을 설정 + const selectedStockData = stockData.find( + (stock) => stock.stockId === selectedStock.stockId + ); + setCurrentPrice(selectedStockData?.current || 0); // undefined 방지 + } + } + }, [stockData, selectedStock]); - const handleQuantityInputChange = (value: number) => { - setQuantity(value); - }; - // 최대구매수량 계산 함수 - const handleMaxPurchaseQuantity = () => { - if (currentPrice && budget) { - const maxQuantity = Math.floor(budget / currentPrice); - setQuantity(maxQuantity > 0 ? maxQuantity : 0); - } - }; - - useEffect(() => { - if (stockData && stockData.length > 0) { - const options = stockData.map((stock) => ({ - stockId: stock.stockId, - name: stock.name, - })); - setStockOptions(options); + // selectedStock이 변경될 때만 수량을 설정하도록 추가 useEffect + useEffect(() => { + if (selectedStock && holdingList) { + const holdingStock = holdingList.find( + (holding) => holding.stockId === selectedStock.stockId + ); + if (holdingStock) { + setQuantity(holdingStock.quantity); // 보유한 수량으로 설정 + } else { + setQuantity(0); // 보유하지 않은 경우 0으로 설정 + } + } + }, [selectedStock, holdingList]); - // selectedStock이 없으면 첫 번째 종목을 선택 - if (!selectedStock && options.length > 0) { - setSelectedStock(options[0]); - setCurrentPrice(stockData[0].current || 0); // 초기값을 0으로 설정 - } else if (selectedStock) { - // 선택한 종목에 맞는 가격을 설정 - const selectedStockData = stockData.find( - (stock) => stock.stockId === selectedStock.stockId - ); - setCurrentPrice(selectedStockData?.current || 0); // undefined 방지 - } - } - }, [stockData, selectedStock]); + return ( +
+ + +
+ {/* 주식 거래하기 */} + handleStockChange("left")} + onRightClick={() => handleStockChange("right")} + currentPrice={currentPrice || 0} // undefined 방지 + handleMaxPurchaseQuantity={ + handleMaxPurchaseQuantity + } + /> + handleQuantityChange("left")} + onRightClick={() => handleQuantityChange("right")} + onQuantityChange={handleQuantityInputChange} // 수량 직접 입력 핸들러 전달 + currentPrice={currentPrice || 0} // undefined 방지 + handleMaxPurchaseQuantity={ + handleMaxPurchaseQuantity + } + /> +
+
거래가능금액: {formatPrice(budget)}
+
+ 총 합계:{" "} + {currentPrice && quantity + ? formatPrice(currentPrice * quantity) + : 0} +
- return ( -
- - -
- {/* 주식 거래하기 */} - handleStockChange("left")} - onRightClick={() => handleStockChange("right")} - currentPrice={currentPrice || 0} // undefined 방지 - handleMaxPurchaseQuantity={handleMaxPurchaseQuantity} + + openTradeConfirmModal("SELL")} + disabled={quantity === 0} // 수량이 0이거나 빈 값일 때 비활성화 + > + 팔기 + + openTradeConfirmModal("BUY")} + disabled={quantity === 0} // 수량이 0이거나 빈 값일 때 비활성화 + > + 사기 + + + + + setIsModalOpen(false)} + stock={selectedStock?.name || ""} + quantity={quantity} + acting={acting!} /> - handleQuantityChange("left")} - onRightClick={() => handleQuantityChange("right")} - onQuantityChange={handleQuantityInputChange} // 수량 직접 입력 핸들러 전달 - currentPrice={currentPrice || 0} // undefined 방지 - handleMaxPurchaseQuantity={handleMaxPurchaseQuantity} - /> -
-
거래가능금액: {formatPrice(budget)}
-
- 총 합계:{" "} - {currentPrice && quantity - ? formatPrice(currentPrice * quantity) - : 0} -
- - - openTradeConfirmModal("SELL")} - disabled={quantity === 0} // 수량이 0이거나 빈 값일 때 비활성화 - > - 팔기 - - openTradeConfirmModal("BUY")} - disabled={quantity === 0} // 수량이 0이거나 빈 값일 때 비활성화 - > - 사기 - - -
-
- setIsModalOpen(false)} - stock={selectedStock?.name || ""} - quantity={quantity} - acting={acting!} - /> -
- ); +
+ ); }; const SwipeModal = styled.div<{ isOpen: boolean }>` - width: 90%; - position: fixed; - left: 50%; - bottom: ${(props) => (props.isOpen ? "0" : "-100%")}; - max-height: ${(props) => (props.isOpen ? "64vh" : "0")}; - height: 64vh; - max-width: 426px; - box-shadow: 0px -2px 10px rgba(0, 0, 0, 0.1); - transition: bottom 0.7s ease, max-height 0.7s ease; - z-index: 1; - overflow: hidden; - border-top-left-radius: 20px; - border-top-right-radius: 20px; - transform: translateX(-50%); - background-color: #f7f7f7; - display: flex; - justify-content: center; + width: 90%; + position: fixed; + left: 50%; + bottom: ${(props) => (props.isOpen ? "0" : "-100%")}; + max-height: ${(props) => (props.isOpen ? "64vh" : "0")}; + height: 64vh; + max-width: 426px; + box-shadow: 0px -2px 10px rgba(0, 0, 0, 0.1); + transition: bottom 0.7s ease, max-height 0.7s ease; + z-index: 1; + overflow: hidden; + border-top-left-radius: 20px; + border-top-right-radius: 20px; + transform: translateX(-50%); + background-color: #f7f7f7; + display: flex; + justify-content: center; `; const SwipeContainer = styled.div` @@ -259,27 +308,34 @@ const SwipeContainer = styled.div` scrollbar-width: none; `; +// const Title = styled.span` +// font-size: 25px; +// font-weight: 700; +// color: #615efc; +// margin-top: 30px; +// `; + const TradeButtonGroup = styled.div` - display: flex; - justify-content: center; - align-items: center; - gap: 30px; - margin: 20px 0; - width: 250px; + display: flex; + justify-content: center; + align-items: center; + gap: 30px; + margin: 20px 0; + width: 250px; `; const TradeButton = styled.button` - width: 100px; - height: 40px; - border-radius: 15px; - background: ${({ disabled }) => - disabled - ? "radial-gradient(circle, #cccccc 0%, #e0e0e0 100%)" - : "radial-gradient(circle, #4834d4 0%, #686de0 100%)"}; - color: #fff; - border: none; - font-size: 14px; - cursor: pointer; + width: 100px; + height: 40px; + border-radius: 15px; + background: ${({ disabled }) => + disabled + ? "radial-gradient(circle, #cccccc 0%, #e0e0e0 100%)" + : "radial-gradient(circle, #4834d4 0%, #686de0 100%)"}; + color: #fff; + border: none; + font-size: 14px; + cursor: pointer; `; export default GameTradeSwipe; diff --git a/src/Component/Game/TradeChoice.tsx b/src/Component/Game/TradeChoice.tsx index c0b36b3..ed98579 100644 --- a/src/Component/Game/TradeChoice.tsx +++ b/src/Component/Game/TradeChoice.tsx @@ -98,10 +98,16 @@ const TradeChoice = ({ {selectedOption} - {currentPrice && ( + {currentPrice === 0 ? ( - {formatPrice(currentPrice)} 원 + 가격정보없음 + ) : ( + currentPrice && ( + + {formatPrice(currentPrice)} 원 + + ) )} diff --git a/src/Component/Game/gameHoldingsView.tsx b/src/Component/Game/gameHoldingsView.tsx index 8bdbcbe..d300122 100644 --- a/src/Component/Game/gameHoldingsView.tsx +++ b/src/Component/Game/gameHoldingsView.tsx @@ -1,6 +1,5 @@ import styled, { keyframes } from "styled-components"; import { formatPrice, formatChangeRate } from "../../util/gameUtil"; -import { holding } from "../../constants/interface"; const fadeIn = keyframes` from{ @@ -14,74 +13,79 @@ const fadeIn = keyframes` `; const TableContainer = styled.div` - animation: ${fadeIn} 0.5s ease-out forwards; - opacity: 0; + animation: ${fadeIn} 0.5s ease-out forwards; + opacity: 0; `; const GameHoldingsView = ({ holdingList }: any) => { - const header = ["종목명", "평균단가", "주식수", " 현재금액", "수익률"]; - return ( -
- - - {holdingList.length < 1 ? ( -

아직 보유한 주식이 없습니다!

- ) : ( - <> - - - {header.map((item, index) => ( - - ))} - - - - {holdingList.map((holding: any, index: any) => ( - - - - - - - - ))} - - - )} -
{item}
{holding.stockName} - {formatPrice(holding.average)} - {holding.quantity} 0 - ? "red" - : holding.profitRate < 0 - ? "blue" - : "black", - textAlign: "right", - }} - > - {formatPrice(holding.price)} - 0 - ? "red" - : holding.profitRate < 0 - ? "blue" - : "black", - }} - > - {formatChangeRate(holding.profitRate)} -
-
-
- ); + const header = ["종목명", "평균단가", "주식수", " 현재금액", "수익률"]; + return ( +
+ + + {holdingList.length < 1 ? ( +

아직 보유한 주식이 없습니다!

+ ) : ( + <> + + + {header.map((item, index) => ( + + ))} + + + + {holdingList.map((holding: any, index: any) => ( + + + + + + + + ))} + + + )} +
{item}
{holding.stockName} + {formatPrice(holding.average)} + {formatPrice(holding.quantity)} 0 + ? "red" + : holding.profitRate < 0 + ? "blue" + : "black", + textAlign: "right", + }} + > + {formatPrice(holding.price)} + 0 + ? "red" + : holding.profitRate < 0 + ? "blue" + : "black", + }} + > + {formatChangeRate( + holding.profitRate + )} +
+
+
+ ); }; export default GameHoldingsView; diff --git a/src/Component/Portfolio/PortfolioDetail.tsx b/src/Component/Portfolio/PortfolioDetail.tsx index 84d1b6b..1e87cc2 100644 --- a/src/Component/Portfolio/PortfolioDetail.tsx +++ b/src/Component/Portfolio/PortfolioDetail.tsx @@ -7,126 +7,123 @@ import axios from "axios"; import { usePortfolioStore } from "../../store/usePortfolioStore"; import DeleteConfirmationModal from "../Modal/deletePortfolio"; import swal from "sweetalert"; -import DeleteButton from "../Button/DeleteButton"; import DeleteButton2 from "../Button/DeleteButton2"; import styled from "styled-components"; const TitleDiv = styled.div` - width: 95%; - display: flex; - align-items: center; - position: relative; - margin-left: 1rem; - justify-content: space-between; - @media (max-width: 768px) { - width: 100%; - } + width: 95%; + display: flex; + align-items: center; + position: relative; + margin-left: 1rem; + justify-content: space-between; + @media (max-width: 768px) { + width: 100%; + } `; const PortfolioDetail = () => { - const location = useLocation(); - const id = Number(location.pathname.split("/")[2]); - const nav = useNavigate(); + const location = useLocation(); + const id = Number(location.pathname.split("/")[2]); + const nav = useNavigate(); - const setPortfolio = usePortfolioStore((state) => state.setPortfolio); - const setFinancialData = usePortfolioStore((state) => state.setFinancialData); - const pfName = usePortfolioStore((state) => state.pfName); - const data = usePortfolioStore((state) => state.data); - const stockData = usePortfolioStore((state) => state.stockData); - const budget = usePortfolioStore((state) => state.budget); - const principal = usePortfolioStore((state) => state.principal); - const profit = usePortfolioStore((state) => state.profit); - const profitRate = usePortfolioStore((state) => state.profitRate); - const changeStatus = usePortfolioStore((state) => state.change); - const [isDeleteOpen, setIsDeleteOpen] = useState(false); + const setPortfolio = usePortfolioStore((state) => state.setPortfolio); + const setFinancialData = usePortfolioStore( + (state) => state.setFinancialData + ); + const pfName = usePortfolioStore((state) => state.pfName); + const data = usePortfolioStore((state) => state.data); + const stockData = usePortfolioStore((state) => state.stockData); + const changeStatus = usePortfolioStore((state) => state.change); + const [isDeleteOpen, setIsDeleteOpen] = useState(false); - const change = usePortfolioStore((state) => state.change); - const setChange = usePortfolioStore((state) => state.setChange); + const change = usePortfolioStore((state) => state.change); + const setChange = usePortfolioStore((state) => state.setChange); - const deletePortfolio = async (id: number) => { - try { - const res = await axios.delete( - `${process.env.REACT_APP_API_URL}/v1/portfolio/${id}`, - { - withCredentials: true, + const deletePortfolio = async (id: number) => { + try { + const res = await axios.delete( + `${process.env.REACT_APP_API_URL}/v1/portfolio/${id}`, + { + withCredentials: true, + } + ); + if (res.status === 200) { + swal({ + title: "삭제 완료!", + icon: "success", + }).then(() => { + nav("/portfolio"); + setChange(!change); + }); + setIsDeleteOpen(false); + } + } catch (error: any) { + if (error.response && error.response.status === 404) { + nav("/portfolio"); + } } - ); - if (res.status === 200) { - swal({ - title: "삭제 완료!", - icon: "success", - }).then(() => { - nav("/portfolio"); - setChange(!change); - }); - setIsDeleteOpen(false); - } - } catch (error: any) { - if (error.response && error.response.status === 404) { - nav("/portfolio"); - } - } - }; + }; - // 포트폴리오 상세 조회 - useEffect(() => { - axios - .get(`${process.env.REACT_APP_API_URL}/v1/portfolio/${id}`, { - withCredentials: true, - headers: { - "Content-Type": "application/json", - }, - }) - .then((res) => { - if (res.status === 200) { - setPortfolio(res.data.name, res.data, res.data.stocks); - setFinancialData( - res.data.budget, - res.data.principal, - res.data.profit, - res.data.profitRate - ); - } else if (res.status === 401) { - alert("401"); - } - }) - .catch((e) => { - // alert(e); - }); - }, [setPortfolio, setFinancialData, changeStatus]); + // 포트폴리오 상세 조회 + useEffect(() => { + axios + .get(`${process.env.REACT_APP_API_URL}/v1/portfolio/${id}`, { + withCredentials: true, + headers: { + "Content-Type": "application/json", + }, + }) + .then((res) => { + if (res.status === 200) { + setPortfolio(res.data.name, res.data, res.data.stocks); + setFinancialData( + res.data.budget, + res.data.principal, + res.data.profit, + res.data.profitRate + ); + } else if (res.status === 401) { + alert("401"); + } + }) + .catch((e) => { + // alert(e); + }); + }, [setPortfolio, setFinancialData, changeStatus, id]); - if (!data) { - return
포트폴리오를 찾을 수 없습니다.
; - } + if (!data) { + return
포트폴리오를 찾을 수 없습니다.
; + } - const openDeleteModal = () => { - setIsDeleteOpen(true); - }; - return ( -
- -

{pfName}

- -
- - - - deletePortfolio(id)} // 삭제 함수 호출 - onRequestClose={() => setIsDeleteOpen(false)} // 모달 닫기 - showCancelButton={true} - /> -
- ); + const openDeleteModal = () => { + setIsDeleteOpen(true); + }; + return ( +
+ +

{pfName}

+ +
+ + + + deletePortfolio(id)} // 삭제 함수 호출 + onRequestClose={() => setIsDeleteOpen(false)} // 모달 닫기 + showCancelButton={true} + /> +
+ ); }; export default PortfolioDetail; diff --git a/src/Pages/game/playPage.tsx b/src/Pages/game/playPage.tsx index 457fd84..4dc5d58 100644 --- a/src/Pages/game/playPage.tsx +++ b/src/Pages/game/playPage.tsx @@ -10,6 +10,7 @@ import PassConfirmModal from "../../Component/Game/PassConfirmModal"; import axios from "axios"; import "./gameStyle.css"; import HappyNewYearModal from "./HappyNewYearModal"; +import { useStock } from "../../store/stockContext"; import { usePortfolioStore } from "../../store/usePortfolioStore"; import { useGameStore } from "../../store/useGameStore"; import ProgressBar from "../../Game/Loading/progressBar"; @@ -17,190 +18,193 @@ import { GoAlert } from "react-icons/go"; import { Colors } from "../../Styles/Colors"; import Button from "../../Component/Button/button"; import { useHintStore } from "../../store/hintStore"; -import { StocksStore } from "../../store/stockContext"; const Container = styled.div` - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - text-align: center; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; `; const PlayPage = () => { - const { year } = useParams<{ year?: string }>(); - const { stockData, setStockData } = StocksStore(); - const nav = useNavigate(); - const yearValue = year || "2014"; - // 페이지 유효성 검사를 위한 변수 - const yearNumber = parseInt(yearValue, 10); - const [isTradeModalVisible, setIsTradeModalVisible] = useState(false); - const [isPassModalVisible, setIsPassModalVisible] = useState(false); - const [isHappyNewYearModal, setIsHappyNewYearModal] = useState(false); - const [budget, setBudget] = useState(0); - const [loading, setLoading] = useState(false); - - const { check, setCheck } = usePortfolioStore((state) => ({ - check: state.check, - setCheck: state.setCheck, - })); - - const { checkYear, setCheckGameDone } = useGameStore((state) => ({ - checkYear: state.checkYear, - setCheckGameDone: state.setCheckGameDone, - })); - - const startYear = 2014; - const lastYear = 2023; - - // 년도 진행률 표시 - const calculateProgress = () => { - return ( - ((parseInt(yearValue, 10) - startYear) / (lastYear - startYear)) * 100 - ); - }; - - const [progress, setProgress] = useState(calculateProgress); - - // 거래하기 모달 핸들러 - const openTradeModal = () => { - setIsTradeModalVisible(true); - }; - - const closeTradeModal = () => { - setIsTradeModalVisible(false); - }; - - // 넘어가기 모달 핸들러 - const openPassModal = () => { - setIsPassModalVisible(true); - }; - - const closePassModal = () => { - setIsPassModalVisible(false); - }; - - // 넘어가기 버튼 누르면 중간결과 호출 - const handleConfirmPass = async () => { - try { - setLoading(true); - setIsHappyNewYearModal(true); - setIsPassModalVisible(false); - - if (year === "2023") { - setCheckGameDone(true); - nav("/game/result/total"); - } else { - const response = await axios.get( - `${process.env.REACT_APP_API_URL}/v1/game/interim`, - { - withCredentials: true, - headers: { - "Content-Type": "application/json", - }, - } + const { year } = useParams<{ year?: string }>(); + const { stockData, setStockData } = useStock(); + const nav = useNavigate(); + const yearValue = year || "2014"; + // 페이지 유효성 검사를 위한 변수 + const yearNumber = parseInt(yearValue, 10); + const [isTradeModalVisible, setIsTradeModalVisible] = useState(false); + const [isPassModalVisible, setIsPassModalVisible] = useState(false); + const [isHappyNewYearModal, setIsHappyNewYearModal] = useState(false); + const [budget, setBudget] = useState(0); + const [, setLoading] = useState(false); + + const { check, setCheck } = usePortfolioStore((state) => ({ + check: state.check, + setCheck: state.setCheck, + })); + + const { checkYear, setCheckGameDone } = useGameStore((state) => ({ + checkYear: state.checkYear, + setCheckGameDone: state.setCheckGameDone, + })); + + const startYear = 2014; + const lastYear = 2023; + + // 년도 진행률 표시 + const calculateProgress = () => { + return ( + ((parseInt(yearValue, 10) - startYear) / (lastYear - startYear)) * + 100 ); - if (response.status === 200) { - if ( - (parseInt(yearValue, 10) + 1).toString() === - response.data.year.toString() - ) { - const updatedStockList = response.data.stockList; - setStockData(updatedStockList); - } - - // API 완료 후 모달 닫고 페이지 이동 - setIsHappyNewYearModal(false); - const nextYear = (parseInt(yearValue, 10) + 1).toString(); - nav(`/game/play/${nextYear}`); - setCheck(!check); - setProgress( - ((parseInt(nextYear, 10) - startYear) / (lastYear - startYear)) * - 100 - ); - // 로컬 스토리지에서 삭제 - localStorage.removeItem("hint-storage"); - // 주스탠드 스토어 상태 초기화 - useHintStore.getState().resetPurchaseHints(); + }; + + const [progress, setProgress] = useState(calculateProgress); + + // 거래하기 모달 핸들러 + const openTradeModal = () => { + setIsTradeModalVisible(true); + }; + + const closeTradeModal = () => { + setIsTradeModalVisible(false); + }; + + // 넘어가기 모달 핸들러 + const openPassModal = () => { + setIsPassModalVisible(true); + }; + + const closePassModal = () => { + setIsPassModalVisible(false); + }; + + // 넘어가기 버튼 누르면 중간결과 호출 + const handleConfirmPass = async () => { + try { + setLoading(true); + setIsHappyNewYearModal(true); + setIsPassModalVisible(false); + + if (year === "2023") { + setCheckGameDone(true); + nav("/game/result/total"); + } else { + const response = await axios.get( + `${process.env.REACT_APP_API_URL}/v1/game/interim`, + { + withCredentials: true, + headers: { + "Content-Type": "application/json", + }, + } + ); + if (response.status === 200) { + if ( + (parseInt(yearValue, 10) + 1).toString() === + response.data.year.toString() + ) { + const updatedStockList = response.data.stockList; + setStockData(updatedStockList); + } + + // API 완료 후 모달 닫고 페이지 이동 + setIsHappyNewYearModal(false); + const nextYear = (parseInt(yearValue, 10) + 1).toString(); + nav(`/game/play/${nextYear}`); + setCheck(!check); + setProgress( + ((parseInt(nextYear, 10) - startYear) / + (lastYear - startYear)) * + 100 + ); + // 로컬 스토리지에서 삭제 + localStorage.removeItem("hint-storage"); + // 주스탠드 스토어 상태 초기화 + useHintStore.getState().resetPurchaseHints(); + } + } + } catch (error) { + console.error(error); + } finally { + setLoading(false); + closePassModal(); } - } - } catch (error) { - console.error(error); - } finally { - setLoading(false); - closePassModal(); - } - }; - - return ( - <> - {yearNumber !== checkYear ? ( -
- -

정상적인 접근 경로가 아닙니다

-
- ) : ( - - - -
- -
- - - - - - -
- )} - - ); + }; + + return ( + <> + {yearNumber !== checkYear ? ( +
+ +

+ 정상적인 접근 경로가 아닙니다 +

+
+ ) : ( + + + +
+ +
+ + + + + + +
+ )} + + ); }; export default PlayPage;