From 370fc0eb31d2e2fc433b612d7c7f6c131258ffd8 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Wed, 14 Aug 2024 02:12:40 +0400 Subject: [PATCH 01/30] Include the slider to PercentageSlider --- src/app/components/OrderInput.tsx | 42 +++++++++++++++++- src/app/styles/globals.css | 73 +++++++++++++++++++++++++++++-- tailwind.config.js | 4 ++ 3 files changed, 115 insertions(+), 4 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 57e2ddd5..45e040d1 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -806,7 +806,47 @@ function InputTooltip({ message }: { message: string }) { // TODO(dcts): implement percentage slider in future PR function PercentageSlider() { - return <>; + const handleSliderChange = (e: any) => { + let target = e.target; + if (e.target.type !== "range") { + target = document.getElementById("range"); + } + const min = target.min; + const max = target.max; + const val = target.value; + let percentage = ((val - min) * 100) / (max - min); + + if (document.documentElement.dir === "rtl") { + percentage = max - val; + } + + target.style.backgroundSize = percentage + "% 100%"; + }; + + return ( + <> +
+
+ +
+
+ 0% + 25% + 50% + 75% + 100% +
+
+
+ + ); } // Mimics IMask with improved onAccept, triggered only by user input to avoid rerender bugs. diff --git a/src/app/styles/globals.css b/src/app/styles/globals.css index 57dac249..13c9f913 100644 --- a/src/app/styles/globals.css +++ b/src/app/styles/globals.css @@ -122,9 +122,9 @@ input[type="number"]::-ms-clear { /** * GRID AREA CSS: Utilizes global CSS classes for grid areas. - * Justification: TailwindCSS lacks a readable method for implementing - * grid-template-areas. Therefore, all grid area-related styles are - * centralized in global CSS to maintain separation from + * Justification: TailwindCSS lacks a readable method for implementing + * grid-template-areas. Therefore, all grid area-related styles are + * centralized in global CSS to maintain separation from * component-specific styles. */ .grid-container { @@ -239,3 +239,70 @@ input[type="number"]::-ms-clear { .account-history table thead tr th:last-child { padding-right: 16px; } + +/* percentage slider */ +input[type="range"] { + appearance: none; + margin-right: 15px; + width: 100%; + height: 7px; + background: rgba(255, 255, 255, 0.6); + border-radius: 5px; + background-image: linear-gradient(#474d52, #474d52); + background-size: 70% 100%; + background-repeat: no-repeat; +} + +[dir="rtl"] input[type="range"] { + background: #474d52; + background-image: linear-gradient(#fff, #fff); + background-size: 30% 100%; + background-repeat: no-repeat; +} + +input[type="range"]::-webkit-slider-thumb { + appearance: none; + height: 14px; + width: 14px; + border-radius: 50%; + background-color: #474d52; + color: #474d52; + border: 3.5px #ffffff solid; +} + +input[type="range"]::-moz-range-thumb { + appearance: none; + height: 14px; + width: 14px; + background-color: #474d52; + border-radius: 50%; +} + +input[type="range"]::-ms-thumb { + appearance: none; + height: 14px; + width: 14px; + background-color: #474d52; + border-radius: 50%; +} + +input[type="range"]::-webkit-slider-runnable-track { + -webkit-appearance: none; + box-shadow: none; + border: none; + background: transparent; +} + +input[type="range"]::-moz-range-track { + appearance: none; + box-shadow: none; + border: none; + background: transparent; +} + +input[type="range"]::-ms-track { + appearance: none; + box-shadow: none; + border: none; + background: transparent; +} diff --git a/tailwind.config.js b/tailwind.config.js index 9cd32be0..63a669b6 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -33,6 +33,10 @@ module.exports = { "dexter-grey-dark": "#141414", "dexter-grey-light": "#191B1D", "content-dark": "#212A09", + "slider-grey": "#474d52", + }, + fontSize: { + xxs: "0.65rem", }, }, }, From 34e602b3dc28e7e687bf60c615f407f0b1ea7590 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Sat, 17 Aug 2024 02:36:41 +0400 Subject: [PATCH 02/30] Fix the range step and css --- package-lock.json | 34 ++++++++++ package.json | 2 + src/app/components/OrderInput.tsx | 109 ++++++++++++++++++++++++------ src/app/styles/globals.css | 22 +++--- tailwind.config.js | 2 +- 5 files changed, 141 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index 91fd7db5..b36f32d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@radixdlt/radix-dapp-toolkit": "^2.0.0", "@reduxjs/toolkit": "^2.0.1", "@tailwindcss/container-queries": "^0.1.1", + "@tippyjs/react": "^4.2.6", "@types/mdx": "^2.0.10", "@types/node": "20.3.3", "@types/react": "18.2.14", @@ -37,6 +38,7 @@ "resize-observer-polyfill": "^1.5.1", "tailwind-merge": "^2.4.0", "tailwindcss": "3.3.2", + "tippy.js": "^6.3.7", "typescript": "5.1.6" }, "devDependencies": { @@ -1394,6 +1396,16 @@ "fsevents": "2.3.2" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@radixdlt/babylon-gateway-api-sdk": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@radixdlt/babylon-gateway-api-sdk/-/babylon-gateway-api-sdk-1.6.1.tgz", @@ -1744,6 +1756,19 @@ "react-dom": "^18.0.0" } }, + "node_modules/@tippyjs/react": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz", + "integrity": "sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw==", + "license": "MIT", + "dependencies": { + "tippy.js": "^6.3.1" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/@types/acorn": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", @@ -9063,6 +9088,15 @@ "node": ">=14.0.0" } }, + "node_modules/tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", + "license": "MIT", + "dependencies": { + "@popperjs/core": "^2.9.0" + } + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", diff --git a/package.json b/package.json index d133df27..a35fe709 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@radixdlt/radix-dapp-toolkit": "^2.0.0", "@reduxjs/toolkit": "^2.0.1", "@tailwindcss/container-queries": "^0.1.1", + "@tippyjs/react": "^4.2.6", "@types/mdx": "^2.0.10", "@types/node": "20.3.3", "@types/react": "18.2.14", @@ -45,6 +46,7 @@ "resize-observer-polyfill": "^1.5.1", "tailwind-merge": "^2.4.0", "tailwindcss": "3.3.2", + "tippy.js": "^6.3.7", "typescript": "5.1.6" }, "devDependencies": { diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 45e040d1..e597a915 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -1,5 +1,8 @@ import { useEffect, useState, ChangeEvent } from "react"; import { AiOutlineInfoCircle } from "react-icons/ai"; +import Tippy from "@tippyjs/react"; +import "tippy.js/dist/tippy.css"; +import "tippy.js/dist/svg-arrow.css"; import { getPrecision, @@ -806,6 +809,9 @@ function InputTooltip({ message }: { message: string }) { // TODO(dcts): implement percentage slider in future PR function PercentageSlider() { + const [toolTipVisible, setToolTipVisible] = useState(false); + const [sliderValue, setSliderValue] = useState(0); + const handleSliderChange = (e: any) => { let target = e.target; if (e.target.type !== "range") { @@ -817,31 +823,96 @@ function PercentageSlider() { let percentage = ((val - min) * 100) / (max - min); if (document.documentElement.dir === "rtl") { - percentage = max - val; + percentage = 100 - percentage; } - target.style.backgroundSize = percentage + "% 100%"; + target.style.backgroundSize = `${percentage}% 100%`; + setSliderValue(Number(val)); }; return ( <> -
-
- -
-
- 0% - 25% - 50% - 75% - 100% +
+
+ setToolTipVisible(true)} + onMouseUp={() => setToolTipVisible(false)} + onMouseEnter={() => setToolTipVisible(true)} + onMouseLeave={() => setToolTipVisible(false)} + /> + {sliderValue}%} + visible={toolTipVisible} + onClickOutside={() => setToolTipVisible(false)} + arrow={true} + theme="custom" + placement="top" + touch={true} + > +
+
+
+ +
+
+ {Array(5) + .fill(0) + .map((_, index) => ( + + ))} +
+
+
+
+
+ + 0% + + + 25% + + + 50% + + + 75% + + + 100% + +
diff --git a/src/app/styles/globals.css b/src/app/styles/globals.css index 13c9f913..d89b48d0 100644 --- a/src/app/styles/globals.css +++ b/src/app/styles/globals.css @@ -243,20 +243,18 @@ input[type="number"]::-ms-clear { /* percentage slider */ input[type="range"] { appearance: none; - margin-right: 15px; - width: 100%; height: 7px; - background: rgba(255, 255, 255, 0.6); + background: rgba(255, 255, 255, 1); border-radius: 5px; background-image: linear-gradient(#474d52, #474d52); - background-size: 70% 100%; + background-size: 0% 100%; background-repeat: no-repeat; } [dir="rtl"] input[type="range"] { background: #474d52; background-image: linear-gradient(#fff, #fff); - background-size: 30% 100%; + background-size: 0% 100%; background-repeat: no-repeat; } @@ -268,6 +266,8 @@ input[type="range"]::-webkit-slider-thumb { background-color: #474d52; color: #474d52; border: 3.5px #ffffff solid; + position: relative; + z-index: 2; } input[type="range"]::-moz-range-thumb { @@ -290,19 +290,25 @@ input[type="range"]::-webkit-slider-runnable-track { -webkit-appearance: none; box-shadow: none; border: none; - background: transparent; + width: full; } input[type="range"]::-moz-range-track { appearance: none; box-shadow: none; border: none; - background: transparent; } input[type="range"]::-ms-track { appearance: none; box-shadow: none; border: none; - background: transparent; +} + +.dot { + height: 7px; + width: 7px; + background-color: #ffffff; + border-radius: 50%; + z-index: 1; } diff --git a/tailwind.config.js b/tailwind.config.js index 63a669b6..6a196436 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -36,7 +36,7 @@ module.exports = { "slider-grey": "#474d52", }, fontSize: { - xxs: "0.65rem", + xxs: "0.6rem", }, }, }, From 6cf9bd1e57a97360cf5d774cc23ecaabae92dd0a Mon Sep 17 00:00:00 2001 From: saidam90 Date: Sat, 24 Aug 2024 17:44:11 +0400 Subject: [PATCH 03/30] Add trigger for Market Sell function --- src/app/components/OrderInput.tsx | 93 ++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 9 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index e597a915..a5d2f9cd 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -454,13 +454,41 @@ function SubmitButton() { } function UserInputContainer() { - const { side, type } = useAppSelector((state) => state.orderInput); + const { side, type, token1 } = useAppSelector((state) => state.orderInput); + + const balanceToken1 = + useAppSelector((state) => selectBalanceByAddress(state, token1.address)) || + 0; + + // const balanceToken2 = + // useAppSelector((state) => selectBalanceByAddress(state, token2.address)) || + // 0; const isMarketOrder = type === "MARKET"; const isLimitOrder = type === "LIMIT"; const isBuyOrder = side === "BUY"; const isSellOrder = side === "SELL"; + // const [sliderValue, setSliderValue] = useState(0); + + function handleMarketFunction(e: React.ChangeEvent) { + const percentage = parseFloat(e.target.value); + const amount = (percentage / 100) * balanceToken1; // Calculate the amount based on percentage + console.log(`Market function triggered: ${amount} for ${percentage}%`); + } + + function handleLimitFunction(e: React.ChangeEvent) { + console.log("Limit Order:", e.target.value); + } + + // const min = 0; + // const max = 100; // Slider ranges from 0 to 100% + // const value = sliderValue; // The current slider value in percentage + + // const calculatedAmount = isSellOrder + // ? (balanceToken1 * value) / 100 + // : (balanceToken2 * value) / 100; + return (
{isMarketOrder && ( @@ -469,12 +497,17 @@ function UserInputContainer() { userAction={UserAction.UPDATE_PRICE} disabled={true} /> - {isSellOrder && ( // specify "Quantity" - + <> + + + )} {isBuyOrder && ( // specify "Total" - + <> + + + )} )} @@ -482,7 +515,7 @@ function UserInputContainer() { <> - + {isLimitOrder && } @@ -808,11 +841,19 @@ function InputTooltip({ message }: { message: string }) { } // TODO(dcts): implement percentage slider in future PR -function PercentageSlider() { +interface PercentageSliderProps { + onMarketFunction?: (e: React.ChangeEvent) => void; + onLimitFunction?: (e: React.ChangeEvent) => void; +} + +const PercentageSlider: React.FC = ({ + onMarketFunction, + onLimitFunction, +}) => { const [toolTipVisible, setToolTipVisible] = useState(false); const [sliderValue, setSliderValue] = useState(0); - const handleSliderChange = (e: any) => { + const handleChange = (e: any) => { let target = e.target; if (e.target.type !== "range") { target = document.getElementById("range"); @@ -828,8 +869,41 @@ function PercentageSlider() { target.style.backgroundSize = `${percentage}% 100%`; setSliderValue(Number(val)); + + if (onMarketFunction) { + onMarketFunction(e); + } + if (onLimitFunction) { + onLimitFunction(e); + } }; + // const handleSliderChange = (e: any) => { + // let target = e.target; + // if (e.target.type !== "range") { + // target = document.getElementById("range"); + // } + // const min = target.min; + // const max = target.max; + // const val = target.value; + // let percentage = ((val - min) * 100) / (max - min); + + // if (document.documentElement.dir === "rtl") { + // percentage = 100 - percentage; + // } + + // target.style.backgroundSize = `${percentage}% 100%`; + // setSliderValue(Number(val)); + // }; + + // function handleMarketFunction(e: React.ChangeEvent) { + // console.log("Market Order:", e.target.value); + // } + + // function handleLimitFunction(e: React.ChangeEvent) { + // console.log("Limit Order:", e.target.value); + // } + return ( <>
@@ -838,7 +912,8 @@ function PercentageSlider() { type="range" min="0" max="100" - onChange={handleSliderChange} + // onChange={handleSliderChange} + onChange={handleChange} value={sliderValue} step="1" id="range" @@ -918,7 +993,7 @@ function PercentageSlider() {
); -} +}; // Mimics IMask with improved onAccept, triggered only by user input to avoid rerender bugs. function CustomNumericIMask({ From 712e3cbd22476829a486e6d9c17b7f76f8e951f1 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Sun, 25 Aug 2024 19:56:31 +0400 Subject: [PATCH 04/30] Add trigger for Market Buy function and set the amount in input field --- src/app/components/OrderInput.tsx | 126 ++++++++++++++++++++---------- 1 file changed, 84 insertions(+), 42 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index a5d2f9cd..31f5f826 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -50,6 +50,8 @@ interface OrderSideTabProps { interface CurrencyInputGroupProps { disabled?: boolean; // for price input userAction: UserAction; // user can set price, token1, token2 + value?: number; + updateValue?: (value: number) => void; } // Config representing each user action, derived from CurrencyInputGroupProps @@ -454,41 +456,58 @@ function SubmitButton() { } function UserInputContainer() { - const { side, type, token1 } = useAppSelector((state) => state.orderInput); + const { side, type, token1, token2 } = useAppSelector( + (state) => state.orderInput + ); const balanceToken1 = useAppSelector((state) => selectBalanceByAddress(state, token1.address)) || 0; - // const balanceToken2 = - // useAppSelector((state) => selectBalanceByAddress(state, token2.address)) || - // 0; + const balanceToken2 = + useAppSelector((state) => selectBalanceByAddress(state, token2.address)) || + 0; const isMarketOrder = type === "MARKET"; const isLimitOrder = type === "LIMIT"; const isBuyOrder = side === "BUY"; const isSellOrder = side === "SELL"; - // const [sliderValue, setSliderValue] = useState(0); + const [sliderValue, setSliderValue] = useState(0); - function handleMarketFunction(e: React.ChangeEvent) { + function handleSellFunction(e: React.ChangeEvent) { const percentage = parseFloat(e.target.value); - const amount = (percentage / 100) * balanceToken1; // Calculate the amount based on percentage - console.log(`Market function triggered: ${amount} for ${percentage}%`); + const amount = (percentage / 100) * balanceToken1; + setSliderValue(percentage); + console.log( + `Market - Sell function triggered: ${amount} for ${percentage}%` + ); + } + + function handleBuyFunction(e: React.ChangeEvent) { + const percentage = parseFloat(e.target.value); + const amount = (percentage / 100) * balanceToken2; + setSliderValue(percentage); // Update the slider value state + console.log( + `Market - Buy function triggered: ${amount} for ${percentage}%` + ); } - function handleLimitFunction(e: React.ChangeEvent) { - console.log("Limit Order:", e.target.value); + function handleInputChange(value: number) { + if (isSellOrder) { + const percentage = (value / balanceToken1) * 100; + setSliderValue(percentage); // Update the slider value based on input amount + } + if (isBuyOrder) { + const percentage = (value / balanceToken2) * 100; + setSliderValue(percentage); // Update the slider value based on input amount + } } // const min = 0; // const max = 100; // Slider ranges from 0 to 100% // const value = sliderValue; // The current slider value in percentage - // const calculatedAmount = isSellOrder - // ? (balanceToken1 * value) / 100 - // : (balanceToken2 * value) / 100; - return (
{isMarketOrder && ( @@ -499,14 +518,30 @@ function UserInputContainer() { /> {isSellOrder && ( // specify "Quantity" <> - - + + )} {isBuyOrder && ( // specify "Total" <> - - + + )} @@ -515,7 +550,11 @@ function UserInputContainer() { <> - + {isLimitOrder && } @@ -706,17 +745,13 @@ function CurrencyInputGroupSettings( function CurrencyInputGroup({ disabled = false, userAction, + value, + updateValue, }: CurrencyInputGroupProps): JSX.Element | null { const t = useTranslations(); const { type } = useAppSelector((state) => state.orderInput); - const { - label, - currency, - value, - updateValue, - inputValidation, - secondaryLabelProps, - } = CurrencyInputGroupSettings(userAction, disabled); + const { label, currency, inputValidation, secondaryLabelProps } = + CurrencyInputGroupSettings(userAction, disabled); const isMarketOrder = type === "MARKET"; const isUserActionUpdatePrice = userAction === "UPDATE_PRICE"; @@ -735,8 +770,8 @@ function CurrencyInputGroup({ ) : ( {})} inputValidation={inputValidation} /> )} @@ -817,7 +852,7 @@ function CurrencyInput({ value={value} separator={decimalSeparator} scale={scale} - onAccept={updateValue} + onAccept={(value) => updateValue?.(value)} className="text-sm grow w-full text-right pr-2 bg-base-200 rounded-lg" /> {/* CurrencyLabel */} @@ -842,16 +877,20 @@ function InputTooltip({ message }: { message: string }) { // TODO(dcts): implement percentage slider in future PR interface PercentageSliderProps { - onMarketFunction?: (e: React.ChangeEvent) => void; - onLimitFunction?: (e: React.ChangeEvent) => void; + onBuyFunction?: (e: React.ChangeEvent) => void; + onSellFunction?: (e: React.ChangeEvent) => void; + value: number; + setSliderValue: (value: number) => void; } const PercentageSlider: React.FC = ({ - onMarketFunction, - onLimitFunction, + onBuyFunction, + onSellFunction, + value, + setSliderValue, }) => { const [toolTipVisible, setToolTipVisible] = useState(false); - const [sliderValue, setSliderValue] = useState(0); + // const [sliderValue, setSliderValue] = useState(0); const handleChange = (e: any) => { let target = e.target; @@ -870,11 +909,14 @@ const PercentageSlider: React.FC = ({ target.style.backgroundSize = `${percentage}% 100%`; setSliderValue(Number(val)); - if (onMarketFunction) { - onMarketFunction(e); + const newValue = parseFloat(e.target.value); + setSliderValue(newValue); + + if (onBuyFunction) { + onBuyFunction(e); } - if (onLimitFunction) { - onLimitFunction(e); + if (onSellFunction) { + onSellFunction(e); } }; @@ -914,7 +956,7 @@ const PercentageSlider: React.FC = ({ max="100" // onChange={handleSliderChange} onChange={handleChange} - value={sliderValue} + value={value} step="1" id="range" className="w-full absolute cursor-pointer text-base" @@ -924,7 +966,7 @@ const PercentageSlider: React.FC = ({ onMouseLeave={() => setToolTipVisible(false)} /> {sliderValue}%} + content={{value}%} visible={toolTipVisible} onClickOutside={() => setToolTipVisible(false)} arrow={true} @@ -935,7 +977,7 @@ const PercentageSlider: React.FC = ({
Date: Sun, 25 Aug 2024 21:01:33 +0400 Subject: [PATCH 05/30] Fix issue with percentage color filling --- src/app/components/OrderInput.tsx | 92 +++++++++++++++++++++---------- src/app/styles/globals.css | 9 +++ 2 files changed, 73 insertions(+), 28 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 31f5f826..5785a7ba 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState, ChangeEvent } from "react"; +import { useEffect, useState, useRef, ChangeEvent } from "react"; import { AiOutlineInfoCircle } from "react-icons/ai"; import Tippy from "@tippyjs/react"; import "tippy.js/dist/tippy.css"; @@ -474,11 +474,12 @@ function UserInputContainer() { const isSellOrder = side === "SELL"; const [sliderValue, setSliderValue] = useState(0); + const [inputValue, setInputValue] = useState(0); function handleSellFunction(e: React.ChangeEvent) { const percentage = parseFloat(e.target.value); const amount = (percentage / 100) * balanceToken1; - setSliderValue(percentage); + setInputValue(amount); console.log( `Market - Sell function triggered: ${amount} for ${percentage}%` ); @@ -487,7 +488,7 @@ function UserInputContainer() { function handleBuyFunction(e: React.ChangeEvent) { const percentage = parseFloat(e.target.value); const amount = (percentage / 100) * balanceToken2; - setSliderValue(percentage); // Update the slider value state + setInputValue(amount); console.log( `Market - Buy function triggered: ${amount} for ${percentage}%` ); @@ -502,11 +503,23 @@ function UserInputContainer() { const percentage = (value / balanceToken2) * 100; setSliderValue(percentage); // Update the slider value based on input amount } + setInputValue(value); // Also update the input value state } - // const min = 0; - // const max = 100; // Slider ranges from 0 to 100% - // const value = sliderValue; // The current slider value in percentage + function handleValueUpdate(newValue: number) { + if (isNaN(newValue) || newValue < 0) { + setSliderValue(0); // Reset to 0 if input is invalid or negative + setInputValue(0); // Reset input value to 0 + } else { + setSliderValue(newValue); + if (isSellOrder) { + setInputValue((newValue / 100) * balanceToken1); + } + if (isBuyOrder) { + setInputValue((newValue / 100) * balanceToken2); + } + } + } return (
@@ -521,11 +534,11 @@ function UserInputContainer() { @@ -535,11 +548,11 @@ function UserInputContainer() { @@ -553,7 +566,7 @@ function UserInputContainer() { {isLimitOrder && } @@ -880,37 +893,42 @@ interface PercentageSliderProps { onBuyFunction?: (e: React.ChangeEvent) => void; onSellFunction?: (e: React.ChangeEvent) => void; value: number; - setSliderValue: (value: number) => void; + updateValue: (newValue: number) => void; } const PercentageSlider: React.FC = ({ onBuyFunction, onSellFunction, value, - setSliderValue, + updateValue, }) => { const [toolTipVisible, setToolTipVisible] = useState(false); + const sliderRef = useRef(null); + // const [sliderValue, setSliderValue] = useState(0); const handleChange = (e: any) => { let target = e.target; - if (e.target.type !== "range") { - target = document.getElementById("range"); - } - const min = target.min; - const max = target.max; - const val = target.value; + // if (e.target.type !== "range") { + // target = document.getElementById("range"); + // } + const min = parseFloat(target.min); + const max = parseFloat(target.max); + const val = parseFloat(target.value); + let percentage = ((val - min) * 100) / (max - min); - if (document.documentElement.dir === "rtl") { - percentage = 100 - percentage; + if (sliderRef.current) { + sliderRef.current.style.backgroundSize = `${percentage}% 100%`; } - target.style.backgroundSize = `${percentage}% 100%`; - setSliderValue(Number(val)); + updateValue(val); - const newValue = parseFloat(e.target.value); - setSliderValue(newValue); + // target.style.backgroundSize = `${percentage}% 100%`; + // updateValue(Number(val)); + + // const newValue = parseFloat(e.target.value); + // updateValue(val); if (onBuyFunction) { onBuyFunction(e); @@ -920,6 +938,23 @@ const PercentageSlider: React.FC = ({ } }; + useEffect(() => { + if (sliderRef.current) { + const target = sliderRef.current; + const min = parseFloat(target.min); + const max = parseFloat(target.max); + const val = parseFloat(value.toString()); + + let percentage = ((val - min) * 100) / (max - min); + + if (document.documentElement.dir === "rtl") { + percentage = 100 - percentage; + } + + target.style.backgroundSize = `${percentage}% 100%`; + } + }, [value]); + // const handleSliderChange = (e: any) => { // let target = e.target; // if (e.target.type !== "range") { @@ -958,6 +993,7 @@ const PercentageSlider: React.FC = ({ onChange={handleChange} value={value} step="1" + ref={sliderRef} id="range" className="w-full absolute cursor-pointer text-base" onMouseDown={() => setToolTipVisible(true)} @@ -969,7 +1005,7 @@ const PercentageSlider: React.FC = ({ content={{value}%} visible={toolTipVisible} onClickOutside={() => setToolTipVisible(false)} - arrow={true} + arrow={false} theme="custom" placement="top" touch={true} @@ -979,13 +1015,13 @@ const PercentageSlider: React.FC = ({ style={{ left: `${value}%`, transform: "translateX(-50%)", - top: "-5px", + // top: "-5px", }} >
-
+
{Array(5) .fill(0) diff --git a/src/app/styles/globals.css b/src/app/styles/globals.css index d89b48d0..0bdcef7a 100644 --- a/src/app/styles/globals.css +++ b/src/app/styles/globals.css @@ -249,6 +249,7 @@ input[type="range"] { background-image: linear-gradient(#474d52, #474d52); background-size: 0% 100%; background-repeat: no-repeat; + cursor: pointer; } [dir="rtl"] input[type="range"] { @@ -256,6 +257,7 @@ input[type="range"] { background-image: linear-gradient(#fff, #fff); background-size: 0% 100%; background-repeat: no-repeat; + cursor: pointer; } input[type="range"]::-webkit-slider-thumb { @@ -268,6 +270,7 @@ input[type="range"]::-webkit-slider-thumb { border: 3.5px #ffffff solid; position: relative; z-index: 2; + cursor: pointer; } input[type="range"]::-moz-range-thumb { @@ -276,6 +279,7 @@ input[type="range"]::-moz-range-thumb { width: 14px; background-color: #474d52; border-radius: 50%; + cursor: pointer; } input[type="range"]::-ms-thumb { @@ -284,6 +288,7 @@ input[type="range"]::-ms-thumb { width: 14px; background-color: #474d52; border-radius: 50%; + cursor: pointer; } input[type="range"]::-webkit-slider-runnable-track { @@ -291,18 +296,21 @@ input[type="range"]::-webkit-slider-runnable-track { box-shadow: none; border: none; width: full; + cursor: pointer; } input[type="range"]::-moz-range-track { appearance: none; box-shadow: none; border: none; + cursor: pointer; } input[type="range"]::-ms-track { appearance: none; box-shadow: none; border: none; + cursor: pointer; } .dot { @@ -311,4 +319,5 @@ input[type="range"]::-ms-track { background-color: #ffffff; border-radius: 50%; z-index: 1; + cursor: pointer; } From 25c4445464b77435bafd7a12af59bbff141f8c3e Mon Sep 17 00:00:00 2001 From: saidam90 Date: Sun, 25 Aug 2024 21:23:31 +0400 Subject: [PATCH 06/30] Reset the input when tabs are switched --- src/app/components/OrderInput.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 5785a7ba..c4805cb0 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -476,6 +476,13 @@ function UserInputContainer() { const [sliderValue, setSliderValue] = useState(0); const [inputValue, setInputValue] = useState(0); + useEffect(() => { + if (isBuyOrder || isSellOrder) { + setInputValue(0); + setSliderValue(0); + } + }, [side, type]); + function handleSellFunction(e: React.ChangeEvent) { const percentage = parseFloat(e.target.value); const amount = (percentage / 100) * balanceToken1; From 16fc0fd1ec9eb2e290e01d74d04eb262043989fc Mon Sep 17 00:00:00 2001 From: saidam90 Date: Mon, 26 Aug 2024 00:16:50 +0400 Subject: [PATCH 07/30] Fix Limit Sell orders --- src/app/components/OrderInput.tsx | 10 +++++++--- src/app/styles/globals.css | 7 ++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index c4805cb0..e5360a19 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -569,7 +569,11 @@ function UserInputContainer() { {isLimitOrder && ( <> - + = ({ // const [sliderValue, setSliderValue] = useState(0); const handleChange = (e: any) => { - let target = e.target; + const target = e.target as HTMLInputElement; // if (e.target.type !== "range") { // target = document.getElementById("range"); // } @@ -1015,7 +1019,7 @@ const PercentageSlider: React.FC = ({ arrow={false} theme="custom" placement="top" - touch={true} + // touch={true} >
Date: Mon, 26 Aug 2024 00:45:41 +0400 Subject: [PATCH 08/30] Delete outcommented code --- src/app/components/OrderInput.tsx | 57 ++++--------------------------- 1 file changed, 6 insertions(+), 51 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index e5360a19..f796bc2a 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -487,36 +487,30 @@ function UserInputContainer() { const percentage = parseFloat(e.target.value); const amount = (percentage / 100) * balanceToken1; setInputValue(amount); - console.log( - `Market - Sell function triggered: ${amount} for ${percentage}%` - ); } function handleBuyFunction(e: React.ChangeEvent) { const percentage = parseFloat(e.target.value); const amount = (percentage / 100) * balanceToken2; setInputValue(amount); - console.log( - `Market - Buy function triggered: ${amount} for ${percentage}%` - ); } function handleInputChange(value: number) { if (isSellOrder) { const percentage = (value / balanceToken1) * 100; - setSliderValue(percentage); // Update the slider value based on input amount + setSliderValue(percentage); } if (isBuyOrder) { const percentage = (value / balanceToken2) * 100; - setSliderValue(percentage); // Update the slider value based on input amount + setSliderValue(percentage); } - setInputValue(value); // Also update the input value state + setInputValue(value); } function handleValueUpdate(newValue: number) { if (isNaN(newValue) || newValue < 0) { - setSliderValue(0); // Reset to 0 if input is invalid or negative - setInputValue(0); // Reset input value to 0 + setSliderValue(0); + setInputValue(0); } else { setSliderValue(newValue); if (isSellOrder) { @@ -916,13 +910,9 @@ const PercentageSlider: React.FC = ({ const [toolTipVisible, setToolTipVisible] = useState(false); const sliderRef = useRef(null); - // const [sliderValue, setSliderValue] = useState(0); - const handleChange = (e: any) => { const target = e.target as HTMLInputElement; - // if (e.target.type !== "range") { - // target = document.getElementById("range"); - // } + const min = parseFloat(target.min); const max = parseFloat(target.max); const val = parseFloat(target.value); @@ -935,12 +925,6 @@ const PercentageSlider: React.FC = ({ updateValue(val); - // target.style.backgroundSize = `${percentage}% 100%`; - // updateValue(Number(val)); - - // const newValue = parseFloat(e.target.value); - // updateValue(val); - if (onBuyFunction) { onBuyFunction(e); } @@ -966,32 +950,6 @@ const PercentageSlider: React.FC = ({ } }, [value]); - // const handleSliderChange = (e: any) => { - // let target = e.target; - // if (e.target.type !== "range") { - // target = document.getElementById("range"); - // } - // const min = target.min; - // const max = target.max; - // const val = target.value; - // let percentage = ((val - min) * 100) / (max - min); - - // if (document.documentElement.dir === "rtl") { - // percentage = 100 - percentage; - // } - - // target.style.backgroundSize = `${percentage}% 100%`; - // setSliderValue(Number(val)); - // }; - - // function handleMarketFunction(e: React.ChangeEvent) { - // console.log("Market Order:", e.target.value); - // } - - // function handleLimitFunction(e: React.ChangeEvent) { - // console.log("Limit Order:", e.target.value); - // } - return ( <>
@@ -1000,7 +958,6 @@ const PercentageSlider: React.FC = ({ type="range" min="0" max="100" - // onChange={handleSliderChange} onChange={handleChange} value={value} step="1" @@ -1019,14 +976,12 @@ const PercentageSlider: React.FC = ({ arrow={false} theme="custom" placement="top" - // touch={true} >
From 3ed04a68f990f68fe296e15d8f59e0e27bfa8b91 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Wed, 28 Aug 2024 19:42:11 +0400 Subject: [PATCH 09/30] Delete tippy.js --- package-lock.json | 1 - package.json | 1 - 2 files changed, 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ef196516..b392defd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,6 @@ "resize-observer-polyfill": "^1.5.1", "tailwind-merge": "^2.4.0", "tailwindcss": "3.3.2", - "tippy.js": "^6.3.7", "typescript": "5.1.6" }, "devDependencies": { diff --git a/package.json b/package.json index 05a88726..9158ec09 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "resize-observer-polyfill": "^1.5.1", "tailwind-merge": "^2.4.0", "tailwindcss": "3.3.2", - "tippy.js": "^6.3.7", "typescript": "5.1.6" }, "devDependencies": { From ae8518e1f32786b5049d00a12379f85e0e7d2226 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Thu, 29 Aug 2024 00:40:25 +0400 Subject: [PATCH 10/30] Simplify slider, reduce number of props --- src/app/components/OrderInput.tsx | 194 ++++++++---------------------- 1 file changed, 48 insertions(+), 146 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index f796bc2a..e76df779 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -50,8 +50,6 @@ interface OrderSideTabProps { interface CurrencyInputGroupProps { disabled?: boolean; // for price input userAction: UserAction; // user can set price, token1, token2 - value?: number; - updateValue?: (value: number) => void; } // Config representing each user action, derived from CurrencyInputGroupProps @@ -456,71 +454,23 @@ function SubmitButton() { } function UserInputContainer() { - const { side, type, token1, token2 } = useAppSelector( - (state) => state.orderInput - ); - - const balanceToken1 = - useAppSelector((state) => selectBalanceByAddress(state, token1.address)) || - 0; - - const balanceToken2 = - useAppSelector((state) => selectBalanceByAddress(state, token2.address)) || - 0; + const { side, type } = useAppSelector((state) => state.orderInput); const isMarketOrder = type === "MARKET"; const isLimitOrder = type === "LIMIT"; const isBuyOrder = side === "BUY"; const isSellOrder = side === "SELL"; - const [sliderValue, setSliderValue] = useState(0); - const [inputValue, setInputValue] = useState(0); - - useEffect(() => { - if (isBuyOrder || isSellOrder) { - setInputValue(0); - setSliderValue(0); - } - }, [side, type]); - - function handleSellFunction(e: React.ChangeEvent) { - const percentage = parseFloat(e.target.value); - const amount = (percentage / 100) * balanceToken1; - setInputValue(amount); - } - - function handleBuyFunction(e: React.ChangeEvent) { - const percentage = parseFloat(e.target.value); - const amount = (percentage / 100) * balanceToken2; - setInputValue(amount); - } - - function handleInputChange(value: number) { - if (isSellOrder) { - const percentage = (value / balanceToken1) * 100; - setSliderValue(percentage); - } - if (isBuyOrder) { - const percentage = (value / balanceToken2) * 100; - setSliderValue(percentage); - } - setInputValue(value); - } - - function handleValueUpdate(newValue: number) { - if (isNaN(newValue) || newValue < 0) { - setSliderValue(0); - setInputValue(0); - } else { - setSliderValue(newValue); - if (isSellOrder) { - setInputValue((newValue / 100) * balanceToken1); - } - if (isBuyOrder) { - setInputValue((newValue / 100) * balanceToken2); - } - } - } + const sliderCallbackMarketOrder = (newPercentage: number) => { + console.error( + `Calling sliderCallback for MARKET order with newPercentage value of ${newPercentage}` + ); + }; + const sliderCallbackLimitOrder = (newPercentage: number) => { + console.error( + `Calling sliderCallback for LIMIT order with newPercentage value of ${newPercentage}` + ); + }; return (
@@ -530,48 +480,25 @@ function UserInputContainer() { userAction={UserAction.UPDATE_PRICE} disabled={true} /> + {isSellOrder && ( // specify "Quantity" - <> - - - + )} {isBuyOrder && ( // specify "Total" - <> - - - + )} )} {isLimitOrder && ( <> - + {isLimitOrder && } @@ -763,13 +690,17 @@ function CurrencyInputGroupSettings( function CurrencyInputGroup({ disabled = false, userAction, - value, - updateValue, }: CurrencyInputGroupProps): JSX.Element | null { const t = useTranslations(); const { type } = useAppSelector((state) => state.orderInput); - const { label, currency, inputValidation, secondaryLabelProps } = - CurrencyInputGroupSettings(userAction, disabled); + const { + label, + currency, + value, + updateValue, + inputValidation, + secondaryLabelProps, + } = CurrencyInputGroupSettings(userAction, disabled); const isMarketOrder = type === "MARKET"; const isUserActionUpdatePrice = userAction === "UPDATE_PRICE"; @@ -788,8 +719,8 @@ function CurrencyInputGroup({ ) : ( {})} + value={value} + updateValue={updateValue} inputValidation={inputValidation} /> )} @@ -870,7 +801,7 @@ function CurrencyInput({ value={value} separator={decimalSeparator} scale={scale} - onAccept={(value) => updateValue?.(value)} + onAccept={updateValue} className="text-sm grow w-full text-right pr-2 bg-base-200 rounded-lg" /> {/* CurrencyLabel */} @@ -895,60 +826,31 @@ function InputTooltip({ message }: { message: string }) { // TODO(dcts): implement percentage slider in future PR interface PercentageSliderProps { - onBuyFunction?: (e: React.ChangeEvent) => void; - onSellFunction?: (e: React.ChangeEvent) => void; - value: number; - updateValue: (newValue: number) => void; + initialPercentage: number; + callbackOnPercentageUpdate: (newPercentage: number) => void; } const PercentageSlider: React.FC = ({ - onBuyFunction, - onSellFunction, - value, - updateValue, + initialPercentage, + callbackOnPercentageUpdate, }) => { + const [percentage, setPercentage] = useState(initialPercentage); const [toolTipVisible, setToolTipVisible] = useState(false); const sliderRef = useRef(null); - const handleChange = (e: any) => { - const target = e.target as HTMLInputElement; - - const min = parseFloat(target.min); - const max = parseFloat(target.max); - const val = parseFloat(target.value); - - let percentage = ((val - min) * 100) / (max - min); - - if (sliderRef.current) { - sliderRef.current.style.backgroundSize = `${percentage}% 100%`; - } - - updateValue(val); - - if (onBuyFunction) { - onBuyFunction(e); - } - if (onSellFunction) { - onSellFunction(e); - } + const handleChange = (e: React.ChangeEvent) => { + const newPercentage = parseInt(e.target.value, 10); + setPercentage(newPercentage); + callbackOnPercentageUpdate(newPercentage); }; useEffect(() => { - if (sliderRef.current) { - const target = sliderRef.current; - const min = parseFloat(target.min); - const max = parseFloat(target.max); - const val = parseFloat(value.toString()); - - let percentage = ((val - min) * 100) / (max - min); - - if (document.documentElement.dir === "rtl") { - percentage = 100 - percentage; - } - - target.style.backgroundSize = `${percentage}% 100%`; + if (!sliderRef.current) { + return; } - }, [value]); + const target = sliderRef.current; + target.style.backgroundSize = `${percentage}% 100%`; + }, [percentage]); return ( <> @@ -959,7 +861,7 @@ const PercentageSlider: React.FC = ({ min="0" max="100" onChange={handleChange} - value={value} + value={percentage} step="1" ref={sliderRef} id="range" @@ -970,7 +872,7 @@ const PercentageSlider: React.FC = ({ onMouseLeave={() => setToolTipVisible(false)} /> {value}%} + content={{percentage}%} visible={toolTipVisible} onClickOutside={() => setToolTipVisible(false)} arrow={false} @@ -980,7 +882,7 @@ const PercentageSlider: React.FC = ({
From ebb2721a38591fece2e808742bff089b5f0e57de Mon Sep 17 00:00:00 2001 From: saidam90 Date: Wed, 4 Sep 2024 20:49:25 +0400 Subject: [PATCH 11/30] Sync the slider track filling with the input percentage --- src/app/components/OrderInput.tsx | 126 +++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 10 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index e76df779..d4f25616 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -454,7 +454,19 @@ function SubmitButton() { } function UserInputContainer() { - const { side, type } = useAppSelector((state) => state.orderInput); + const dispatch = useAppDispatch(); + const { side, type, token1, token2 } = useAppSelector( + (state) => state.orderInput + ); + const balanceToken1 = + useAppSelector((state) => selectBalanceByAddress(state, token1.address)) || + 0; + const balanceToken2 = + useAppSelector((state) => selectBalanceByAddress(state, token2.address)) || + 0; + const bestBuy = useAppSelector((state) => state.orderBook.bestBuy) || 0; + const bestSell = useAppSelector((state) => state.orderBook.bestSell) || 0; + // const token2InputValue = useAppSelector((state) => state.orderInput.token2); const isMarketOrder = type === "MARKET"; const isLimitOrder = type === "LIMIT"; @@ -462,14 +474,67 @@ function UserInputContainer() { const isSellOrder = side === "SELL"; const sliderCallbackMarketOrder = (newPercentage: number) => { - console.error( - `Calling sliderCallback for MARKET order with newPercentage value of ${newPercentage}` - ); + let amount; + if (isBuyOrder) { + amount = (balanceToken2 * newPercentage) / 100; + // Update Total field for Buy orders + dispatch( + orderInputSlice.actions.setTokenAmount({ + amount: amount, + bestBuy, + bestSell, + balanceToken1: balanceToken1, + balanceToken2: balanceToken2, + specifiedToken: SpecifiedToken.TOKEN_2, + }) + ); + } else if (isSellOrder) { + amount = (balanceToken1 * newPercentage) / 100; + // Update Quantity field for Sell orders + dispatch( + orderInputSlice.actions.setTokenAmount({ + amount: amount, + bestBuy, + bestSell, + balanceToken1: balanceToken1, + balanceToken2: balanceToken2, + specifiedToken: SpecifiedToken.TOKEN_1, + }) + ); + } + // console.log(amount); }; + const sliderCallbackLimitOrder = (newPercentage: number) => { - console.error( - `Calling sliderCallback for LIMIT order with newPercentage value of ${newPercentage}` - ); + let amount; + if (isBuyOrder) { + amount = (balanceToken2 * newPercentage) / 100; + dispatch( + orderInputSlice.actions.setTokenAmount({ + amount: amount, + bestBuy, + bestSell, + balanceToken1: balanceToken1, + balanceToken2: balanceToken2, + specifiedToken: SpecifiedToken.TOKEN_2, + }) + ); + } else if (isSellOrder) { + amount = (balanceToken1 * newPercentage) / 100; + dispatch( + orderInputSlice.actions.setTokenAmount({ + amount: amount, + bestBuy, + bestSell, + balanceToken1: balanceToken1, + balanceToken2: balanceToken2, + specifiedToken: SpecifiedToken.TOKEN_1, + }) + ); + } + // console.error( + // `Calling sliderCallback for LIMIT order with newPercentage value of ${newPercentage}` + // ); }; return ( @@ -516,6 +581,7 @@ function CurrencyInputGroupSettings( ): CurrencyInputGroupConfig { const t = useTranslations(); const dispatch = useAppDispatch(); + const { side, type, @@ -536,6 +602,8 @@ function CurrencyInputGroupSettings( const bestBuy = useAppSelector((state) => state.orderBook.bestBuy) || 0; const bestSell = useAppSelector((state) => state.orderBook.bestSell) || 0; + const sliderRef = useRef(null); + const updateToken1 = (value: number) => { dispatch( orderInputSlice.actions.setTokenAmount({ @@ -837,6 +905,17 @@ const PercentageSlider: React.FC = ({ const [percentage, setPercentage] = useState(initialPercentage); const [toolTipVisible, setToolTipVisible] = useState(false); const sliderRef = useRef(null); + const { token1, token2 } = useAppSelector((state) => state.orderInput); + + const inputToken1 = useAppSelector((state) => state.orderInput.token1.amount); + const inputToken2 = useAppSelector((state) => state.orderInput.token2.amount); + + const balanceToken1 = + useAppSelector((state) => selectBalanceByAddress(state, token1.address)) || + 0; + const balanceToken2 = + useAppSelector((state) => selectBalanceByAddress(state, token2.address)) || + 0; const handleChange = (e: React.ChangeEvent) => { const newPercentage = parseInt(e.target.value, 10); @@ -844,13 +923,40 @@ const PercentageSlider: React.FC = ({ callbackOnPercentageUpdate(newPercentage); }; + // useEffect(() => { + // if (!sliderRef.current) { + // return; + // } + + // const target = sliderRef.current; + + // if (!inputToken2 || inputToken2 === 0) { + // setPercentage(0); + // target.value = "0"; + // target.style.backgroundSize = "0% 100%"; + // } else { + // target.style.backgroundSize = `${percentage}% 100%`; + // } + // }, [percentage, inputToken2]); + useEffect(() => { if (!sliderRef.current) { return; } - const target = sliderRef.current; - target.style.backgroundSize = `${percentage}% 100%`; - }, [percentage]); + if (balanceToken2 && inputToken2 > 0) { + const newPercentage = + inputToken2 > 0 ? (inputToken2 / balanceToken2) * 100 : 0; + setPercentage(newPercentage); + sliderRef.current.style.backgroundSize = `${newPercentage}% 100%`; + } else if (balanceToken1 && inputToken1 > 0) { + const newPercentage = + inputToken1 > 0 ? (inputToken1 / balanceToken1) * 100 : 0; + setPercentage(newPercentage); + sliderRef.current.style.backgroundSize = `${newPercentage}% 100%`; + } else { + sliderRef.current.style.backgroundSize = `0% 100%`; + } + }, [inputToken2, balanceToken2, inputToken1, balanceToken1]); return ( <> From a91348222d81519ca03906d2be852d6e8421a0c3 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Thu, 5 Sep 2024 00:56:21 +0400 Subject: [PATCH 12/30] Reset the thumb when tabs are switched --- src/app/components/OrderInput.tsx | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index d4f25616..f8c8d8f4 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -466,18 +466,25 @@ function UserInputContainer() { 0; const bestBuy = useAppSelector((state) => state.orderBook.bestBuy) || 0; const bestSell = useAppSelector((state) => state.orderBook.bestSell) || 0; - // const token2InputValue = useAppSelector((state) => state.orderInput.token2); const isMarketOrder = type === "MARKET"; const isLimitOrder = type === "LIMIT"; const isBuyOrder = side === "BUY"; const isSellOrder = side === "SELL"; + useEffect(() => { + // Reset the slider when switching between buy/sell or market/limit orders + if (isMarketOrder) { + sliderCallbackMarketOrder(0); // Reset to 0% for market orders + } else if (isLimitOrder) { + sliderCallbackLimitOrder(0); // Reset to 0% for limit orders + } + }, [isBuyOrder, isSellOrder, isMarketOrder, isLimitOrder]); // Runs when any of these states change + const sliderCallbackMarketOrder = (newPercentage: number) => { let amount; if (isBuyOrder) { amount = (balanceToken2 * newPercentage) / 100; - // Update Total field for Buy orders dispatch( orderInputSlice.actions.setTokenAmount({ amount: amount, @@ -490,7 +497,6 @@ function UserInputContainer() { ); } else if (isSellOrder) { amount = (balanceToken1 * newPercentage) / 100; - // Update Quantity field for Sell orders dispatch( orderInputSlice.actions.setTokenAmount({ amount: amount, @@ -502,7 +508,6 @@ function UserInputContainer() { }) ); } - // console.log(amount); }; const sliderCallbackLimitOrder = (newPercentage: number) => { @@ -602,8 +607,6 @@ function CurrencyInputGroupSettings( const bestBuy = useAppSelector((state) => state.orderBook.bestBuy) || 0; const bestSell = useAppSelector((state) => state.orderBook.bestSell) || 0; - const sliderRef = useRef(null); - const updateToken1 = (value: number) => { dispatch( orderInputSlice.actions.setTokenAmount({ @@ -943,6 +946,11 @@ const PercentageSlider: React.FC = ({ if (!sliderRef.current) { return; } + if (sliderRef.current) { + sliderRef.current.value = "0"; + sliderRef.current.style.backgroundSize = `0% 100%`; + setPercentage(0); + } if (balanceToken2 && inputToken2 > 0) { const newPercentage = inputToken2 > 0 ? (inputToken2 / balanceToken2) * 100 : 0; @@ -956,7 +964,7 @@ const PercentageSlider: React.FC = ({ } else { sliderRef.current.style.backgroundSize = `0% 100%`; } - }, [inputToken2, balanceToken2, inputToken1, balanceToken1]); + }, [inputToken1, balanceToken1, inputToken2, balanceToken2]); return ( <> From 5f3052074df6d1e13e8153bb8e060448eb84ce26 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Thu, 5 Sep 2024 01:01:01 +0400 Subject: [PATCH 13/30] Fix useEffect function --- src/app/components/OrderInput.tsx | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index f8c8d8f4..60ef0e22 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -946,23 +946,19 @@ const PercentageSlider: React.FC = ({ if (!sliderRef.current) { return; } - if (sliderRef.current) { - sliderRef.current.value = "0"; - sliderRef.current.style.backgroundSize = `0% 100%`; - setPercentage(0); - } + + sliderRef.current.value = "0"; + sliderRef.current.style.backgroundSize = `0% 100%`; + setPercentage(0); + if (balanceToken2 && inputToken2 > 0) { - const newPercentage = - inputToken2 > 0 ? (inputToken2 / balanceToken2) * 100 : 0; + const newPercentage = (inputToken2 / balanceToken2) * 100; setPercentage(newPercentage); sliderRef.current.style.backgroundSize = `${newPercentage}% 100%`; } else if (balanceToken1 && inputToken1 > 0) { - const newPercentage = - inputToken1 > 0 ? (inputToken1 / balanceToken1) * 100 : 0; + const newPercentage = (inputToken1 / balanceToken1) * 100; setPercentage(newPercentage); sliderRef.current.style.backgroundSize = `${newPercentage}% 100%`; - } else { - sliderRef.current.style.backgroundSize = `0% 100%`; } }, [inputToken1, balanceToken1, inputToken2, balanceToken2]); From 690fa955fd9d43cd0f93a2ffb88c65189bc3e3b9 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Thu, 5 Sep 2024 02:50:33 +0400 Subject: [PATCH 14/30] Remove comments --- src/app/components/OrderInput.tsx | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 60ef0e22..5e112089 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -473,13 +473,12 @@ function UserInputContainer() { const isSellOrder = side === "SELL"; useEffect(() => { - // Reset the slider when switching between buy/sell or market/limit orders if (isMarketOrder) { - sliderCallbackMarketOrder(0); // Reset to 0% for market orders + sliderCallbackMarketOrder(0); } else if (isLimitOrder) { - sliderCallbackLimitOrder(0); // Reset to 0% for limit orders + sliderCallbackLimitOrder(0); } - }, [isBuyOrder, isSellOrder, isMarketOrder, isLimitOrder]); // Runs when any of these states change + }, [isBuyOrder, isSellOrder, isMarketOrder, isLimitOrder]); const sliderCallbackMarketOrder = (newPercentage: number) => { let amount; @@ -537,9 +536,6 @@ function UserInputContainer() { }) ); } - // console.error( - // `Calling sliderCallback for LIMIT order with newPercentage value of ${newPercentage}` - // ); }; return ( @@ -926,22 +922,6 @@ const PercentageSlider: React.FC = ({ callbackOnPercentageUpdate(newPercentage); }; - // useEffect(() => { - // if (!sliderRef.current) { - // return; - // } - - // const target = sliderRef.current; - - // if (!inputToken2 || inputToken2 === 0) { - // setPercentage(0); - // target.value = "0"; - // target.style.backgroundSize = "0% 100%"; - // } else { - // target.style.backgroundSize = `${percentage}% 100%`; - // } - // }, [percentage, inputToken2]); - useEffect(() => { if (!sliderRef.current) { return; From 67c6f58c6eba41a4582cbd45c04a18180f8e6ac5 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Thu, 5 Sep 2024 12:05:25 +0400 Subject: [PATCH 15/30] Fix slider to sync only with one field in Limit orders --- src/app/components/OrderInput.tsx | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 5e112089..f9527582 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -549,6 +549,9 @@ function UserInputContainer() { {isSellOrder && ( // specify "Quantity" @@ -565,6 +568,9 @@ function UserInputContainer() { {isLimitOrder && } @@ -895,11 +901,17 @@ function InputTooltip({ message }: { message: string }) { interface PercentageSliderProps { initialPercentage: number; callbackOnPercentageUpdate: (newPercentage: number) => void; + isLimitOrder: boolean; + isBuyOrder: boolean; + isSellOrder: boolean; } const PercentageSlider: React.FC = ({ initialPercentage, callbackOnPercentageUpdate, + isLimitOrder, + isBuyOrder, + isSellOrder, }) => { const [percentage, setPercentage] = useState(initialPercentage); const [toolTipVisible, setToolTipVisible] = useState(false); @@ -931,7 +943,11 @@ const PercentageSlider: React.FC = ({ sliderRef.current.style.backgroundSize = `0% 100%`; setPercentage(0); - if (balanceToken2 && inputToken2 > 0) { + if (inputToken1 > 0 && isLimitOrder && isBuyOrder) { + return; + } else if (inputToken2 > 0 && isLimitOrder && isSellOrder) { + return; + } else if (balanceToken2 && inputToken2 > 0) { const newPercentage = (inputToken2 / balanceToken2) * 100; setPercentage(newPercentage); sliderRef.current.style.backgroundSize = `${newPercentage}% 100%`; @@ -940,7 +956,15 @@ const PercentageSlider: React.FC = ({ setPercentage(newPercentage); sliderRef.current.style.backgroundSize = `${newPercentage}% 100%`; } - }, [inputToken1, balanceToken1, inputToken2, balanceToken2]); + }, [ + inputToken1, + balanceToken1, + inputToken2, + balanceToken2, + isLimitOrder, + isBuyOrder, + isSellOrder, + ]); return ( <> From e1a4e651c528be21c9c33ca1caa1efa6b0f0afda Mon Sep 17 00:00:00 2001 From: saidam90 Date: Thu, 5 Sep 2024 12:14:10 +0400 Subject: [PATCH 16/30] Refactor sliderCallback function --- src/app/components/OrderInput.tsx | 83 +++++++++---------------------- 1 file changed, 24 insertions(+), 59 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index f9527582..fb704099 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -474,68 +474,29 @@ function UserInputContainer() { useEffect(() => { if (isMarketOrder) { - sliderCallbackMarketOrder(0); + sliderCallback(0, "MARKET"); } else if (isLimitOrder) { - sliderCallbackLimitOrder(0); + sliderCallback(0, "LIMIT"); } }, [isBuyOrder, isSellOrder, isMarketOrder, isLimitOrder]); - const sliderCallbackMarketOrder = (newPercentage: number) => { - let amount; - if (isBuyOrder) { - amount = (balanceToken2 * newPercentage) / 100; - dispatch( - orderInputSlice.actions.setTokenAmount({ - amount: amount, - bestBuy, - bestSell, - balanceToken1: balanceToken1, - balanceToken2: balanceToken2, - specifiedToken: SpecifiedToken.TOKEN_2, - }) - ); - } else if (isSellOrder) { - amount = (balanceToken1 * newPercentage) / 100; - dispatch( - orderInputSlice.actions.setTokenAmount({ - amount: amount, - bestBuy, - bestSell, - balanceToken1: balanceToken1, - balanceToken2: balanceToken2, - specifiedToken: SpecifiedToken.TOKEN_1, - }) - ); - } - }; + const sliderCallback = (newPercentage: number, type: string) => { + const balance = isBuyOrder ? balanceToken2 : balanceToken1; + const amount = (balance * newPercentage) / 100; + const specifiedToken = isBuyOrder + ? SpecifiedToken.TOKEN_2 + : SpecifiedToken.TOKEN_1; - const sliderCallbackLimitOrder = (newPercentage: number) => { - let amount; - if (isBuyOrder) { - amount = (balanceToken2 * newPercentage) / 100; - dispatch( - orderInputSlice.actions.setTokenAmount({ - amount: amount, - bestBuy, - bestSell, - balanceToken1: balanceToken1, - balanceToken2: balanceToken2, - specifiedToken: SpecifiedToken.TOKEN_2, - }) - ); - } else if (isSellOrder) { - amount = (balanceToken1 * newPercentage) / 100; - dispatch( - orderInputSlice.actions.setTokenAmount({ - amount: amount, - bestBuy, - bestSell, - balanceToken1: balanceToken1, - balanceToken2: balanceToken2, - specifiedToken: SpecifiedToken.TOKEN_1, - }) - ); - } + dispatch( + orderInputSlice.actions.setTokenAmount({ + amount, + bestBuy, + bestSell, + balanceToken1, + balanceToken2, + specifiedToken, + }) + ); }; return ( @@ -548,7 +509,9 @@ function UserInputContainer() { /> + sliderCallback(newPercentage, type) + } isLimitOrder={isLimitOrder} isBuyOrder={isBuyOrder} isSellOrder={isSellOrder} @@ -567,7 +530,9 @@ function UserInputContainer() { + sliderCallback(newPercentage, type) + } isLimitOrder={isLimitOrder} isBuyOrder={isBuyOrder} isSellOrder={isSellOrder} From 78c26a857f92dad4e1423af9ef9ad99d78c0633a Mon Sep 17 00:00:00 2001 From: saidam90 Date: Thu, 5 Sep 2024 12:42:15 +0400 Subject: [PATCH 17/30] Subtract xrd fee when the slider is used --- src/app/components/OrderInput.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index fb704099..fd25b197 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -481,7 +481,15 @@ function UserInputContainer() { }, [isBuyOrder, isSellOrder, isMarketOrder, isLimitOrder]); const sliderCallback = (newPercentage: number, type: string) => { - const balance = isBuyOrder ? balanceToken2 : balanceToken1; + const isXRDToken = isBuyOrder + ? token2.symbol === "XRD" + : token1.symbol === "XRD"; + let balance = isBuyOrder ? balanceToken2 : balanceToken1; + + if (newPercentage === 100 && isXRDToken) { + balance = Math.max(balance - XRD_FEE_ALLOWANCE, 0); + } + const amount = (balance * newPercentage) / 100; const specifiedToken = isBuyOrder ? SpecifiedToken.TOKEN_2 From f175e67948e5b6d2f315f811c43059fca61c2360 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Thu, 5 Sep 2024 12:55:14 +0400 Subject: [PATCH 18/30] Add dependencies in sliderCallback function --- src/app/components/OrderInput.tsx | 70 ++++++++++++++++++------------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index fd25b197..3316d224 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState, useRef, ChangeEvent } from "react"; +import { useEffect, useState, useRef, ChangeEvent, useCallback } from "react"; import { AiOutlineInfoCircle } from "react-icons/ai"; import Tippy from "@tippyjs/react"; import "tippy.js/dist/tippy.css"; @@ -472,40 +472,52 @@ function UserInputContainer() { const isBuyOrder = side === "BUY"; const isSellOrder = side === "SELL"; + const sliderCallback = useCallback( + (newPercentage: number, type: string) => { + const isXRDToken = isBuyOrder + ? token2.symbol === "XRD" + : token1.symbol === "XRD"; + let balance = isBuyOrder ? balanceToken2 : balanceToken1; + + if (newPercentage === 100 && isXRDToken) { + balance = Math.max(balance - XRD_FEE_ALLOWANCE, 0); + } + + const amount = (balance * newPercentage) / 100; + const specifiedToken = isBuyOrder + ? SpecifiedToken.TOKEN_2 + : SpecifiedToken.TOKEN_1; + + dispatch( + orderInputSlice.actions.setTokenAmount({ + amount, + bestBuy, + bestSell, + balanceToken1, + balanceToken2, + specifiedToken, + }) + ); + }, + [ + balanceToken1, + balanceToken2, + bestBuy, + bestSell, + dispatch, + isBuyOrder, + token1.symbol, + token2.symbol, + ] + ); + useEffect(() => { if (isMarketOrder) { sliderCallback(0, "MARKET"); } else if (isLimitOrder) { sliderCallback(0, "LIMIT"); } - }, [isBuyOrder, isSellOrder, isMarketOrder, isLimitOrder]); - - const sliderCallback = (newPercentage: number, type: string) => { - const isXRDToken = isBuyOrder - ? token2.symbol === "XRD" - : token1.symbol === "XRD"; - let balance = isBuyOrder ? balanceToken2 : balanceToken1; - - if (newPercentage === 100 && isXRDToken) { - balance = Math.max(balance - XRD_FEE_ALLOWANCE, 0); - } - - const amount = (balance * newPercentage) / 100; - const specifiedToken = isBuyOrder - ? SpecifiedToken.TOKEN_2 - : SpecifiedToken.TOKEN_1; - - dispatch( - orderInputSlice.actions.setTokenAmount({ - amount, - bestBuy, - bestSell, - balanceToken1, - balanceToken2, - specifiedToken, - }) - ); - }; + }, [isBuyOrder, isSellOrder, isMarketOrder, isLimitOrder, sliderCallback]); return (
From 454e4848fca07f4876c165757eef4a179825eb82 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Thu, 5 Sep 2024 13:05:56 +0400 Subject: [PATCH 19/30] Fix lint error --- src/app/components/OrderInput.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 3316d224..7e4c19e1 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -474,6 +474,8 @@ function UserInputContainer() { const sliderCallback = useCallback( (newPercentage: number, type: string) => { + console.log(`Type is: ${type}`); + const isXRDToken = isBuyOrder ? token2.symbol === "XRD" : token1.symbol === "XRD"; From 7dc0d40630ec5a453810665639faa6c4fc5a6131 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Thu, 5 Sep 2024 13:24:29 +0400 Subject: [PATCH 20/30] Remove dependencies from the callBack function --- src/app/components/OrderInput.tsx | 62 +++++++++++++------------------ 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 7e4c19e1..9d81ae4c 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -472,46 +472,34 @@ function UserInputContainer() { const isBuyOrder = side === "BUY"; const isSellOrder = side === "SELL"; - const sliderCallback = useCallback( - (newPercentage: number, type: string) => { - console.log(`Type is: ${type}`); + const sliderCallback = useCallback((newPercentage: number, type: string) => { + console.log(`Type is: ${type}`); - const isXRDToken = isBuyOrder - ? token2.symbol === "XRD" - : token1.symbol === "XRD"; - let balance = isBuyOrder ? balanceToken2 : balanceToken1; + const isXRDToken = isBuyOrder + ? token2.symbol === "XRD" + : token1.symbol === "XRD"; + let balance = isBuyOrder ? balanceToken2 : balanceToken1; - if (newPercentage === 100 && isXRDToken) { - balance = Math.max(balance - XRD_FEE_ALLOWANCE, 0); - } + if (newPercentage === 100 && isXRDToken) { + balance = Math.max(balance - XRD_FEE_ALLOWANCE, 0); + } - const amount = (balance * newPercentage) / 100; - const specifiedToken = isBuyOrder - ? SpecifiedToken.TOKEN_2 - : SpecifiedToken.TOKEN_1; - - dispatch( - orderInputSlice.actions.setTokenAmount({ - amount, - bestBuy, - bestSell, - balanceToken1, - balanceToken2, - specifiedToken, - }) - ); - }, - [ - balanceToken1, - balanceToken2, - bestBuy, - bestSell, - dispatch, - isBuyOrder, - token1.symbol, - token2.symbol, - ] - ); + const amount = (balance * newPercentage) / 100; + const specifiedToken = isBuyOrder + ? SpecifiedToken.TOKEN_2 + : SpecifiedToken.TOKEN_1; + + dispatch( + orderInputSlice.actions.setTokenAmount({ + amount, + bestBuy, + bestSell, + balanceToken1, + balanceToken2, + specifiedToken, + }) + ); + }, []); useEffect(() => { if (isMarketOrder) { From db5878c34b84660bbcdc1cd606bbb26c72f66ea7 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Thu, 5 Sep 2024 13:28:35 +0400 Subject: [PATCH 21/30] Fix bug in the callBack function --- src/app/components/OrderInput.tsx | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 9d81ae4c..3ca72112 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState, useRef, ChangeEvent, useCallback } from "react"; +import { useEffect, useState, useRef, ChangeEvent } from "react"; import { AiOutlineInfoCircle } from "react-icons/ai"; import Tippy from "@tippyjs/react"; import "tippy.js/dist/tippy.css"; @@ -472,9 +472,16 @@ function UserInputContainer() { const isBuyOrder = side === "BUY"; const isSellOrder = side === "SELL"; - const sliderCallback = useCallback((newPercentage: number, type: string) => { - console.log(`Type is: ${type}`); + useEffect(() => { + if (isMarketOrder) { + sliderCallback(0, "MARKET"); + } else if (isLimitOrder) { + sliderCallback(0, "LIMIT"); + } + }, [isBuyOrder, isSellOrder, isMarketOrder, isLimitOrder]); + const sliderCallback = (newPercentage: number, type: string) => { + console.log(`Type is: ${type}`); const isXRDToken = isBuyOrder ? token2.symbol === "XRD" : token1.symbol === "XRD"; @@ -499,15 +506,7 @@ function UserInputContainer() { specifiedToken, }) ); - }, []); - - useEffect(() => { - if (isMarketOrder) { - sliderCallback(0, "MARKET"); - } else if (isLimitOrder) { - sliderCallback(0, "LIMIT"); - } - }, [isBuyOrder, isSellOrder, isMarketOrder, isLimitOrder, sliderCallback]); + }; return (
From 8ff692a4c1435b7715a6a1c17109f6642ff4d336 Mon Sep 17 00:00:00 2001 From: saidam90 Date: Mon, 9 Sep 2024 22:40:28 +0400 Subject: [PATCH 22/30] Make css inline where possible --- src/app/components/OrderInput.tsx | 16 ++++++++++++-- src/app/styles/globals.css | 36 ++----------------------------- 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 3ca72112..cedc748c 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -953,7 +953,19 @@ const PercentageSlider: React.FC = ({ step="1" ref={sliderRef} id="range" - className="w-full absolute cursor-pointer text-base" + className="w-full absolute cursor-pointer text-base appearance-none h-[7px] rounded-md" + style={{ + background: + typeof document !== "undefined" && document.dir === "rtl" + ? "#474d52" + : "transparent", + backgroundImage: + typeof document !== "undefined" && document.dir === "rtl" + ? "linear-gradient(#fff, #fff)" + : "linear-gradient(#474d52, #474d52)", + backgroundSize: `${percentage}% 100%`, + backgroundRepeat: "no-repeat", + }} onMouseDown={() => setToolTipVisible(true)} onMouseUp={() => setToolTipVisible(false)} onMouseEnter={() => setToolTipVisible(true)} @@ -984,7 +996,7 @@ const PercentageSlider: React.FC = ({ .map((_, index) => ( Date: Wed, 11 Sep 2024 23:17:20 +0400 Subject: [PATCH 23/30] Replace calculations with Calculator class --- src/app/components/OrderInput.tsx | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index cedc748c..022ee31b 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -491,7 +491,12 @@ function UserInputContainer() { balance = Math.max(balance - XRD_FEE_ALLOWANCE, 0); } - const amount = (balance * newPercentage) / 100; + // const amount = (balance * newPercentage) / 100; + const amount = Calculator.divide( + Calculator.multiply(balance, newPercentage), + 100 + ); + const specifiedToken = isBuyOrder ? SpecifiedToken.TOKEN_2 : SpecifiedToken.TOKEN_1; @@ -922,11 +927,19 @@ const PercentageSlider: React.FC = ({ } else if (inputToken2 > 0 && isLimitOrder && isSellOrder) { return; } else if (balanceToken2 && inputToken2 > 0) { - const newPercentage = (inputToken2 / balanceToken2) * 100; + // const newPercentage = (inputToken2 / balanceToken2) * 100; + const newPercentage = Calculator.multiply( + Calculator.divide(inputToken2, balanceToken2), + 100 + ); setPercentage(newPercentage); sliderRef.current.style.backgroundSize = `${newPercentage}% 100%`; } else if (balanceToken1 && inputToken1 > 0) { - const newPercentage = (inputToken1 / balanceToken1) * 100; + // const newPercentage = (inputToken1 / balanceToken1) * 100; + const newPercentage = Calculator.multiply( + Calculator.divide(inputToken1, balanceToken1), + 100 + ); setPercentage(newPercentage); sliderRef.current.style.backgroundSize = `${newPercentage}% 100%`; } @@ -972,7 +985,7 @@ const PercentageSlider: React.FC = ({ onMouseLeave={() => setToolTipVisible(false)} /> {percentage}%} + content={{Math.round(percentage)}%} visible={toolTipVisible} onClickOutside={() => setToolTipVisible(false)} arrow={false} @@ -999,7 +1012,8 @@ const PercentageSlider: React.FC = ({ className="dot h-[7px] w-[7px] bg-white rounded-full z-[1] cursor-pointer" style={ { - left: `${(index * 100) / 5}%`, + // left: `${(index * 100) / 5}%`, + left: `Calculator.divide((Calculator.multiply(index, 100)), 5)}%`, } as React.CSSProperties } > @@ -1012,7 +1026,10 @@ const PercentageSlider: React.FC = ({ 0% - + 25% = ({ 75% From df24521b5270d5ae20af4881d503ef20960df03f Mon Sep 17 00:00:00 2001 From: saidam90 Date: Wed, 11 Sep 2024 23:20:29 +0400 Subject: [PATCH 24/30] Delete comments --- src/app/components/OrderInput.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 022ee31b..2c5b3970 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -491,7 +491,6 @@ function UserInputContainer() { balance = Math.max(balance - XRD_FEE_ALLOWANCE, 0); } - // const amount = (balance * newPercentage) / 100; const amount = Calculator.divide( Calculator.multiply(balance, newPercentage), 100 @@ -927,7 +926,6 @@ const PercentageSlider: React.FC = ({ } else if (inputToken2 > 0 && isLimitOrder && isSellOrder) { return; } else if (balanceToken2 && inputToken2 > 0) { - // const newPercentage = (inputToken2 / balanceToken2) * 100; const newPercentage = Calculator.multiply( Calculator.divide(inputToken2, balanceToken2), 100 @@ -935,7 +933,6 @@ const PercentageSlider: React.FC = ({ setPercentage(newPercentage); sliderRef.current.style.backgroundSize = `${newPercentage}% 100%`; } else if (balanceToken1 && inputToken1 > 0) { - // const newPercentage = (inputToken1 / balanceToken1) * 100; const newPercentage = Calculator.multiply( Calculator.divide(inputToken1, balanceToken1), 100 @@ -1012,7 +1009,6 @@ const PercentageSlider: React.FC = ({ className="dot h-[7px] w-[7px] bg-white rounded-full z-[1] cursor-pointer" style={ { - // left: `${(index * 100) / 5}%`, left: `Calculator.divide((Calculator.multiply(index, 100)), 5)}%`, } as React.CSSProperties } From 04dcee33c9323a1675c927fa820674ad04dd61cc Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 21 Sep 2024 00:42:16 +0200 Subject: [PATCH 25/30] fix linter errors --- src/app/components/OrderInput.tsx | 83 +++++++++++++++++-------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 2c5b3970..26215a04 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState, useRef, ChangeEvent } from "react"; +import { useEffect, useState, useRef, ChangeEvent, useCallback } from "react"; import { AiOutlineInfoCircle } from "react-icons/ai"; import Tippy from "@tippyjs/react"; import "tippy.js/dist/tippy.css"; @@ -472,45 +472,52 @@ function UserInputContainer() { const isBuyOrder = side === "BUY"; const isSellOrder = side === "SELL"; - useEffect(() => { - if (isMarketOrder) { - sliderCallback(0, "MARKET"); - } else if (isLimitOrder) { - sliderCallback(0, "LIMIT"); - } - }, [isBuyOrder, isSellOrder, isMarketOrder, isLimitOrder]); - - const sliderCallback = (newPercentage: number, type: string) => { - console.log(`Type is: ${type}`); - const isXRDToken = isBuyOrder - ? token2.symbol === "XRD" - : token1.symbol === "XRD"; - let balance = isBuyOrder ? balanceToken2 : balanceToken1; + const sliderCallback = useCallback( + (newPercentage: number) => { + const isXRDToken = isBuyOrder + ? token2.symbol === "XRD" + : token1.symbol === "XRD"; + let balance = isBuyOrder ? balanceToken2 : balanceToken1; - if (newPercentage === 100 && isXRDToken) { - balance = Math.max(balance - XRD_FEE_ALLOWANCE, 0); - } + if (newPercentage === 100 && isXRDToken) { + balance = Math.max(balance - XRD_FEE_ALLOWANCE, 0); + } - const amount = Calculator.divide( - Calculator.multiply(balance, newPercentage), - 100 - ); + const amount = Calculator.divide( + Calculator.multiply(balance, newPercentage), + 100 + ); - const specifiedToken = isBuyOrder - ? SpecifiedToken.TOKEN_2 - : SpecifiedToken.TOKEN_1; + const specifiedToken = isBuyOrder + ? SpecifiedToken.TOKEN_2 + : SpecifiedToken.TOKEN_1; + + dispatch( + orderInputSlice.actions.setTokenAmount({ + amount, + bestBuy, + bestSell, + balanceToken1, + balanceToken2, + specifiedToken, + }) + ); + }, + [ + isBuyOrder, + token1.symbol, + token2.symbol, + balanceToken1, + balanceToken2, + bestBuy, + bestSell, + dispatch, + ] + ); - dispatch( - orderInputSlice.actions.setTokenAmount({ - amount, - bestBuy, - bestSell, - balanceToken1, - balanceToken2, - specifiedToken, - }) - ); - }; + useEffect(() => { + sliderCallback(0); + }, [isBuyOrder, isSellOrder, isMarketOrder, isLimitOrder, sliderCallback]); return (
@@ -523,7 +530,7 @@ function UserInputContainer() { - sliderCallback(newPercentage, type) + sliderCallback(newPercentage) } isLimitOrder={isLimitOrder} isBuyOrder={isBuyOrder} @@ -544,7 +551,7 @@ function UserInputContainer() { - sliderCallback(newPercentage, type) + sliderCallback(newPercentage) } isLimitOrder={isLimitOrder} isBuyOrder={isBuyOrder} From 66da34800837861ce93a48c9e2f83a25198a5f0b Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 21 Sep 2024 01:05:33 +0200 Subject: [PATCH 26/30] remove NONZERO_AMOUNT error, and disable button if nonzero amount is selected instead --- src/app/components/OrderInput.tsx | 3 +++ src/app/state/locales/en/errors.json | 1 - src/app/state/locales/pt/errors.json | 1 - src/app/state/orderInputSlice.ts | 16 ---------------- 4 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 26215a04..e8df96a4 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -370,6 +370,7 @@ function SubmitButton() { side, type, token1, + token2, quote, quoteDescription, quoteError, @@ -382,7 +383,9 @@ function SubmitButton() { const hasQuoteError = quoteError !== undefined; const isLimitOrder = type === OrderType.LIMIT; const isBuyOrder = side === OrderSide.BUY; + const isZeroAmount = token1.amount === 0 || token2.amount === 0; const disabled = + isZeroAmount || !hasQuote || hasQuoteError || !isConnected || diff --git a/src/app/state/locales/en/errors.json b/src/app/state/locales/en/errors.json index 7ed58ff1..2ff0e430 100644 --- a/src/app/state/locales/en/errors.json +++ b/src/app/state/locales/en/errors.json @@ -1,7 +1,6 @@ { "UNSPECIFIED_PRICE": "Price must be specified", "NONZERO_PRICE": "Price must be greater than 0", - "NONZERO_AMOUNT": "Amount must be greater than 0", "HIGH_PRICE": "Price is significantly higher than best sell", "LOW_PRICE": "Price is significantly lower than best buy", "EXCESSIVE_DECIMALS": "Too many decimal places", diff --git a/src/app/state/locales/pt/errors.json b/src/app/state/locales/pt/errors.json index dbd78f14..dda644fc 100644 --- a/src/app/state/locales/pt/errors.json +++ b/src/app/state/locales/pt/errors.json @@ -1,7 +1,6 @@ { "UNSPECIFIED_PRICE": "Preço deve ser especificado", "NONZERO_PRICE": "Preço deve ser maior que 0", - "NONZERO_AMOUNT": "Quantidade deve ser maior que 0", "HIGH_PRICE": "Preço está significativamente maior que a melhor oferta de venda", "LOW_PRICE": "Preço está significativamente menor que a melhor oferta de compra", "EXCESSIVE_DECIMALS": "Excesso de casas decimais", diff --git a/src/app/state/orderInputSlice.ts b/src/app/state/orderInputSlice.ts index 9d0239f4..0dd8e85c 100644 --- a/src/app/state/orderInputSlice.ts +++ b/src/app/state/orderInputSlice.ts @@ -40,7 +40,6 @@ export enum SpecifiedToken { export enum ErrorMessage { NONZERO_PRICE = "NONZERO_PRICE", - NONZERO_AMOUNT = "NONZERO_AMOUNT", INSUFFICIENT_FUNDS = "INSUFFICIENT_FUNDS", COULD_NOT_GET_QUOTE = "COULD_NOT_GET_QUOTE", INSUFFICIENT_LIQUDITIY = "INSUFFICIENT_LIQUDITIY", @@ -422,21 +421,6 @@ export const orderInputSlice = createSlice({ state.price = bestPrice; } - // Set zero amount error - if (amount === 0) { - if (specifiedToken === SpecifiedToken.TOKEN_1) { - state.validationToken1 = { - valid: false, - message: ErrorMessage.NONZERO_AMOUNT, - }; - } else if (specifiedToken === SpecifiedToken.TOKEN_2) { - state.validationToken2 = { - valid: false, - message: ErrorMessage.NONZERO_AMOUNT, - }; - } - } - // Set insufficient balance for specifiedToken if ( specifiedToken === SpecifiedToken.TOKEN_1 && From 842c772a4f8e55c1848dbe56d2fb6318d9094b78 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 21 Sep 2024 01:07:11 +0200 Subject: [PATCH 27/30] move slider below input field for MARKET orders --- src/app/components/OrderInput.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index e8df96a4..1ed0d9b0 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -530,6 +530,12 @@ function UserInputContainer() { userAction={UserAction.UPDATE_PRICE} disabled={true} /> + {isSellOrder && ( // specify "Quantity" + + )} + {isBuyOrder && ( // specify "Total" + + )} @@ -539,12 +545,6 @@ function UserInputContainer() { isBuyOrder={isBuyOrder} isSellOrder={isSellOrder} /> - {isSellOrder && ( // specify "Quantity" - - )} - {isBuyOrder && ( // specify "Total" - - )} )} {isLimitOrder && ( From 11396f565c08aab75af4a1a8334702857ff8804b Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 21 Sep 2024 01:09:12 +0200 Subject: [PATCH 28/30] reduce emphasis on the slider by adding opacity 70% --- src/app/components/OrderInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 1ed0d9b0..4b6e4ae5 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -962,7 +962,7 @@ const PercentageSlider: React.FC = ({ return ( <> -
+
Date: Sat, 21 Sep 2024 01:17:12 +0200 Subject: [PATCH 29/30] add possibility to click labels to set the percentage --- src/app/components/OrderInput.tsx | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/app/components/OrderInput.tsx b/src/app/components/OrderInput.tsx index 4b6e4ae5..21e18b7d 100644 --- a/src/app/components/OrderInput.tsx +++ b/src/app/components/OrderInput.tsx @@ -960,6 +960,11 @@ const PercentageSlider: React.FC = ({ isSellOrder, ]); + const handleClickOnLabel = (newPercentage: number) => { + setPercentage(newPercentage); + callbackOnPercentageUpdate(newPercentage); + }; + return ( <>
@@ -1029,30 +1034,38 @@ const PercentageSlider: React.FC = ({
- + handleClickOnLabel(0)} + > 0% handleClickOnLabel(25)} > 25% handleClickOnLabel(50)} > 50% handleClickOnLabel(75)} > 75% handleClickOnLabel(100)} > 100% From 12f2e974072f95212b3c6a8cbd265496e546f064 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 9 Nov 2024 00:51:49 +0100 Subject: [PATCH 30/30] removed zero token1 and token2 validation, as setting the slider UI to 0 will trigger that warning, which we do not want --- src/app/state/orderInputSlice.test.ts | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/app/state/orderInputSlice.test.ts b/src/app/state/orderInputSlice.test.ts index 1d3d07f3..a8a919bd 100644 --- a/src/app/state/orderInputSlice.test.ts +++ b/src/app/state/orderInputSlice.test.ts @@ -66,32 +66,6 @@ describe("OrderInputSlice", () => { ); }); - it("Validation works for zero token1 amount", () => { - store.dispatch( - orderInputSlice.actions.setTokenAmount({ - amount: 0, - specifiedToken: SpecifiedToken.TOKEN_1, - }) - ); - expect(store.getState().orderInput.validationToken1.valid).toBe(false); - expect(store.getState().orderInput.validationToken1.message).toBe( - ErrorMessage.NONZERO_AMOUNT - ); - }); - - it("Validation works for zero token2 amount", () => { - store.dispatch( - orderInputSlice.actions.setTokenAmount({ - amount: 0, - specifiedToken: SpecifiedToken.TOKEN_2, - }) - ); - expect(store.getState().orderInput.validationToken2.valid).toBe(false); - expect(store.getState().orderInput.validationToken2.message).toBe( - ErrorMessage.NONZERO_AMOUNT - ); - }); - it("Validation works for insufficient balance for token1 on sell order ", () => { store.dispatch(orderInputSlice.actions.setSide(OrderSide.SELL)); store.dispatch(