feat: debounce input sliders (#784)
* feat: debounce input sliders * fix: fixed the debounce function
This commit is contained in:
parent
6d5e7c7325
commit
6ac7708ca5
@ -24,6 +24,7 @@ interface Props {
|
|||||||
onClose: () => void
|
onClose: () => void
|
||||||
onChange: (value: BigNumber) => void
|
onChange: (value: BigNumber) => void
|
||||||
onAction: (value: BigNumber, isMax: boolean) => void
|
onAction: (value: BigNumber, isMax: boolean) => void
|
||||||
|
onDebounce: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AssetAmountSelectActionModal(props: Props) {
|
export default function AssetAmountSelectActionModal(props: Props) {
|
||||||
@ -36,6 +37,7 @@ export default function AssetAmountSelectActionModal(props: Props) {
|
|||||||
onClose,
|
onClose,
|
||||||
onChange,
|
onChange,
|
||||||
onAction,
|
onAction,
|
||||||
|
onDebounce,
|
||||||
} = props
|
} = props
|
||||||
const [amount, setAmount] = useState(BN_ZERO)
|
const [amount, setAmount] = useState(BN_ZERO)
|
||||||
const maxAmount = BN(coinBalances.find(byDenom(asset.denom))?.amount ?? 0)
|
const maxAmount = BN(coinBalances.find(byDenom(asset.denom))?.amount ?? 0)
|
||||||
@ -74,6 +76,7 @@ export default function AssetAmountSelectActionModal(props: Props) {
|
|||||||
<TokenInputWithSlider
|
<TokenInputWithSlider
|
||||||
asset={asset}
|
asset={asset}
|
||||||
onChange={handleAmountChange}
|
onChange={handleAmountChange}
|
||||||
|
onDebounce={onDebounce}
|
||||||
amount={amount}
|
amount={amount}
|
||||||
max={maxAmount}
|
max={maxAmount}
|
||||||
hasSelect
|
hasSelect
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
|
|
||||||
import AccountSummary from 'components/account/AccountSummary'
|
import Modal from 'components/Modals/Modal'
|
||||||
import AssetImage from 'components/common/assets/AssetImage'
|
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
|
||||||
import Button from 'components/common/Button'
|
import Button from 'components/common/Button'
|
||||||
import Card from 'components/common/Card'
|
import Card from 'components/common/Card'
|
||||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||||
@ -13,7 +13,7 @@ import Switch from 'components/common/Switch'
|
|||||||
import Text from 'components/common/Text'
|
import Text from 'components/common/Text'
|
||||||
import TitleAndSubCell from 'components/common/TitleAndSubCell'
|
import TitleAndSubCell from 'components/common/TitleAndSubCell'
|
||||||
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
||||||
import Modal from 'components/Modals/Modal'
|
import AssetImage from 'components/common/assets/AssetImage'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||||
import useMarkets from 'hooks/markets/useMarkets'
|
import useMarkets from 'hooks/markets/useMarkets'
|
||||||
@ -29,7 +29,6 @@ import { byDenom } from 'utils/array'
|
|||||||
import { formatPercent } from 'utils/formatters'
|
import { formatPercent } from 'utils/formatters'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import { getDebtAmountWithInterest } from 'utils/tokens'
|
import { getDebtAmountWithInterest } from 'utils/tokens'
|
||||||
import AccountSummaryInModal from 'components/account/AccountSummary/AccountSummaryInModal'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
account: Account
|
account: Account
|
||||||
@ -92,6 +91,7 @@ function BorrowModal(props: Props) {
|
|||||||
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
||||||
const { computeMaxBorrowAmount } = useHealthComputer(account)
|
const { computeMaxBorrowAmount } = useHealthComputer(account)
|
||||||
const totalDebt = BN(getDebtAmount(modal))
|
const totalDebt = BN(getDebtAmount(modal))
|
||||||
|
const accountDebt = account.debts.find(byDenom(asset.denom))?.amount ?? BN_ZERO
|
||||||
const markets = useMarkets()
|
const markets = useMarkets()
|
||||||
|
|
||||||
const [depositBalance, lendBalance] = useMemo(
|
const [depositBalance, lendBalance] = useMemo(
|
||||||
@ -102,34 +102,34 @@ function BorrowModal(props: Props) {
|
|||||||
[account, asset.denom],
|
[account, asset.denom],
|
||||||
)
|
)
|
||||||
|
|
||||||
const totalDebtRepayAmount = useMemo(
|
const accountDebtWithInterest = useMemo(
|
||||||
() => getDebtAmountWithInterest(totalDebt, apy),
|
() => getDebtAmountWithInterest(accountDebt, apy),
|
||||||
[totalDebt, apy],
|
[accountDebt, apy],
|
||||||
)
|
)
|
||||||
|
|
||||||
const overpayExeedsCap = useMemo(() => {
|
const overpayExeedsCap = useMemo(() => {
|
||||||
const marketAsset = markets.find((market) => market.asset.denom === asset.denom)
|
const marketAsset = markets.find((market) => market.asset.denom === asset.denom)
|
||||||
if (!marketAsset) return
|
if (!marketAsset) return
|
||||||
const overpayAmount = totalDebtRepayAmount.minus(totalDebt)
|
const overpayAmount = accountDebtWithInterest.minus(accountDebt)
|
||||||
const marketCapAfterOverpay = marketAsset.cap.used.plus(overpayAmount)
|
const marketCapAfterOverpay = marketAsset.cap.used.plus(overpayAmount)
|
||||||
|
|
||||||
return marketAsset.cap.max.isLessThanOrEqualTo(marketCapAfterOverpay)
|
return marketAsset.cap.max.isLessThanOrEqualTo(marketCapAfterOverpay)
|
||||||
}, [markets, asset.denom, totalDebt, totalDebtRepayAmount])
|
}, [markets, asset.denom, accountDebt, accountDebtWithInterest])
|
||||||
|
|
||||||
const maxRepayAmount = useMemo(() => {
|
const maxRepayAmount = useMemo(() => {
|
||||||
const maxBalance = repayFromWallet
|
const maxBalance = repayFromWallet
|
||||||
? BN(walletBalances.find(byDenom(asset.denom))?.amount ?? 0)
|
? BN(walletBalances.find(byDenom(asset.denom))?.amount ?? 0)
|
||||||
: depositBalance.plus(lendBalance)
|
: depositBalance.plus(lendBalance)
|
||||||
return isRepay
|
return isRepay
|
||||||
? BigNumber.min(maxBalance, overpayExeedsCap ? totalDebt : totalDebtRepayAmount)
|
? BigNumber.min(maxBalance, overpayExeedsCap ? accountDebt : accountDebtWithInterest)
|
||||||
: BN_ZERO
|
: BN_ZERO
|
||||||
}, [
|
}, [
|
||||||
depositBalance,
|
depositBalance,
|
||||||
lendBalance,
|
lendBalance,
|
||||||
isRepay,
|
isRepay,
|
||||||
totalDebtRepayAmount,
|
accountDebtWithInterest,
|
||||||
overpayExeedsCap,
|
overpayExeedsCap,
|
||||||
totalDebt,
|
accountDebt,
|
||||||
walletBalances,
|
walletBalances,
|
||||||
asset.denom,
|
asset.denom,
|
||||||
repayFromWallet,
|
repayFromWallet,
|
||||||
@ -149,7 +149,7 @@ function BorrowModal(props: Props) {
|
|||||||
repay({
|
repay({
|
||||||
accountId: account.id,
|
accountId: account.id,
|
||||||
coin: BNCoin.fromDenomAndBigNumber(asset.denom, amount),
|
coin: BNCoin.fromDenomAndBigNumber(asset.denom, amount),
|
||||||
accountBalance: amount.isEqualTo(totalDebtRepayAmount),
|
accountBalance: amount.isEqualTo(accountDebtWithInterest),
|
||||||
lend: repayFromWallet ? BNCoin.fromDenomAndBigNumber(asset.denom, BN_ZERO) : lend,
|
lend: repayFromWallet ? BNCoin.fromDenomAndBigNumber(asset.denom, BN_ZERO) : lend,
|
||||||
fromWallet: repayFromWallet,
|
fromWallet: repayFromWallet,
|
||||||
})
|
})
|
||||||
@ -172,17 +172,39 @@ function BorrowModal(props: Props) {
|
|||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(newAmount: BigNumber) => {
|
(newAmount: BigNumber) => {
|
||||||
const coin = BNCoin.fromDenomAndBigNumber(asset.denom, newAmount)
|
|
||||||
if (!amount.isEqualTo(newAmount)) setAmount(newAmount)
|
if (!amount.isEqualTo(newAmount)) setAmount(newAmount)
|
||||||
if (!isRepay) return
|
|
||||||
const repayCoin = coin.amount.isGreaterThan(totalDebt)
|
|
||||||
? BNCoin.fromDenomAndBigNumber(asset.denom, totalDebt)
|
|
||||||
: coin
|
|
||||||
simulateRepay(repayCoin, repayFromWallet)
|
|
||||||
},
|
},
|
||||||
[amount, asset.denom, isRepay, simulateRepay, totalDebt, repayFromWallet],
|
[amount, setAmount],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const onDebounce = useCallback(() => {
|
||||||
|
if (isRepay) {
|
||||||
|
const repayCoin = BNCoin.fromDenomAndBigNumber(
|
||||||
|
asset.denom,
|
||||||
|
amount.isGreaterThan(accountDebt) ? accountDebt : amount,
|
||||||
|
)
|
||||||
|
simulateRepay(repayCoin, repayFromWallet)
|
||||||
|
} else {
|
||||||
|
const borrowCoin = BNCoin.fromDenomAndBigNumber(
|
||||||
|
asset.denom,
|
||||||
|
amount.isGreaterThan(max) ? max : amount,
|
||||||
|
)
|
||||||
|
const target = borrowToWallet ? 'wallet' : isAutoLendEnabled ? 'lend' : 'deposit'
|
||||||
|
simulateBorrow(target, borrowCoin)
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
amount,
|
||||||
|
isRepay,
|
||||||
|
repayFromWallet,
|
||||||
|
maxRepayAmount,
|
||||||
|
max,
|
||||||
|
asset,
|
||||||
|
borrowToWallet,
|
||||||
|
isAutoLendEnabled,
|
||||||
|
simulateBorrow,
|
||||||
|
simulateRepay,
|
||||||
|
])
|
||||||
|
|
||||||
const maxBorrow = useMemo(() => {
|
const maxBorrow = useMemo(() => {
|
||||||
const maxBorrowAmount = isRepay
|
const maxBorrowAmount = isRepay
|
||||||
? BN_ZERO
|
? BN_ZERO
|
||||||
@ -209,13 +231,6 @@ function BorrowModal(props: Props) {
|
|||||||
setAmount(max)
|
setAmount(max)
|
||||||
}, [amount, max, handleChange])
|
}, [amount, max, handleChange])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isRepay) return
|
|
||||||
const coin = BNCoin.fromDenomAndBigNumber(asset.denom, amount.isGreaterThan(max) ? max : amount)
|
|
||||||
const target = borrowToWallet ? 'wallet' : isAutoLendEnabled ? 'lend' : 'deposit'
|
|
||||||
simulateBorrow(target, coin)
|
|
||||||
}, [isRepay, borrowToWallet, isAutoLendEnabled, simulateBorrow, asset, amount, max])
|
|
||||||
|
|
||||||
if (!modal || !asset) return null
|
if (!modal || !asset) return null
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -257,7 +272,7 @@ function BorrowModal(props: Props) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Text size='xs' className='text-white/50' tag='span'>
|
<Text size='xs' className='text-white/50' tag='span'>
|
||||||
Borrowed
|
Total Borrowed
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@ -294,6 +309,7 @@ function BorrowModal(props: Props) {
|
|||||||
<TokenInputWithSlider
|
<TokenInputWithSlider
|
||||||
asset={asset}
|
asset={asset}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
onDebounce={onDebounce}
|
||||||
amount={amount}
|
amount={amount}
|
||||||
max={max}
|
max={max}
|
||||||
disabled={max.isZero()}
|
disabled={max.isZero()}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import { useEffect, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
|
|
||||||
import Button from 'components/common/Button'
|
import Button from 'components/common/Button'
|
||||||
import Divider from 'components/common/Divider'
|
import Divider from 'components/common/Divider'
|
||||||
@ -86,17 +86,10 @@ export default function WithdrawFromAccount(props: Props) {
|
|||||||
useStore.setState({ fundAndWithdrawModal: null })
|
useStore.setState({ fundAndWithdrawModal: null })
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
const onDebounce = useCallback(() => {
|
||||||
const coin = BNCoin.fromDenomAndBigNumber(currentAsset.denom, withdrawAmount.plus(debtAmount))
|
const coin = BNCoin.fromDenomAndBigNumber(currentAsset.denom, withdrawAmount.plus(debtAmount))
|
||||||
simulateWithdraw(withdrawWithBorrowing, coin)
|
simulateWithdraw(withdrawWithBorrowing, coin)
|
||||||
}, [
|
}, [withdrawWithBorrowing, currentAsset.denom, debtAmount, simulateWithdraw, withdrawAmount])
|
||||||
amount,
|
|
||||||
withdrawWithBorrowing,
|
|
||||||
currentAsset.denom,
|
|
||||||
debtAmount,
|
|
||||||
simulateWithdraw,
|
|
||||||
withdrawAmount,
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -104,6 +97,7 @@ export default function WithdrawFromAccount(props: Props) {
|
|||||||
<TokenInputWithSlider
|
<TokenInputWithSlider
|
||||||
asset={currentAsset}
|
asset={currentAsset}
|
||||||
onChange={onChangeAmount}
|
onChange={onChangeAmount}
|
||||||
|
onDebounce={onDebounce}
|
||||||
onChangeAsset={(asset) => {
|
onChangeAsset={(asset) => {
|
||||||
setAmount(BN_ZERO)
|
setAmount(BN_ZERO)
|
||||||
setWithdrawWithBorrowing(false)
|
setWithdrawWithBorrowing(false)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useCallback } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
|
|
||||||
import AssetAmountSelectActionModal from 'components/Modals/AssetAmountSelectActionModal'
|
import AssetAmountSelectActionModal from 'components/Modals/AssetAmountSelectActionModal'
|
||||||
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
|
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
|
||||||
@ -27,6 +27,7 @@ function LendAndReclaimModal({ currentAccount, config }: Props) {
|
|||||||
const reclaim = useStore((s) => s.reclaim)
|
const reclaim = useStore((s) => s.reclaim)
|
||||||
const { close } = useLendAndReclaimModal()
|
const { close } = useLendAndReclaimModal()
|
||||||
const { simulateLending } = useUpdatedAccount(currentAccount)
|
const { simulateLending } = useUpdatedAccount(currentAccount)
|
||||||
|
const [coin, setCoin] = useState<BNCoin>()
|
||||||
|
|
||||||
const { data, action } = config
|
const { data, action } = config
|
||||||
const { asset } = data
|
const { asset } = data
|
||||||
@ -37,12 +38,16 @@ function LendAndReclaimModal({ currentAccount, config }: Props) {
|
|||||||
|
|
||||||
const handleAmountChange = useCallback(
|
const handleAmountChange = useCallback(
|
||||||
(value: BigNumber) => {
|
(value: BigNumber) => {
|
||||||
const coin = BNCoin.fromDenomAndBigNumber(asset.denom, value)
|
setCoin(BNCoin.fromDenomAndBigNumber(asset.denom, value))
|
||||||
simulateLending(isLendAction, coin)
|
|
||||||
},
|
},
|
||||||
[asset.denom, isLendAction, simulateLending],
|
[asset.denom],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const onDebounce = useCallback(() => {
|
||||||
|
if (!coin) return
|
||||||
|
simulateLending(isLendAction, coin)
|
||||||
|
}, [coin, isLendAction, simulateLending])
|
||||||
|
|
||||||
const handleAction = useCallback(
|
const handleAction = useCallback(
|
||||||
(value: BigNumber, isMax: boolean) => {
|
(value: BigNumber, isMax: boolean) => {
|
||||||
const coin = BNCoin.fromDenomAndBigNumber(asset.denom, value)
|
const coin = BNCoin.fromDenomAndBigNumber(asset.denom, value)
|
||||||
@ -70,6 +75,7 @@ function LendAndReclaimModal({ currentAccount, config }: Props) {
|
|||||||
onClose={close}
|
onClose={close}
|
||||||
onAction={handleAction}
|
onAction={handleAction}
|
||||||
onChange={handleAmountChange}
|
onChange={handleAmountChange}
|
||||||
|
onDebounce={onDebounce}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -95,10 +95,6 @@ export default function AccountFundContent(props: Props) {
|
|||||||
}
|
}
|
||||||
}, [baseBalance])
|
}, [baseBalance])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
simulateDeposits(isLending ? 'lend' : 'deposit', fundingAssets)
|
|
||||||
}, [isLending, fundingAssets, simulateDeposits])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentSelectedDenom = fundingAssets.map((asset) => asset.denom)
|
const currentSelectedDenom = fundingAssets.map((asset) => asset.denom)
|
||||||
|
|
||||||
@ -125,6 +121,10 @@ export default function AccountFundContent(props: Props) {
|
|||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const onDebounce = useCallback(() => {
|
||||||
|
simulateDeposits(isLending ? 'lend' : 'deposit', fundingAssets)
|
||||||
|
}, [isLending, fundingAssets, simulateDeposits])
|
||||||
|
|
||||||
const depositCapReachedCoins = useMemo(() => {
|
const depositCapReachedCoins = useMemo(() => {
|
||||||
const depositCapReachedCoins: BNCoin[] = []
|
const depositCapReachedCoins: BNCoin[] = []
|
||||||
fundingAssets.forEach((asset) => {
|
fundingAssets.forEach((asset) => {
|
||||||
@ -159,6 +159,7 @@ export default function AccountFundContent(props: Props) {
|
|||||||
amount={coin.amount ?? BN_ZERO}
|
amount={coin.amount ?? BN_ZERO}
|
||||||
isConfirming={isConfirming}
|
isConfirming={isConfirming}
|
||||||
updateFundingAssets={updateFundingAssets}
|
updateFundingAssets={updateFundingAssets}
|
||||||
|
onDebounce={onDebounce}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -10,6 +10,7 @@ interface Props {
|
|||||||
denom: string
|
denom: string
|
||||||
isConfirming: boolean
|
isConfirming: boolean
|
||||||
updateFundingAssets: (amount: BigNumber, denom: string) => void
|
updateFundingAssets: (amount: BigNumber, denom: string) => void
|
||||||
|
onDebounce: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AccountFundRow(props: Props) {
|
export default function AccountFundRow(props: Props) {
|
||||||
@ -23,6 +24,7 @@ export default function AccountFundRow(props: Props) {
|
|||||||
<TokenInputWithSlider
|
<TokenInputWithSlider
|
||||||
asset={asset}
|
asset={asset}
|
||||||
onChange={(amount) => props.updateFundingAssets(amount, asset.denom)}
|
onChange={(amount) => props.updateFundingAssets(amount, asset.denom)}
|
||||||
|
onDebounce={props.onDebounce}
|
||||||
amount={props.amount}
|
amount={props.amount}
|
||||||
max={balance}
|
max={balance}
|
||||||
balances={props.balances}
|
balances={props.balances}
|
||||||
|
@ -11,7 +11,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function BorrowActionButtons(props: Props) {
|
export default function BorrowActionButtons(props: Props) {
|
||||||
const { asset, debt } = props.data
|
const { asset, accountDebt } = props.data
|
||||||
const marketAssets = useMarketEnabledAssets()
|
const marketAssets = useMarketEnabledAssets()
|
||||||
const currentAsset = marketAssets.find((a) => a.denom === asset.denom)
|
const currentAsset = marketAssets.find((a) => a.denom === asset.denom)
|
||||||
|
|
||||||
@ -33,10 +33,10 @@ export default function BorrowActionButtons(props: Props) {
|
|||||||
leftIcon={<Plus className='w-3' />}
|
leftIcon={<Plus className='w-3' />}
|
||||||
onClick={borrowHandler}
|
onClick={borrowHandler}
|
||||||
color='secondary'
|
color='secondary'
|
||||||
text={debt ? 'Borrow more' : 'Borrow'}
|
text={accountDebt ? 'Borrow more' : 'Borrow'}
|
||||||
className='min-w-40 text-center'
|
className='text-center min-w-40'
|
||||||
/>
|
/>
|
||||||
{debt && (
|
{accountDebt && (
|
||||||
<Button color='tertiary' leftIcon={<HandCoins />} text='Repay' onClick={repayHandler} />
|
<Button color='tertiary' leftIcon={<HandCoins />} text='Repay' onClick={repayHandler} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { ChangeEvent, useCallback } from 'react'
|
import debounce from 'lodash.debounce'
|
||||||
|
import { ChangeEvent, useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
import InputOverlay from 'components/common/LeverageSlider/InputOverlay'
|
import InputOverlay from 'components/common/LeverageSlider/InputOverlay'
|
||||||
|
|
||||||
@ -13,20 +14,41 @@ type Props = {
|
|||||||
marginThreshold?: number
|
marginThreshold?: number
|
||||||
wrapperClassName?: string
|
wrapperClassName?: string
|
||||||
onChange: (value: number) => void
|
onChange: (value: number) => void
|
||||||
|
onDebounce?: () => void
|
||||||
onBlur?: () => void
|
onBlur?: () => void
|
||||||
type: LeverageSliderType
|
type: LeverageSliderType
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LeverageSliderType = 'margin' | 'long' | 'short'
|
export type LeverageSliderType = 'margin' | 'long' | 'short'
|
||||||
function LeverageSlider(props: Props) {
|
function LeverageSlider(props: Props) {
|
||||||
const { value, max, onChange, wrapperClassName, disabled, marginThreshold, onBlur, type } = props
|
const {
|
||||||
|
value,
|
||||||
|
max,
|
||||||
|
onChange,
|
||||||
|
wrapperClassName,
|
||||||
|
disabled,
|
||||||
|
marginThreshold,
|
||||||
|
onBlur,
|
||||||
|
type,
|
||||||
|
onDebounce,
|
||||||
|
} = props
|
||||||
const min = props.min ?? 0
|
const min = props.min ?? 0
|
||||||
|
|
||||||
|
const debounceFunction = useMemo(
|
||||||
|
() =>
|
||||||
|
debounce(() => {
|
||||||
|
if (!onDebounce) return
|
||||||
|
onDebounce()
|
||||||
|
}, 250),
|
||||||
|
[onDebounce],
|
||||||
|
)
|
||||||
|
|
||||||
const handleOnChange = useCallback(
|
const handleOnChange = useCallback(
|
||||||
(event: ChangeEvent<HTMLInputElement>) => {
|
(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
onChange(parseFloat(event.target.value))
|
onChange(parseFloat(event.target.value))
|
||||||
|
debounceFunction()
|
||||||
},
|
},
|
||||||
[onChange],
|
[onChange, debounceFunction],
|
||||||
)
|
)
|
||||||
|
|
||||||
const markPosPercent = 100 / (max / (marginThreshold ?? 1))
|
const markPosPercent = 100 / (max / (marginThreshold ?? 1))
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
import debounce from 'lodash.debounce'
|
||||||
import { ChangeEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { ChangeEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import Draggable from 'react-draggable'
|
import Draggable from 'react-draggable'
|
||||||
|
|
||||||
@ -19,6 +20,7 @@ const colors = {
|
|||||||
type Props = {
|
type Props = {
|
||||||
value: number
|
value: number
|
||||||
onChange: (value: number) => void
|
onChange: (value: number) => void
|
||||||
|
onDebounce?: () => void
|
||||||
leverage?: {
|
leverage?: {
|
||||||
current: number
|
current: number
|
||||||
max: number
|
max: number
|
||||||
@ -28,6 +30,7 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Slider(props: Props) {
|
export default function Slider(props: Props) {
|
||||||
|
const { value, onChange, onDebounce, leverage, className, disabled } = props
|
||||||
const [showTooltip, setShowTooltip] = useToggle()
|
const [showTooltip, setShowTooltip] = useToggle()
|
||||||
const [sliderRect, setSliderRect] = useState({ width: 0, left: 0, right: 0 })
|
const [sliderRect, setSliderRect] = useState({ width: 0, left: 0, right: 0 })
|
||||||
const ref = useRef<HTMLDivElement>(null)
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
@ -52,6 +55,20 @@ export default function Slider(props: Props) {
|
|||||||
}
|
}
|
||||||
}, [sliderRect.left, sliderRect.right, sliderRect.width])
|
}, [sliderRect.left, sliderRect.right, sliderRect.width])
|
||||||
|
|
||||||
|
const debounceFunction = useMemo(
|
||||||
|
() =>
|
||||||
|
debounce(() => {
|
||||||
|
if (!onDebounce) return
|
||||||
|
onDebounce()
|
||||||
|
}, 250),
|
||||||
|
[onDebounce],
|
||||||
|
)
|
||||||
|
|
||||||
|
function handleOnChange(value: number) {
|
||||||
|
onChange(value)
|
||||||
|
debounceFunction()
|
||||||
|
}
|
||||||
|
|
||||||
function handleDrag(e: any) {
|
function handleDrag(e: any) {
|
||||||
if (!isDragging) {
|
if (!isDragging) {
|
||||||
setIsDragging(true)
|
setIsDragging(true)
|
||||||
@ -60,24 +77,24 @@ export default function Slider(props: Props) {
|
|||||||
const current: number = e.clientX
|
const current: number = e.clientX
|
||||||
|
|
||||||
if (current < sliderRect.left) {
|
if (current < sliderRect.left) {
|
||||||
props.onChange(0)
|
handleOnChange(0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current > sliderRect.right) {
|
if (current > sliderRect.right) {
|
||||||
props.onChange(100)
|
handleOnChange(100)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = Math.round(((current - sliderRect.left) / sliderRect.width) * 100)
|
const currentValue = Math.round(((current - sliderRect.left) / sliderRect.width) * 100)
|
||||||
|
|
||||||
if (value !== props.value) {
|
if (currentValue !== value) {
|
||||||
props.onChange(value)
|
handleOnChange(currentValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSliderClick(e: ChangeEvent<HTMLInputElement>) {
|
function handleSliderClick(e: ChangeEvent<HTMLInputElement>) {
|
||||||
props.onChange(Number(e.target.value))
|
handleOnChange(Number(e.target.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleShowTooltip() {
|
function handleShowTooltip() {
|
||||||
@ -89,21 +106,22 @@ export default function Slider(props: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getActiveIndex() {
|
function getActiveIndex() {
|
||||||
if (props.value >= 100) return '5'
|
if (value >= 100) return '5'
|
||||||
if (props.value >= 75) return '4'
|
if (value >= 75) return '4'
|
||||||
if (props.value >= 50) return '3'
|
if (value >= 50) return '3'
|
||||||
if (props.value >= 25) return '2'
|
if (value >= 25) return '2'
|
||||||
return '1'
|
return '1'
|
||||||
}
|
}
|
||||||
|
|
||||||
const DraggableElement: any = Draggable
|
const DraggableElement: any = Draggable
|
||||||
|
|
||||||
const [positionOffset, position] = useMemo(() => {
|
const [positionOffset, position] = useMemo(() => {
|
||||||
|
debounceFunction()
|
||||||
return [
|
return [
|
||||||
{ x: (props.value / 100) * -12, y: 0 },
|
{ x: (value / 100) * -12, y: 0 },
|
||||||
{ x: (sliderRect.width / 100) * props.value, y: -2 },
|
{ x: (sliderRect.width / 100) * value, y: -2 },
|
||||||
]
|
]
|
||||||
}, [props.value, sliderRect.width])
|
}, [value, sliderRect.width])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleSliderRect()
|
handleSliderRect()
|
||||||
@ -115,60 +133,60 @@ export default function Slider(props: Props) {
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'relative min-h-3 w-full transition-opacity',
|
'relative min-h-3 w-full transition-opacity',
|
||||||
props.className,
|
className,
|
||||||
props.disabled && 'pointer-events-none',
|
disabled && 'pointer-events-none',
|
||||||
)}
|
)}
|
||||||
onMouseEnter={handleSliderRect}
|
onMouseEnter={handleSliderRect}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type='range'
|
type='range'
|
||||||
value={props.value}
|
value={value}
|
||||||
onChange={handleSliderClick}
|
onChange={handleSliderClick}
|
||||||
onMouseDown={handleShowTooltip}
|
onMouseDown={handleShowTooltip}
|
||||||
className='absolute z-2 w-full hover:cursor-pointer appearance-none bg-transparent [&::-webkit-slider-thumb]:h-3 [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:appearance-none'
|
className='absolute z-2 w-full hover:cursor-pointer appearance-none bg-transparent [&::-webkit-slider-thumb]:h-3 [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:appearance-none'
|
||||||
/>
|
/>
|
||||||
<div className='absolute flex items-center w-full gap-1.5'>
|
<div className='absolute flex items-center w-full gap-1.5'>
|
||||||
<Mark
|
<Mark
|
||||||
onClick={props.onChange}
|
onClick={() => handleOnChange(0)}
|
||||||
value={0}
|
value={0}
|
||||||
sliderValue={props.value}
|
sliderValue={value}
|
||||||
disabled={props.disabled}
|
disabled={disabled}
|
||||||
style={{ backgroundColor: colors['1'] }}
|
style={{ backgroundColor: colors['1'] }}
|
||||||
/>
|
/>
|
||||||
<Track maxValue={23} sliderValue={props.value} bg='before:gradient-slider-1' />
|
<Track maxValue={23} sliderValue={value} bg='before:gradient-slider-1' />
|
||||||
<Mark
|
<Mark
|
||||||
onClick={props.onChange}
|
onClick={() => handleOnChange(25)}
|
||||||
value={25}
|
value={25}
|
||||||
sliderValue={props.value}
|
sliderValue={value}
|
||||||
disabled={props.disabled}
|
disabled={disabled}
|
||||||
style={{ backgroundColor: colors['2'] }}
|
style={{ backgroundColor: colors['2'] }}
|
||||||
/>
|
/>
|
||||||
<Track maxValue={48} sliderValue={props.value} bg='before:gradient-slider-2' />
|
<Track maxValue={48} sliderValue={value} bg='before:gradient-slider-2' />
|
||||||
<Mark
|
<Mark
|
||||||
onClick={props.onChange}
|
onClick={() => handleOnChange(50)}
|
||||||
value={50}
|
value={50}
|
||||||
sliderValue={props.value}
|
sliderValue={value}
|
||||||
disabled={props.disabled}
|
disabled={disabled}
|
||||||
style={{ backgroundColor: colors['3'] }}
|
style={{ backgroundColor: colors['3'] }}
|
||||||
/>
|
/>
|
||||||
<Track maxValue={73} sliderValue={props.value} bg='before:gradient-slider-3' />
|
<Track maxValue={73} sliderValue={value} bg='before:gradient-slider-3' />
|
||||||
<Mark
|
<Mark
|
||||||
onClick={props.onChange}
|
onClick={() => handleOnChange(75)}
|
||||||
value={75}
|
value={75}
|
||||||
sliderValue={props.value}
|
sliderValue={value}
|
||||||
disabled={props.disabled}
|
disabled={disabled}
|
||||||
style={{ backgroundColor: colors['4'] }}
|
style={{ backgroundColor: colors['4'] }}
|
||||||
/>
|
/>
|
||||||
<Track maxValue={98} sliderValue={props.value} bg='before:gradient-slider-4' />
|
<Track maxValue={98} sliderValue={value} bg='before:gradient-slider-4' />
|
||||||
<Mark
|
<Mark
|
||||||
onClick={props.onChange}
|
onClick={() => handleOnChange(100)}
|
||||||
value={100}
|
value={100}
|
||||||
sliderValue={props.value}
|
sliderValue={value}
|
||||||
disabled={props.disabled}
|
disabled={disabled}
|
||||||
style={{ backgroundColor: colors['5'] }}
|
style={{ backgroundColor: colors['5'] }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!props.disabled && (
|
{!disabled && (
|
||||||
<div onMouseEnter={handleShowTooltip} onMouseLeave={handleHideTooltip}>
|
<div onMouseEnter={handleShowTooltip} onMouseLeave={handleHideTooltip}>
|
||||||
<DraggableElement
|
<DraggableElement
|
||||||
nodeRef={nodeRef}
|
nodeRef={nodeRef}
|
||||||
@ -187,12 +205,12 @@ export default function Slider(props: Props) {
|
|||||||
)}
|
)}
|
||||||
style={{ background: colors[getActiveIndex()] }}
|
style={{ background: colors[getActiveIndex()] }}
|
||||||
/>
|
/>
|
||||||
{props.leverage ? (
|
{leverage ? (
|
||||||
<div className='pt-2.5'>
|
<div className='pt-2.5'>
|
||||||
<LeverageLabel
|
<LeverageLabel
|
||||||
leverage={props.leverage.current}
|
leverage={leverage.current}
|
||||||
decimals={1}
|
decimals={1}
|
||||||
className={props.leverage.current >= 10 ? '-translate-x-2' : '-translate-x-1'}
|
className={leverage.current >= 10 ? '-translate-x-2' : '-translate-x-1'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@ -203,7 +221,7 @@ export default function Slider(props: Props) {
|
|||||||
'absolute h-2 -translate-x-1/2 -bottom-2 left-1/2 -z-1 text-fuchsia',
|
'absolute h-2 -translate-x-1/2 -bottom-2 left-1/2 -z-1 text-fuchsia',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{props.value.toFixed(0)}%
|
{value.toFixed(0)}%
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
@ -212,19 +230,19 @@ export default function Slider(props: Props) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{props.leverage && (
|
{leverage && (
|
||||||
<div className='flex justify-between pt-2'>
|
<div className='flex justify-between pt-2'>
|
||||||
<LeverageLabel
|
<LeverageLabel
|
||||||
leverage={1}
|
leverage={1}
|
||||||
decimals={0}
|
decimals={0}
|
||||||
className='-translate-x-0.5'
|
className='-translate-x-0.5'
|
||||||
style={{ opacity: props.value < 5 ? 0 : 1 }}
|
style={{ opacity: value < 5 ? 0 : 1 }}
|
||||||
/>
|
/>
|
||||||
<LeverageLabel
|
<LeverageLabel
|
||||||
leverage={props.leverage.max || 1}
|
leverage={leverage.max || 1}
|
||||||
decimals={0}
|
decimals={0}
|
||||||
className='translate-x-1.5'
|
className='translate-x-1.5'
|
||||||
style={{ opacity: props.value > 95 ? 0 : 1 }}
|
style={{ opacity: value > 95 ? 0 : 1 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -12,6 +12,7 @@ interface Props {
|
|||||||
asset: Asset
|
asset: Asset
|
||||||
max: BigNumber
|
max: BigNumber
|
||||||
onChange: (amount: BigNumber) => void
|
onChange: (amount: BigNumber) => void
|
||||||
|
onDebounce?: () => void
|
||||||
accountId?: string
|
accountId?: string
|
||||||
balances?: BNCoin[]
|
balances?: BNCoin[]
|
||||||
className?: string
|
className?: string
|
||||||
@ -37,6 +38,11 @@ export default function TokenInputWithSlider(props: Props) {
|
|||||||
props.onChange(newAmount)
|
props.onChange(newAmount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onDebounce() {
|
||||||
|
if (!props.onDebounce) return
|
||||||
|
props.onDebounce()
|
||||||
|
}
|
||||||
|
|
||||||
function onChangeAmount(newAmount: BigNumber) {
|
function onChangeAmount(newAmount: BigNumber) {
|
||||||
setAmount(newAmount)
|
setAmount(newAmount)
|
||||||
setPercentage(BN(newAmount).dividedBy(props.max).multipliedBy(100).toNumber())
|
setPercentage(BN(newAmount).dividedBy(props.max).multipliedBy(100).toNumber())
|
||||||
@ -76,6 +82,7 @@ export default function TokenInputWithSlider(props: Props) {
|
|||||||
<Slider
|
<Slider
|
||||||
value={percentage || 0}
|
value={percentage || 0}
|
||||||
onChange={(value) => onChangeSlider(value)}
|
onChange={(value) => onChangeSlider(value)}
|
||||||
|
onDebounce={onDebounce}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
leverage={props.leverage}
|
leverage={props.leverage}
|
||||||
/>
|
/>
|
||||||
|
@ -61,6 +61,10 @@ export function PerpsModule() {
|
|||||||
previousTradeDirection,
|
previousTradeDirection,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const onDebounce = useCallback(() => {
|
||||||
|
// TODO: Implement debounced simulation
|
||||||
|
}, [])
|
||||||
|
|
||||||
const setLeverage = useCallback((leverage: number) => {
|
const setLeverage = useCallback((leverage: number) => {
|
||||||
// TODO: Implement leverage setting
|
// TODO: Implement leverage setting
|
||||||
}, [])
|
}, [])
|
||||||
@ -116,6 +120,7 @@ export function PerpsModule() {
|
|||||||
max={10}
|
max={10}
|
||||||
value={leverage}
|
value={leverage}
|
||||||
onChange={setLeverage}
|
onChange={setLeverage}
|
||||||
|
onDebounce={onDebounce}
|
||||||
type={tradeDirection}
|
type={tradeDirection}
|
||||||
/>
|
/>
|
||||||
<LeverageButtons />
|
<LeverageButtons />
|
||||||
|
@ -201,7 +201,7 @@ export default function SwapForm(props: Props) {
|
|||||||
isAutoLendEnabled && !isAutoRepayChecked ? 'lend' : 'deposit',
|
isAutoLendEnabled && !isAutoRepayChecked ? 'lend' : 'deposit',
|
||||||
isAutoRepayChecked,
|
isAutoRepayChecked,
|
||||||
)
|
)
|
||||||
}, 100),
|
}, 250),
|
||||||
[simulateTrade, isAutoLendEnabled, isAutoRepayChecked],
|
[simulateTrade, isAutoLendEnabled, isAutoRepayChecked],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user