From 7764e4d558e1eb06c43d468bf71fdc57d30859b1 Mon Sep 17 00:00:00 2001 From: novice1993 Date: Mon, 4 Sep 2023 02:34:51 +0900 Subject: [PATCH] =?UTF-8?q?[Feat]=20=EC=A3=BC=EA=B0=80=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EB=B0=8F=20=EB=B3=80=EA=B2=BD=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 주가 선택 및 변경 기능 일부 구현 - 지정가/시장가 변환 관련 기능 구현 예정 Issues 12 --- .../StockOrderSection/PriceSetting.tsx | 102 +++++++++++++++--- .../StockOrderSection/StockOrderBtn.tsx | 1 + .../StockOrderSection/StockOrderSetting.tsx | 13 ++- .../StockOrderSection/StockPrice.tsx | 47 ++++---- .../components/StockOrderSection/dummyData.ts | 3 +- client/src/models/stateProps.ts | 2 + client/src/reducer/StockOrderPrice-Reducer.ts | 26 +++++ client/src/reducer/StockPriceType-Reducer.ts | 15 +++ client/src/store/config.ts | 4 + 9 files changed, 165 insertions(+), 48 deletions(-) create mode 100644 client/src/reducer/StockOrderPrice-Reducer.ts create mode 100644 client/src/reducer/StockPriceType-Reducer.ts diff --git a/client/src/components/StockOrderSection/PriceSetting.tsx b/client/src/components/StockOrderSection/PriceSetting.tsx index 0ead4c64..98a01aaa 100644 --- a/client/src/components/StockOrderSection/PriceSetting.tsx +++ b/client/src/components/StockOrderSection/PriceSetting.tsx @@ -1,24 +1,60 @@ +import { useSelector, useDispatch } from "react-redux"; import { styled } from "styled-components"; +import { setSpecifiedPrice, setMarketPrice } from "../../reducer/stockPriceType-Reducer"; +import { plusStockOrderPrice, minusStockOrderPrice } from "../../reducer/StockOrderPrice-Reducer"; +import { StateProps } from "../../models/stateProps"; const priceSettingTitle: string = "가격"; const specifiedPriceBtnText: string = "지정가"; const marketPriceBtnText: string = "시장가"; +const unitText: string = "원"; const PriceSetting = () => { + const priceType = useSelector((state: StateProps) => state.stockPriceType); + const orderPrice = useSelector((state: StateProps) => state.stockOrderPrice); + const dispatch = useDispatch(); + + // 시장가, 지정가 변경 + const handleSetSepcifiedPrice = () => { + dispatch(setSpecifiedPrice()); + }; + + const handleSetMarketPrice = () => { + dispatch(setMarketPrice()); + }; + + // 거래가 증가/감소 + const handlePlusOrderPrice = () => { + dispatch(plusStockOrderPrice(10)); + }; + + const handleMinusOrderPrice = () => { + dispatch(minusStockOrderPrice(10)); + }; + return ( {priceSettingTitle} - {specifiedPriceBtnText} - {marketPriceBtnText} + + {specifiedPriceBtnText} + + + {marketPriceBtnText} + - + + {unitText} - - + + @@ -27,6 +63,12 @@ const PriceSetting = () => { export default PriceSetting; +// type 정의 +interface PriceTypeProps { + priceType: boolean; +} + +// component 생성 const Container = styled.div` width: 100%; margin-top: 16px; @@ -47,26 +89,40 @@ const Title = styled.div` `; const ButtonContainer = styled.div` - width: 105px; - height: 27px; - background-color: #ded9d9; + position: relative; + width: 100px; + height: 25px; + background-color: #f2f2f2; border-radius: 0.3rem; display: flex; flex-direction: row; justify-content: center; align-items: center; + gap: 2px; `; -const SepcifiedPriceBtn = styled.button` - width: 50px; - height: 23px; - padding: 4px; +const SepcifiedPriceBtn = styled.button` + width: 46px; + height: 21px; border: none; - background-color: #ded9d9; + box-shadow: ${(props) => !props.priceType && "0.7px 0.7px 3px rgba(0, 0, 0, 0.4);"}; + border-radius: 0.3rem; + background-color: ${(props) => (props.priceType ? "f2f2f2" : "white")}; + color: ${(props) => (props.priceType ? "#999999" : "black")}; + font-size: 13px; `; -const MarketPriceBtn = styled(SepcifiedPriceBtn)``; +const MarketPriceBtn = styled.button` + width: 46px; + height: 21px; + border: none; + border-radius: 0.3rem; + box-shadow: ${(props) => props.priceType && "0.7px 0.7px 3px rgba(0, 0, 0, 0.4);"}; + background-color: ${(props) => (props.priceType ? "white" : "f2f2f2")}; + color: ${(props) => (props.priceType ? "black" : "#999999")}; + font-size: 13px; +`; const PriceSettingBox = styled.div` display: flex; @@ -79,6 +135,24 @@ const PriceController = styled.input` border: 1px solid darkgray; border-right: none; border-radius: 0.2rem 0 0 0.2rem; + font-size: 15px; + font-weight: 500; + text-align: right; + padding-bottom: 3px; +`; + +const UnitContent = styled.div` + height: 30px; + color: #999999; + font-size: 13px; + font-weight: 400; + display: flex; + justify-content: center; + align-items: center; + padding-right: 8px; + border-top: 1px solid darkgray; + border-bottom: 1px solid darkgray; + background-color: #ffffff; `; const DirectionBox = styled.div` diff --git a/client/src/components/StockOrderSection/StockOrderBtn.tsx b/client/src/components/StockOrderSection/StockOrderBtn.tsx index 725ef6db..394fed40 100644 --- a/client/src/components/StockOrderSection/StockOrderBtn.tsx +++ b/client/src/components/StockOrderSection/StockOrderBtn.tsx @@ -84,6 +84,7 @@ const OrderBtn = styled.button` border: none; border-radius: 0.25rem; background-color: ${(props) => (props.ordertype ? "#2679ed" : "#e22926")}; + transition: background-color 0.5s; color: #ffffff; font-weight: 400; `; diff --git a/client/src/components/StockOrderSection/StockOrderSetting.tsx b/client/src/components/StockOrderSection/StockOrderSetting.tsx index cff36549..52ec57d1 100644 --- a/client/src/components/StockOrderSection/StockOrderSetting.tsx +++ b/client/src/components/StockOrderSection/StockOrderSetting.tsx @@ -33,7 +33,7 @@ const StockOrderSetting = () => { {orderType02} - + @@ -43,7 +43,7 @@ const StockOrderSetting = () => { export default StockOrderSetting; -const TypeDividingLine = () => { +const OrderTypeDividingLine = () => { const stockOrderType = useSelector((state: StateProps) => state.stockOrderType); return ( @@ -63,9 +63,10 @@ const Container = styled.div` const OrderType = styled.div` width: 100%; - height: 32px; + height: 31px; display: flex; flex-direction: row; + color: #9999; `; const Buying = styled.div` @@ -76,6 +77,7 @@ const Buying = styled.div` height: 31px; font-size: 14px; color: ${(props) => !props.ordertype && "#e22926"}; + transition: color 0.5s; `; const Selling = styled.div` @@ -86,6 +88,7 @@ const Selling = styled.div` height: 31px; font-size: 14px; color: ${(props) => props.ordertype && "#2679ed"}; + transition: color 0.5s; `; const DividingContainer = styled.div` @@ -96,11 +99,11 @@ const DefaultLine = styled.div` transform: translateX(${(props) => (props.ordertype ? "50%" : "0")}); transition: transform 0.3s ease-in-out; width: 100%; - height: 1.2px; + height: 2px; `; const DivdingLine = styled.div` width: 50%; - height: 1.2px; + height: 2px; background-color: ${(props) => (props.ordertype ? "#2679ed" : "#e22926")}; `; diff --git a/client/src/components/StockOrderSection/StockPrice.tsx b/client/src/components/StockOrderSection/StockPrice.tsx index 89fa0251..19c15345 100644 --- a/client/src/components/StockOrderSection/StockPrice.tsx +++ b/client/src/components/StockOrderSection/StockPrice.tsx @@ -1,5 +1,8 @@ +import { useSelector, useDispatch } from "react-redux"; import { useRef, useEffect } from "react"; import { styled } from "styled-components"; +import { setStockOrderPrice } from "../../reducer/StockOrderPrice-Reducer"; +import { StateProps } from "../../models/stateProps"; // dummyData import { dummyPrice } from "./dummyData"; @@ -14,13 +17,7 @@ const StockPrice = () => { {dummyPrice.map((item, idx) => ( - + ))} @@ -37,6 +34,12 @@ const PriceInfo = (props: PriceInfoProps) => { const { index, price, changeRate, volume } = props; const ref = useRef(null); + const stockOrderPrice = useSelector((state: StateProps) => state.stockOrderPrice); + const dispatch = useDispatch(); + const handleSetOrderPrice = () => { + dispatch(setStockOrderPrice(price)); + }; + const changeRateText01: string = changeRate > 0 ? "+" : ""; const changeRateText02: string = "%"; @@ -48,7 +51,7 @@ const PriceInfo = (props: PriceInfoProps) => { if (index === 10) { return ( - +
{price}
@@ -59,19 +62,14 @@ const PriceInfo = (props: PriceInfoProps) => {
{volume}
- +
); } return ( - +
{price}
@@ -82,12 +80,7 @@ const PriceInfo = (props: PriceInfoProps) => {
{volume}
- +
); @@ -103,6 +96,8 @@ interface PriceInfoProps { interface InfoContainerProps { index: number; + price: number; + orderPrice: number; } interface VolumeProps { @@ -147,6 +142,7 @@ const InfoContainer = styled.div` margin-bottom: 2px; background-color: ${(props) => (props.index > 9 ? "#FDE8E7" : "#E7F0FD")}; border: ${(props) => (props.index === 10 ? "1px solid #2F4F4F" : "none")}; + border-left: ${(props) => (props.price === props.orderPrice ? "3px solid red" : props.index > 9 ? "3px solid #FDE8E7" : "3px solid #E7F0FD")}; display: flex; flex-direction: row; `; @@ -154,7 +150,7 @@ const InfoContainer = styled.div` const Price = styled.div` width: 50%; display: flex; - padding-right: 8px; + padding-right: 11px; flex-direction: column; align-items: flex-end; @@ -190,12 +186,7 @@ const Volume = styled.div` `; const VolumePercentge = styled.span` - width: ${(props) => - (props.volume / - (props.index < 10 - ? props.upperPriceVolumeSum - : props.lowerPriceVolumeSum)) * - 100}%; + width: ${(props) => (props.volume / (props.index < 10 ? props.upperPriceVolumeSum : props.lowerPriceVolumeSum)) * 100}%; height: 2px; background-color: ${(props) => (props.index < 10 ? "#2679ed" : "#e22926")}; diff --git a/client/src/components/StockOrderSection/dummyData.ts b/client/src/components/StockOrderSection/dummyData.ts index 87285c75..285cf917 100644 --- a/client/src/components/StockOrderSection/dummyData.ts +++ b/client/src/components/StockOrderSection/dummyData.ts @@ -1,5 +1,6 @@ // dummyData export const dummyPrice: dummyProps[] = [ + { price: 200, changeRate: 90, volume: 300 }, { price: 190, changeRate: 90, volume: 500 }, { price: 180, changeRate: 80, volume: 120 }, { price: 170, changeRate: 70, volume: 78 }, @@ -19,8 +20,8 @@ export const dummyPrice: dummyProps[] = [ { price: 30, changeRate: -70, volume: 1100 }, { price: 20, changeRate: -80, volume: 800 }, { price: 10, changeRate: -90, volume: 500 }, - { price: 5, changeRate: -95, volume: 800 }, ]; +export const standardPrice = 100; export const upperPriceVolumeSum = 1000; export const lowerPriceVolumeSum = 2000; export const availableMoney = 10000000; diff --git a/client/src/models/stateProps.ts b/client/src/models/stateProps.ts index 7ea6ad4b..4d308885 100644 --- a/client/src/models/stateProps.ts +++ b/client/src/models/stateProps.ts @@ -1,3 +1,5 @@ export interface StateProps { stockOrderType: boolean; + stockPriceType: boolean; + stockOrderPrice: number; } diff --git a/client/src/reducer/StockOrderPrice-Reducer.ts b/client/src/reducer/StockOrderPrice-Reducer.ts new file mode 100644 index 00000000..790eff3a --- /dev/null +++ b/client/src/reducer/StockOrderPrice-Reducer.ts @@ -0,0 +1,26 @@ +import { createSlice } from "@reduxjs/toolkit"; +import { dummyPrice } from "../components/StockOrderSection/dummyData"; + +const initialState: number = dummyPrice[10].price; + +const stockPriceOrderSlice = createSlice({ + name: "stockOrderPrice", + initialState: initialState, + reducers: { + setStockOrderPrice: (state, action) => { + return action.payload; + }, + plusStockOrderPrice: (state, action) => { + return state + action.payload; + }, + minusStockOrderPrice: (state, action) => { + if (state > action.payload) { + return state - action.payload; + } + return state; + }, + }, +}); + +export const { setStockOrderPrice, plusStockOrderPrice, minusStockOrderPrice } = stockPriceOrderSlice.actions; +export const stockOrderPriceReducer = stockPriceOrderSlice.reducer; diff --git a/client/src/reducer/StockPriceType-Reducer.ts b/client/src/reducer/StockPriceType-Reducer.ts new file mode 100644 index 00000000..1bb2062a --- /dev/null +++ b/client/src/reducer/StockPriceType-Reducer.ts @@ -0,0 +1,15 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const initialState: boolean = false; + +const stockPriceTypeSlice = createSlice({ + name: "stockPriceType", + initialState: initialState, + reducers: { + setSpecifiedPrice: () => false, + setMarketPrice: () => true, + }, +}); + +export const { setSpecifiedPrice, setMarketPrice } = stockPriceTypeSlice.actions; +export const stockPriceTypeReducer = stockPriceTypeSlice.reducer; diff --git a/client/src/store/config.ts b/client/src/store/config.ts index 622cb788..2a5b7c14 100644 --- a/client/src/store/config.ts +++ b/client/src/store/config.ts @@ -1,9 +1,13 @@ import { configureStore } from "@reduxjs/toolkit"; import { stockOrderTypeReducer } from "../reducer/StockOrderType-Reducer"; +import { stockPriceTypeReducer } from "../reducer/stockPriceType-Reducer"; +import { stockOrderPriceReducer } from "../reducer/StockOrderPrice-Reducer"; const store = configureStore({ reducer: { stockOrderType: stockOrderTypeReducer, + stockPriceType: stockPriceTypeReducer, + stockOrderPrice: stockOrderPriceReducer, }, });