13 changed files with 411 additions and 245 deletions
@ -0,0 +1,132 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React, { PureComponent } from 'react' |
||||
|
|
||||
|
import { parseCurrencyUnit, formatCurrencyUnit } from '@ledgerhq/currencies' |
||||
|
|
||||
|
import noop from 'lodash/noop' |
||||
|
import isNaN from 'lodash/isNaN' |
||||
|
|
||||
|
import Input from 'components/base/Input' |
||||
|
|
||||
|
import type { Unit } from '@ledgerhq/currencies' |
||||
|
|
||||
|
function parseValue(value) { |
||||
|
return value.toString().replace(/,/, '.') |
||||
|
} |
||||
|
|
||||
|
function format(unit: Unit, value: Value) { |
||||
|
let v = value === '' ? 0 : Number(value) |
||||
|
v *= 10 ** unit.magnitude |
||||
|
return formatCurrencyUnit(unit, v, { |
||||
|
disableRounding: true, |
||||
|
showAllDigits: false, |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function unformat(unit, value) { |
||||
|
if (value === 0 || value === '') { |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
let v = parseCurrencyUnit(unit, value.toString()) |
||||
|
v /= 10 ** unit.magnitude |
||||
|
|
||||
|
return v |
||||
|
} |
||||
|
|
||||
|
type Value = string | number |
||||
|
|
||||
|
type Props = { |
||||
|
onChange: Function, |
||||
|
value: Value, |
||||
|
unit: Unit, |
||||
|
} |
||||
|
|
||||
|
type State = { |
||||
|
isFocus: boolean, |
||||
|
value: Value, |
||||
|
} |
||||
|
|
||||
|
class InputCurrency extends PureComponent<Props, State> { |
||||
|
static defaultProps = { |
||||
|
onChange: noop, |
||||
|
value: 0, |
||||
|
} |
||||
|
|
||||
|
state = { |
||||
|
isFocus: false, |
||||
|
value: this.props.value, |
||||
|
} |
||||
|
|
||||
|
componentWillReceiveProps(nextProps: Props) { |
||||
|
if (this.props.value !== nextProps.value) { |
||||
|
const { isFocus } = this.state |
||||
|
const value = isFocus ? nextProps.value : format(nextProps.unit, nextProps.value) |
||||
|
this.setState({ |
||||
|
value, |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
handleChange = (v: Value) => { |
||||
|
v = parseValue(v) |
||||
|
|
||||
|
// Check if value is valid Number
|
||||
|
if (isNaN(Number(v))) { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
this.emitOnChange(v) |
||||
|
this.setState({ |
||||
|
value: v, |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
handleBlur = () => { |
||||
|
const { unit } = this.props |
||||
|
const { value } = this.state |
||||
|
|
||||
|
const v = format(unit, value) |
||||
|
|
||||
|
this.setState({ |
||||
|
isFocus: false, |
||||
|
value: v, |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
handleFocus = () => { |
||||
|
const { unit } = this.props |
||||
|
|
||||
|
this.setState(prev => ({ |
||||
|
isFocus: true, |
||||
|
value: unformat(unit, prev.value), |
||||
|
})) |
||||
|
} |
||||
|
|
||||
|
emitOnChange = (v: Value) => { |
||||
|
const { onChange } = this.props |
||||
|
const { value } = this.state |
||||
|
|
||||
|
if (value.toString() !== v.toString()) { |
||||
|
onChange(v.toString()) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const { value } = this.state |
||||
|
|
||||
|
return ( |
||||
|
<Input |
||||
|
{...this.props} |
||||
|
ff="Rubik" |
||||
|
value={value} |
||||
|
onChange={this.handleChange} |
||||
|
onFocus={this.handleFocus} |
||||
|
onBlur={this.handleBlur} |
||||
|
/> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default InputCurrency |
@ -0,0 +1,15 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React from 'react' |
||||
|
import { storiesOf } from '@storybook/react' |
||||
|
import { action } from '@storybook/addon-actions' |
||||
|
|
||||
|
import { getDefaultUnitByCoinType } from '@ledgerhq/currencies' |
||||
|
|
||||
|
import InputCurrency from 'components/base/InputCurrency' |
||||
|
|
||||
|
const stories = storiesOf('Components/InputCurrency', module) |
||||
|
|
||||
|
const unit = getDefaultUnitByCoinType(1) |
||||
|
|
||||
|
stories.add('basic', () => <InputCurrency unit={unit} onChange={action('onChange')} />) |
Loading…
Reference in new issue