fix: amount input field to properly interpret BTC (#800)

This commit is contained in:
apX13_ 2024-08-17 17:34:04 +05:30 committed by GitHub
parent ead874a366
commit 072a41950d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 95 additions and 65 deletions

View file

@ -95,4 +95,25 @@ describe('<BitcoinAmountInput />', () => {
expect(inputElement.dataset.displayUnit).toBe(undefined)
expect(inputElement.dataset.displayValue).toBe('')
})
it('amount 1.0 should be interpreted as 1 BTC', async () => {
setup({
label: 'test-label',
})
const inputElement = screen.getByLabelText('test-label')
await user.type(inputElement, '1.0')
expect(inputElement).toHaveFocus()
expect(inputElement.dataset.value).toBe('100000000')
expect(inputElement.dataset.displayUnit).toBe('BTC')
expect(inputElement.dataset.displayValue).toBe(`1.0`)
await user.tab()
expect(inputElement).not.toHaveFocus()
expect(inputElement.dataset.value).toBe('100000000')
expect(inputElement.dataset.displayUnit).toBe('BTC')
expect(inputElement.dataset.displayValue).toBe(`1.00 000 000`)
})
})

View file

@ -61,6 +61,78 @@ const BitcoinAmountInput = forwardRef(
: undefined
}, [field, inputType])
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
setInputType({
type: 'text',
inputMode: 'decimal',
})
let displayValue = String(field.value?.value || '')
if (isValidNumber(field.value?.value)) {
displayValue = formatBtcDisplayValue(field.value!.value!)
}
form.setFieldValue(
field.name,
{
...field.value,
displayValue,
},
false,
)
field.onBlur(e)
}
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const rawUserInputOrEmpty = e.target.value ?? ''
const validNumberRegex = /^-?\d*\.?\d*$/
if (!validNumberRegex.test(rawUserInputOrEmpty)) {
return
}
const floatValueOrNan = parseFloat(rawUserInputOrEmpty)
if (!isValidNumber(floatValueOrNan)) {
form.setFieldValue(
field.name,
{
...field.value,
value: null,
userRawInputValue: e.target.value,
displayValue: e.target.value,
},
true,
)
return
} else {
const value: number = floatValueOrNan
let numberValues: string | undefined
const unit =
rawUserInputOrEmpty.includes('.') && parseFloat(rawUserInputOrEmpty)
? unitFromValue(String(rawUserInputOrEmpty))
: unitFromValue(String(value))
if (unit === 'BTC') {
const splitted = String(value).split('.')
const [integerPart, fractionalPart = ''] = splitted
const paddedFractionalPart = fractionalPart.padEnd(8, '0').substring(0, 8)
numberValues = `${integerPart}${paddedFractionalPart}`
} else {
numberValues = value.toLocaleString('en-US', {
maximumFractionDigits: 0,
useGrouping: false,
})
}
form.setFieldValue(
field.name,
{
value: parseInt(numberValues, 10),
userRawInputValue: e.target.value,
displayValue: e.target.value,
},
true,
)
}
}
return (
<>
<rb.InputGroup hasValidation={true}>
@ -77,7 +149,6 @@ const BitcoinAmountInput = forwardRef(
data-display-value={field.value?.displayValue}
name={field.name}
autoComplete="off"
type={inputType.type}
inputMode={inputType.inputMode}
className={classNames('slashed-zeroes', className)}
value={
@ -92,70 +163,8 @@ const BitcoinAmountInput = forwardRef(
onFocus={() => {
setInputType({ type: 'number' })
}}
onBlur={(e) => {
setInputType({
type: 'text',
inputMode: 'decimal',
})
let displayValue = String(field.value?.value || '')
if (isValidNumber(field.value?.value)) {
displayValue = formatBtcDisplayValue(field.value!.value!)
}
form.setFieldValue(
field.name,
{
...field.value,
displayValue,
},
false,
)
field.onBlur(e)
}}
onChange={(e) => {
const valueOrNan = parseFloat(e.target.value ?? '')
if (!isValidNumber(valueOrNan)) {
form.setFieldValue(
field.name,
{
...field.value,
value: null,
userRawInputValue: e.target.value,
displayValue: e.target.value,
},
true,
)
return
} else {
const value: number = valueOrNan
let numberValues: string | undefined
const unit = unitFromValue(String(value))
if (unit === 'BTC') {
const splitted = String(value).split('.')
const [integerPart, fractionalPart = ''] = splitted
const paddedFractionalPart = fractionalPart.padEnd(8, '0').substring(0, 8)
numberValues = `${integerPart}${paddedFractionalPart}`
} else {
numberValues = value.toLocaleString('en-US', {
maximumFractionDigits: 0,
useGrouping: false,
})
}
form.setFieldValue(
field.name,
{
value: parseInt(numberValues, 10),
userRawInputValue: e.target.value,
displayValue: e.target.value,
},
true,
)
}
}}
onBlur={handleBlur}
onChange={handleChange}
/>
{children}
<rb.Form.Control.Feedback type="invalid">