From 836bf2e1a38bb6917f1b7fe9db0604c8143c7adf Mon Sep 17 00:00:00 2001 From: Chi Kei Chan Date: Mon, 11 Sep 2017 23:18:54 -0700 Subject: Add frontend validation to send-token --- ui/app/components/input-number.js | 2 +- ui/app/components/send-token/index.js | 98 ++++++++++++++++++++++++++++--- ui/app/components/send/currency-toggle.js | 4 +- 3 files changed, 93 insertions(+), 11 deletions(-) (limited to 'ui/app/components') diff --git a/ui/app/components/input-number.js b/ui/app/components/input-number.js index 63e841288..2824d77aa 100644 --- a/ui/app/components/input-number.js +++ b/ui/app/components/input-number.js @@ -22,7 +22,7 @@ InputNumber.prototype.componentWillMount = function () { } InputNumber.prototype.setValue = function (newValue) { - const { fixed, min, onChange } = this.props + const { fixed, min = -1, onChange } = this.props if (fixed) newValue = Number(newValue.toFixed(4)) diff --git a/ui/app/components/send-token/index.js b/ui/app/components/send-token/index.js index 985116409..439ea45b7 100644 --- a/ui/app/components/send-token/index.js +++ b/ui/app/components/send-token/index.js @@ -2,6 +2,7 @@ const Component = require('react').Component const connect = require('react-redux').connect const h = require('react-hyperscript') const ethUtil = require('ethereumjs-util') +const classnames = require('classnames') const inherits = require('util').inherits const actions = require('../../actions') const selectors = require('../../selectors') @@ -62,10 +63,60 @@ function SendTokenScreen () { Component.call(this) this.state = { to: '', + amount: null, selectedCurrency: 'USD', isGasTooltipOpen: false, gasPrice: '0x5d21dba00', gasLimit: '0x7b0d', + errors: {}, + } +} + +SendTokenScreen.prototype.validate = function () { + const { + to, + amount, + gasPrice: hexGasPrice, + gasLimit: hexGasLimit, + } = this.state + + const gasPrice = parseInt(hexGasPrice, 16) + const gasLimit = parseInt(hexGasLimit, 16) / 1000000000 + + if (to && amount && gasPrice && gasLimit) { + return { + isValid: true, + errors: {}, + } + } + + const errors = { + to: !to ? 'Required' : null, + amount: !Number(amount) ? 'Required' : null, + gasPrice: !gasPrice ? 'Gas Price Required' : null, + gasLimit: !gasLimit ? 'Gas Limit Required' : null, + } + + return { + isValid: false, + errors, + } +} + +SendTokenScreen.prototype.submit = function () { + // const { + // to, + // amount, + // selectedCurrency, + // isGasTooltipOpen, + // gasPrice, + // gasLimit, + // } = this.state + + const { isValid, errors } = this.validate() + + if (!isValid) { + return this.setState({ errors }) } } @@ -77,16 +128,24 @@ SendTokenScreen.prototype.renderToAddressInput = function () { const { to, + errors: { to: errorMessage }, } = this.state - return h('div.send-screen-input-wrapper', {}, [ + return h('div', { + className: classnames('send-screen-input-wrapper', { + 'send-screen-input-wrapper--error': errorMessage, + }), + }, [ h('div', ['To:']), h('input.large-input.send-screen-input', { name: 'address', list: 'addresses', placeholder: 'Address', value: to, - onChange: e => this.setState({ to: e.target.value }), + onChange: e => this.setState({ + to: e.target.value, + errors: {}, + }), }), h('datalist#addresses', [ // Corresponds to the addresses owned. @@ -105,23 +164,30 @@ SendTokenScreen.prototype.renderToAddressInput = function () { }) }), ]), + h('div.send-screen-input-wrapper__error-message', [ errorMessage ]), ]) } SendTokenScreen.prototype.renderAmountInput = function () { const { selectedCurrency, + amount, + errors: { amount: errorMessage }, } = this.state const { selectedToken: {symbol}, } = this.props - return h('div.send-screen-input-wrapper', {}, [ + return h('div.send-screen-input-wrapper', { + className: classnames('send-screen-input-wrapper', { + 'send-screen-input-wrapper--error': errorMessage, + }), + }, [ h('div.send-screen-amount-labels', [ h('span', ['Amount']), h(CurrencyToggle, { - selectedCurrency, + currentCurrency: selectedCurrency, currencies: [ symbol, 'USD' ], onClick: currency => this.setState({ selectedCurrency: currency }), }), @@ -129,8 +195,13 @@ SendTokenScreen.prototype.renderAmountInput = function () { h('input.large-input.send-screen-input', { placeholder: `0 ${symbol}`, type: 'number', - onChange: e => this.setState({ amount: e.target.value }), + value: amount, + onChange: e => this.setState({ + amount: e.target.value, + errors: {}, + }), }), + h('div.send-screen-input-wrapper__error-message', [ errorMessage ]), ]) } @@ -140,6 +211,10 @@ SendTokenScreen.prototype.renderGasInput = function () { gasPrice, gasLimit, selectedCurrency, + errors: { + gasPrice: gasPriceErrorMessage, + gasLimit: gasLimitErrorMessage, + }, } = this.state const { @@ -147,14 +222,18 @@ SendTokenScreen.prototype.renderGasInput = function () { currentBlockGasLimit, } = this.props - return h('div.send-screen-input-wrapper', [ + return h('div.send-screen-input-wrapper', { + className: classnames('send-screen-input-wrapper', { + 'send-screen-input-wrapper--error': gasPriceErrorMessage || gasLimitErrorMessage, + }), + }, [ isGasTooltipOpen && h(GasTooltip, { className: 'send-tooltip', gasPrice, gasLimit, onClose: () => this.setState({ isGasTooltipOpen: false }), onFeeChange: ({ gasLimit, gasPrice }) => { - this.setState({ gasLimit, gasPrice }) + this.setState({ gasLimit, gasPrice, errors: {} }) }, }), @@ -176,6 +255,9 @@ SendTokenScreen.prototype.renderGasInput = function () { ['Customize'] ), ]), + h('div.send-screen-input-wrapper__error-message', [ + gasPriceErrorMessage || gasLimitErrorMessage, + ]), ]) } @@ -194,7 +276,7 @@ SendTokenScreen.prototype.renderButtons = function () { return h('div.send-token__button-group', [ h('button.send-token__button-next.btn-secondary', { - + onClick: () => this.submit(), }, ['Next']), h('button.send-token__button-cancel.btn-tertiary', { onClick: () => backToAccountDetail(selectedAddress), diff --git a/ui/app/components/send/currency-toggle.js b/ui/app/components/send/currency-toggle.js index adaade301..2b59ace4a 100644 --- a/ui/app/components/send/currency-toggle.js +++ b/ui/app/components/send/currency-toggle.js @@ -22,14 +22,14 @@ CurrencyToggle.prototype.render = function () { 'currency-toggle__item--selected': currencyA === currentCurrency, }), onClick: () => onClick(currencyA), - }, ['ETH']), + }, [ currencyA ]), '<>', h('span', { className: classnames('currency-toggle__item', { 'currency-toggle__item--selected': currencyB === currentCurrency, }), onClick: () => onClick(currencyB), - }, ['USD']), + }, [ currencyB ]), ]) // holding on icon from design } -- cgit v1.2.3