From 8203e04fe63567328b421a3d41b1f1eda5599451 Mon Sep 17 00:00:00 2001 From: novice1993 Date: Fri, 1 Sep 2023 01:25:48 +0900 Subject: [PATCH 01/10] =?UTF-8?q?[Feat]=20=EC=A3=BC=EC=8B=9D=EC=A3=BC?= =?UTF-8?q?=EB=AC=B8=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=95=84=EC=9B=83=20=EC=9D=BC=EB=B6=80=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 주식주문 컴포넌트 (매수/매도 버튼 클릭시 렌더링 되는 화면) 레이아웃 일부 구현 - 상단바 구현 Issues #12 --- client/src/components/StockOrder/Index.tsx | 20 +++++++++ client/src/components/StockOrder/UpperBar.tsx | 42 +++++++++++++++++++ client/src/page/MainPage.tsx | 21 +++++----- 3 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 client/src/components/StockOrder/Index.tsx create mode 100644 client/src/components/StockOrder/UpperBar.tsx diff --git a/client/src/components/StockOrder/Index.tsx b/client/src/components/StockOrder/Index.tsx new file mode 100644 index 00000000..9d5657fe --- /dev/null +++ b/client/src/components/StockOrder/Index.tsx @@ -0,0 +1,20 @@ +import { styled } from "styled-components"; + +import UpperBar from "./UpperBar"; + +const StockOrder = () => { + return ( + + + + ); +}; + +export default StockOrder; + +const Container = styled.div` + flex: 3.3 0 0; + min-width: 400px; + height: 100%; + border-left: 1px solid #2f4f4f; +`; diff --git a/client/src/components/StockOrder/UpperBar.tsx b/client/src/components/StockOrder/UpperBar.tsx new file mode 100644 index 00000000..afe3e3b4 --- /dev/null +++ b/client/src/components/StockOrder/UpperBar.tsx @@ -0,0 +1,42 @@ +import { styled } from "styled-components"; + +const titleText: string = "주식주문"; + +const UpperBar = () => { + return ( + + {titleText} + + + ); +}; + +export default UpperBar; + +const Container = styled.div` + position: relative; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + width: 100%; + height: 43px; + border-bottom: 1px solid black; +`; + +const Title = styled.div` + font-size: 17px; + font-weight: 450; + color: #1c1c1c; +`; + +const CloseBtn = styled.button` + position: absolute; + right: 10px; + width: 28px; + height: 100%; + border: none; + font-size: 20px; + color: #525252; + background-color: #ffff; +`; diff --git a/client/src/page/MainPage.tsx b/client/src/page/MainPage.tsx index cc799abc..42508741 100644 --- a/client/src/page/MainPage.tsx +++ b/client/src/page/MainPage.tsx @@ -1,16 +1,17 @@ import { styled } from "styled-components"; -import LogoutHeader from "../components/Headers/LogoutHeader" -import LoginHeader from "../components/Headers/LoginHeader" + +import LoginHeader from "../components/Headers/LoginHeader"; +import StockOrder from "../components/StockOrder/Index"; const MainPage = () => { return ( -
- + + {/* */}
); @@ -38,12 +39,12 @@ const LeftSection = styled.section` border: 1px solid black; `; -const RightSection = styled.section` - flex: 3.3 0 0; - min-width: 400px; - height: 100%; - border: 1px solid black; -`; +// const RightSection = styled.section` +// flex: 3.3 0 0; +// min-width: 400px; +// height: 100%; +// border: 1px solid black; +// `; const CentralSection = styled.section` flex: 6.7 0 0; From 679c2b7ee01560cc8f9128f88e3bc3d764a80c23 Mon Sep 17 00:00:00 2001 From: novice1993 Date: Fri, 1 Sep 2023 02:28:42 +0900 Subject: [PATCH 02/10] =?UTF-8?q?[Feat]=20=EC=A3=BC=EC=8B=9D=EC=A3=BC?= =?UTF-8?q?=EB=AC=B8=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=83=81?= =?UTF-8?q?=EB=8B=A8=20=EC=A2=85=EB=AA=A9=EB=AA=85=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 주식주문 컴포넌트 상단 종목명 관련 레이아웃 구현 Issues #12 --- .../src/asset/CentralSectionMenu-dummyImg.png | Bin 0 -> 4955 bytes client/src/asset/README.md | 0 client/src/components/StockOrder/Index.tsx | 8 ++- .../src/components/StockOrder/StockName.tsx | 58 ++++++++++++++++++ client/src/components/StockOrder/UpperBar.tsx | 2 +- 5 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 client/src/asset/CentralSectionMenu-dummyImg.png delete mode 100644 client/src/asset/README.md create mode 100644 client/src/components/StockOrder/StockName.tsx diff --git a/client/src/asset/CentralSectionMenu-dummyImg.png b/client/src/asset/CentralSectionMenu-dummyImg.png new file mode 100644 index 0000000000000000000000000000000000000000..808ee025441f8840110598e337633b7e2a93fc51 GIT binary patch literal 4955 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 literal 0 HcmV?d00001 diff --git a/client/src/asset/README.md b/client/src/asset/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/client/src/components/StockOrder/Index.tsx b/client/src/components/StockOrder/Index.tsx index 9d5657fe..a005fac6 100644 --- a/client/src/components/StockOrder/Index.tsx +++ b/client/src/components/StockOrder/Index.tsx @@ -1,18 +1,24 @@ import { styled } from "styled-components"; import UpperBar from "./UpperBar"; +import StockName from "./StockName"; const StockOrder = () => { return ( + ); }; export default StockOrder; -const Container = styled.div` +const Container = styled.aside` + position: fixed; + right: 0px; + transition: right 0.3s ease-in-out; + flex: 3.3 0 0; min-width: 400px; height: 100%; diff --git a/client/src/components/StockOrder/StockName.tsx b/client/src/components/StockOrder/StockName.tsx new file mode 100644 index 00000000..8b8b75cc --- /dev/null +++ b/client/src/components/StockOrder/StockName.tsx @@ -0,0 +1,58 @@ +import { styled } from "styled-components"; + +// dummyData +import logoImg from "../../asset/CentralSectionMenu-dummyImg.png"; +const corpName: string = "카카오"; +const stockCode: string = "035720"; +const marketType: string = "코스피"; + +const StockName = () => { + return ( + + + + {corpName} + + {stockCode} {marketType} + + + + ); +}; + +export default StockName; + +const Container = styled.section` + width: 100%; + height: 64px; + display: flex; + flex-direction: row; + align-items: center; + padding-top: 16px; + padding-bottom: 8px; + padding-left: 16px; + gap: 9px; + border-bottom: 1px solid black; +`; + +const CorpLogo = styled.img` + width: 28px; + height: 28px; + border-radius: 50%; +`; + +const NameContainer = styled.div` + height: 40px; + display: flex; + flex-direction: column; +`; + +const CorpName = styled.div` + font-size: 16px; + font-weight: 500; + color: #1c1c1c; +`; +const StockCode = styled.div` + font-size: 14px; + color: #999999; +`; diff --git a/client/src/components/StockOrder/UpperBar.tsx b/client/src/components/StockOrder/UpperBar.tsx index afe3e3b4..ece088fc 100644 --- a/client/src/components/StockOrder/UpperBar.tsx +++ b/client/src/components/StockOrder/UpperBar.tsx @@ -24,7 +24,7 @@ const Container = styled.div` border-bottom: 1px solid black; `; -const Title = styled.div` +const Title = styled.h2` font-size: 17px; font-weight: 450; color: #1c1c1c; From 2e77a5190473339f1826fc01ff74823e1f1fc00e Mon Sep 17 00:00:00 2001 From: novice1993 Date: Fri, 1 Sep 2023 03:54:52 +0900 Subject: [PATCH 03/10] =?UTF-8?q?[Feat]=20=EC=A3=BC=EA=B0=80=20=EB=B0=8F?= =?UTF-8?q?=20=EC=A3=BC=EB=AC=B8=EC=84=A4=EC=A0=95=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20=EC=9D=BC=EB=B6=80=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 주가 및 주문설정 관련 전체 레이아웃 설정 - 레이아웃 내부에 들어가는 요소 구현 중 Issues #12 --- .../Index.tsx | 13 +++++- .../StockOrderSection/OrderRequest.tsx | 23 +++++++++++ .../StockOrderSection/OrderResult.tsx | 12 ++++++ .../StockName.tsx | 0 .../StockOrderSection/StockOrderSetting.tsx | 41 +++++++++++++++++++ .../StockOrderSection/StockPriceInfo.tsx | 37 +++++++++++++++++ .../UpperBar.tsx | 0 client/src/page/MainPage.tsx | 4 +- 8 files changed, 126 insertions(+), 4 deletions(-) rename client/src/components/{StockOrder => StockOrderSection}/Index.tsx (58%) create mode 100644 client/src/components/StockOrderSection/OrderRequest.tsx create mode 100644 client/src/components/StockOrderSection/OrderResult.tsx rename client/src/components/{StockOrder => StockOrderSection}/StockName.tsx (100%) create mode 100644 client/src/components/StockOrderSection/StockOrderSetting.tsx create mode 100644 client/src/components/StockOrderSection/StockPriceInfo.tsx rename client/src/components/{StockOrder => StockOrderSection}/UpperBar.tsx (100%) diff --git a/client/src/components/StockOrder/Index.tsx b/client/src/components/StockOrderSection/Index.tsx similarity index 58% rename from client/src/components/StockOrder/Index.tsx rename to client/src/components/StockOrderSection/Index.tsx index a005fac6..c574f006 100644 --- a/client/src/components/StockOrder/Index.tsx +++ b/client/src/components/StockOrderSection/Index.tsx @@ -2,22 +2,31 @@ import { styled } from "styled-components"; import UpperBar from "./UpperBar"; import StockName from "./StockName"; +import OrderRequest from "./OrderRequest"; +import OrderResult from "./OrderResult"; -const StockOrder = () => { +const StockOrderSection = () => { return ( + + ); }; -export default StockOrder; +export default StockOrderSection; const Container = styled.aside` + // 우측 슬라이드 관련 설정 position: fixed; right: 0px; transition: right 0.3s ease-in-out; + // + + display: flex; + flex-direction: column; flex: 3.3 0 0; min-width: 400px; diff --git a/client/src/components/StockOrderSection/OrderRequest.tsx b/client/src/components/StockOrderSection/OrderRequest.tsx new file mode 100644 index 00000000..1d8c8550 --- /dev/null +++ b/client/src/components/StockOrderSection/OrderRequest.tsx @@ -0,0 +1,23 @@ +import { styled } from "styled-components"; + +import StockPriceInfo from "./StockPriceInfo"; +import StockOrderSetting from "./StockOrderSetting"; + +const OrderRequest = () => { + return ( + + + + + ); +}; + +export default OrderRequest; + +const Container = styled.div` + height: 414px; + border-bottom: 1px solid black; + + display: flex; + flex-direction: row; +`; diff --git a/client/src/components/StockOrderSection/OrderResult.tsx b/client/src/components/StockOrderSection/OrderResult.tsx new file mode 100644 index 00000000..c5c211ad --- /dev/null +++ b/client/src/components/StockOrderSection/OrderResult.tsx @@ -0,0 +1,12 @@ +import { styled } from "styled-components"; + +const OrderResult = () => { + return ; +}; + +export default OrderResult; + +const Container = styled.div` + flex: 1 0 0; + border-bottom: 1px solid black; +`; diff --git a/client/src/components/StockOrder/StockName.tsx b/client/src/components/StockOrderSection/StockName.tsx similarity index 100% rename from client/src/components/StockOrder/StockName.tsx rename to client/src/components/StockOrderSection/StockName.tsx diff --git a/client/src/components/StockOrderSection/StockOrderSetting.tsx b/client/src/components/StockOrderSection/StockOrderSetting.tsx new file mode 100644 index 00000000..9fd60f5b --- /dev/null +++ b/client/src/components/StockOrderSection/StockOrderSetting.tsx @@ -0,0 +1,41 @@ +import { styled } from "styled-components"; + +const orderType01: string = "매수"; +const orderType02: string = "매도"; + +const StockOrderSetting = () => { + return ( + + +
{orderType01}
+
{orderType02}
+
+
+ ); +}; + +export default StockOrderSetting; + +const Container = styled.div` + width: 208px; + height: 100%; + border-left: 1px solid black; + border-right: 1px solid black; +`; + +const OrderType = styled.div` + width: 100%; + height: 32px; + display: flex; + flex-direction: row; + + & div { + flex: 1 0 0; + display: flex; + justify-content: center; + align-items: center; + height: 31px; + font-size: 14px; + border-bottom: 1px solid darkgray; + } +`; diff --git a/client/src/components/StockOrderSection/StockPriceInfo.tsx b/client/src/components/StockOrderSection/StockPriceInfo.tsx new file mode 100644 index 00000000..9a536345 --- /dev/null +++ b/client/src/components/StockOrderSection/StockPriceInfo.tsx @@ -0,0 +1,37 @@ +import { styled } from "styled-components"; + +const StockPriceInfo = () => { + return ( + + + + + + ); +}; + +export default StockPriceInfo; + +const Container = styled.div` + width: 160px; + height: 100%; + margin-right: 16px; + border-right: 1px solid black; +`; + +const HighFigure = styled.div` + width: 100%; + height: 32px; + border-bottom: 1px solid black; +`; + +const PriceInfo = styled.div` + width: 100%; + height: 348px; + border-bottom: 1px solid black; +`; + +const LowerFigure = styled.div` + width: 100%; + height: 32px; +`; diff --git a/client/src/components/StockOrder/UpperBar.tsx b/client/src/components/StockOrderSection/UpperBar.tsx similarity index 100% rename from client/src/components/StockOrder/UpperBar.tsx rename to client/src/components/StockOrderSection/UpperBar.tsx diff --git a/client/src/page/MainPage.tsx b/client/src/page/MainPage.tsx index 42508741..538cb41b 100644 --- a/client/src/page/MainPage.tsx +++ b/client/src/page/MainPage.tsx @@ -1,7 +1,7 @@ import { styled } from "styled-components"; import LoginHeader from "../components/Headers/LoginHeader"; -import StockOrder from "../components/StockOrder/Index"; +import StockOrderSection from "../components/StockOrderSection/Index"; const MainPage = () => { return ( @@ -10,7 +10,7 @@ const MainPage = () => {
- + {/* */}
From 323b525cfd0caf8445b7931bc25fa6b32bef9fad Mon Sep 17 00:00:00 2001 From: novice1993 Date: Fri, 1 Sep 2023 14:54:47 +0900 Subject: [PATCH 04/10] =?UTF-8?q?[Feat]=20=EC=A3=BC=EC=8B=9D=EC=A3=BC?= =?UTF-8?q?=EB=AC=B8=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20=ED=8B=80=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 주식주문 컴포넌트 전체 레이아웃 틀 구현 완료 - 세부적인 요소 및 디자인 추가 예정 Issues #12 --- .../components/StockOrderSection/Index.tsx | 4 +- .../StockOrderSection/OrderRequest.tsx | 4 +- .../StockOrderSection/OrderResult.tsx | 44 ++++++- .../StockOrderSection/PriceSetting.tsx | 93 ++++++++++++++ .../StockOrderSection/StockOrderBtn.tsx | 83 +++++++++++++ .../StockOrderSection/StockOrderSetting.tsx | 10 +- .../{StockPriceInfo.tsx => StockPrice.tsx} | 6 +- .../components/StockOrderSection/UpperBar.tsx | 4 +- .../StockOrderSection/VolumeSetteing.tsx | 115 ++++++++++++++++++ client/src/page/MainPage.tsx | 14 +-- 10 files changed, 357 insertions(+), 20 deletions(-) create mode 100644 client/src/components/StockOrderSection/PriceSetting.tsx create mode 100644 client/src/components/StockOrderSection/StockOrderBtn.tsx rename client/src/components/StockOrderSection/{StockPriceInfo.tsx => StockPrice.tsx} (87%) create mode 100644 client/src/components/StockOrderSection/VolumeSetteing.tsx diff --git a/client/src/components/StockOrderSection/Index.tsx b/client/src/components/StockOrderSection/Index.tsx index c574f006..2112a12d 100644 --- a/client/src/components/StockOrderSection/Index.tsx +++ b/client/src/components/StockOrderSection/Index.tsx @@ -5,6 +5,8 @@ import StockName from "./StockName"; import OrderRequest from "./OrderRequest"; import OrderResult from "./OrderResult"; +// test + const StockOrderSection = () => { return ( @@ -28,7 +30,7 @@ const Container = styled.aside` display: flex; flex-direction: column; - flex: 3.3 0 0; + width: 26%; min-width: 400px; height: 100%; border-left: 1px solid #2f4f4f; diff --git a/client/src/components/StockOrderSection/OrderRequest.tsx b/client/src/components/StockOrderSection/OrderRequest.tsx index 1d8c8550..ae80f801 100644 --- a/client/src/components/StockOrderSection/OrderRequest.tsx +++ b/client/src/components/StockOrderSection/OrderRequest.tsx @@ -1,12 +1,12 @@ import { styled } from "styled-components"; -import StockPriceInfo from "./StockPriceInfo"; +import StockPrice from "./StockPrice"; import StockOrderSetting from "./StockOrderSetting"; const OrderRequest = () => { return ( - + ); diff --git a/client/src/components/StockOrderSection/OrderResult.tsx b/client/src/components/StockOrderSection/OrderResult.tsx index c5c211ad..37a721c9 100644 --- a/client/src/components/StockOrderSection/OrderResult.tsx +++ b/client/src/components/StockOrderSection/OrderResult.tsx @@ -1,12 +1,52 @@ import { styled } from "styled-components"; +const titleText: string = "주문내역"; +const orderPendingTitle: string = "미체결"; +const orderPendingEmptyMessage: string = "미체결 내역이 없습니다"; + const OrderResult = () => { - return ; + return ( + + {titleText} + +
{orderPendingTitle}
+
{orderPendingEmptyMessage}
+
+
+ ); }; export default OrderResult; const Container = styled.div` flex: 1 0 0; - border-bottom: 1px solid black; + padding-top: 16px; + display: flex; + flex-direction: column; +`; + +const Title = styled.div` + font-size: 16px; + font-weight: 500; + padding-left: 16px; + padding-bottom: 16px; + /* border-bottom: 1px solid black; */ +`; + +const OrderPending = styled.div` + .orderPendingTitle { + padding-left: 16px; + margin-bottom: 8px; + } + + .emptyIndicator { + width: 100%; + height: 48px; + display: flex; + justify-content: center; + align-items: center; + font-size: 14px; + font-weight: 350; + color: #999999; + } `; diff --git a/client/src/components/StockOrderSection/PriceSetting.tsx b/client/src/components/StockOrderSection/PriceSetting.tsx new file mode 100644 index 00000000..5dfba289 --- /dev/null +++ b/client/src/components/StockOrderSection/PriceSetting.tsx @@ -0,0 +1,93 @@ +import { styled } from "styled-components"; + +const priceSettingTitle: string = "가격"; +const specifiedPriceBtnText: string = "지정가"; +const marketPriceBtnText: string = "시장가"; + +const PriceSetting = () => { + return ( + + + {priceSettingTitle} + + {specifiedPriceBtnText} + {marketPriceBtnText} + + + + + + + + + + + ); +}; + +export default PriceSetting; + +const Container = styled.div` + width: 100%; + margin-top: 16px; + margin-bottom: 32px; +`; + +const PriceCategoryBox = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + margin-bottom: 8px; +`; + +const Title = styled.div` + padding-left: 5px; + font-size: 13px; + color: #999999; +`; + +const ButtonContainer = styled.div` + width: 105px; + height: 27px; + background-color: #ded9d9; + border-radius: 0.3rem; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +`; + +const SepcifiedPriceBtn = styled.button` + width: 50px; + height: 23px; + padding: 4px; + border: none; + background-color: #ded9d9; + font-size: 13px; +`; + +const MarketPriceBtn = styled(SepcifiedPriceBtn)``; + +const PriceSettingBox = styled.div` + display: flex; + flex-direction: row; +`; + +const PriceController = styled.input` + flex: 1 0 0; + height: 30px; +`; + +const DirectionBox = styled.div` + display: flex; + flex-direction: column; + + & button { + width: 31px; + height: 15px; + display: flex; + justify-content: center; + align-items: center; + font-size: 10px; + } +`; diff --git a/client/src/components/StockOrderSection/StockOrderBtn.tsx b/client/src/components/StockOrderSection/StockOrderBtn.tsx new file mode 100644 index 00000000..a02d72b9 --- /dev/null +++ b/client/src/components/StockOrderSection/StockOrderBtn.tsx @@ -0,0 +1,83 @@ +import { styled } from "styled-components"; + +const availableMoneyText01: string = "최대"; +const availableMoneyText02: string = "원"; +const totalAmountText01: string = "주문총액"; +const totalAmountText02: string = "원"; +const orderBtnText: string = "매수"; + +// dummyData +const dummyMoney: string = "9,990,086"; +const dummyAmount: string = "0"; + +const StockOrderBtn = () => { + return ( + + + {availableMoneyText01} + {dummyMoney} + {availableMoneyText02} + + +
{totalAmountText01}
+
{dummyAmount}
+
{totalAmountText02}
+
+ {orderBtnText} +
+ ); +}; + +export default StockOrderBtn; + +const Container = styled.div``; + +const AvailableMoney = styled.div` + display: flex; + flex-direction: row; + justify-content: flex-end; + gap: 4px; + + & span { + font-size: 14px; + color: #999999; + } + + .availableMoney { + color: #ed2926; + } +`; + +const TotalAmount = styled.div` + display: flex; + flex-direction: row; + margin-top: 4px; + gap: 4px; + + & div { + font-size: 13px; + color: #999999; + display: flex; + align-items: center; + } + + .totalAmountText01 { + flex: 8 0 0; + } + + .totalAmount { + color: black; + font-size: 15.5px; + } +`; + +const OrderBtn = styled.button` + width: 100%; + height: 32px; + margin-top: 16px; + border: none; + border-radius: 0.25rem; + background-color: #ed2926; + color: #ffffff; + font-weight: 400; +`; diff --git a/client/src/components/StockOrderSection/StockOrderSetting.tsx b/client/src/components/StockOrderSection/StockOrderSetting.tsx index 9fd60f5b..4c1a04ad 100644 --- a/client/src/components/StockOrderSection/StockOrderSetting.tsx +++ b/client/src/components/StockOrderSection/StockOrderSetting.tsx @@ -1,4 +1,7 @@ import { styled } from "styled-components"; +import PriceSetting from "./PriceSetting"; +import VolumeSetting from "./VolumeSetteing"; +import StockOrderBtn from "./StockOrderBtn"; const orderType01: string = "매수"; const orderType02: string = "매도"; @@ -10,6 +13,9 @@ const StockOrderSetting = () => {
{orderType01}
{orderType02}
+ + +
); }; @@ -17,10 +23,8 @@ const StockOrderSetting = () => { export default StockOrderSetting; const Container = styled.div` - width: 208px; + width: 51%; height: 100%; - border-left: 1px solid black; - border-right: 1px solid black; `; const OrderType = styled.div` diff --git a/client/src/components/StockOrderSection/StockPriceInfo.tsx b/client/src/components/StockOrderSection/StockPrice.tsx similarity index 87% rename from client/src/components/StockOrderSection/StockPriceInfo.tsx rename to client/src/components/StockOrderSection/StockPrice.tsx index 9a536345..49690418 100644 --- a/client/src/components/StockOrderSection/StockPriceInfo.tsx +++ b/client/src/components/StockOrderSection/StockPrice.tsx @@ -1,6 +1,6 @@ import { styled } from "styled-components"; -const StockPriceInfo = () => { +const StockPrice = () => { return ( @@ -10,10 +10,10 @@ const StockPriceInfo = () => { ); }; -export default StockPriceInfo; +export default StockPrice; const Container = styled.div` - width: 160px; + width: 40%; height: 100%; margin-right: 16px; border-right: 1px solid black; diff --git a/client/src/components/StockOrderSection/UpperBar.tsx b/client/src/components/StockOrderSection/UpperBar.tsx index ece088fc..5e76d089 100644 --- a/client/src/components/StockOrderSection/UpperBar.tsx +++ b/client/src/components/StockOrderSection/UpperBar.tsx @@ -20,7 +20,7 @@ const Container = styled.div` justify-content: center; align-items: center; width: 100%; - height: 43px; + min-height: 43px; border-bottom: 1px solid black; `; @@ -34,7 +34,7 @@ const CloseBtn = styled.button` position: absolute; right: 10px; width: 28px; - height: 100%; + height: 95%; border: none; font-size: 20px; color: #525252; diff --git a/client/src/components/StockOrderSection/VolumeSetteing.tsx b/client/src/components/StockOrderSection/VolumeSetteing.tsx new file mode 100644 index 00000000..3e0a4579 --- /dev/null +++ b/client/src/components/StockOrderSection/VolumeSetteing.tsx @@ -0,0 +1,115 @@ +import { styled } from "styled-components"; + +const volumeSettingTitle: string = "수량"; +const maximumVolumeText01: string = "최대"; +const maximumVolumeText02: string = "주"; + +const percentageBtnText01: string = "10%"; +const percentageBtnText02: string = "25%"; +const percentageBtnText03: string = "50%"; +const percentageBtnText04: string = "100%"; + +// dummyData +const dummyMaximum: number = 203; + +const VolumeSetting = () => { + return ( + + + {volumeSettingTitle} + + {maximumVolumeText01} + {dummyMaximum} + {maximumVolumeText02} + + + + + + + + + + + + + + + + + ); +}; + +export default VolumeSetting; + +const Container = styled.div` + width: 100%; + margin-top: 16px; + margin-bottom: 46px; +`; + +const TitleContainer = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + margin-bottom: 8px; +`; + +const Title = styled.div` + padding-left: 5px; + font-size: 13px; + color: #999999; +`; + +const MaximumVolumeBox = styled.div` + display: flex; + flex-direction: row; + gap: 3px; + + & span { + font-size: 14px; + color: #999999; + } + + .maximumVolume { + color: #ed2926; + } +`; + +const VolumeSettingBox = styled.div` + display: flex; + flex-direction: row; +`; + +const VolumeController = styled.input` + flex: 1 0 0; + height: 30px; +`; + +const DirectionBox = styled.div` + display: flex; + flex-direction: column; + + & button { + width: 31px; + height: 15px; + display: flex; + justify-content: center; + align-items: center; + font-size: 10px; + } +`; + +const PercentageBox = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + margin-top: 8px; + + & button { + width: 46px; + height: 28px; + border: none; + border-radius: 0.2rem; + } +`; diff --git a/client/src/page/MainPage.tsx b/client/src/page/MainPage.tsx index 538cb41b..884ed941 100644 --- a/client/src/page/MainPage.tsx +++ b/client/src/page/MainPage.tsx @@ -11,7 +11,7 @@ const MainPage = () => { - {/* */} + ); @@ -39,12 +39,12 @@ const LeftSection = styled.section` border: 1px solid black; `; -// const RightSection = styled.section` -// flex: 3.3 0 0; -// min-width: 400px; -// height: 100%; -// border: 1px solid black; -// `; +export const RightSection = styled.section` + width: 26%; + min-width: 400px; + height: 100%; + border: 1px solid black; +`; const CentralSection = styled.section` flex: 6.7 0 0; From 7c156d7070a373be4afa080c76417c0c8156cccb Mon Sep 17 00:00:00 2001 From: novice1993 Date: Sat, 2 Sep 2023 03:09:57 +0900 Subject: [PATCH 05/10] =?UTF-8?q?[Design]=20=EC=9D=BC=EB=B6=80=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20CSS=20=EC=86=8D=EC=84=B1=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 가격 및 거래량 컨트롤러 관련 CSS 속성 변경 Issues #12 --- client/src/components/StockOrderSection/PriceSetting.tsx | 8 ++++++++ .../src/components/StockOrderSection/VolumeSetteing.tsx | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/client/src/components/StockOrderSection/PriceSetting.tsx b/client/src/components/StockOrderSection/PriceSetting.tsx index 5dfba289..ac719730 100644 --- a/client/src/components/StockOrderSection/PriceSetting.tsx +++ b/client/src/components/StockOrderSection/PriceSetting.tsx @@ -76,6 +76,8 @@ const PriceSettingBox = styled.div` const PriceController = styled.input` flex: 1 0 0; height: 30px; + border: 1px solid darkgray; + border-right: none; `; const DirectionBox = styled.div` @@ -89,5 +91,11 @@ const DirectionBox = styled.div` justify-content: center; align-items: center; font-size: 10px; + border: 1px solid darkgray; + border-radius: 0%; + + &.PriceUp { + border-bottom: none; + } } `; diff --git a/client/src/components/StockOrderSection/VolumeSetteing.tsx b/client/src/components/StockOrderSection/VolumeSetteing.tsx index 3e0a4579..dee00d95 100644 --- a/client/src/components/StockOrderSection/VolumeSetteing.tsx +++ b/client/src/components/StockOrderSection/VolumeSetteing.tsx @@ -84,6 +84,8 @@ const VolumeSettingBox = styled.div` const VolumeController = styled.input` flex: 1 0 0; height: 30px; + border: 1px solid darkgray; + border-right: none; `; const DirectionBox = styled.div` @@ -97,6 +99,12 @@ const DirectionBox = styled.div` justify-content: center; align-items: center; font-size: 10px; + border: 1px solid darkgray; + border-radius: 0%; + + &.VolumeUp { + border-bottom: none; + } } `; From cd6f9a47cb215f3c0609c486e123c79072989aaa Mon Sep 17 00:00:00 2001 From: novice1993 Date: Sat, 2 Sep 2023 03:15:51 +0900 Subject: [PATCH 06/10] =?UTF-8?q?[Design]=20=EC=9D=BC=EB=B6=80=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20CSS=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 가격/거래량 컨트롤러 관련 컴포넌트 CSS 수정 Issues #12 --- client/src/components/StockOrderSection/PriceSetting.tsx | 6 ++++++ client/src/components/StockOrderSection/VolumeSetteing.tsx | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/client/src/components/StockOrderSection/PriceSetting.tsx b/client/src/components/StockOrderSection/PriceSetting.tsx index ac719730..0ead4c64 100644 --- a/client/src/components/StockOrderSection/PriceSetting.tsx +++ b/client/src/components/StockOrderSection/PriceSetting.tsx @@ -78,6 +78,7 @@ const PriceController = styled.input` height: 30px; border: 1px solid darkgray; border-right: none; + border-radius: 0.2rem 0 0 0.2rem; `; const DirectionBox = styled.div` @@ -96,6 +97,11 @@ const DirectionBox = styled.div` &.PriceUp { border-bottom: none; + border-radius: 0 0.2rem 0 0; + } + + &.PriceDown { + border-radius: 0 0 0.2rem 0; } } `; diff --git a/client/src/components/StockOrderSection/VolumeSetteing.tsx b/client/src/components/StockOrderSection/VolumeSetteing.tsx index dee00d95..18cd8bd8 100644 --- a/client/src/components/StockOrderSection/VolumeSetteing.tsx +++ b/client/src/components/StockOrderSection/VolumeSetteing.tsx @@ -86,6 +86,7 @@ const VolumeController = styled.input` height: 30px; border: 1px solid darkgray; border-right: none; + border-radius: 0.2rem 0 0 0.2rem; `; const DirectionBox = styled.div` @@ -104,6 +105,11 @@ const DirectionBox = styled.div` &.VolumeUp { border-bottom: none; + border-radius: 0 0.2rem 0 0; + } + + &.VolumeDown { + border-radius: 0 0 0.2rem 0; } } `; From 8f4d77ccbdb260b73d605ee6b0058ae79b449385 Mon Sep 17 00:00:00 2001 From: novice1993 Date: Sat, 2 Sep 2023 23:23:32 +0900 Subject: [PATCH 07/10] =?UTF-8?q?[Feat]=20=EC=A3=BC=EA=B0=80=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EA=B4=80=EB=A0=A8=20=ED=99=94=EB=A9=B4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 주식주문 컴포넌트의 주가 정보관련 화면 구현 - 세부 기능 추가 예정 Issues #12 --- .../StockOrderSection/StockPrice.tsx | 177 +++++++++++++++++- .../StockOrderSection/VolumeSetteing.tsx | 2 +- 2 files changed, 175 insertions(+), 4 deletions(-) diff --git a/client/src/components/StockOrderSection/StockPrice.tsx b/client/src/components/StockOrderSection/StockPrice.tsx index 49690418..4c6ad3a8 100644 --- a/client/src/components/StockOrderSection/StockPrice.tsx +++ b/client/src/components/StockOrderSection/StockPrice.tsx @@ -1,10 +1,49 @@ import { styled } from "styled-components"; +// dummyData +const dummyPrice: dummyProps[] = [ + { price: 190, changeRate: 90, volume: 500 }, + { price: 180, changeRate: 80, volume: 120 }, + { price: 170, changeRate: 70, volume: 78 }, + { price: 160, changeRate: 60, volume: 55 }, + { price: 150, changeRate: 50, volume: 91 }, + { price: 140, changeRate: 40, volume: 300 }, + { price: 130, changeRate: 30, volume: 10 }, + { price: 120, changeRate: 20, volume: 80 }, + { price: 110, changeRate: 10, volume: 40 }, + { price: 100, changeRate: 0, volume: 180 }, + { price: 90, changeRate: -10, volume: 250 }, + { price: 80, changeRate: -20, volume: 1000 }, + { price: 70, changeRate: -30, volume: 900 }, + { price: 60, changeRate: -40, volume: 850 }, + { price: 50, changeRate: -50, volume: 154 }, + { price: 40, changeRate: -60, volume: 820 }, + { price: 30, changeRate: -70, volume: 1100 }, + { price: 20, changeRate: -80, volume: 800 }, + { price: 10, changeRate: -90, volume: 500 }, + { price: 5, changeRate: -95, volume: 800 }, +]; +const upperPriceVolumeSum = 1000; +const lowerPriceVolumeSum = 2000; +// + const StockPrice = () => { return ( - + + {dummyPrice.map((item, idx) => ( + + ))} + ); @@ -12,11 +51,78 @@ const StockPrice = () => { export default StockPrice; +const PriceInfo = (props: PriceInfoProps) => { + const { + upperPriceVolumeSum, + lowerPriceVolumeSum, + index, + price, + changeRate, + volume, + } = props; + + const changeRateText01: string = changeRate > 0 ? "+" : ""; + const changeRateText02: string = "%"; + + return ( + + +
{price}
+
+ {changeRateText01} + {changeRate} + {changeRateText02} +
+
+ +
{volume}
+ +
+
+ ); +}; + +// dummy 관련 변수 +interface dummyProps { + price: number; + changeRate: number; + volume: number; +} + +interface PriceInfoProps { + upperPriceVolumeSum: number; + lowerPriceVolumeSum: number; + index: number; + price: number; + changeRate: number; + volume: number; +} + +interface InfoContainerProps { + index: number; +} + +interface VolumeProps { + index: number; +} + +interface VolumePercentageProps { + index: number; + volume: number; + upperPriceVolumeSum: number; + lowerPriceVolumeSum: number; +} + +// component 생성 const Container = styled.div` width: 40%; height: 100%; margin-right: 16px; - border-right: 1px solid black; `; const HighFigure = styled.div` @@ -25,10 +131,75 @@ const HighFigure = styled.div` border-bottom: 1px solid black; `; -const PriceInfo = styled.div` +const PriceList = styled.ul` width: 100%; height: 348px; + padding: 0px; border-bottom: 1px solid black; + overflow-y: scroll; + + &::-webkit-scrollbar { + display: none; + } +`; + +const InfoContainer = styled.div` + width: 100%; + height: 36px; + margin-bottom: 2px; + background-color: ${(props) => (props.index > 9 ? "#FDE8E7" : "#E7F0FD")}; + display: flex; + flex-direction: row; +`; + +const Price = styled.div` + width: 50%; + display: flex; + padding-right: 8px; + flex-direction: column; + align-items: flex-end; + + .price { + font-size: 14px; + font-weight: 400; + padding-top: 1px; + } + + .changeRate { + font-size: 12px; + font-weight: 400; + color: #e22926; + padding-top: 1px; + } +`; + +const Volume = styled.div` + width: 50%; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-end; + font-size: 12px; + color: ${(props) => (props.index < 10 ? "#2679ed" : "#e22926")}; + + .volume { + height: 100%; + display: flex; + align-items: center; + padding-right: 8px; + } +`; + +const VolumePercentge = styled.span` + width: ${(props) => + (props.volume / + (props.index < 10 + ? props.upperPriceVolumeSum + : props.lowerPriceVolumeSum)) * + 100}%; + + height: 2px; + background-color: ${(props) => (props.index < 10 ? "#2679ed" : "#e22926")}; `; const LowerFigure = styled.div` diff --git a/client/src/components/StockOrderSection/VolumeSetteing.tsx b/client/src/components/StockOrderSection/VolumeSetteing.tsx index 18cd8bd8..b78300ae 100644 --- a/client/src/components/StockOrderSection/VolumeSetteing.tsx +++ b/client/src/components/StockOrderSection/VolumeSetteing.tsx @@ -121,7 +121,7 @@ const PercentageBox = styled.div` margin-top: 8px; & button { - width: 46px; + width: 56px; height: 28px; border: none; border-radius: 0.2rem; From 6ddcc665524695b49189368f4c317febc17558f5 Mon Sep 17 00:00:00 2001 From: novice1993 Date: Sun, 3 Sep 2023 18:40:30 +0900 Subject: [PATCH 08/10] =?UTF-8?q?[Design]=20=EC=A3=BC=EA=B0=80=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EA=B4=80=EB=A0=A8=20CSS=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 렌더링 시, 중간가격 주가가 리스트 정중앙에 렌더링 되도록 Reack hook 및 css 관련 속성 부여 Issues #12 --- .../components/StockOrderSection/Index.tsx | 4 +- .../StockOrderSection/StockOrderBtn.tsx | 4 +- .../StockOrderSection/StockPrice.tsx | 91 +++++++++---------- .../components/StockOrderSection/dummyData.ts | 33 +++++++ 4 files changed, 82 insertions(+), 50 deletions(-) create mode 100644 client/src/components/StockOrderSection/dummyData.ts diff --git a/client/src/components/StockOrderSection/Index.tsx b/client/src/components/StockOrderSection/Index.tsx index 687f9bbe..818f83a5 100644 --- a/client/src/components/StockOrderSection/Index.tsx +++ b/client/src/components/StockOrderSection/Index.tsx @@ -22,12 +22,10 @@ const Container = styled.aside` position: fixed; right: 0px; transition: right 0.3s ease-in-out; - display: flex; flex-direction: column; - width: 26%; min-width: 400px; height: 100%; - border-left: 1px solid #2f4f4f; + background-color: #ffffff; `; diff --git a/client/src/components/StockOrderSection/StockOrderBtn.tsx b/client/src/components/StockOrderSection/StockOrderBtn.tsx index a02d72b9..9ee8a4c9 100644 --- a/client/src/components/StockOrderSection/StockOrderBtn.tsx +++ b/client/src/components/StockOrderSection/StockOrderBtn.tsx @@ -7,10 +7,12 @@ const totalAmountText02: string = "원"; const orderBtnText: string = "매수"; // dummyData -const dummyMoney: string = "9,990,086"; +import { availableMoney } from "./dummyData"; const dummyAmount: string = "0"; const StockOrderBtn = () => { + const dummyMoney = availableMoney.toLocaleString(); + return ( diff --git a/client/src/components/StockOrderSection/StockPrice.tsx b/client/src/components/StockOrderSection/StockPrice.tsx index 4c6ad3a8..324c61a9 100644 --- a/client/src/components/StockOrderSection/StockPrice.tsx +++ b/client/src/components/StockOrderSection/StockPrice.tsx @@ -1,41 +1,20 @@ +import { useRef, useEffect } from "react"; import { styled } from "styled-components"; // dummyData -const dummyPrice: dummyProps[] = [ - { price: 190, changeRate: 90, volume: 500 }, - { price: 180, changeRate: 80, volume: 120 }, - { price: 170, changeRate: 70, volume: 78 }, - { price: 160, changeRate: 60, volume: 55 }, - { price: 150, changeRate: 50, volume: 91 }, - { price: 140, changeRate: 40, volume: 300 }, - { price: 130, changeRate: 30, volume: 10 }, - { price: 120, changeRate: 20, volume: 80 }, - { price: 110, changeRate: 10, volume: 40 }, - { price: 100, changeRate: 0, volume: 180 }, - { price: 90, changeRate: -10, volume: 250 }, - { price: 80, changeRate: -20, volume: 1000 }, - { price: 70, changeRate: -30, volume: 900 }, - { price: 60, changeRate: -40, volume: 850 }, - { price: 50, changeRate: -50, volume: 154 }, - { price: 40, changeRate: -60, volume: 820 }, - { price: 30, changeRate: -70, volume: 1100 }, - { price: 20, changeRate: -80, volume: 800 }, - { price: 10, changeRate: -90, volume: 500 }, - { price: 5, changeRate: -95, volume: 800 }, -]; -const upperPriceVolumeSum = 1000; -const lowerPriceVolumeSum = 2000; -// +import { dummyPrice } from "./dummyData"; +import { upperPriceVolumeSum, lowerPriceVolumeSum } from "./dummyData"; const StockPrice = () => { return ( - + +
+
+
{dummyPrice.map((item, idx) => ( { /> ))} - + +
+
+
); }; @@ -52,18 +34,42 @@ const StockPrice = () => { export default StockPrice; const PriceInfo = (props: PriceInfoProps) => { - const { - upperPriceVolumeSum, - lowerPriceVolumeSum, - index, - price, - changeRate, - volume, - } = props; + const { index, price, changeRate, volume } = props; + const ref = useRef(null); const changeRateText01: string = changeRate > 0 ? "+" : ""; const changeRateText02: string = "%"; + // 11번째 가격 -> 렌더링 시 정중앙에 위치하도록 + useEffect(() => { + ref.current?.focus(); + ref.current?.scrollIntoView({ block: "center" }); + }, []); + + if (index === 10) { + return ( + + +
{price}
+
+ {changeRateText01} + {changeRate} + {changeRateText02} +
+
+ +
{volume}
+ +
+
+ ); + } + return ( @@ -87,16 +93,8 @@ const PriceInfo = (props: PriceInfoProps) => { ); }; -// dummy 관련 변수 -interface dummyProps { - price: number; - changeRate: number; - volume: number; -} - +// type 지정 interface PriceInfoProps { - upperPriceVolumeSum: number; - lowerPriceVolumeSum: number; index: number; price: number; changeRate: number; @@ -148,6 +146,7 @@ const InfoContainer = styled.div` height: 36px; margin-bottom: 2px; background-color: ${(props) => (props.index > 9 ? "#FDE8E7" : "#E7F0FD")}; + border: ${(props) => (props.index === 10 ? "1px solid #2F4F4F" : "none")}; display: flex; flex-direction: row; `; diff --git a/client/src/components/StockOrderSection/dummyData.ts b/client/src/components/StockOrderSection/dummyData.ts new file mode 100644 index 00000000..87285c75 --- /dev/null +++ b/client/src/components/StockOrderSection/dummyData.ts @@ -0,0 +1,33 @@ +// dummyData +export const dummyPrice: dummyProps[] = [ + { price: 190, changeRate: 90, volume: 500 }, + { price: 180, changeRate: 80, volume: 120 }, + { price: 170, changeRate: 70, volume: 78 }, + { price: 160, changeRate: 60, volume: 55 }, + { price: 150, changeRate: 50, volume: 91 }, + { price: 140, changeRate: 40, volume: 300 }, + { price: 130, changeRate: 30, volume: 10 }, + { price: 120, changeRate: 20, volume: 80 }, + { price: 110, changeRate: 10, volume: 40 }, + { price: 100, changeRate: 0, volume: 180 }, + { price: 90, changeRate: -10, volume: 250 }, + { price: 80, changeRate: -20, volume: 1000 }, + { price: 70, changeRate: -30, volume: 900 }, + { price: 60, changeRate: -40, volume: 850 }, + { price: 50, changeRate: -50, volume: 154 }, + { price: 40, changeRate: -60, volume: 820 }, + { 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 upperPriceVolumeSum = 1000; +export const lowerPriceVolumeSum = 2000; +export const availableMoney = 10000000; + +// dummy 관련 변수 +interface dummyProps { + price: number; + changeRate: number; + volume: number; +} From a42684b189d9d7e2d3cf86b7cbab1c0065e5a35c Mon Sep 17 00:00:00 2001 From: novice1993 Date: Sun, 3 Sep 2023 21:21:09 +0900 Subject: [PATCH 09/10] =?UTF-8?q?[Feat]=20=EC=A3=BC=EC=8B=9D=EC=A3=BC?= =?UTF-8?q?=EB=AC=B8=20=EA=B4=80=EB=A0=A8=20=EC=A1=B0=EA=B1=B4=EB=B6=80=20?= =?UTF-8?q?=EB=A0=8C=EB=8D=94=EB=A7=81=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 주식주문 관련 매수/매도 여부에 따른 조건부 렌더링 일부 구현 - 전역 상태관리도구 (redux-toolkit) 활용하여 상태관리 Issues #12 --- client/package-lock.json | 142 +++++++++++++++++- client/package.json | 2 + .../components/StockOrderSection/Index.tsx | 36 ++++- .../StockOrderSection/OrderResult.tsx | 1 - .../StockOrderSection/StockOrderBtn.tsx | 14 +- .../StockOrderSection/StockOrderSetting.tsx | 83 ++++++++-- .../StockOrderSection/StockPrice.tsx | 2 +- .../components/StockOrderSection/UpperBar.tsx | 42 ------ client/src/main.tsx | 6 +- client/src/models/README.md | 0 client/src/models/orderTypeProps.ts | 3 + client/src/models/stateProps.ts | 3 + client/src/reducer/StockOrderType-Reducer.ts | 19 +++ client/src/store/config.ts | 10 ++ 14 files changed, 294 insertions(+), 69 deletions(-) delete mode 100644 client/src/components/StockOrderSection/UpperBar.tsx delete mode 100644 client/src/models/README.md create mode 100644 client/src/models/orderTypeProps.ts create mode 100644 client/src/models/stateProps.ts create mode 100644 client/src/reducer/StockOrderType-Reducer.ts create mode 100644 client/src/store/config.ts diff --git a/client/package-lock.json b/client/package-lock.json index 0ba4f0e5..1bd60132 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -8,11 +8,13 @@ "name": "vite-project", "version": "0.0.0", "dependencies": { + "@reduxjs/toolkit": "^1.9.5", "axios": "^1.5.0", "echarts": "^5.4.3", "echarts-for-react": "^3.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-redux": "^8.1.2", "styled-components": "^6.0.7" }, "devDependencies": { @@ -2487,6 +2489,38 @@ "node": ">= 8" } }, + "node_modules/@reduxjs/toolkit": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz", + "integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==", + "dependencies": { + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", @@ -2504,14 +2538,12 @@ "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/react": { "version": "18.2.21", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", - "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2522,7 +2554,7 @@ "version": "18.2.7", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", - "dev": true, + "devOptional": true, "dependencies": { "@types/react": "*" } @@ -2530,8 +2562,7 @@ "node_modules/@types/scheduler": { "version": "0.16.3", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" }, "node_modules/@types/semver": { "version": "7.5.1", @@ -2544,6 +2575,11 @@ "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.0.tgz", "integrity": "sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw==" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.5.0.tgz", @@ -3823,6 +3859,19 @@ "node": ">=4" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -3832,6 +3881,15 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -4387,6 +4445,49 @@ "react": "^18.2.0" } }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/react-redux": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.2.tgz", + "integrity": "sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^16.8 || ^17.0 || ^18.0", + "@types/react-dom": "^16.8 || ^17.0 || ^18.0", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0", + "react-native": ">=0.59", + "redux": "^4 || ^5.0.0-beta.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-refresh": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", @@ -4408,6 +4509,22 @@ "node": ">=8.10.0" } }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "peerDependencies": { + "redux": "^4" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -4472,6 +4589,11 @@ "jsesc": "bin/jsesc" } }, + "node_modules/reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, "node_modules/resolve": { "version": "1.22.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", @@ -4929,6 +5051,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/vite": { "version": "4.4.9", "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", diff --git a/client/package.json b/client/package.json index 204529df..51346128 100644 --- a/client/package.json +++ b/client/package.json @@ -10,11 +10,13 @@ "preview": "vite preview" }, "dependencies": { + "@reduxjs/toolkit": "^1.9.5", "axios": "^1.5.0", "echarts": "^5.4.3", "echarts-for-react": "^3.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-redux": "^8.1.2", "styled-components": "^6.0.7" }, "devDependencies": { diff --git a/client/src/components/StockOrderSection/Index.tsx b/client/src/components/StockOrderSection/Index.tsx index 818f83a5..3503d93c 100644 --- a/client/src/components/StockOrderSection/Index.tsx +++ b/client/src/components/StockOrderSection/Index.tsx @@ -1,14 +1,18 @@ import { styled } from "styled-components"; -import UpperBar from "./UpperBar"; import StockName from "./StockName"; import OrderRequest from "./OrderRequest"; import OrderResult from "./OrderResult"; +const titleText: string = "주식주문"; + const StockOrderSection = () => { return ( - + + {titleText} + + @@ -29,3 +33,31 @@ const Container = styled.aside` height: 100%; background-color: #ffffff; `; + +const UpperBar = styled.div` + position: relative; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + width: 100%; + min-height: 43px; + border-bottom: 1px solid black; +`; + +const Title = styled.h2` + font-size: 17px; + font-weight: 450; + color: #1c1c1c; +`; + +const CloseBtn = styled.button` + position: absolute; + right: 10px; + width: 28px; + height: 95%; + border: none; + font-size: 20px; + color: #525252; + background-color: #ffff; +`; diff --git a/client/src/components/StockOrderSection/OrderResult.tsx b/client/src/components/StockOrderSection/OrderResult.tsx index 37a721c9..61e87f86 100644 --- a/client/src/components/StockOrderSection/OrderResult.tsx +++ b/client/src/components/StockOrderSection/OrderResult.tsx @@ -30,7 +30,6 @@ const Title = styled.div` font-weight: 500; padding-left: 16px; padding-bottom: 16px; - /* border-bottom: 1px solid black; */ `; const OrderPending = styled.div` diff --git a/client/src/components/StockOrderSection/StockOrderBtn.tsx b/client/src/components/StockOrderSection/StockOrderBtn.tsx index 9ee8a4c9..725ef6db 100644 --- a/client/src/components/StockOrderSection/StockOrderBtn.tsx +++ b/client/src/components/StockOrderSection/StockOrderBtn.tsx @@ -1,17 +1,21 @@ +import { useSelector } from "react-redux"; import { styled } from "styled-components"; +import { StateProps } from "../../models/stateProps"; +import { OrderTypeProps } from "../../models/orderTypeProps"; const availableMoneyText01: string = "최대"; const availableMoneyText02: string = "원"; const totalAmountText01: string = "주문총액"; const totalAmountText02: string = "원"; -const orderBtnText: string = "매수"; // dummyData import { availableMoney } from "./dummyData"; const dummyAmount: string = "0"; +const dummyMoney = availableMoney.toLocaleString(); const StockOrderBtn = () => { - const dummyMoney = availableMoney.toLocaleString(); + const stockOrderType = useSelector((state: StateProps) => state.stockOrderType); + const orderBtnText: string = stockOrderType ? "매도" : "매수"; return ( @@ -25,7 +29,7 @@ const StockOrderBtn = () => {
{dummyAmount}
{totalAmountText02}
- {orderBtnText} + {orderBtnText}
); }; @@ -73,13 +77,13 @@ const TotalAmount = styled.div` } `; -const OrderBtn = styled.button` +const OrderBtn = styled.button` width: 100%; height: 32px; margin-top: 16px; border: none; border-radius: 0.25rem; - background-color: #ed2926; + background-color: ${(props) => (props.ordertype ? "#2679ed" : "#e22926")}; color: #ffffff; font-weight: 400; `; diff --git a/client/src/components/StockOrderSection/StockOrderSetting.tsx b/client/src/components/StockOrderSection/StockOrderSetting.tsx index 4c1a04ad..cff36549 100644 --- a/client/src/components/StockOrderSection/StockOrderSetting.tsx +++ b/client/src/components/StockOrderSection/StockOrderSetting.tsx @@ -1,4 +1,9 @@ +import { useSelector, useDispatch } from "react-redux"; +import { orderTypeBuying, orderTypeSelling } from "../../reducer/StockOrderType-Reducer"; import { styled } from "styled-components"; +import { StateProps } from "../../models/stateProps"; +import { OrderTypeProps } from "../../models/orderTypeProps"; + import PriceSetting from "./PriceSetting"; import VolumeSetting from "./VolumeSetteing"; import StockOrderBtn from "./StockOrderBtn"; @@ -7,12 +12,28 @@ const orderType01: string = "매수"; const orderType02: string = "매도"; const StockOrderSetting = () => { + const stockOrderType = useSelector((state: StateProps) => state.stockOrderType); + const dispatch = useDispatch(); + + const handleSetBuying = () => { + dispatch(orderTypeBuying()); + }; + + const handleSetSelling = () => { + dispatch(orderTypeSelling()); + }; + return ( -
{orderType01}
-
{orderType02}
+ + {orderType01} + + + {orderType02} +
+ @@ -22,6 +43,19 @@ const StockOrderSetting = () => { export default StockOrderSetting; +const TypeDividingLine = () => { + const stockOrderType = useSelector((state: StateProps) => state.stockOrderType); + + return ( + + + + + + ); +}; + +// component 생성 const Container = styled.div` width: 51%; height: 100%; @@ -32,14 +66,41 @@ const OrderType = styled.div` height: 32px; display: flex; flex-direction: row; +`; + +const Buying = styled.div` + flex: 1 0 0; + display: flex; + justify-content: center; + align-items: center; + height: 31px; + font-size: 14px; + color: ${(props) => !props.ordertype && "#e22926"}; +`; + +const Selling = styled.div` + flex: 1 0 0; + display: flex; + justify-content: center; + align-items: center; + height: 31px; + font-size: 14px; + color: ${(props) => props.ordertype && "#2679ed"}; +`; + +const DividingContainer = styled.div` + background-color: darkgray; +`; + +const DefaultLine = styled.div` + transform: translateX(${(props) => (props.ordertype ? "50%" : "0")}); + transition: transform 0.3s ease-in-out; + width: 100%; + height: 1.2px; +`; - & div { - flex: 1 0 0; - display: flex; - justify-content: center; - align-items: center; - height: 31px; - font-size: 14px; - border-bottom: 1px solid darkgray; - } +const DivdingLine = styled.div` + width: 50%; + height: 1.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 324c61a9..89fa0251 100644 --- a/client/src/components/StockOrderSection/StockPrice.tsx +++ b/client/src/components/StockOrderSection/StockPrice.tsx @@ -43,7 +43,7 @@ const PriceInfo = (props: PriceInfoProps) => { // 11번째 가격 -> 렌더링 시 정중앙에 위치하도록 useEffect(() => { ref.current?.focus(); - ref.current?.scrollIntoView({ block: "center" }); + ref.current?.scrollIntoView({ behavior: "smooth", block: "center" }); }, []); if (index === 10) { diff --git a/client/src/components/StockOrderSection/UpperBar.tsx b/client/src/components/StockOrderSection/UpperBar.tsx deleted file mode 100644 index 5e76d089..00000000 --- a/client/src/components/StockOrderSection/UpperBar.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { styled } from "styled-components"; - -const titleText: string = "주식주문"; - -const UpperBar = () => { - return ( - - {titleText} - - - ); -}; - -export default UpperBar; - -const Container = styled.div` - position: relative; - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - width: 100%; - min-height: 43px; - border-bottom: 1px solid black; -`; - -const Title = styled.h2` - font-size: 17px; - font-weight: 450; - color: #1c1c1c; -`; - -const CloseBtn = styled.button` - position: absolute; - right: 10px; - width: 28px; - height: 95%; - border: none; - font-size: 20px; - color: #525252; - background-color: #ffff; -`; diff --git a/client/src/main.tsx b/client/src/main.tsx index 95e2bdc2..dc075919 100644 --- a/client/src/main.tsx +++ b/client/src/main.tsx @@ -1,9 +1,13 @@ import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App.tsx"; +import { Provider } from "react-redux"; +import store from "./store/config.ts"; ReactDOM.createRoot(document.getElementById("root")!).render( - + + + ); diff --git a/client/src/models/README.md b/client/src/models/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/client/src/models/orderTypeProps.ts b/client/src/models/orderTypeProps.ts new file mode 100644 index 00000000..c50c2081 --- /dev/null +++ b/client/src/models/orderTypeProps.ts @@ -0,0 +1,3 @@ +export interface OrderTypeProps { + ordertype: boolean; +} diff --git a/client/src/models/stateProps.ts b/client/src/models/stateProps.ts new file mode 100644 index 00000000..7ea6ad4b --- /dev/null +++ b/client/src/models/stateProps.ts @@ -0,0 +1,3 @@ +export interface StateProps { + stockOrderType: boolean; +} diff --git a/client/src/reducer/StockOrderType-Reducer.ts b/client/src/reducer/StockOrderType-Reducer.ts new file mode 100644 index 00000000..9999de9e --- /dev/null +++ b/client/src/reducer/StockOrderType-Reducer.ts @@ -0,0 +1,19 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const initialState: boolean = false; + +const stockOrderTypeSlice = createSlice({ + name: "stockOrderType", + initialState: initialState, + reducers: { + orderTypeBuying: () => { + return false; + }, + orderTypeSelling: () => { + return true; + }, + }, +}); + +export const { orderTypeBuying, orderTypeSelling } = stockOrderTypeSlice.actions; +export const stockOrderTypeReducer = stockOrderTypeSlice.reducer; diff --git a/client/src/store/config.ts b/client/src/store/config.ts new file mode 100644 index 00000000..622cb788 --- /dev/null +++ b/client/src/store/config.ts @@ -0,0 +1,10 @@ +import { configureStore } from "@reduxjs/toolkit"; +import { stockOrderTypeReducer } from "../reducer/StockOrderType-Reducer"; + +const store = configureStore({ + reducer: { + stockOrderType: stockOrderTypeReducer, + }, +}); + +export default store; From 7764e4d558e1eb06c43d468bf71fdc57d30859b1 Mon Sep 17 00:00:00 2001 From: novice1993 Date: Mon, 4 Sep 2023 02:34:51 +0900 Subject: [PATCH 10/10] =?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, }, });