From 2d248f64694269acc740ecbf272ff4c08165d20c Mon Sep 17 00:00:00 2001 From: petitPapillon Date: Sat, 19 Aug 2017 20:13:40 +0200 Subject: [PATCH] Send form - add validation --- .../components/dashboard/sendCoin/sendCoin.js | 108 +++++++++++++++++- .../dashboard/sendCoin/sendCoin.render.js | 8 +- react/src/translate/en.js | 7 +- react/src/util/number.js | 7 ++ 4 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 react/src/util/number.js diff --git a/react/src/components/dashboard/sendCoin/sendCoin.js b/react/src/components/dashboard/sendCoin/sendCoin.js index e80716e..cd4e5b5 100644 --- a/react/src/components/dashboard/sendCoin/sendCoin.js +++ b/react/src/components/dashboard/sendCoin/sendCoin.js @@ -29,8 +29,8 @@ import { SendCoinRender } from './sendCoin.render'; -import { SocketProvider } from 'socket.io-react'; import io from 'socket.io-client'; +import { isPositiveNumber } from '../../../util/number'; const socket = io.connect(`http://127.0.0.1:${Config.agamaPort}`); // TODO: prevent any cache updates rather than utxo while on send coin form @@ -380,6 +380,12 @@ class SendCoin extends React.Component { }); } + if (step === 1) { + if (!this.validateSendFormData()) { + return; + } + } + if (step === 1 || step === 2) { this.setState(Object.assign({}, this.state, { @@ -757,6 +763,106 @@ class SendCoin extends React.Component { return null; } + // TODO same as in walletsNav and receiveCoin, find a way to reuse it? + checkTotalBalance() { + let _balance = '0'; + const _mode = this.props.ActiveCoin.mode; + + if (_mode === 'full') { + _balance = this.props.ActiveCoin.balance || 0; + } else if (_mode === 'basilisk') { + if (this.props.ActiveCoin.cache) { + const _cache = this.props.ActiveCoin.cache; + const _coin = this.props.ActiveCoin.coin; + const _address = this.props.ActiveCoin.activeAddress; + + if (_address && + _cache[_coin] && + _cache[_coin][_address] && + _cache[_coin][_address].getbalance && + _cache[_coin][_address].getbalance.data && + (_cache[_coin][_address].getbalance.data.balance || + _cache[_coin][_address].getbalance.data.interest)) { + const _regBalance = _cache[_coin][_address].getbalance.data.balance ? _cache[_coin][_address].getbalance.data.balance : 0; + const _regInterest = _cache[_coin][_address].getbalance.data.interest ? _cache[_coin][_address].getbalance.data.interest : 0; + + _balance = _regBalance + _regInterest; + } + } + } else if (_mode === 'native') { + if (this.props.ActiveCoin.balance && + this.props.ActiveCoin.balance.total) { + _balance = this.props.ActiveCoin.balance.total; + } + } + + return +_balance; + } + + validateSendFormData() { + let valid = true; + if (!this.state.sendTo || this.state.sendTo.length < 64) { + Store.dispatch( + triggerToaster( + translate('SEND.SEND_TO_ADDRESS_MIN_LENGTH'), + '', + 'error' + ) + ); + valid = false; + } + + if (!isPositiveNumber(this.state.amount)) { + Store.dispatch( + triggerToaster( + translate('SEND.AMOUNT_POSITIVE_NUMBER'), + '', + 'error' + ) + ); + valid = false; + } + + if (!isPositiveNumber(this.state.fee)) { + Store.dispatch( + triggerToaster( + translate('SEND.FEE_POSITIVE_NUMBER'), + '', + 'error' + ) + ); + valid = false; + } + + if (!isPositiveNumber(this.getTotalAmount())) { + Store.dispatch( + triggerToaster( + translate('SEND.TOTAL_AMOUNT_POSITIVE_NUMBER'), + '', + 'error' + ) + ); + valid = false; + } + + if (this.state.amount > this.checkTotalBalance()) { + Store.dispatch( + triggerToaster( + translate('SEND.INSUFFICIENT_FUNDS'), + '', + 'error' + ) + ); + valid = false; + } + + return valid; + } + + getTotalAmount() { + return Number(this.state.amount) - Number(this.state.fee); + } + render() { if (this.props.ActiveCoin && this.props.ActiveCoin.send && diff --git a/react/src/components/dashboard/sendCoin/sendCoin.render.js b/react/src/components/dashboard/sendCoin/sendCoin.render.js index 43672d8..b55c7c1 100644 --- a/react/src/components/dashboard/sendCoin/sendCoin.render.js +++ b/react/src/components/dashboard/sendCoin/sendCoin.render.js @@ -248,7 +248,8 @@ export const SendCoinRender = function() { { this.props.ActiveCoin.coin }   - { Number(this.state.amount) - Number(this.state.fee) } { this.props.ActiveCoin.coin } + { this.getTotalAmount() } { this.props.ActiveCoin.coin }
diff --git a/react/src/translate/en.js b/react/src/translate/en.js index 95af166..8c9f259 100644 --- a/react/src/translate/en.js +++ b/react/src/translate/en.js @@ -519,7 +519,12 @@ export const _lang = { 'SEND_VIA': 'Alternative send method', 'ENTER_AN_ADDRESS': 'Enter an address', 'YOU_PICKED_OPT': 'You picked option', - 'PLEASE_WAIT': 'Please wait' + 'PLEASE_WAIT': 'Please wait', + 'SEND_TO_ADDRESS_MIN_LENGTH': 'Send to address must be at least 64 characters long', + 'AMOUNT_POSITIVE_NUMBER': 'Amount must be a positive number', + 'FEE_POSITIVE_NUMBER': 'Fee must be a positive number', + 'TOTAL_AMOUNT_POSITIVE_NUMBER': 'Total amount (amount - fee) must be a positive number', + 'INSUFFICIENT_FUNDS': 'You don\'t have the necessary funds to make this transaction' }, 'FIAT_CURRENCIES': { 'AUD': 'Australian Dollar (AUD)', diff --git a/react/src/util/number.js b/react/src/util/number.js new file mode 100644 index 0000000..0deb56f --- /dev/null +++ b/react/src/util/number.js @@ -0,0 +1,7 @@ +export function isNumber(value) { + return !isNaN(parseFloat(value)) && isFinite(value); +} + +export function isPositiveNumber(value) { + return isNumber(value) && (+value) > 0; +} \ No newline at end of file