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 +- ui/app/css/itcss/components/confirm.scss | 1 + ui/app/css/itcss/components/hero-balance.scss | 5 +- ui/app/css/itcss/components/network.scss | 2 + ui/app/css/itcss/components/send.scss | 21 ++++++ 7 files changed, 119 insertions(+), 14 deletions(-) (limited to 'ui/app') 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 } diff --git a/ui/app/css/itcss/components/confirm.scss b/ui/app/css/itcss/components/confirm.scss index da1d00777..865915c30 100644 --- a/ui/app/css/itcss/components/confirm.scss +++ b/ui/app/css/itcss/components/confirm.scss @@ -1,5 +1,6 @@ .confirm-screen-container { position: absolute; + align-items: center; @media screen and (max-width: 575px) { margin-top: 35px; diff --git a/ui/app/css/itcss/components/hero-balance.scss b/ui/app/css/itcss/components/hero-balance.scss index f7b3cc3e5..8f6731358 100644 --- a/ui/app/css/itcss/components/hero-balance.scss +++ b/ui/app/css/itcss/components/hero-balance.scss @@ -87,10 +87,10 @@ } button.btn-clear { - font-size: 75%; background: $white; border: 1px solid; border-radius: 2px; + font-size: 12px; @media screen and (max-width: $break-small) { width: 23%; @@ -99,10 +99,9 @@ } @media screen and (min-width: $break-large) { - font-size: .6em; border-color: $curious-blue; color: $curious-blue; - padding: 0px; + padding: 0; width: 85px; height: 34px; } diff --git a/ui/app/css/itcss/components/network.scss b/ui/app/css/itcss/components/network.scss index 3f75beb85..012b1faf6 100644 --- a/ui/app/css/itcss/components/network.scss +++ b/ui/app/css/itcss/components/network.scss @@ -42,6 +42,8 @@ .network-check__transparent { opacity: 0; + width: 16px; + margin: 0; } .menu-icon-circle, .menu-icon-circle--active { diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss index 091816e7d..847b893ab 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -46,6 +46,27 @@ .send-screen-input-wrapper { width: 95%; position: relative; + + &__error-message { + display: none; + } + + &--error { + input, + .send-screen-gas-input { + border-color: $red !important; + } + + .send-screen-input-wrapper__error-message { + display: block; + position: absolute; + bottom: 4px; + font-size: 12px; + line-height: 12px; + left: 8px; + color: $red; + } + } } .send-screen-input { -- cgit