You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

149 lines
3.6 KiB

/* eslint-disable react/no-multi-comp */
import React from 'react'
import PropTypes from 'prop-types'
import { asField } from 'informed'
import * as yup from 'yup'
import { convert } from 'lib/utils/btc'
import { formatValue, parseNumber } from 'lib/utils/crypto'
import Input from 'components/UI/Input'
/**
* @render react
* @name CryptoAmountInput
*/
class CryptoAmountInput extends React.Component {
static propTypes = {
currency: PropTypes.string.isRequired,
required: PropTypes.bool,
onChange: PropTypes.func,
onBlur: PropTypes.func
}
/**
* Reformat the value when the currency unit has changed.
*/
componentDidUpdate(prevProps) {
const { currency, fieldApi } = this.props
// Reformat the value when the currency unit has changed.
if (currency !== prevProps.currency) {
const { fieldApi } = this.props
let value = fieldApi.getValue()
const convertedValue = convert(prevProps.currency, currency, value)
const [integer, fractional] = parseNumber(convertedValue, this.getRules().precision)
value = formatValue(integer, fractional)
fieldApi.setValue(value)
}
// If the value has changed, reformat it if needed.
const valueBefore = prevProps.fieldState.value
const valueAfter = fieldApi.getValue()
if (valueAfter !== valueBefore) {
const [integer, fractional] = parseNumber(valueAfter, this.getRules().precision)
const formattedValue = formatValue(integer, fractional)
if (formattedValue !== valueAfter) {
fieldApi.setValue(formattedValue)
}
}
}
getRules = () => {
const { currency } = this.props
switch (currency) {
case 'btc':
return {
precision: 8,
placeholder: '0.00000000',
pattern: '[0-9]*.?[0-9]{0,8}?'
}
case 'bits':
return {
precision: 2,
placeholder: '0.00',
pattern: '[0-9]*.?[0-9]{0,2}?'
}
case 'sats':
return {
precision: 0,
placeholder: '00000000',
pattern: '[0-9]*'
}
default:
return {
precision: 2,
pattern: '[0-9]*'
}
}
}
handleKeyDown = e => {
// Do nothing if the user did select all key combo.
if (e.metaKey && e.key === 'a') {
return
}
// Do not allow multiple dots.
let { value } = e.target
if (e.key === '.') {
if (value.search(/\./) >= 0) {
e.preventDefault()
}
return
}
if (e.key.length === 1 && !e.key.match(/^[0-9.]$/)) {
e.preventDefault()
return
}
}
render() {
const rules = this.getRules()
return (
<Input
{...this.props}
type="text"
placeholder={rules.placeholder}
pattern={rules.pattern}
onKeyDown={this.handleKeyDown}
/>
)
}
}
const CryptoAmountInputAsField = asField(CryptoAmountInput)
class WrappedCryptoAmountInputAsField extends React.Component {
validate = value => {
const { disabled, required } = this.props
if (disabled) {
return
}
try {
let validator = yup
.number()
.positive()
.min(0)
.typeError('A number is required')
if (required) {
validator = validator.required().moreThan(0)
}
validator.validateSync(Number(value))
} catch (error) {
return error.message
}
// Run any additional validation provided by the caller.
const { validate } = this.props
if (validate) {
return validate(value)
}
}
render() {
return <CryptoAmountInputAsField validate={this.validate} {...this.props} />
}
}
export default WrappedCryptoAmountInputAsField