diff options
Diffstat (limited to 'ui/app/components')
7 files changed, 96 insertions, 15 deletions
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js index 0e7e30347..c3fdf51e5 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js @@ -7,6 +7,8 @@ import { setGasPrice, createSpeedUpTransaction, hideSidebar, + updateSendAmount, + setGasTotal, } from '../../../../store/actions' import { setCustomGasPrice, @@ -18,6 +20,7 @@ import { } from '../../../../ducks/gas/gas.duck' import { hideGasButtonGroup, + updateSendErrors, } from '../../../../ducks/send/send.duck' import { updateGasAndCalculate, @@ -46,6 +49,9 @@ import { isCustomPriceSafe, } from '../../../../selectors/custom-gas' import { + getTokenBalance, +} from '../../../../pages/send/send.selectors' +import { submittedPendingTransactionsSelector, } from '../../../../selectors/transactions' import { @@ -53,6 +59,7 @@ import { } from '../../../../helpers/utils/confirm-tx.util' import { addHexWEIsToDec, + subtractHexWEIsToDec, decEthToConvertedCurrency as ethTotalToConvertedCurrency, decGWEIToHexWEI, hexWEIToDecGWEI, @@ -66,6 +73,8 @@ import { } from '../../../../pages/send/send.utils' import { addHexPrefix } from 'ethereumjs-util' import { getAdjacentGasPrices, extrapolateY } from '../gas-price-chart/gas-price-chart.utils' +import { getMaxModeOn } from '../../../../pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.selectors' +import { calcMaxAmount } from '../../../../pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils' const mapStateToProps = (state, ownProps) => { const { transaction = {} } = ownProps @@ -75,8 +84,6 @@ const mapStateToProps = (state, ownProps) => { const { gasPrice: currentGasPrice, gas: currentGasLimit, value } = getTxParams(state, transaction.id) const customModalGasPriceInHex = getCustomGasPrice(state) || currentGasPrice const customModalGasLimitInHex = getCustomGasLimit(state) || currentGasLimit - const gasTotal = calcGasTotal(customModalGasLimitInHex, customModalGasPriceInHex) - const customGasTotal = calcGasTotal(customModalGasLimitInHex, customModalGasPriceInHex) const gasButtonInfo = getRenderableBasicEstimateData(state, customModalGasLimitInHex) @@ -90,6 +97,8 @@ const mapStateToProps = (state, ownProps) => { const customGasPrice = calcCustomGasPrice(customModalGasPriceInHex) + const maxModeOn = getMaxModeOn(state) + const gasPrices = getEstimatedGasPrices(state) const estimatedTimes = getEstimatedGasTimes(state) const balance = getCurrentEthBalance(state) @@ -98,9 +107,13 @@ const mapStateToProps = (state, ownProps) => { const isMainnet = getIsMainnet(state) const showFiat = Boolean(isMainnet || showFiatInTestnets) - const insufficientBalance = !isBalanceSufficient({ + const newTotalEth = maxModeOn ? addHexWEIsToRenderableEth(balance, '0x0') : addHexWEIsToRenderableEth(value, customGasTotal) + + const sendAmount = maxModeOn ? subtractHexWEIsFromRenderableEth(balance, customGasTotal) : addHexWEIsToRenderableEth(value, '0x0') + + const insufficientBalance = maxModeOn ? false : !isBalanceSufficient({ amount: value, - gasTotal, + gasTotal: customGasTotal, balance, conversionRate, }) @@ -112,10 +125,12 @@ const mapStateToProps = (state, ownProps) => { customModalGasLimitInHex, customGasPrice, customGasLimit: calcCustomGasLimit(customModalGasLimitInHex), + customGasTotal, newTotalFiat, currentTimeEstimate: getRenderableTimeEstimate(customGasPrice, gasPrices, estimatedTimes), blockTime: getBasicGasEstimateBlockTime(state), customPriceIsSafe: isCustomPriceSafe(state), + maxModeOn, gasPriceButtonGroupProps: { buttonDataLoading, defaultActiveButtonIndex: getDefaultActiveButtonIndex(gasButtonInfo, customModalGasPriceInHex), @@ -129,12 +144,12 @@ const mapStateToProps = (state, ownProps) => { estimatedTimesMax: estimatedTimes[0], }, infoRowProps: { - originalTotalFiat: addHexWEIsToRenderableFiat(value, gasTotal, currentCurrency, conversionRate), - originalTotalEth: addHexWEIsToRenderableEth(value, gasTotal), + originalTotalFiat: addHexWEIsToRenderableFiat(value, customGasTotal, currentCurrency, conversionRate), + originalTotalEth: addHexWEIsToRenderableEth(value, customGasTotal), newTotalFiat: showFiat ? newTotalFiat : '', - newTotalEth: addHexWEIsToRenderableEth(value, customGasTotal), + newTotalEth, transactionFee: addHexWEIsToRenderableEth('0x0', customGasTotal), - sendAmount: addHexWEIsToRenderableEth(value, '0x0'), + sendAmount, }, isSpeedUp: transaction.status === 'submitted', txId: transaction.id, @@ -142,6 +157,9 @@ const mapStateToProps = (state, ownProps) => { gasEstimatesLoading, isMainnet, isEthereumNetwork: isEthereumNetwork(state), + selectedToken: getSelectedToken(state), + balance, + tokenBalance: getTokenBalance(state), } } @@ -174,11 +192,16 @@ const mapDispatchToProps = dispatch => { hideSidebar: () => dispatch(hideSidebar()), fetchGasEstimates: (blockTime) => dispatch(fetchGasEstimates(blockTime)), fetchBasicGasAndTimeEstimates: () => dispatch(fetchBasicGasAndTimeEstimates()), + setGasTotal: (total) => dispatch(setGasTotal(total)), + setAmountToMax: (maxAmountDataObject) => { + dispatch(updateSendErrors({ amount: null })) + dispatch(updateSendAmount(calcMaxAmount(maxAmountDataObject))) + }, } } const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { gasPriceButtonGroupProps, isConfirm, txId, isSpeedUp, insufficientBalance, customGasPrice } = stateProps + const { gasPriceButtonGroupProps, isConfirm, txId, isSpeedUp, insufficientBalance, maxModeOn, customGasPrice, customGasTotal, balance, selectedToken, tokenBalance} = stateProps const { updateCustomGasPrice: dispatchUpdateCustomGasPrice, hideGasButtonGroup: dispatchHideGasButtonGroup, @@ -188,6 +211,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { hideSidebar: dispatchHideSidebar, cancelAndClose: dispatchCancelAndClose, hideModal: dispatchHideModal, + setAmountToMax: dispatchSetAmountToMax, ...otherDispatchProps } = dispatchProps @@ -208,6 +232,14 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { dispatchHideGasButtonGroup() dispatchCancelAndClose() } + if (maxModeOn) { + dispatchSetAmountToMax({ + balance, + gasTotal: customGasTotal, + selectedToken, + tokenBalance, + }) + } }, gasPriceButtonGroupProps: { ...gasPriceButtonGroupProps, @@ -258,6 +290,13 @@ function addHexWEIsToRenderableEth (aHexWEI, bHexWEI) { )(aHexWEI, bHexWEI) } +function subtractHexWEIsFromRenderableEth (aHexWEI, bHexWei) { + return pipe( + subtractHexWEIsToDec, + formatETHFee + )(aHexWEI, bHexWei) +} + function addHexWEIsToRenderableFiat (aHexWEI, bHexWEI, convertedCurrency, conversionRate) { return pipe( addHexWEIsToDec, diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js index ab24b9c0e..dbe61d5cf 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js @@ -46,6 +46,10 @@ proxyquire('../gas-modal-page-container.container.js', { '../../../../ducks/send/send.duck': sendActionSpies, '../../../../selectors/selectors.js': { getCurrentEthBalance: (state) => state.metamask.balance || '0x0', + getSelectedToken: () => null, + }, + '../../../../pages/send/send.selectors': { + getTokenBalance: (state) => state.metamask.send.tokenBalance || '0x0', }, }) @@ -68,6 +72,7 @@ describe('gas-modal-page-container container', () => { gasLimit: '16', gasPrice: '32', amount: '64', + maxModeOn: false, }, currentCurrency: 'abc', conversionRate: 50, @@ -106,6 +111,7 @@ describe('gas-modal-page-container container', () => { }, } const baseExpectedResult = { + balance: '0x0', isConfirm: true, customGasPrice: 4.294967295, customGasLimit: 2863311530, @@ -114,6 +120,7 @@ describe('gas-modal-page-container container', () => { blockTime: 12, customModalGasLimitInHex: 'aaaaaaaa', customModalGasPriceInHex: 'ffffffff', + customGasTotal: 'aaaaaaa955555556', customPriceIsSafe: true, gasChartProps: { 'currentPrice': 4.294967295, @@ -142,6 +149,9 @@ describe('gas-modal-page-container container', () => { txId: 34, isEthereumNetwork: true, isMainnet: true, + maxModeOn: false, + selectedToken: null, + tokenBalance: '0x0', } const baseMockOwnProps = { transaction: { id: 34 } } const tests = [ @@ -150,7 +160,7 @@ describe('gas-modal-page-container container', () => { mockState: Object.assign({}, baseMockState, { metamask: { ...baseMockState.metamask, balance: '0xfffffffffffffffffffff' }, }), - expectedResult: Object.assign({}, baseExpectedResult, { insufficientBalance: false }), + expectedResult: Object.assign({}, baseExpectedResult, { balance: '0xfffffffffffffffffffff', insufficientBalance: false }), mockOwnProps: baseMockOwnProps, }, { diff --git a/ui/app/components/ui/currency-input/currency-input.component.js b/ui/app/components/ui/currency-input/currency-input.component.js index b5be0972b..1876c9591 100644 --- a/ui/app/components/ui/currency-input/currency-input.component.js +++ b/ui/app/components/ui/currency-input/currency-input.component.js @@ -18,6 +18,7 @@ export default class CurrencyInput extends PureComponent { static propTypes = { conversionRate: PropTypes.number, currentCurrency: PropTypes.string, + maxModeOn: PropTypes.bool, nativeCurrency: PropTypes.string, onChange: PropTypes.func, onBlur: PropTypes.func, @@ -136,7 +137,7 @@ export default class CurrencyInput extends PureComponent { } render () { - const { fiatSuffix, nativeSuffix, ...restProps } = this.props + const { fiatSuffix, nativeSuffix, maxModeOn, ...restProps } = this.props const { decimalValue } = this.state return ( @@ -146,6 +147,7 @@ export default class CurrencyInput extends PureComponent { onChange={this.handleChange} onBlur={this.handleBlur} value={decimalValue} + maxModeOn={maxModeOn} actionComponent={( <div className="currency-input__swap-component" diff --git a/ui/app/components/ui/currency-input/currency-input.container.js b/ui/app/components/ui/currency-input/currency-input.container.js index b5d7dfe6d..46e70bace 100644 --- a/ui/app/components/ui/currency-input/currency-input.container.js +++ b/ui/app/components/ui/currency-input/currency-input.container.js @@ -1,18 +1,21 @@ import { connect } from 'react-redux' import CurrencyInput from './currency-input.component' import { ETH } from '../../../helpers/constants/common' +import { getMaxModeOn } from '../../../pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.selectors' import {getIsMainnet, preferencesSelector} from '../../../selectors/selectors' const mapStateToProps = state => { const { metamask: { nativeCurrency, currentCurrency, conversionRate } } = state const { showFiatInTestnets } = preferencesSelector(state) const isMainnet = getIsMainnet(state) + const maxModeOn = getMaxModeOn(state) return { nativeCurrency, currentCurrency, conversionRate, hideFiat: (!isMainnet && !showFiatInTestnets), + maxModeOn, } } diff --git a/ui/app/components/ui/currency-input/tests/currency-input.container.test.js b/ui/app/components/ui/currency-input/tests/currency-input.container.test.js index 259fe594a..f10abe09a 100644 --- a/ui/app/components/ui/currency-input/tests/currency-input.container.test.js +++ b/ui/app/components/ui/currency-input/tests/currency-input.container.test.js @@ -30,6 +30,9 @@ describe('CurrencyInput container', () => { provider: { type: 'mainnet', }, + send: { + maxModeOn: false, + }, }, }, expected: { @@ -37,6 +40,7 @@ describe('CurrencyInput container', () => { currentCurrency: 'usd', nativeCurrency: 'ETH', hideFiat: false, + maxModeOn: false, }, }, // Test # 2 @@ -53,6 +57,9 @@ describe('CurrencyInput container', () => { provider: { type: 'rinkeby', }, + send: { + maxModeOn: false, + }, }, }, expected: { @@ -60,6 +67,7 @@ describe('CurrencyInput container', () => { currentCurrency: 'usd', nativeCurrency: 'ETH', hideFiat: true, + maxModeOn: false, }, }, // Test # 3 @@ -76,6 +84,9 @@ describe('CurrencyInput container', () => { provider: { type: 'rinkeby', }, + send: { + maxModeOn: false, + }, }, }, expected: { @@ -83,6 +94,7 @@ describe('CurrencyInput container', () => { currentCurrency: 'usd', nativeCurrency: 'ETH', hideFiat: false, + maxModeOn: false, }, }, // Test # 4 @@ -99,6 +111,9 @@ describe('CurrencyInput container', () => { provider: { type: 'mainnet', }, + send: { + maxModeOn: false, + }, }, }, expected: { @@ -106,6 +121,7 @@ describe('CurrencyInput container', () => { currentCurrency: 'usd', nativeCurrency: 'ETH', hideFiat: false, + maxModeOn: false, }, }, ] diff --git a/ui/app/components/ui/unit-input/index.scss b/ui/app/components/ui/unit-input/index.scss index adc4a3531..58a10c9a1 100644 --- a/ui/app/components/ui/unit-input/index.scss +++ b/ui/app/components/ui/unit-input/index.scss @@ -42,6 +42,10 @@ max-width: 22ch; height: 16px; line-height: 18px; + + &__disabled { + background-color: rgb(222, 222, 222); + } } &__input-container { @@ -59,4 +63,9 @@ &--error { border-color: $red; } + + &__disabled { + background-color: #F2F3F4; + } + } diff --git a/ui/app/components/ui/unit-input/unit-input.component.js b/ui/app/components/ui/unit-input/unit-input.component.js index 6a53f4c6f..9085a0677 100644 --- a/ui/app/components/ui/unit-input/unit-input.component.js +++ b/ui/app/components/ui/unit-input/unit-input.component.js @@ -13,6 +13,7 @@ export default class UnitInput extends PureComponent { children: PropTypes.node, actionComponent: PropTypes.node, error: PropTypes.bool, + maxModeOn: PropTypes.bool, onBlur: PropTypes.func, onChange: PropTypes.func, placeholder: PropTypes.string, @@ -71,25 +72,26 @@ export default class UnitInput extends PureComponent { } render () { - const { error, placeholder, suffix, actionComponent, children } = this.props + const { error, placeholder, suffix, actionComponent, children, maxModeOn } = this.props const { value } = this.state return ( <div - className={classnames('unit-input', { 'unit-input--error': error })} - onClick={this.handleFocus} + className={classnames('unit-input', { 'unit-input--error': error }, { 'unit-input__disabled': maxModeOn })} + onClick={maxModeOn ? null : this.handleFocus} > <div className="unit-input__inputs"> <div className="unit-input__input-container"> <input type="number" - className="unit-input__input" + className={classnames('unit-input__input', { 'unit-input__disabled': maxModeOn })} value={value} placeholder={placeholder} onChange={this.handleChange} onBlur={this.handleBlur} style={{ width: this.getInputWidth(value) }} ref={ref => { this.unitInput = ref }} + disabled={maxModeOn} /> { suffix && ( |