Browse Source

Finally get rid of magnitude manipulation

master
meriadec 7 years ago
parent
commit
cbd607c223
No known key found for this signature in database GPG Key ID: 1D2FC2305E2CB399
  1. 77
      src/components/RequestAmount/index.js
  2. 39
      src/components/RequestAmount/stories.js
  3. 71
      src/components/base/InputCurrency/index.js
  4. 18
      src/components/base/InputCurrency/stories.js
  5. 4
      src/components/modals/Send/01-step-amount.js
  6. 20
      src/components/modals/Send/Footer.js
  7. 23
      src/components/modals/Send/index.js

77
src/components/RequestAmount/index.js

@ -52,7 +52,7 @@ type Props = {
max: number,
// change handler
onChange: ({ left: number, right: number }) => void,
onChange: number => void,
// used to determine the left input unit
account: Account,
@ -66,91 +66,40 @@ type Props = {
getReverseCounterValue: CalculateCounterValue,
}
type State = {
leftUnit: Unit,
rightUnit: Unit,
leftValue: number,
rightValue: number,
}
export class RequestAmount extends PureComponent<Props, State> {
constructor(props: Props) {
super(props)
const { account, rightUnit, value, getCounterValue } = this.props
// @TODO forced to do those horrible and redondant calculations in order
// to make `getCounterValue` works. `getCounterValue` should take ticker code,
// and the both units in parameter. Not "a currency and a unit".
const rawLeftValue = value * 10 ** account.unit.magnitude
const rawRightValue = getCounterValue(account.currency, rightUnit)(rawLeftValue)
const rightValue = rawRightValue / 10 ** rightUnit.magnitude
this.state = {
leftUnit: account.unit,
rightUnit,
leftValue: value,
rightValue,
}
}
export class RequestAmount extends PureComponent<Props> {
handleClickMax = () => {
const leftValue = this.props.max / 10 ** this.props.account.unit.magnitude
this.handleChangeAmount('left')(leftValue)
this.setState({ leftValue })
this.props.onChange(this.props.max)
}
handleChangeAmount = (changedField: string) => (val: number) => {
const { getCounterValue, getReverseCounterValue, account, max, onChange } = this.props
const { rightUnit } = this.state
// @TODO forced to do those horrible and redondant calculations in order
// to make `getCounterValue` works. `getCounterValue` should take ticker code,
// and the both units in parameter. Not "a currency and a unit".
const { rightUnit, getReverseCounterValue, account, max, onChange } = this.props
if (changedField === 'left') {
let rawLeftValue = val * 10 ** account.unit.magnitude
if (rawLeftValue > max) {
rawLeftValue = max
}
const leftValue = rawLeftValue / 10 ** account.unit.magnitude
const rawRightValue = getCounterValue(account.currency, rightUnit)(rawLeftValue)
const rightValue = rawRightValue / 10 ** rightUnit.magnitude
this.setState({ rightValue, leftValue })
onChange({ left: rawLeftValue, right: rawRightValue })
onChange(val > max ? max : val)
} else if (changedField === 'right') {
let rawRightValue = val * 10 ** rightUnit.magnitude
let rawLeftValue = getReverseCounterValue(account.currency, rightUnit)(rawRightValue)
if (rawLeftValue > max) {
rawLeftValue = max
rawRightValue = getCounterValue(account.currency, rightUnit)(rawLeftValue)
}
const rightValue = rawRightValue / 10 ** rightUnit.magnitude
const leftValue = rawLeftValue / 10 ** account.unit.magnitude
this.setState({ rightValue, leftValue })
onChange({ left: rawLeftValue, right: rawRightValue })
const leftVal = getReverseCounterValue(account.currency, rightUnit)(val)
onChange(leftVal > max ? max : leftVal)
}
}
render() {
const { t } = this.props
const { leftUnit, rightUnit, leftValue, rightValue } = this.state
const { t, value, account, rightUnit, getCounterValue } = this.props
const right = getCounterValue(account.currency, rightUnit)(value)
return (
<Box horizontal flow="5">
<Box horizontal align="center">
<InputCurrency
containerProps={{ style: { width: 156 } }}
unit={leftUnit}
value={leftValue}
unit={account.unit}
value={value}
onChange={this.handleChangeAmount('left')}
renderRight={<InputRight>{leftUnit.code}</InputRight>}
renderRight={<InputRight>{account.unit.code}</InputRight>}
/>
<InputCenter>=</InputCenter>
<InputCurrency
containerProps={{ style: { width: 156 } }}
unit={rightUnit}
value={rightValue}
value={right}
onChange={this.handleChangeAmount('right')}
renderRight={<InputRight>{rightUnit.code}</InputRight>}
/>

39
src/components/RequestAmount/stories.js

@ -1,6 +1,6 @@
// @flow
import React from 'react'
import React, { PureComponent } from 'react'
import { storiesOf } from '@storybook/react'
import { action } from '@storybook/addon-actions'
@ -10,13 +10,30 @@ import RequestAmount from 'components/RequestAmount'
const stories = storiesOf('Components', module)
stories.add('RequestAmount', () => (
<RequestAmount
t={k => k}
counterValue="USD"
account={accounts[0]}
onChange={action('onChange')}
value={3}
max={400000000000}
/>
))
type State = {
value: number,
}
class Wrapper extends PureComponent<any, State> {
state = {
value: 3e8,
}
handleChange = value => {
action('onChange')(value)
this.setState({ value })
}
render() {
const { value } = this.state
return (
<RequestAmount
counterValue="USD"
account={accounts[0]}
onChange={this.handleChange}
value={value}
max={4e8}
/>
)
}
}
stories.add('RequestAmount', () => <Wrapper />)

71
src/components/base/InputCurrency/index.js

@ -17,10 +17,8 @@ function parseValue(value) {
return value.toString().replace(/,/g, '.')
}
function format(unit: Unit, value: Value) {
let v = value === '' ? 0 : Number(value)
v *= 10 ** unit.magnitude
return formatCurrencyUnit(unit, v, {
function format(unit: Unit, value: number) {
return formatCurrencyUnit(unit, value, {
disableRounding: true,
showAllDigits: false,
})
@ -28,13 +26,13 @@ function format(unit: Unit, value: Value) {
function unformat(unit, value) {
if (value === 0 || value === '') {
return 0
return '0'
}
let v = parseCurrencyUnit(unit, value.toString())
v /= 10 ** unit.magnitude
return v
return v.toString()
}
const Currencies = styled(Box)`
@ -50,19 +48,17 @@ const Currency = styled(Box).attrs({
pr: 1,
})``
type Value = string | number
type Props = {
onChange: Function,
renderRight: any,
unit: Unit,
units: Array<Unit>,
value: Value,
value: number,
}
type State = {
isFocus: boolean,
value: Value,
displayValue: string,
}
class InputCurrency extends PureComponent<Props, State> {
@ -75,43 +71,46 @@ class InputCurrency extends PureComponent<Props, State> {
state = {
isFocus: false,
value: this.props.value,
displayValue: '0',
}
componentWillMount() {
const { value, unit } = this.props
const displayValue = format(unit, value)
this.setState({ displayValue })
}
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,
})
const displayValue = isFocus
? (nextProps.value / 10 ** nextProps.unit.magnitude).toString()
: format(nextProps.unit, nextProps.value)
this.setState({ displayValue })
}
}
handleChange = (v: Value) => {
handleChange = (v: string) => {
// const { displayValue } = this.state
v = parseValue(v)
if (v.startsWith('00')) {
return
}
// Check if value is valid Number
if (isNaN(Number(v))) {
return
}
this.emitOnChange(v)
this.setState({
value: v,
})
this.setState({ displayValue: v || '0' })
}
handleBlur = () => {
const { unit } = this.props
const { value } = this.state
const { unit, value } = this.props
const v = format(unit, value)
this.setState({
isFocus: false,
value: v,
})
this.setState({ isFocus: false, displayValue: v })
}
handleFocus = () => {
@ -119,22 +118,22 @@ class InputCurrency extends PureComponent<Props, State> {
this.setState(prev => ({
isFocus: true,
value: unformat(unit, prev.value),
displayValue: unformat(unit, prev.displayValue),
}))
}
emitOnChange = (v: Value) => {
emitOnChange = (v: string) => {
const { onChange, unit } = this.props
const { value } = this.state
const { displayValue } = this.state
if (value.toString() !== v.toString()) {
onChange(Number(v), unit)
if (displayValue.toString() !== v.toString()) {
const satoshiValue = Number(v) * 10 ** unit.magnitude
onChange(satoshiValue, unit)
}
}
renderListUnits = () => {
const { unit, units, onChange } = this.props
const { value } = this.state
const { unit, units, onChange, value } = this.props
if (units.length <= 1) {
return null
@ -158,13 +157,13 @@ class InputCurrency extends PureComponent<Props, State> {
render() {
const { renderRight } = this.props
const { value } = this.state
const { displayValue } = this.state
return (
<Input
{...this.props}
ff="Rubik"
value={value}
value={displayValue}
onChange={this.handleChange}
onFocus={this.handleFocus}
onBlur={this.handleBlur}

18
src/components/base/InputCurrency/stories.js

@ -2,28 +2,26 @@
import React, { Component } from 'react'
import { storiesOf } from '@storybook/react'
import { action } from '@storybook/addon-actions'
import { getDefaultUnitByCoinType, getFiatUnit } from '@ledgerhq/currencies'
import { getCurrencyByCoinType } from '@ledgerhq/currencies'
import InputCurrency from 'components/base/InputCurrency'
const stories = storiesOf('Components', module)
const units = [
getDefaultUnitByCoinType(1),
getDefaultUnitByCoinType(2),
getDefaultUnitByCoinType(3),
getDefaultUnitByCoinType(6),
getFiatUnit('USD'),
]
const { units } = getCurrencyByCoinType(1)
class Wrapper extends Component<any, any> {
state = {
value: 0,
value: 1e8,
unit: units[0],
}
handleChange = (value, unit) => this.setState({ value, unit })
handleChange = (value, unit) => {
action('onChange')(value, unit)
this.setState({ value, unit })
}
render() {
const { render } = this.props

4
src/components/modals/Send/01-step-amount.js

@ -22,7 +22,7 @@ type PropsStepAmount = {
account: Account | null,
onChange: Function,
recipientAddress: string,
amount: { left: number, right: number },
amount: number,
fees: {
value: number,
unit: Unit | null,
@ -64,7 +64,7 @@ function StepAmount(props: PropsStepAmount) {
max={account.balance - 0}
account={account}
onChange={onChange('amount')}
value={amount.left}
value={amount}
/>
</Box>

20
src/components/modals/Send/Footer.js

@ -8,6 +8,7 @@ import type { T } from 'types/common'
import { ModalFooter } from 'components/base/Modal'
import Box from 'components/base/Box'
import Label from 'components/base/Label'
import CounterValue from 'components/CounterValue'
import FormattedVal from 'components/base/FormattedVal'
import Button from 'components/base/Button'
import Text from 'components/base/Text'
@ -15,35 +16,28 @@ import Text from 'components/base/Text'
type Props = {
t: T,
account: Account,
amount: { left: number, right: number },
amount: number,
onNext: Function,
canNext: boolean,
counterValue: string,
}
function Footer({ account, amount, t, onNext, canNext, counterValue }: Props) {
function Footer({ account, amount, t, onNext, canNext }: Props) {
return (
<ModalFooter horizontal alignItems="center">
<Box grow>
<Label>{t('send:totalSpent')}</Label>
<Box horizontal flow={2} align="center">
<FormattedVal
disableRounding
color="dark"
val={amount.left}
unit={account.unit}
showCode
/>
<FormattedVal disableRounding color="dark" val={amount} unit={account.unit} showCode />
<Box horizontal align="center">
<Text ff="Rubik" fontSize={3}>
{'('}
</Text>
<FormattedVal
<CounterValue
ticker={account.currency.units[0].code}
value={amount}
disableRounding
color="grey"
fontSize={3}
val={amount.right}
fiat={counterValue}
showCode
/>
<Text ff="Rubik" fontSize={3}>

23
src/components/modals/Send/index.js

@ -1,8 +1,6 @@
// @flow
import React, { PureComponent } from 'react'
import { compose } from 'redux'
import { connect } from 'react-redux'
import { translate } from 'react-i18next'
import get from 'lodash/get'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
@ -12,8 +10,6 @@ import type { T } from 'types/common'
import { MODAL_SEND } from 'config/constants'
import { getCounterValueCode } from 'reducers/settings'
import Breadcrumb from 'components/Breadcrumb'
import Modal, { ModalBody, ModalTitle, ModalContent } from 'components/base/Modal'
@ -24,19 +20,14 @@ import StepConnectDevice from './02-step-connect-device'
import StepVerification from './03-step-verification'
import StepConfirmation from './04-step-confirmation'
const mapStateToProps = state => ({
counterValue: getCounterValueCode(state),
})
type Props = {
t: T,
counterValue: string,
}
type State = {
stepIndex: number,
isDeviceReady: boolean,
amount: { left: number, right: number },
amount: number,
account: Account | null,
recipientAddress: string,
fees: {
@ -58,10 +49,7 @@ const INITIAL_STATE = {
isDeviceReady: false,
account: null,
recipientAddress: '',
amount: {
left: 0,
right: 0,
},
amount: 0,
fees: {
value: 0,
unit: null,
@ -80,7 +68,7 @@ class SendModal extends PureComponent<Props, State> {
// informations
if (stepIndex === 0) {
const { amount, recipientAddress } = this.state
return !!amount.left && !!recipientAddress && !!account
return !!amount && !!recipientAddress && !!account
}
// connect device
@ -121,7 +109,7 @@ class SendModal extends PureComponent<Props, State> {
}
render() {
const { t, counterValue } = this.props
const { t } = this.props
const { stepIndex, amount, account } = this.state
return (
@ -140,7 +128,6 @@ class SendModal extends PureComponent<Props, State> {
</ModalContent>
{acc && (
<Footer
counterValue={counterValue}
canNext={canNext}
onNext={this.handleNextStep}
account={acc}
@ -156,4 +143,4 @@ class SendModal extends PureComponent<Props, State> {
}
}
export default compose(connect(mapStateToProps), translate())(SendModal)
export default translate()(SendModal)

Loading…
Cancel
Save