From 2d77bf0da98a115e81b9480206667a312300796c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Fri, 15 Jun 2018 10:09:39 +0200 Subject: [PATCH] Improve InputCurrency - you have more control on what you type, no more weird "empty input" cases - it prevents to type more digits than the currency allows of magnitude - it do everything to prevent you from typing weird things --- src/components/base/InputCurrency/index.js | 85 ++++++++++++---------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/src/components/base/InputCurrency/index.js b/src/components/base/InputCurrency/index.js index 97623746..da1963b0 100644 --- a/src/components/base/InputCurrency/index.js +++ b/src/components/base/InputCurrency/index.js @@ -6,7 +6,6 @@ import styled from 'styled-components' import { formatCurrencyUnit } from '@ledgerhq/live-common/lib/helpers/currencies' import noop from 'lodash/noop' -import isNaN from 'lodash/isNaN' import Box from 'components/base/Box' import Input from 'components/base/Input' @@ -14,6 +13,43 @@ import Select from 'components/base/LegacySelect' import type { Unit } from '@ledgerhq/live-common/lib/types' +// TODO move this back to live common +const numbers = '0123456789' +const sanitizeValueString = ( + unit: Unit, + valueString: string, +): { + display: string, + value: string, +} => { + let display = '' + let value = '' + let decimals = -1 + for (let i = 0; i < valueString.length; i++) { + const c = valueString[i] + if (numbers.indexOf(c) !== -1) { + if (decimals >= 0) { + decimals++ + if (decimals > unit.magnitude) break + value += c + display += c + } else if (value !== '0') { + value += c + display += c + } + } else if (decimals === -1 && (c === ',' || c === '.')) { + if (i === 0) display = '0' + decimals = 0 + display += '.' + } + } + for (let i = decimals; i < unit.magnitude; ++i) { + value += '0' + } + if (!value) value = '0' + return { display, value } +} + function format(unit: Unit, value: number, { isFocused, showAllDigits, subMagnitude }) { // FIXME do we need locale for the input too ? return formatCurrencyUnit(unit, value, { @@ -81,9 +117,10 @@ class InputCurrency extends PureComponent { componentWillReceiveProps(nextProps: Props) { const { value, showAllDigits, unit } = this.props const needsToBeReformatted = - value !== nextProps.value || - showAllDigits !== nextProps.showAllDigits || - unit !== nextProps.unit + !this.state.isFocused && + (value !== nextProps.value || + showAllDigits !== nextProps.showAllDigits || + unit !== nextProps.unit) if (needsToBeReformatted) { const { isFocused } = this.state this.setState({ @@ -100,31 +137,13 @@ class InputCurrency extends PureComponent { } handleChange = (v: string) => { - // FIXME this is to refactor. this is hacky and don't cover everything.. - - v = v.toString().replace(/,/g, '.') - - // allow to type directly `.` in input to have `0.` - if (v.startsWith('.')) { - v = `0${v}` - } - - // forbid multiple 0 at start - if (v === '' || v.startsWith('00')) { - const { onChange, unit } = this.props - onChange(0, unit) - this.setState({ displayValue: '' }) - return - } - - // Check if value is valid Number - const asNumber = parseFloat(v) - if (isNaN(asNumber) || !isFinite(asNumber) || asNumber < 0) { - return + const { onChange, unit, value } = this.props + const r = sanitizeValueString(unit, v) + const satoshiValue = parseInt(r.value, 10) + if (value !== satoshiValue) { + onChange(satoshiValue, unit) } - - this.emitOnChange(v) - this.setState({ displayValue: v || '' }) + this.setState({ displayValue: r.display }) } handleBlur = () => { @@ -148,16 +167,6 @@ class InputCurrency extends PureComponent { }) } - emitOnChange = (v: string) => { - const { onChange, unit } = this.props - const { displayValue } = this.state - - if (displayValue.toString() !== v.toString()) { - const satoshiValue = Number(v) * 10 ** unit.magnitude - onChange(satoshiValue, unit) - } - } - renderItem = item => item.code renderSelected = item => {item.code}