aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ui/app/actions.js10
-rw-r--r--ui/app/components/send/currency-display.js23
-rw-r--r--ui/app/components/send/send-v2-container.js1
-rw-r--r--ui/app/components/send/to-autocomplete.js10
-rw-r--r--ui/app/conversion-util.js11
-rw-r--r--ui/app/css/itcss/components/send.scss11
-rw-r--r--ui/app/reducers/metamask.js16
-rw-r--r--ui/app/send-v2.js97
8 files changed, 151 insertions, 28 deletions
diff --git a/ui/app/actions.js b/ui/app/actions.js
index ed1ff75e5..25a4abda6 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -140,6 +140,7 @@ var actions = {
UPDATE_SEND_TO: 'UPDATE_SEND_TO',
UPDATE_SEND_AMOUNT: 'UPDATE_SEND_AMOUNT',
UPDATE_SEND_MEMO: 'UPDATE_SEND_MEMO',
+ UPDATE_SEND_ERRORS: 'UPDATE_SEND_ERRORS',
updateGasLimit,
updateGasPrice,
updateGasTotal,
@@ -147,6 +148,7 @@ var actions = {
updateSendTo,
updateSendAmount,
updateSendMemo,
+ updateSendErrors,
setSelectedAddress,
// app messages
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) {
log.info(`actions - sendTx: ${JSON.stringify(txData.txParams)}`)
diff --git a/ui/app/components/send/currency-display.js b/ui/app/components/send/currency-display.js
index d56c119f1..f7fbb2379 100644
--- a/ui/app/components/send/currency-display.js
+++ b/ui/app/components/send/currency-display.js
@@ -28,16 +28,12 @@ function resetCaretIfPastEnd (value, event) {
}
}
-CurrencyDisplay.prototype.handleChangeInHexWei = function (value) {
- const { handleChange } = this.props
-
- const valueInHexWei = conversionUtil(value, {
+function toHexWei (value) {
+ return conversionUtil(value, {
fromNumericBase: 'dec',
toNumericBase: 'hex',
toDenomination: 'WEI',
})
-
- handleChange(valueInHexWei)
}
CurrencyDisplay.prototype.render = function () {
@@ -51,7 +47,10 @@ CurrencyDisplay.prototype.render = function () {
convertedPrefix = '',
placeholder = '0',
readOnly = false,
+ inError = false,
value: initValue,
+ handleChange,
+ validate,
} = this.props
const { value } = this.state
@@ -73,6 +72,9 @@ CurrencyDisplay.prototype.render = function () {
return h('div', {
className,
+ style: {
+ borderColor: inError ? 'red' : null,
+ },
}, [
h('div.currency-display__primary-row', [
@@ -100,8 +102,13 @@ CurrencyDisplay.prototype.render = function () {
this.setState({ value: newValue })
}
},
- onBlur: event => !readOnly && this.handleChangeInHexWei(event.target.value.split(' ')[0]),
- onKeyUp: event => !readOnly && resetCaretIfPastEnd(value || initValueToRender, event),
+ onBlur: event => !readOnly && handleChange(toHexWei(event.target.value.split(' ')[0])),
+ onKeyUp: event => {
+ if (!readOnly) {
+ validate(toHexWei(value || initValueToRender))
+ resetCaretIfPastEnd(value || initValueToRender, event)
+ }
+ },
onClick: event => !readOnly && resetCaretIfPastEnd(value || initValueToRender, event),
}),
diff --git a/ui/app/components/send/send-v2-container.js b/ui/app/components/send/send-v2-container.js
index dcf764048..f20d80073 100644
--- a/ui/app/components/send/send-v2-container.js
+++ b/ui/app/components/send/send-v2-container.js
@@ -76,5 +76,6 @@ function mapDispatchToProps (dispatch) {
updateSendTo: newTo => dispatch(actions.updateSendTo(newTo)),
updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)),
updateSendMemo: newMemo => dispatch(actions.updateSendMemo(newMemo)),
+ updateSendErrors: newError => dispatch(actions.updateSendErrors(newError)),
}
}
diff --git a/ui/app/components/send/to-autocomplete.js b/ui/app/components/send/to-autocomplete.js
index 1bf1e1907..686a7a23e 100644
--- a/ui/app/components/send/to-autocomplete.js
+++ b/ui/app/components/send/to-autocomplete.js
@@ -11,7 +11,7 @@ function ToAutoComplete () {
}
ToAutoComplete.prototype.render = function () {
- const { to, accounts, onChange } = this.props
+ const { to, accounts, onChange, inError } = this.props
return h('div.send-v2__to-autocomplete', [
@@ -19,15 +19,15 @@ ToAutoComplete.prototype.render = function () {
name: 'address',
list: 'addresses',
placeholder: 'Recipient Address',
+ className: inError ? `send-v2__error-border` : '',
value: to,
onChange,
- // onBlur: () => {
- // this.setErrorsFor('to')
- // },
onFocus: event => {
- // this.clearErrorsFor('to')
to && event.target.select()
},
+ style: {
+ borderColor: inError ? 'red' : null,
+ }
}),
h('datalist#addresses', [
diff --git a/ui/app/conversion-util.js b/ui/app/conversion-util.js
index 3a9e9ad0f..1ef276a39 100644
--- a/ui/app/conversion-util.js
+++ b/ui/app/conversion-util.js
@@ -157,14 +157,11 @@ const multiplyCurrencies = (a, b, options = {}) => {
}
const conversionGreaterThan = (
- { value, fromNumericBase },
- { value: compareToValue, fromNumericBase: compareToBase },
+ { ...firstProps },
+ { ...secondProps },
) => {
- const firstValue = converter({ value, fromNumericBase })
- const secondValue = converter({
- value: compareToValue,
- fromNumericBase: compareToBase,
- })
+ const firstValue = converter({ ...firstProps })
+ const secondValue = converter({ ...secondProps })
return firstValue.gt(secondValue)
}
diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss
index ddabdee2e..7e72e8399 100644
--- a/ui/app/css/itcss/components/send.scss
+++ b/ui/app/css/itcss/components/send.scss
@@ -497,6 +497,17 @@
width: 287px;
}
+ &__error {
+ font-size: 12px;
+ line-height: 12px;
+ left: 8px;
+ color: $red;
+ }
+
+ &__error-border {
+ color: $red;
+ }
+
&__form {
display: flex;
flex-direction: column;
diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js
index 6915dbb0f..fb2b2e674 100644
--- a/ui/app/reducers/metamask.js
+++ b/ui/app/reducers/metamask.js
@@ -29,6 +29,7 @@ function reduceMetamask (state, action) {
to: '',
amount: '0x0',
memo: '',
+ errors: {},
},
}, 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:
return metamaskState
diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js
index e3182689d..8d368044a 100644
--- a/ui/app/send-v2.js
+++ b/ui/app/send-v2.js
@@ -12,7 +12,8 @@ const GasFeeDisplay = require('./components/send/gas-fee-display-v2')
const { showModal } = require('./actions')
-const { multiplyCurrencies } = require('./conversion-util')
+const { multiplyCurrencies, conversionGreaterThan } = require('./conversion-util')
+const { isValidAddress } = require('./util')
module.exports = SendTransactionScreen
@@ -22,10 +23,15 @@ function SendTransactionScreen () {
this.state = {
dropdownOpen: false,
+ errors: {
+ to: null,
+ amount: null,
+ },
}
this.handleToChange = this.handleToChange.bind(this)
this.handleAmountChange = this.handleAmountChange.bind(this)
+ this.validateAmount = this.validateAmount.bind(this)
}
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 () {
const {
from,
@@ -155,57 +171,122 @@ SendTransactionScreen.prototype.renderFromRow = function () {
}
SendTransactionScreen.prototype.handleToChange = function (event) {
- const { updateSendTo } = this.props
+ const { updateSendTo, updateSendErrors } = this.props
const to = event.target.value
+ let toError = null
+
+ if (!to) {
+ toError = 'Required'
+ } else if (!isValidAddress(to)) {
+ toError = 'Recipient address is invalid.'
+ }
updateSendTo(to)
+ updateSendErrors({ to: toError })
}
SendTransactionScreen.prototype.renderToRow = function () {
- const { toAccounts } = this.props
+ const { toAccounts, errors } = this.props
const { to } = this.state
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, {
to,
accounts: toAccounts,
onChange: this.handleToChange,
+ inError: Boolean(errors.to),
}),
])
}
SendTransactionScreen.prototype.handleAmountChange = function (value) {
- const { updateSendAmount } = this.props
const amount = value
+ const { updateSendAmount } = this.props
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 () {
const {
selectedToken,
primaryCurrency = 'ETH',
amountConversionRate,
+ errors,
} = this.props
const { amount } = this.state
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, {
+ inError: Boolean(errors.amount),
primaryCurrency,
convertedCurrency: 'USD',
value: amount,
conversionRate: amountConversionRate,
convertedPrefix: '$',
- handleChange: this.handleAmountChange
- }),
+ handleChange: this.handleAmountChange,
+ validate: this.validateAmount,
+ }),
])
}