mars-v2-frontend/src/components/NumberInput.tsx

158 lines
4.6 KiB
TypeScript
Raw Normal View History

'use client'
import BigNumber from 'bignumber.js'
import classNames from 'classnames'
import React, { useEffect, useState } from 'react'
import { demagnify, formatValue, magnify } from 'utils/formatters'
import { BN } from 'utils/helpers'
interface Props {
asset: Asset
amount: BigNumber
min?: BigNumber
max?: BigNumber
className: string
maxDecimals: number
maxLength?: number
allowNegative?: boolean
style?: {}
Mp 2344 fund credit account flow (#145) * MP-2344: first draft for the fund account flow * tidy: refactor * fix: fixed the callback functions * fix: fixed the toast message for funding * fix: some logic fixes * feat: enabled closing of “fund account” * fix: z-1 to isolate use isolate to create a stacking context * tidy: deleted icons * MP-2344: updated the tooltip * MP-2344: new create and funding logic * MP-2344: finished AccountList UI * tidy: svg icon updates * chore: updated dependencies * feat: convert inputValues to amounts and amounts to inputValues * fix: build fix * fix: fixed imports * fix: pr updated * fix: fixed the SWR queries to not override themselves * tidy: refactor * feat: added TokenInputWithSlider * tidy: refactor TokenInputWithSlider * feat: preparations for the accountBalance calculations * fix: removed formatCurrency from store * feat: added global Coin type * tidy: refactor delete and create credit account * add useCallback to FundAccount * update api + swr * refactor naming, ssr accounts menu * wip: added static params and href to DesktopNavigation * fix: added TODO statement * add middleware to get url * feat: added scrolling to the active account * tidy: UX improvement on the accounts list * fix: updated the page params * fix: fixed the navigation * fix: fixed the getRouteParams * fix: some logic updates * fix: fixed the accountMenu view * Keep page when selecting new account * fix: fixed useParams * fix: navigation update * fix pr comments * fixed build --------- Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
2023-04-06 17:20:17 +00:00
disabled?: boolean
onChange: (amount: BigNumber) => void
onBlur?: () => void
onFocus?: () => void
onRef?: (ref: React.RefObject<HTMLInputElement>) => void
}
export default function NumberInput(props: Props) {
const inputRef = React.useRef<HTMLInputElement>(null)
const cursorRef = React.useRef(0)
// const max = props.max ? demagnify(props.max, props.asset) : undefined
const [formattedAmount, setFormattedAmount] = useState(
props.amount.shiftedBy(-1 * props.asset.decimals).toString(),
)
useEffect(() => {
setFormattedAmount(
formatValue(props.amount.toNumber(), {
decimals: props.asset.decimals,
maxDecimals: props.asset.decimals,
thousandSeparator: false,
}),
)
Mp 2344 fund credit account flow (#145) * MP-2344: first draft for the fund account flow * tidy: refactor * fix: fixed the callback functions * fix: fixed the toast message for funding * fix: some logic fixes * feat: enabled closing of “fund account” * fix: z-1 to isolate use isolate to create a stacking context * tidy: deleted icons * MP-2344: updated the tooltip * MP-2344: new create and funding logic * MP-2344: finished AccountList UI * tidy: svg icon updates * chore: updated dependencies * feat: convert inputValues to amounts and amounts to inputValues * fix: build fix * fix: fixed imports * fix: pr updated * fix: fixed the SWR queries to not override themselves * tidy: refactor * feat: added TokenInputWithSlider * tidy: refactor TokenInputWithSlider * feat: preparations for the accountBalance calculations * fix: removed formatCurrency from store * feat: added global Coin type * tidy: refactor delete and create credit account * add useCallback to FundAccount * update api + swr * refactor naming, ssr accounts menu * wip: added static params and href to DesktopNavigation * fix: added TODO statement * add middleware to get url * feat: added scrolling to the active account * tidy: UX improvement on the accounts list * fix: updated the page params * fix: fixed the navigation * fix: fixed the getRouteParams * fix: some logic updates * fix: fixed the accountMenu view * Keep page when selecting new account * fix: fixed useParams * fix: navigation update * fix pr comments * fixed build --------- Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
2023-04-06 17:20:17 +00:00
}, [props.amount, props.asset])
useEffect(() => {
if (!props.onRef) return
props.onRef(inputRef)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [inputRef, props.onRef])
const onInputFocus = () => {
inputRef.current?.select()
props.onFocus && props.onFocus()
}
const updateValues = (formatted: string, amount: BigNumber) => {
const lastChar = formatted.charAt(formatted.length - 1)
if (lastChar === '.') {
cursorRef.current = (inputRef.current?.selectionEnd || 0) + 1
} else {
cursorRef.current = inputRef.current?.selectionEnd || 0
}
setFormattedAmount(formatted)
if (!props.amount.isEqualTo(amount)) {
props.onChange(amount)
}
}
useEffect(() => {
if (!inputRef.current) return
const cursor = cursorRef.current
const length = formattedAmount.length
if (cursor > length) {
inputRef.current.setSelectionRange(length, length)
return
}
inputRef.current.setSelectionRange(cursor, cursor)
}, [formattedAmount, inputRef])
const onInputChange = (formattedAmount: string) => {
const numberCount = formattedAmount.match(/[0-9]/g)?.length || 0
const decimals = formattedAmount.split('.')[1]?.length || 0
const lastChar = formattedAmount.charAt(formattedAmount.length - 1)
const isNumber = !isNaN(Number(formattedAmount))
const hasMultipleDots = (formattedAmount.match(/[.,]/g)?.length || 0) > 1
const isSeparator = lastChar === '.' || lastChar === ','
const isNegative = formattedAmount.indexOf('-') > -1
const isLowerThanMinimum =
props.min !== undefined && props.min.isGreaterThan(magnify(formattedAmount, props.asset))
const isHigherThanMaximum =
props.max !== undefined && props.max.isLessThan(magnify(formattedAmount, props.asset))
const isTooLong = props.maxLength !== undefined && numberCount > props.maxLength
const exceedsMaxDecimals = props.maxDecimals !== undefined && decimals > props.maxDecimals
if (isNegative && !props.allowNegative) return
if (isSeparator && formattedAmount.length === 1) {
updateValues('0.', BN(0))
return
}
if (isSeparator && !hasMultipleDots) {
updateValues(formattedAmount.replace(',', '.'), props.amount)
return
}
if (!isNumber || hasMultipleDots) return
if (exceedsMaxDecimals) {
formattedAmount = formattedAmount.substring(0, formattedAmount.length - 1)
}
if (isTooLong) return
if (isLowerThanMinimum && props.min) {
updateValues(String(demagnify(props.min, props.asset)), props.min)
return
}
if (isHigherThanMaximum && props.max) {
updateValues(String(demagnify(props.max, props.asset)), props.max)
return
}
const amount = BN(formattedAmount).shiftedBy(props.asset.decimals)
if (lastChar === '0' && amount.isEqualTo(props.amount)) {
cursorRef.current = (inputRef.current?.selectionEnd || 0) + 1
setFormattedAmount(formattedAmount)
return
}
updateValues(amount.shiftedBy(-1 * props.asset.decimals).toString(), amount)
}
return (
<input
ref={inputRef}
type='text'
value={formattedAmount === '0' ? '' : formattedAmount}
onFocus={onInputFocus}
onChange={(e) => onInputChange(e.target.value)}
onBlur={props.onBlur}
Mp 2344 fund credit account flow (#145) * MP-2344: first draft for the fund account flow * tidy: refactor * fix: fixed the callback functions * fix: fixed the toast message for funding * fix: some logic fixes * feat: enabled closing of “fund account” * fix: z-1 to isolate use isolate to create a stacking context * tidy: deleted icons * MP-2344: updated the tooltip * MP-2344: new create and funding logic * MP-2344: finished AccountList UI * tidy: svg icon updates * chore: updated dependencies * feat: convert inputValues to amounts and amounts to inputValues * fix: build fix * fix: fixed imports * fix: pr updated * fix: fixed the SWR queries to not override themselves * tidy: refactor * feat: added TokenInputWithSlider * tidy: refactor TokenInputWithSlider * feat: preparations for the accountBalance calculations * fix: removed formatCurrency from store * feat: added global Coin type * tidy: refactor delete and create credit account * add useCallback to FundAccount * update api + swr * refactor naming, ssr accounts menu * wip: added static params and href to DesktopNavigation * fix: added TODO statement * add middleware to get url * feat: added scrolling to the active account * tidy: UX improvement on the accounts list * fix: updated the page params * fix: fixed the navigation * fix: fixed the getRouteParams * fix: some logic updates * fix: fixed the accountMenu view * Keep page when selecting new account * fix: fixed useParams * fix: navigation update * fix pr comments * fixed build --------- Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
2023-04-06 17:20:17 +00:00
disabled={props.disabled}
className={classNames(
'w-full cursor-pointer appearance-none border-none bg-transparent text-right outline-none',
props.className,
)}
style={props.style}
/>
)
}