12 changed files with 477 additions and 53 deletions
@ -0,0 +1,287 @@ |
|||
// @flow
|
|||
|
|||
import React, { PureComponent } from 'react' |
|||
import { connect } from 'react-redux' |
|||
import { getDefaultUnitByCoinType, getFiatUnit } from '@ledgerhq/currencies' |
|||
|
|||
import isNaN from 'lodash/isNaN' |
|||
|
|||
import type { Account } from 'types/common' |
|||
|
|||
import { getCounterValue } from 'reducers/settings' |
|||
|
|||
import Input from 'components/base/Input' |
|||
import Box from 'components/base/Box' |
|||
|
|||
const mapStateToProps = state => ({ |
|||
counterValue: getCounterValue(state), |
|||
counterValues: state.counterValues, |
|||
}) |
|||
|
|||
function calculateMax(props) { |
|||
const { account, counterValue, lastCounterValue } = props |
|||
|
|||
const unit = { |
|||
currency: getDefaultUnitByCoinType(account.coinType), |
|||
fiat: getFiatUnit(counterValue), |
|||
} |
|||
|
|||
const leftMax = account.balance / 10 ** unit.currency.magnitude |
|||
|
|||
return { |
|||
left: account.balance / 10 ** unit.currency.magnitude, |
|||
right: leftMax * lastCounterValue, |
|||
} |
|||
} |
|||
|
|||
function formatCur(unit, val) { |
|||
if (val === '') { |
|||
return '' |
|||
} |
|||
if (val === '0' || val <= 0) { |
|||
return 0 |
|||
} |
|||
const factor = 10 ** unit.magnitude |
|||
return (Math.round(val * factor) / factor).toFixed(unit.magnitude) |
|||
} |
|||
|
|||
function cleanValue(value) { |
|||
return { |
|||
left: value.left || 0, |
|||
right: value.right || 0, |
|||
} |
|||
} |
|||
|
|||
function parseValue(value) { |
|||
return value.toString().replace(/,/, '.') |
|||
} |
|||
|
|||
function getUnit({ account, counterValue }) { |
|||
return { |
|||
currency: getDefaultUnitByCoinType(account.coinType), |
|||
fiat: getFiatUnit(counterValue), |
|||
} |
|||
} |
|||
|
|||
function calculateValues({ |
|||
dir, |
|||
value, |
|||
max, |
|||
unit, |
|||
lastCounterValue, |
|||
}: { |
|||
dir: string, |
|||
value: string | number, |
|||
max: Object, |
|||
unit: Object, |
|||
lastCounterValue: number, |
|||
}) { |
|||
value = parseValue(value) |
|||
|
|||
const getMax = (d, v) => { |
|||
const result = v > max[d] ? max[d] : v |
|||
return isNaN(result) ? 0 : result |
|||
} |
|||
|
|||
const newValue = {} |
|||
|
|||
if (dir === 'left') { |
|||
newValue.left = value === '' ? value : getMax('left', value) |
|||
newValue.right = formatCur(unit.fiat, getMax('right', Number(value) * lastCounterValue)) |
|||
} |
|||
|
|||
if (dir === 'right') { |
|||
newValue.left = formatCur(unit.currency, getMax('left', Number(value) / lastCounterValue)) |
|||
newValue.right = value === '' ? value : getMax('right', value) |
|||
} |
|||
|
|||
return newValue |
|||
} |
|||
|
|||
type Direction = 'left' | 'right' |
|||
|
|||
type Props = { |
|||
account: Account, |
|||
lastCounterValue: number, |
|||
counterValue: string, |
|||
onChange: Function, |
|||
value: Object, |
|||
} |
|||
|
|||
type State = { |
|||
max: { |
|||
left: number, |
|||
right: number, |
|||
}, |
|||
value: { |
|||
left: string | number, |
|||
right: string | number, |
|||
}, |
|||
} |
|||
|
|||
export class RequestAmount extends PureComponent<Props, State> { |
|||
static defaultProps = { |
|||
value: {}, |
|||
} |
|||
|
|||
constructor(props: Props) { |
|||
super() |
|||
|
|||
this.props = props |
|||
|
|||
const max = calculateMax(props) |
|||
|
|||
let value = {} |
|||
|
|||
if (props.value.left) { |
|||
value = { |
|||
...calculateValues({ |
|||
dir: 'left', |
|||
value: props.value.left, |
|||
max, |
|||
lastCounterValue: props.lastCounterValue, |
|||
unit: getUnit({ |
|||
account: props.account, |
|||
counterValue: props.counterValue, |
|||
}), |
|||
}), |
|||
} |
|||
} |
|||
|
|||
if (props.value.right) { |
|||
value = { |
|||
...calculateValues({ |
|||
dir: 'right', |
|||
value: props.value.right, |
|||
max, |
|||
lastCounterValue: props.lastCounterValue, |
|||
unit: getUnit({ |
|||
account: props.account, |
|||
counterValue: props.counterValue, |
|||
}), |
|||
}), |
|||
} |
|||
} |
|||
|
|||
value = cleanValue(value) |
|||
|
|||
this.state = { |
|||
max, |
|||
value, |
|||
} |
|||
} |
|||
|
|||
componentWillReceiveProps(nextProps: Props) { |
|||
if (this.props.account !== nextProps.account) { |
|||
this.setState({ |
|||
max: calculateMax(nextProps), |
|||
}) |
|||
} |
|||
|
|||
if (this.props.value.left !== nextProps.value.left) { |
|||
this.setState({ |
|||
value: cleanValue({ |
|||
...calculateValues({ |
|||
dir: 'left', |
|||
value: nextProps.value.left, |
|||
max: this.state.max, |
|||
lastCounterValue: nextProps.lastCounterValue, |
|||
unit: getUnit({ |
|||
account: nextProps.account, |
|||
counterValue: nextProps.counterValue, |
|||
}), |
|||
}), |
|||
}), |
|||
}) |
|||
} |
|||
|
|||
if (this.props.value.right !== nextProps.value.right) { |
|||
this.setState({ |
|||
value: cleanValue({ |
|||
...calculateValues({ |
|||
dir: 'right', |
|||
value: nextProps.value.right, |
|||
max: this.state.max, |
|||
lastCounterValue: nextProps.lastCounterValue, |
|||
unit: getUnit({ |
|||
account: nextProps.account, |
|||
counterValue: nextProps.counterValue, |
|||
}), |
|||
}), |
|||
}), |
|||
}) |
|||
} |
|||
} |
|||
|
|||
handleChangeAmount = (dir: Direction) => (v: string) => { |
|||
const { onChange, lastCounterValue, account, counterValue } = this.props |
|||
const { max } = this.state |
|||
|
|||
v = parseValue(v) |
|||
|
|||
// Check if value is valid Number
|
|||
if (isNaN(Number(v))) { |
|||
return |
|||
} |
|||
|
|||
const newValue = calculateValues({ |
|||
dir, |
|||
value: v, |
|||
max, |
|||
lastCounterValue, |
|||
unit: getUnit({ |
|||
account, |
|||
counterValue, |
|||
}), |
|||
}) |
|||
|
|||
this.setState({ |
|||
value: newValue, |
|||
}) |
|||
|
|||
onChange(cleanValue(newValue)) |
|||
} |
|||
|
|||
handleBlur = () => |
|||
this.setState(prev => ({ |
|||
value: cleanValue(prev.value), |
|||
})) |
|||
|
|||
render() { |
|||
const { value } = this.state |
|||
const { account, counterValue } = this.props |
|||
|
|||
const unit = getUnit({ |
|||
account, |
|||
counterValue, |
|||
}) |
|||
|
|||
return ( |
|||
<Box horizontal flow={2}> |
|||
<Box grow horizontal flow={2}> |
|||
<Box justifyContent="center">{unit.currency.code}</Box> |
|||
<Box grow> |
|||
<Input |
|||
value={value.left} |
|||
onBlur={this.handleBlur} |
|||
onChange={this.handleChangeAmount('left')} |
|||
/> |
|||
</Box> |
|||
</Box> |
|||
<Box justifyContent="center">=</Box> |
|||
<Box grow horizontal flow={2}> |
|||
<Box justifyContent="center">{unit.fiat.code}</Box> |
|||
<Box grow> |
|||
<Input |
|||
value={value.right} |
|||
onBlur={this.handleBlur} |
|||
onChange={this.handleChangeAmount('right')} |
|||
/> |
|||
</Box> |
|||
</Box> |
|||
</Box> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(RequestAmount) |
@ -0,0 +1,29 @@ |
|||
// @flow
|
|||
|
|||
import React from 'react' |
|||
import { storiesOf } from '@storybook/react' |
|||
import { action } from '@storybook/addon-actions' |
|||
import { text } from '@storybook/addon-knobs' |
|||
|
|||
import { accounts } from 'components/SelectAccount/stories' |
|||
|
|||
import { RequestAmount } from 'components/RequestAmount' |
|||
|
|||
const stories = storiesOf('Components/RequestAmount', module) |
|||
|
|||
const props = { |
|||
counterValue: 'USD', |
|||
lastCounterValue: 9177.69, |
|||
account: accounts[0], |
|||
} |
|||
|
|||
stories.add('basic', () => ( |
|||
<RequestAmount |
|||
{...props} |
|||
onChange={action('onChange')} |
|||
value={{ |
|||
left: text('left value', 0), |
|||
right: text('right value', 0), |
|||
}} |
|||
/> |
|||
)) |
Loading…
Reference in new issue