aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChi Kei Chan <chikeichan@gmail.com>2017-09-12 14:18:54 +0800
committerChi Kei Chan <chikeichan@gmail.com>2017-09-12 14:18:54 +0800
commit836bf2e1a38bb6917f1b7fe9db0604c8143c7adf (patch)
tree9971f4349e4ffb39f2769b562dd339f8e9f1854b
parent1e83835ba8cce0fdf794092a8c55b6c68664204a (diff)
downloadtangerine-wallet-browser-836bf2e1a38bb6917f1b7fe9db0604c8143c7adf.tar
tangerine-wallet-browser-836bf2e1a38bb6917f1b7fe9db0604c8143c7adf.tar.gz
tangerine-wallet-browser-836bf2e1a38bb6917f1b7fe9db0604c8143c7adf.tar.bz2
tangerine-wallet-browser-836bf2e1a38bb6917f1b7fe9db0604c8143c7adf.tar.lz
tangerine-wallet-browser-836bf2e1a38bb6917f1b7fe9db0604c8143c7adf.tar.xz
tangerine-wallet-browser-836bf2e1a38bb6917f1b7fe9db0604c8143c7adf.tar.zst
tangerine-wallet-browser-836bf2e1a38bb6917f1b7fe9db0604c8143c7adf.zip
Add frontend validation to send-token
-rw-r--r--ui/app/components/input-number.js2
-rw-r--r--ui/app/components/send-token/index.js98
-rw-r--r--ui/app/components/send/currency-toggle.js4
-rw-r--r--ui/app/css/itcss/components/confirm.scss1
-rw-r--r--ui/app/css/itcss/components/hero-balance.scss5
-rw-r--r--ui/app/css/itcss/components/network.scss2
-rw-r--r--ui/app/css/itcss/components/send.scss21
7 files changed, 119 insertions, 14 deletions
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 {