diff --git a/src/Component/Chart/chart.tsx b/src/Component/Chart/chart.tsx index af189ec..27bd889 100644 --- a/src/Component/Chart/chart.tsx +++ b/src/Component/Chart/chart.tsx @@ -21,7 +21,7 @@ const Chart = ({ data }: CandleData) => { const [newsHtml, setNewsHtml] = useState(""); const latestDate = new Date(data[data.length - 1].x).getTime(); const initialZoomMin = new Date( - latestDate - 90 * 24 * 60 * 60 * 1000 + latestDate - 60 * 24 * 60 * 60 * 1000 ).getTime(); const onRequestClose = () => { diff --git a/src/Component/Dropdown/gameDropdown.tsx b/src/Component/Dropdown/gameDropdown.tsx index a7ac9fc..d9c324e 100644 --- a/src/Component/Dropdown/gameDropdown.tsx +++ b/src/Component/Dropdown/gameDropdown.tsx @@ -11,6 +11,7 @@ import { Button, Menu, } from "./gameStyle"; +import { useHintStore } from "../../store/hintStore"; export interface StockItemProps { onSelectStock: (stockId: number) => void; @@ -20,6 +21,7 @@ const StockItem: React.FC = ({ onSelectStock }) => { const [isOpen, setIsOpen] = useState(false); const [selectedStock, setSelectedStock] = useState(null); const { stockData } = useStock(); + const { purchaseHints, setPurchaseHints } = useHintStore(); const toggleDropdown = () => { setIsOpen(!isOpen); @@ -54,16 +56,40 @@ const StockItem: React.FC = ({ onSelectStock }) => { style={{ pointerEvents: isOpen ? "auto" : "none" }} > {stockData && - stockData.map((item) => ( -
  • handleSelect(item)} - style={{ marginTop: "0.5rem" }} - > - {item.name} -
  • - ))} + stockData.map((item) => { + // 해당 종목에서 구매한 단계들 찾기 + const purchasedLevels = purchaseHints[item.stockId] + ? Object.keys(purchaseHints[item.stockId]) + .filter( + (level) => purchaseHints[item.stockId][level].purchased + ) // 구매된 단계만 필터링 + // .map((level) => "🔑".repeat(parseInt(level))) + .join(", ") // 구매된 단계들을 문자열로 합침 + : null; + + return ( +
  • handleSelect(item)} + style={{ marginTop: "0.5rem" }} + > + {item.name} + {purchaseHints[item.stockId] && ( + + {purchasedLevels} ✅ + + )} +
  • + ); + })} diff --git a/src/Component/Dropdown/gameStyle.ts b/src/Component/Dropdown/gameStyle.ts index 5a43f33..97a0c08 100644 --- a/src/Component/Dropdown/gameStyle.ts +++ b/src/Component/Dropdown/gameStyle.ts @@ -51,6 +51,9 @@ export const Li = styled(motion.li)` color: #6600ff; display: block; z-index: 3000; + display: flex; + justify-content: space-between; + align-items: center; `; export const dropdownVariants: Variants = { diff --git a/src/Component/Layout/Layout.tsx b/src/Component/Layout/Layout.tsx index 5a838dd..ea9c746 100644 --- a/src/Component/Layout/Layout.tsx +++ b/src/Component/Layout/Layout.tsx @@ -3,6 +3,7 @@ import Header from "./Header/Header"; import NavBar from "./NavBar/NavBar"; import styled from "styled-components"; import { useAuth } from "../../contexts/authContext"; +import BentoBar from "../../Game/Main/BentoBar/bentoBar"; const Main = styled.main` width: 500px; @@ -31,12 +32,15 @@ const Layout = (props: { children: React.ReactNode }) => { const location = useLocation(); const isLoginPage = location.pathname === "/nologin"; const isGame = location.pathname.includes("/game"); + const GameNav = location.pathname.includes( + "/rank" || "/total" || "gameStocks" + ); return ( {!isLoginPage && !isGame &&
    }
    {props.children}
    - {!isLoginPage && !isGame && } + {!isLoginPage && !isGame ? : GameNav ? : ""} ); }; diff --git a/src/Game/Main/BentoBar/bentoBar.tsx b/src/Game/Main/BentoBar/bentoBar.tsx index 602cd05..3aa7365 100644 --- a/src/Game/Main/BentoBar/bentoBar.tsx +++ b/src/Game/Main/BentoBar/bentoBar.tsx @@ -48,14 +48,17 @@ const BentoBar = () => { }, [outsideRef]); return ( - <> +
    @@ -71,7 +74,7 @@ const BentoBar = () => { <> )} - +
    ); }; diff --git a/src/Game/Main/BentoBar/bentoStyle.ts b/src/Game/Main/BentoBar/bentoStyle.ts index 913e446..a22da02 100644 --- a/src/Game/Main/BentoBar/bentoStyle.ts +++ b/src/Game/Main/BentoBar/bentoStyle.ts @@ -2,18 +2,18 @@ import styled, { keyframes } from "styled-components"; import { Colors } from "../../../Styles/Colors"; export const Restart = styled.div` - display: flex; - width: 90px; - height: 40px; - border: 1px solid #615efc; - border-radius: 20px; - font-size: 12px; - align-items: center; - justify-content: center; - margin-bottom: 0.5rem; - box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px; - background-color: white; - color: black; + display: flex; + width: 90px; + height: 40px; + border: 1px solid #615efc; + border-radius: 20px; + font-size: 12px; + align-items: center; + justify-content: center; + margin-bottom: 0.5rem; + box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px; + background-color: white; + color: black; `; const fadeIn = keyframes` @@ -28,27 +28,28 @@ const fadeIn = keyframes` `; export const ListBox = styled.div` - position: absolute; - bottom: 50px; - width: 100px; - height: 150px; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin-top: 0.5rem; - animation: ${fadeIn} 0.5s ease-out forwards; - opacity: 0; + position: absolute; + bottom: 50px; + width: 100px; + height: 150px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-top: 0.5rem; + animation: ${fadeIn} 0.5s ease-out forwards; + opacity: 0; `; export const IconDiv = styled.div` - border-radius: 25px; - width: 50px; - height: 50px; - position: relative; - display: flex; - justify-content: center; - align-items: center; - color: ${Colors.main}; - box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; + border-radius: 25px; + width: 50px; + height: 50px; + position: relative; + display: flex; + justify-content: center; + align-items: center; + color: ${Colors.main}; + background-color: white; + box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; `; diff --git a/src/Game/Shop/exchangeStoreMain.tsx b/src/Game/Shop/exchangeStoreMain.tsx index a733384..fa25e86 100644 --- a/src/Game/Shop/exchangeStoreMain.tsx +++ b/src/Game/Shop/exchangeStoreMain.tsx @@ -4,7 +4,6 @@ import styled from "styled-components"; import StockItem from "../../Component/Dropdown/gameDropdown"; import { useLocation } from "react-router-dom"; import { formatPrice } from "../../util/gameUtil"; -import HintShop from "./hintshop"; const Container = styled.div` width: 500px; diff --git a/src/Game/Shop/hintshop.tsx b/src/Game/Shop/hintshop.tsx deleted file mode 100644 index 739c8f9..0000000 --- a/src/Game/Shop/hintshop.tsx +++ /dev/null @@ -1,270 +0,0 @@ -import { useState } from "react"; -import { ShopProps } from "./shop"; -import { usePurchaseStore } from "../../store/hintStore"; -import { useLocation, useNavigate } from "react-router-dom"; -import { Ingredient, initialTabs as tabs } from "./ingredient"; -import { useStock } from "../../store/stockContext"; -import swal from "sweetalert"; -import Button from "../../Component/Button/button"; -import * as S from "./shopStyle"; -import axios from "axios"; -import { motion, AnimatePresence } from "framer-motion"; - -const HintShop: React.FC = ({ - selectedStock, - budget, - setBudget, -}) => { - const [selectedTab, setSelectedTab] = useState(tabs[0]); - const [hint, setHint] = useState<{ [level: string]: string | null }>({ - 1: null, - 2: null, - 3: null, - }); // 힌트 상태로 뉴스 표시 여부 관리 - const purchaseComplete = usePurchaseStore((state) => state.purchaseComplete); // 단계별 구매 상태 - const setPurchaseComplete = usePurchaseStore( - (state) => state.setPurchaseComplete - ); - - const location = useLocation(); - const year = location.pathname.split("/")[3]; - const { stockData } = useStock(); - const navigate = useNavigate(); - - const selectedStockData = stockData?.find( - (stock) => stock.stockId === selectedStock - ); - - function handleGame() { - navigate(`/game/play/${year}`); - } - - const onSubmitHandler = async () => { - if (!selectedStock) { - swal({ - icon: "error", - title: "종목을 선택해주세요!", - }); - return; - } - - if (budget < parseInt(selectedTab.price.replace(/[^\d]/g, ""), 10)) { - swal({ - icon: "error", - title: "잔액이 부족합니다.", - }); - return; - } - - // 해당 단계가 이미 전역 상태에서 구매되었는지 확인 - if (purchaseComplete[selectedStock]?.[selectedTab.level]) { - swal({ - icon: "error", - title: "이 단계의 정보는 이미 구매하였습니다.", - }); - return; - } - - try { - const res = await axios.get( - `${process.env.REACT_APP_API_URL}/v1/game/hint`, - { - params: { - stockId: selectedStock, - hintLevel: selectedTab.id, - }, - withCredentials: true, - } - ); - if (res.status === 200) { - swal({ - icon: "success", - title: "구매가 완료되었습니다.", - }); - setHint(res.data.hint); - setBudget( - budget - parseInt(selectedTab.price.replace(/[^\d]/g, ""), 10) - ); - setPurchaseComplete(selectedStock, selectedTab.level); // 해당 단계 구매 상태 없데이트 - } - } catch (error) { - console.error("server Error : ", error); - } - }; - - return ( - <> - - - - {tabs.map((item) => ( - setSelectedTab(item)} - > - {`${item.icon} ${item.label}`} - {item === selectedTab ? ( - - ) : null} - - ))} - - - - - - {selectedTab && ( - <> - {/* 해당 단게의 힌트가 있으면 뉴스를 표시 */} - {hint[selectedTab.level] ? ( -
    -
    -

    Skrr News

    -
    -
    -
    -

    - {selectedStockData ? selectedStockData.name : ""}{" "} - {""} - {selectedTab.level} -

    -

    - {year} -

    -
    -
    -

    - {hint[selectedTab.level]} -

    -
    -
    - -
    - ) : ( - // 구매 가능한 상태 표시 -
    -

    - {selectedTab.icon} {selectedTab.level} 정보 -

    -

    - {year}년{" "} - {selectedStockData ? selectedStockData.name : ""}의 - 정보는 {selectedTab.price}원 입니다. -

    -

    - 구매하시겠습니까? -

    -
    - -
    - -
    -
    - )} - - )} -
    -
    -
    -
    - - ); -}; - -export default HintShop; diff --git a/src/Game/Shop/shop.tsx b/src/Game/Shop/shop.tsx index 4ae2e52..243bb96 100644 --- a/src/Game/Shop/shop.tsx +++ b/src/Game/Shop/shop.tsx @@ -9,7 +9,6 @@ import { Ingredient } from "./ingredient"; import swal from "sweetalert"; import { useStock } from "../../store/stockContext"; import { useHintStore, usePurchaseStore } from "../../store/hintStore"; -import ModalOpen from "../../Component/Modal/modal"; export interface ShopProps { selectedStock: number | null; @@ -40,17 +39,6 @@ const Shop: React.FC = ({ selectedStock, budget, setBudget }) => { (stock) => stock.stockId === selectedStock ); - const [isOpen, setIsOpen] = useState(false); - - const handleCancel = () => { - setIsOpen(false); - }; - - const handleConfirm = () => { - setIsOpen(false); - navigate(`/game/play/${year}`); - }; - const handleGame = () => { // setIsOpen(true); navigate(`/game/play/${year}`); @@ -68,15 +56,6 @@ const Shop: React.FC = ({ selectedStock, budget, setBudget }) => { const savedHint = purchaseHints[selectedStock][selectedTab.level]?.hintData; - // console.log( - // "Saved Hint for Stock", - // selectedStock, - // "Level", - // selectedTab.level, - // ":", - // savedHint - // ); - // 해당 종목과 레벨에 맞는 힌트만 표시 // if (purchaseComplete[selectedStock]?.[selectedTab.level]) { if (savedHint) { @@ -90,10 +69,6 @@ const Shop: React.FC = ({ selectedStock, budget, setBudget }) => { // } }, [purchaseHints, selectedStock, selectedTab.level, purchaseComplete]); - // useEffect(() => { - // console.log("current hint state: ", hint); - // }, [hint]); - //구매 요청 처리 const onSubmitHandler = async (data: Ingredient) => { if (!selectedStock) { @@ -153,7 +128,8 @@ const Shop: React.FC = ({ selectedStock, budget, setBudget }) => { if (error.response && error.response.status === 400) { swal({ icon: "error", - title: "해당 단계의 힌트는 이미 구매하였습니다.", + title: "Oops...", + text: "해당 단계의 힌트는 이미 구매하였습니다.", }); } else { console.error("server Error : ", error); diff --git a/src/Pages/game/gameStocks.tsx b/src/Pages/game/gameStocks.tsx index f29bfa6..8b06b0c 100644 --- a/src/Pages/game/gameStocks.tsx +++ b/src/Pages/game/gameStocks.tsx @@ -35,7 +35,7 @@ const GameStocks = () => { ) : (

    데이터가 없습니다.

    )} - + {/* */} ); }; diff --git a/src/Pages/game/rank.tsx b/src/Pages/game/rank.tsx index 1a17210..9785756 100644 --- a/src/Pages/game/rank.tsx +++ b/src/Pages/game/rank.tsx @@ -44,7 +44,7 @@ const Rank = () => {

    수익률

    - + {/* */} ); }; diff --git a/src/Pages/game/totalResult.tsx b/src/Pages/game/totalResult.tsx index d0ca08b..3e3bbe5 100644 --- a/src/Pages/game/totalResult.tsx +++ b/src/Pages/game/totalResult.tsx @@ -159,7 +159,7 @@ const TotalResult = () => { nav("/game/gameStocks"); }} /> - + {/* */} ); };