Handling to and amount errors.

feature/default_network_editable
Dan 7 years ago committed by Chi Kei Chan
parent f81226fbe9
commit 60eda592b5
  1. 10
      ui/app/actions.js
  2. 23
      ui/app/components/send/currency-display.js
  3. 1
      ui/app/components/send/send-v2-container.js
  4. 10
      ui/app/components/send/to-autocomplete.js
  5. 11
      ui/app/conversion-util.js
  6. 11
      ui/app/css/itcss/components/send.scss
  7. 16
      ui/app/reducers/metamask.js
  8. 95
      ui/app/send-v2.js

@ -140,6 +140,7 @@ var actions = {
UPDATE_SEND_TO: 'UPDATE_SEND_TO', UPDATE_SEND_TO: 'UPDATE_SEND_TO',
UPDATE_SEND_AMOUNT: 'UPDATE_SEND_AMOUNT', UPDATE_SEND_AMOUNT: 'UPDATE_SEND_AMOUNT',
UPDATE_SEND_MEMO: 'UPDATE_SEND_MEMO', UPDATE_SEND_MEMO: 'UPDATE_SEND_MEMO',
UPDATE_SEND_ERRORS: 'UPDATE_SEND_ERRORS',
updateGasLimit, updateGasLimit,
updateGasPrice, updateGasPrice,
updateGasTotal, updateGasTotal,
@ -147,6 +148,7 @@ var actions = {
updateSendTo, updateSendTo,
updateSendAmount, updateSendAmount,
updateSendMemo, updateSendMemo,
updateSendErrors,
setSelectedAddress, setSelectedAddress,
// app messages // app messages
confirmSeedWords: confirmSeedWords, confirmSeedWords: confirmSeedWords,
@ -553,6 +555,14 @@ function updateSendMemo (memo) {
} }
} }
function updateSendErrors (error) {
console.log(`updateSendErrors error`, error);
return {
type: actions.UPDATE_SEND_ERRORS,
value: error,
}
}
function sendTx (txData) { function sendTx (txData) {
log.info(`actions - sendTx: ${JSON.stringify(txData.txParams)}`) log.info(`actions - sendTx: ${JSON.stringify(txData.txParams)}`)

@ -28,16 +28,12 @@ function resetCaretIfPastEnd (value, event) {
} }
} }
CurrencyDisplay.prototype.handleChangeInHexWei = function (value) { function toHexWei (value) {
const { handleChange } = this.props return conversionUtil(value, {
const valueInHexWei = conversionUtil(value, {
fromNumericBase: 'dec', fromNumericBase: 'dec',
toNumericBase: 'hex', toNumericBase: 'hex',
toDenomination: 'WEI', toDenomination: 'WEI',
}) })
handleChange(valueInHexWei)
} }
CurrencyDisplay.prototype.render = function () { CurrencyDisplay.prototype.render = function () {
@ -51,7 +47,10 @@ CurrencyDisplay.prototype.render = function () {
convertedPrefix = '', convertedPrefix = '',
placeholder = '0', placeholder = '0',
readOnly = false, readOnly = false,
inError = false,
value: initValue, value: initValue,
handleChange,
validate,
} = this.props } = this.props
const { value } = this.state const { value } = this.state
@ -73,6 +72,9 @@ CurrencyDisplay.prototype.render = function () {
return h('div', { return h('div', {
className, className,
style: {
borderColor: inError ? 'red' : null,
},
}, [ }, [
h('div.currency-display__primary-row', [ h('div.currency-display__primary-row', [
@ -100,8 +102,13 @@ CurrencyDisplay.prototype.render = function () {
this.setState({ value: newValue }) this.setState({ value: newValue })
} }
}, },
onBlur: event => !readOnly && this.handleChangeInHexWei(event.target.value.split(' ')[0]), onBlur: event => !readOnly && handleChange(toHexWei(event.target.value.split(' ')[0])),
onKeyUp: event => !readOnly && resetCaretIfPastEnd(value || initValueToRender, event), onKeyUp: event => {
if (!readOnly) {
validate(toHexWei(value || initValueToRender))
resetCaretIfPastEnd(value || initValueToRender, event)
}
},
onClick: event => !readOnly && resetCaretIfPastEnd(value || initValueToRender, event), onClick: event => !readOnly && resetCaretIfPastEnd(value || initValueToRender, event),
}), }),

@ -76,5 +76,6 @@ function mapDispatchToProps (dispatch) {
updateSendTo: newTo => dispatch(actions.updateSendTo(newTo)), updateSendTo: newTo => dispatch(actions.updateSendTo(newTo)),
updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)), updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)),
updateSendMemo: newMemo => dispatch(actions.updateSendMemo(newMemo)), updateSendMemo: newMemo => dispatch(actions.updateSendMemo(newMemo)),
updateSendErrors: newError => dispatch(actions.updateSendErrors(newError)),
} }
} }

@ -11,7 +11,7 @@ function ToAutoComplete () {
} }
ToAutoComplete.prototype.render = function () { ToAutoComplete.prototype.render = function () {
const { to, accounts, onChange } = this.props const { to, accounts, onChange, inError } = this.props
return h('div.send-v2__to-autocomplete', [ return h('div.send-v2__to-autocomplete', [
@ -19,15 +19,15 @@ ToAutoComplete.prototype.render = function () {
name: 'address', name: 'address',
list: 'addresses', list: 'addresses',
placeholder: 'Recipient Address', placeholder: 'Recipient Address',
className: inError ? `send-v2__error-border` : '',
value: to, value: to,
onChange, onChange,
// onBlur: () => {
// this.setErrorsFor('to')
// },
onFocus: event => { onFocus: event => {
// this.clearErrorsFor('to')
to && event.target.select() to && event.target.select()
}, },
style: {
borderColor: inError ? 'red' : null,
}
}), }),
h('datalist#addresses', [ h('datalist#addresses', [

@ -157,14 +157,11 @@ const multiplyCurrencies = (a, b, options = {}) => {
} }
const conversionGreaterThan = ( const conversionGreaterThan = (
{ value, fromNumericBase }, { ...firstProps },
{ value: compareToValue, fromNumericBase: compareToBase }, { ...secondProps },
) => { ) => {
const firstValue = converter({ value, fromNumericBase }) const firstValue = converter({ ...firstProps })
const secondValue = converter({ const secondValue = converter({ ...secondProps })
value: compareToValue,
fromNumericBase: compareToBase,
})
return firstValue.gt(secondValue) return firstValue.gt(secondValue)
} }

@ -497,6 +497,17 @@
width: 287px; width: 287px;
} }
&__error {
font-size: 12px;
line-height: 12px;
left: 8px;
color: $red;
}
&__error-border {
color: $red;
}
&__form { &__form {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

@ -29,6 +29,7 @@ function reduceMetamask (state, action) {
to: '', to: '',
amount: '0x0', amount: '0x0',
memo: '', memo: '',
errors: {},
}, },
}, state.metamask) }, state.metamask)
@ -224,6 +225,21 @@ function reduceMetamask (state, action) {
}, },
}) })
case actions.UPDATE_SEND_ERRORS:
console.log(123, {
...metamaskState.send.errors,
...action.value,
})
return extend(metamaskState, {
send: {
...metamaskState.send,
errors: {
...metamaskState.send.errors,
...action.value,
}
},
})
default: default:
return metamaskState return metamaskState

@ -12,7 +12,8 @@ const GasFeeDisplay = require('./components/send/gas-fee-display-v2')
const { showModal } = require('./actions') const { showModal } = require('./actions')
const { multiplyCurrencies } = require('./conversion-util') const { multiplyCurrencies, conversionGreaterThan } = require('./conversion-util')
const { isValidAddress } = require('./util')
module.exports = SendTransactionScreen module.exports = SendTransactionScreen
@ -22,10 +23,15 @@ function SendTransactionScreen () {
this.state = { this.state = {
dropdownOpen: false, dropdownOpen: false,
errors: {
to: null,
amount: null,
},
} }
this.handleToChange = this.handleToChange.bind(this) this.handleToChange = this.handleToChange.bind(this)
this.handleAmountChange = this.handleAmountChange.bind(this) this.handleAmountChange = this.handleAmountChange.bind(this)
this.validateAmount = this.validateAmount.bind(this)
} }
SendTransactionScreen.prototype.componentWillMount = function () { SendTransactionScreen.prototype.componentWillMount = function () {
@ -126,6 +132,16 @@ SendTransactionScreen.prototype.renderHeader = function () {
]) ])
} }
SendTransactionScreen.prototype.renderErrorMessage = function(errorType) {
const { errors } = this.props
console.log(`! errors`, errors);
const errorMessage = errors[errorType];
console.log(`errorMessage`, errorMessage);
return errorMessage
? h('div.send-v2__error', [ errorMessage ] )
: null
}
SendTransactionScreen.prototype.renderFromRow = function () { SendTransactionScreen.prototype.renderFromRow = function () {
const { const {
from, from,
@ -155,56 +171,121 @@ SendTransactionScreen.prototype.renderFromRow = function () {
} }
SendTransactionScreen.prototype.handleToChange = function (event) { SendTransactionScreen.prototype.handleToChange = function (event) {
const { updateSendTo } = this.props const { updateSendTo, updateSendErrors } = this.props
const to = event.target.value const to = event.target.value
let toError = null
if (!to) {
toError = 'Required'
} else if (!isValidAddress(to)) {
toError = 'Recipient address is invalid.'
}
updateSendTo(to) updateSendTo(to)
updateSendErrors({ to: toError })
} }
SendTransactionScreen.prototype.renderToRow = function () { SendTransactionScreen.prototype.renderToRow = function () {
const { toAccounts } = this.props const { toAccounts, errors } = this.props
const { to } = this.state const { to } = this.state
return h('div.send-v2__form-row', [ return h('div.send-v2__form-row', [
h('div.send-v2__form-label', 'To:'), h('div.send-v2__form-label', [
'To:',
this.renderErrorMessage('to'),
]),
h(ToAutoComplete, { h(ToAutoComplete, {
to, to,
accounts: toAccounts, accounts: toAccounts,
onChange: this.handleToChange, onChange: this.handleToChange,
inError: Boolean(errors.to),
}), }),
]) ])
} }
SendTransactionScreen.prototype.handleAmountChange = function (value) { SendTransactionScreen.prototype.handleAmountChange = function (value) {
const { updateSendAmount } = this.props
const amount = value const amount = value
const { updateSendAmount } = this.props
updateSendAmount(amount) updateSendAmount(amount)
} }
SendTransactionScreen.prototype.validateAmount = function (value) {
const {
from: { balance },
updateSendErrors,
amountConversionRate,
conversionRate,
primaryCurrency,
toCurrency,
selectedToken
} = this.props
const amount = value
let amountError = null
const sufficientBalance = conversionGreaterThan(
{
value: balance,
fromNumericBase: 'hex',
fromCurrency: primaryCurrency,
conversionRate,
},
{
value: amount,
fromNumericBase: 'hex',
conversionRate: amountConversionRate,
fromCurrency: selectedToken || primaryCurrency,
conversionRate: amountConversionRate,
},
)
console.log(`sufficientBalance`, sufficientBalance);
const amountLessThanZero = conversionGreaterThan(
{ value: 0, fromNumericBase: 'dec' },
{ value: amount, fromNumericBase: 'hex' },
)
if (!sufficientBalance) {
amountError = 'Insufficient funds.'
} else if (amountLessThanZero) {
amountError = 'Can not send negative amounts of ETH.'
}
updateSendErrors({ amount: amountError })
}
SendTransactionScreen.prototype.renderAmountRow = function () { SendTransactionScreen.prototype.renderAmountRow = function () {
const { const {
selectedToken, selectedToken,
primaryCurrency = 'ETH', primaryCurrency = 'ETH',
amountConversionRate, amountConversionRate,
errors,
} = this.props } = this.props
const { amount } = this.state const { amount } = this.state
return h('div.send-v2__form-row', [ return h('div.send-v2__form-row', [
h('div.send-v2__form-label', 'Amount:'), h('div.send-v2__form-label', [
'Amount:',
this.renderErrorMessage('amount'),
]),
h(CurrencyDisplay, { h(CurrencyDisplay, {
inError: Boolean(errors.amount),
primaryCurrency, primaryCurrency,
convertedCurrency: 'USD', convertedCurrency: 'USD',
value: amount, value: amount,
conversionRate: amountConversionRate, conversionRate: amountConversionRate,
convertedPrefix: '$', convertedPrefix: '$',
handleChange: this.handleAmountChange handleChange: this.handleAmountChange,
validate: this.validateAmount,
}), }),
]) ])

Loading…
Cancel
Save