Add frontend validation to send-token

feature/default_network_editable
Chi Kei Chan 7 years ago
parent 1e83835ba8
commit 836bf2e1a3
  1. 2
      ui/app/components/input-number.js
  2. 98
      ui/app/components/send-token/index.js
  3. 4
      ui/app/components/send/currency-toggle.js
  4. 1
      ui/app/css/itcss/components/confirm.scss
  5. 5
      ui/app/css/itcss/components/hero-balance.scss
  6. 2
      ui/app/css/itcss/components/network.scss
  7. 21
      ui/app/css/itcss/components/send.scss

@ -22,7 +22,7 @@ InputNumber.prototype.componentWillMount = function () {
} }
InputNumber.prototype.setValue = function (newValue) { 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)) if (fixed) newValue = Number(newValue.toFixed(4))

@ -2,6 +2,7 @@ const Component = require('react').Component
const connect = require('react-redux').connect const connect = require('react-redux').connect
const h = require('react-hyperscript') const h = require('react-hyperscript')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const classnames = require('classnames')
const inherits = require('util').inherits const inherits = require('util').inherits
const actions = require('../../actions') const actions = require('../../actions')
const selectors = require('../../selectors') const selectors = require('../../selectors')
@ -62,10 +63,60 @@ function SendTokenScreen () {
Component.call(this) Component.call(this)
this.state = { this.state = {
to: '', to: '',
amount: null,
selectedCurrency: 'USD', selectedCurrency: 'USD',
isGasTooltipOpen: false, isGasTooltipOpen: false,
gasPrice: '0x5d21dba00', gasPrice: '0x5d21dba00',
gasLimit: '0x7b0d', 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 { const {
to, to,
errors: { to: errorMessage },
} = this.state } = 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('div', ['To:']),
h('input.large-input.send-screen-input', { h('input.large-input.send-screen-input', {
name: 'address', name: 'address',
list: 'addresses', list: 'addresses',
placeholder: 'Address', placeholder: 'Address',
value: to, value: to,
onChange: e => this.setState({ to: e.target.value }), onChange: e => this.setState({
to: e.target.value,
errors: {},
}),
}), }),
h('datalist#addresses', [ h('datalist#addresses', [
// Corresponds to the addresses owned. // 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 () { SendTokenScreen.prototype.renderAmountInput = function () {
const { const {
selectedCurrency, selectedCurrency,
amount,
errors: { amount: errorMessage },
} = this.state } = this.state
const { const {
selectedToken: {symbol}, selectedToken: {symbol},
} = this.props } = 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('div.send-screen-amount-labels', [
h('span', ['Amount']), h('span', ['Amount']),
h(CurrencyToggle, { h(CurrencyToggle, {
selectedCurrency, currentCurrency: selectedCurrency,
currencies: [ symbol, 'USD' ], currencies: [ symbol, 'USD' ],
onClick: currency => this.setState({ selectedCurrency: currency }), onClick: currency => this.setState({ selectedCurrency: currency }),
}), }),
@ -129,8 +195,13 @@ SendTokenScreen.prototype.renderAmountInput = function () {
h('input.large-input.send-screen-input', { h('input.large-input.send-screen-input', {
placeholder: `0 ${symbol}`, placeholder: `0 ${symbol}`,
type: 'number', 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, gasPrice,
gasLimit, gasLimit,
selectedCurrency, selectedCurrency,
errors: {
gasPrice: gasPriceErrorMessage,
gasLimit: gasLimitErrorMessage,
},
} = this.state } = this.state
const { const {
@ -147,14 +222,18 @@ SendTokenScreen.prototype.renderGasInput = function () {
currentBlockGasLimit, currentBlockGasLimit,
} = this.props } = 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, { isGasTooltipOpen && h(GasTooltip, {
className: 'send-tooltip', className: 'send-tooltip',
gasPrice, gasPrice,
gasLimit, gasLimit,
onClose: () => this.setState({ isGasTooltipOpen: false }), onClose: () => this.setState({ isGasTooltipOpen: false }),
onFeeChange: ({ gasLimit, gasPrice }) => { onFeeChange: ({ gasLimit, gasPrice }) => {
this.setState({ gasLimit, gasPrice }) this.setState({ gasLimit, gasPrice, errors: {} })
}, },
}), }),
@ -176,6 +255,9 @@ SendTokenScreen.prototype.renderGasInput = function () {
['Customize'] ['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', [ return h('div.send-token__button-group', [
h('button.send-token__button-next.btn-secondary', { h('button.send-token__button-next.btn-secondary', {
onClick: () => this.submit(),
}, ['Next']), }, ['Next']),
h('button.send-token__button-cancel.btn-tertiary', { h('button.send-token__button-cancel.btn-tertiary', {
onClick: () => backToAccountDetail(selectedAddress), onClick: () => backToAccountDetail(selectedAddress),

@ -22,14 +22,14 @@ CurrencyToggle.prototype.render = function () {
'currency-toggle__item--selected': currencyA === currentCurrency, 'currency-toggle__item--selected': currencyA === currentCurrency,
}), }),
onClick: () => onClick(currencyA), onClick: () => onClick(currencyA),
}, ['ETH']), }, [ currencyA ]),
'<>', '<>',
h('span', { h('span', {
className: classnames('currency-toggle__item', { className: classnames('currency-toggle__item', {
'currency-toggle__item--selected': currencyB === currentCurrency, 'currency-toggle__item--selected': currencyB === currentCurrency,
}), }),
onClick: () => onClick(currencyB), onClick: () => onClick(currencyB),
}, ['USD']), }, [ currencyB ]),
]) // holding on icon from design ]) // holding on icon from design
} }

@ -1,5 +1,6 @@
.confirm-screen-container { .confirm-screen-container {
position: absolute; position: absolute;
align-items: center;
@media screen and (max-width: 575px) { @media screen and (max-width: 575px) {
margin-top: 35px; margin-top: 35px;

@ -87,10 +87,10 @@
} }
button.btn-clear { button.btn-clear {
font-size: 75%;
background: $white; background: $white;
border: 1px solid; border: 1px solid;
border-radius: 2px; border-radius: 2px;
font-size: 12px;
@media screen and (max-width: $break-small) { @media screen and (max-width: $break-small) {
width: 23%; width: 23%;
@ -99,10 +99,9 @@
} }
@media screen and (min-width: $break-large) { @media screen and (min-width: $break-large) {
font-size: .6em;
border-color: $curious-blue; border-color: $curious-blue;
color: $curious-blue; color: $curious-blue;
padding: 0px; padding: 0;
width: 85px; width: 85px;
height: 34px; height: 34px;
} }

@ -42,6 +42,8 @@
.network-check__transparent { .network-check__transparent {
opacity: 0; opacity: 0;
width: 16px;
margin: 0;
} }
.menu-icon-circle, .menu-icon-circle--active { .menu-icon-circle, .menu-icon-circle--active {

@ -46,6 +46,27 @@
.send-screen-input-wrapper { .send-screen-input-wrapper {
width: 95%; width: 95%;
position: relative; 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 { .send-screen-input {

Loading…
Cancel
Save