diff options
author | Dan Miller <danjm.com@gmail.com> | 2018-09-21 00:06:23 +0800 |
---|---|---|
committer | Dan Miller <danjm.com@gmail.com> | 2018-12-04 11:36:04 +0800 |
commit | b95eb30ec60e4d169a61d987ad86fe333aa49523 (patch) | |
tree | 3256fc562d35022559d068f223bdedfd80248149 | |
parent | 5354325fab9b9ab3091e3c49e6b940fa713d1799 (diff) | |
download | tangerine-wallet-browser-b95eb30ec60e4d169a61d987ad86fe333aa49523.tar.gz tangerine-wallet-browser-b95eb30ec60e4d169a61d987ad86fe333aa49523.tar.zst tangerine-wallet-browser-b95eb30ec60e4d169a61d987ad86fe333aa49523.zip |
Adds redesign for the customize gas advanced tab.
19 files changed, 332 insertions, 152 deletions
diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js index 56d10cc2b..5218dd477 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js +++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js @@ -1,6 +1,6 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import TimeRemaining from './time-remaining' +import GasPriceChart from '../../gas-price-chart' export default class AdvancedTabContent extends Component { static contextTypes = { @@ -14,6 +14,7 @@ export default class AdvancedTabContent extends Component { customGasLimit: PropTypes.number, millisecondsRemaining: PropTypes.number, totalFee: PropTypes.string, + timeRemaining: PropTypes.string, } gasInput (value, onChange, min, precision, showGWEI) { @@ -27,9 +28,6 @@ export default class AdvancedTabContent extends Component { precision={precision} onChange={event => onChange(Number(event.target.value))} /> - {showGWEI - ? <span className="advanced-tab__gas-edit-row__gwei-symbol">GWEI</span> - : null} </div> ) } @@ -38,7 +36,7 @@ export default class AdvancedTabContent extends Component { return <i className="fa fa-info-circle" onClick={onClick} /> } - renderDataSummary (totalFee, millisecondsRemaining) { + renderDataSummary (totalFee, timeRemaining) { return ( <div className="advanced-tab__transaction-data-summary"> <div className="advanced-tab__transaction-data-summary__titles"> @@ -49,9 +47,7 @@ export default class AdvancedTabContent extends Component { <div className="advanced-tab__transaction-data-summary__fee"> {totalFee} </div> - <TimeRemaining - milliseconds={millisecondsRemaining} - /> + <div className="time-remaining">{timeRemaining}</div> </div> </div> ) @@ -72,7 +68,7 @@ export default class AdvancedTabContent extends Component { renderGasEditRows (customGasPrice, updateCustomGasPrice, customGasLimit, updateCustomGasLimit) { return ( <div className="advanced-tab__gas-edit-rows"> - { this.renderGasEditRow('gasPriceNoDenom', customGasPrice, updateCustomGasPrice, customGasPrice, 9, true) } + { this.renderGasEditRow('gasPrice', customGasPrice, updateCustomGasPrice, customGasPrice, 9, true) } { this.renderGasEditRow('gasLimit', customGasLimit, updateCustomGasLimit, customGasLimit, 0) } </div> ) @@ -82,7 +78,7 @@ export default class AdvancedTabContent extends Component { const { updateCustomGasPrice, updateCustomGasLimit, - millisecondsRemaining, + timeRemaining, customGasPrice, customGasLimit, totalFee, @@ -90,17 +86,16 @@ export default class AdvancedTabContent extends Component { return ( <div className="advanced-tab"> - { this.renderDataSummary(totalFee, millisecondsRemaining) } - <div className="advanced-tab__fee-chart-title"> - { this.context.t('feeChartTitle') } + { this.renderDataSummary(totalFee, timeRemaining) } + <div className="advanced-tab__fee-chart"> + { this.renderGasEditRows( + customGasPrice, + updateCustomGasPrice, + customGasLimit, + updateCustomGasLimit + ) } + <GasPriceChart /> </div> - <div className="advanced-tab__fee-chart" /> - { this.renderGasEditRows( - customGasPrice, - updateCustomGasPrice, - customGasLimit, - updateCustomGasLimit - ) } </div> ) } diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss index aced75449..ae99ba4aa 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss +++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss @@ -3,11 +3,9 @@ .advanced-tab { display: flex; flex-flow: column; - height: 430px; &__transaction-data-summary, - &__fee-chart-title, - &__gas-edit-row { + &__fee-chart-title { padding-left: 24px; padding-right: 24px; } @@ -17,6 +15,8 @@ flex-flow: column; color: $mid-gray; margin-top: 12px; + padding-left: 18px; + padding-right: 18px; &__titles, &__container { @@ -24,11 +24,17 @@ flex-flow: row; justify-content: space-between; font-size: 12px; + color: #888EA3; } &__container { - font-size: 26px; - margin-top: 6px; + font-size: 16px; + margin-top: 0px; + } + + &__fee { + font-size: 16px; + color: #313A5E; } } @@ -40,8 +46,11 @@ &__fee-chart { padding-left: 10px; - margin-top: 24px; - height: 134px; + margin-top: 8px; + height: 258px; + background: #F8F9FB; + border-bottom: 1px solid #d2d8dd; + border-top: 1px solid #d2d8dd; } &__slider-container { @@ -50,21 +59,25 @@ } &__gas-edit-rows { - margin-top: 44px; height: 87px; display: flex; - flex-flow: column; + flex-flow: row; justify-content: space-between; + margin-left: 10px; + margin-right: 10px; + margin-top: 9px; } &__gas-edit-row { display: flex; - flex-flow: row; - justify-content: space-between; + flex-flow: column; &__label { - color: $mid-gray; - font-size: 16px; + color: #313B5E; + font-size: 14px; + display: flex; + justify-content: space-between; + align-items: center; .fa-info-circle { color: $silver; @@ -87,10 +100,11 @@ border-radius: 4px; color: $mid-gray; font-size: 16px; - height: 37px; - width: 163px; + height: 24px; + width: 155px; padding-left: 8px; padding-top: 2px; + margin-top: 7px; } input[type="number"]::-webkit-inner-spin-button { diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js index 0ef286b8a..1489c7696 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js +++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/tests/advanced-tab-content-component.test.js @@ -4,7 +4,7 @@ import shallow from '../../../../../../lib/shallow-with-context' import sinon from 'sinon' import AdvancedTabContent from '../advanced-tab-content.component.js' -import TimeRemaining from '../time-remaining' +import GasPriceChart from '../../../gas-price-chart' const propsMethodSpies = { updateCustomGasPrice: sinon.spy(), @@ -13,6 +13,8 @@ const propsMethodSpies = { sinon.spy(AdvancedTabContent.prototype, 'renderGasEditRow') sinon.spy(AdvancedTabContent.prototype, 'gasInput') +sinon.spy(AdvancedTabContent.prototype, 'renderGasEditRows') +sinon.spy(AdvancedTabContent.prototype, 'renderDataSummary') describe('AdvancedTabContent Component', function () { let wrapper @@ -23,7 +25,7 @@ describe('AdvancedTabContent Component', function () { updateCustomGasLimit={propsMethodSpies.updateCustomGasLimit} customGasPrice={11} customGasLimit={23456} - millisecondsRemaining={21500} + timeRemaining={21500} totalFee={'$0.25'} />, { context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } }) }) @@ -31,6 +33,10 @@ describe('AdvancedTabContent Component', function () { afterEach(() => { propsMethodSpies.updateCustomGasPrice.resetHistory() propsMethodSpies.updateCustomGasLimit.resetHistory() + AdvancedTabContent.prototype.renderGasEditRow.resetHistory() + AdvancedTabContent.prototype.gasInput.resetHistory() + AdvancedTabContent.prototype.renderGasEditRows.resetHistory() + AdvancedTabContent.prototype.renderDataSummary.resetHistory() }) describe('render()', () => { @@ -40,12 +46,31 @@ describe('AdvancedTabContent Component', function () { it('should render the expected four children of the advanced-tab div', () => { const advancedTabChildren = wrapper.children() - assert.equal(advancedTabChildren.length, 4) + assert.equal(advancedTabChildren.length, 2) assert(advancedTabChildren.at(0).hasClass('advanced-tab__transaction-data-summary')) - assert(advancedTabChildren.at(1).hasClass('advanced-tab__fee-chart-title')) - assert(advancedTabChildren.at(2).hasClass('advanced-tab__fee-chart')) - assert(advancedTabChildren.at(3).hasClass('advanced-tab__gas-edit-rows')) + assert(advancedTabChildren.at(1).hasClass('advanced-tab__fee-chart')) + + const feeChartDiv = advancedTabChildren.at(1) + + assert(feeChartDiv.childAt(0).hasClass('advanced-tab__gas-edit-rows')) + assert(feeChartDiv.childAt(1).is(GasPriceChart)) + }) + + it('should call renderDataSummary with the expected params', () => { + assert.equal(AdvancedTabContent.prototype.renderGasEditRows.callCount, 1) + const renderDataSummaryArgs = AdvancedTabContent.prototype.renderDataSummary.getCall(0).args + assert.deepEqual(renderDataSummaryArgs, ['$0.25', 21500]) + + assert.equal(AdvancedTabContent.prototype.renderGasEditRows.callCount, 1) + const renderGasEditRowArgs = AdvancedTabContent.prototype.renderGasEditRows.getCall(0).args + assert.deepEqual(renderGasEditRowArgs, [ + 11, propsMethodSpies.updateCustomGasPrice, 23456, propsMethodSpies.updateCustomGasLimit, + ]) + }) + + it('should call renderGasEditRows with the expected params', () => { + }) }) @@ -71,8 +96,8 @@ describe('AdvancedTabContent Component', function () { const dataNode = dataSummary.children().at(1) assert(dataNode.hasClass('advanced-tab__transaction-data-summary__container')) assert.equal(dataNode.children().at(0).text(), 'mockTotalFee') - assert(dataNode.children().at(1).is(TimeRemaining)) - assert.equal(dataNode.children().at(1).props().milliseconds, 'mockMsRemaining') + assert(dataNode.children().at(1).hasClass('time-remaining')) + assert.equal(dataNode.children().at(1).text(), 'mockMsRemaining') }) }) @@ -138,7 +163,7 @@ describe('AdvancedTabContent Component', function () { const renderGasEditRowSpyArgs = AdvancedTabContent.prototype.renderGasEditRow.args assert.equal(renderGasEditRowSpyArgs.length, 2) assert.deepEqual(renderGasEditRowSpyArgs[0].map(String), [ - 'gasPriceNoDenom', 'mockGasPrice', () => 'mockUpdateCustomGasPriceReturn', 'mockGasPrice', 9, true, + 'gasPrice', 'mockGasPrice', () => 'mockUpdateCustomGasPriceReturn', 'mockGasPrice', 9, true, ].map(String)) assert.deepEqual(renderGasEditRowSpyArgs[1].map(String), [ 'gasLimit', 'mockGasLimit', () => 'mockUpdateCustomGasLimitReturn', 'mockGasLimit', 0, @@ -186,19 +211,6 @@ describe('AdvancedTabContent Component', function () { assert(gasInput.children().at(0).hasClass('advanced-tab__gas-edit-row__input')) }) - it('should show GWEI if the showGWEI prop is truthy', () => { - const gasInputWithGWEI = shallow(wrapper.instance().gasInput( - 321, - value => value + 7, - 0, - 8, - true - )) - assert.equal(gasInputWithGWEI.children().length, 2) - assert(gasInputWithGWEI.children().at(0).hasClass('advanced-tab__gas-edit-row__input')) - assert(gasInputWithGWEI.children().at(1).hasClass('advanced-tab__gas-edit-row__gwei-symbol')) - }) - it('should pass the correct value min and precision props to the input', () => { const inputProps = gasInput.find('input').props() assert.equal(inputProps.min, 0) diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss index 01bb06268..e2115af7f 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss +++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss @@ -1,13 +1,17 @@ .time-remaining { + color: #313A5E; + font-size: 16px; + .minutes-num, .seconds-num { - font-size: 26px; + font-size: 16px; } .seconds-num { margin-left: 7px; + font-size: 16px; } .minutes-label, .seconds-label { - font-size: 14px; + font-size: 16px; } }
\ No newline at end of file diff --git a/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/index.scss b/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/index.scss index d5eb5d414..b7b6c0f94 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/index.scss +++ b/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/index.scss @@ -3,6 +3,7 @@ flex-direction: column; align-items: center; margin-bottom: 22px; + height: 291px; &__title { margin-top: 19px; diff --git a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js index 41fe901fa..07e55a1f0 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js +++ b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js @@ -24,8 +24,9 @@ export default class GasModalPageContainer extends Component { newTotalEth: PropTypes.string, }), onSubmit: PropTypes.func, - customGasPriceInHex: PropTypes.string, - customGasLimitInHex: PropTypes.string, + customModalGasPriceInHex: PropTypes.string, + customModalGasLimitInHex: PropTypes.string, + cancelAndClose: PropTypes.func, } state = {} @@ -51,32 +52,34 @@ export default class GasModalPageContainer extends Component { updateCustomGasLimit={convertThenUpdateCustomGasLimit} customGasPrice={customGasPrice} customGasLimit={customGasLimit} - millisecondsRemaining={91000} + timeRemaining={'1 min 31 sec'} totalFee={newTotalFiat} /> ) } - renderInfoRow (className, totalLabelKey, fiatTotal, cryptoTotal) { - return ( - <div className={className}> - <div className={`${className}__total-info`}> - <span className={`${className}__total-info__total-label`}>{`${this.context.t(totalLabelKey)}:`}</span> - <span className={`${className}__total-info__total-value`}>{fiatTotal}</span> - </div> - <div className={`${className}__sum-info`}> - <span className={`${className}__sum-info__sum-label`}>{`${this.context.t('amountPlusTxFee')}`}</span> - <span className={`${className}__sum-info__sum-value`}>{cryptoTotal}</span> - </div> - </div> - ) - } + renderInfoRows (newTotalFiat, newTotalEth, sendAmount, transactionFee) { + const baseClassName = 'gas-modal-content__info-row' - renderInfoRows (originalTotalFiat, originalTotalEth, newTotalFiat, newTotalEth) { return ( <div> - { this.renderInfoRow('gas-modal-content__info-row--fade', 'originalTotal', originalTotalFiat, originalTotalEth) } - { this.renderInfoRow('gas-modal-content__info-row', 'newTotal', newTotalFiat, newTotalEth) } + <div className={baseClassName}> + <div className={`${baseClassName}__send-info`}> + <span className={`${baseClassName}__send-info__label`}>{`Send Amount`}</span> + <span className={`${baseClassName}__send-info__value`}>{sendAmount}</span> + </div> + <div className={`${baseClassName}__transaction-info`}> + <span className={`${baseClassName}__transaction-info__label`}>{`Transaction Fee`}</span> + <span className={`${baseClassName}__transaction-info__value`}>{transactionFee}</span> + </div> + <div className={`${baseClassName}__total-info`}> + <span className={`${baseClassName}__total-info__label`}>{`New Total`}</span> + <span className={`${baseClassName}__total-info__value`}>{newTotalEth}</span> + </div> + <div className={`${baseClassName}__fiat-total-info`}> + <span className={`${baseClassName}__fiat-total-info__value`}>{newTotalFiat}</span> + </div> + </div> </div> ) } @@ -86,6 +89,8 @@ export default class GasModalPageContainer extends Component { originalTotalEth, newTotalFiat, newTotalEth, + sendAmount, + transactionFee, }, { gasPriceButtonGroupProps, @@ -106,7 +111,7 @@ export default class GasModalPageContainer extends Component { {tabsToRender.map(({ name, content }, i) => <Tab name={this.context.t(name)} key={`gas-modal-tab-${i}`}> <div className="gas-modal-content"> { content } - { this.renderInfoRows(originalTotalFiat, originalTotalEth, newTotalFiat, newTotalEth) } + { this.renderInfoRows(newTotalFiat, newTotalEth, sendAmount, transactionFee) } </div> </Tab> )} @@ -116,11 +121,11 @@ export default class GasModalPageContainer extends Component { render () { const { - hideModal, + cancelAndClose, infoRowProps, onSubmit, - customGasPriceInHex, - customGasLimitInHex, + customModalGasPriceInHex, + customModalGasLimitInHex, ...tabProps } = this.props @@ -131,13 +136,15 @@ export default class GasModalPageContainer extends Component { subtitle={this.context.t('customGasSubTitle')} tabsComponent={this.renderTabs(infoRowProps, tabProps)} disabled={false} - onCancel={() => hideModal()} - onClose={() => hideModal()} + onCancel={() => cancelAndClose()} + onClose={() => cancelAndClose()} onSubmit={() => { - onSubmit(customGasLimitInHex, customGasPriceInHex) - hideModal() + onSubmit(customModalGasLimitInHex, customModalGasPriceInHex) + cancelAndClose() }} submitText={this.context.t('save')} + headerCloseText={'Close'} + hideCancel={true} /> </div> ) diff --git a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js index f9ed1cebb..ae233578b 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js +++ b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js @@ -9,6 +9,7 @@ import { import { setCustomGasPrice, setCustomGasLimit, + resetCustomData, } from '../../../ducks/gas.duck' import { hideGasButtonGroup, @@ -48,12 +49,12 @@ import { addHexPrefix } from 'ethereumjs-util' const mapStateToProps = state => { const buttonDataLoading = getBasicGasEstimateLoadingStatus(state) - const { gasPrice, gas: gasLimit, value } = getTxParams(state) - const gasTotal = calcGasTotal(gasLimit, gasPrice) + const { gasPrice: currentGasPrice, gas: currentGasLimit, value } = getTxParams(state) + const gasTotal = calcGasTotal(currentGasLimit, currentGasPrice) - const customGasPriceInHex = getCustomGasPrice(state) - const customGasLimitInHex = getCustomGasLimit(state) - const customGasTotal = calcGasTotal(customGasLimitInHex || gasLimit, customGasPriceInHex || gasPrice) + const customModalGasPriceInHex = getCustomGasPrice(state) || currentGasPrice + const customModalGasLimitInHex = getCustomGasLimit(state) || currentGasLimit + const customGasTotal = calcGasTotal(customModalGasLimitInHex, customModalGasPriceInHex) const gasButtonInfo = getRenderableBasicEstimateData(state) @@ -67,14 +68,14 @@ const mapStateToProps = state => { return { hideBasic, isConfirm: isConfirm(state), - customGasPriceInHex, - customGasLimitInHex, - customGasPrice: calcCustomGasPrice(customGasPriceInHex, gasPrice), - customGasLimit: calcCustomGasLimit(customGasLimitInHex, gasLimit), + customModalGasPriceInHex, + customModalGasLimitInHex, + customGasPrice: calcCustomGasPrice(customModalGasPriceInHex), + customGasLimit: calcCustomGasLimit(customModalGasLimitInHex), newTotalFiat, gasPriceButtonGroupProps: { buttonDataLoading, - defaultActiveButtonIndex: getDefaultActiveButtonIndex(gasButtonInfo, customGasPriceInHex, gasPrice), + defaultActiveButtonIndex: getDefaultActiveButtonIndex(gasButtonInfo, customModalGasPriceInHex), gasButtonInfo, }, infoRowProps: { @@ -82,6 +83,8 @@ const mapStateToProps = state => { originalTotalEth: addHexWEIsToRenderableEth(value, gasTotal), newTotalFiat, newTotalEth: addHexWEIsToRenderableEth(value, customGasTotal), + transactionFee: addHexWEIsToRenderableEth('0x0', customGasTotal), + sendAmount: addHexWEIsToRenderableEth(value, '0x0'), }, } } @@ -90,7 +93,10 @@ const mapDispatchToProps = dispatch => { const updateCustomGasPrice = newPrice => dispatch(setCustomGasPrice(addHexPrefix(newPrice))) return { - hideModal: () => dispatch(hideModal()), + cancelAndClose: () => { + dispatch(resetCustomData()) + dispatch(hideModal()) + }, updateCustomGasPrice, convertThenUpdateCustomGasPrice: newPrice => updateCustomGasPrice(decGWEIToHexWEI(newPrice)), convertThenUpdateCustomGasLimit: newLimit => dispatch(setCustomGasLimit(addHexPrefix(newLimit.toString(16)))), @@ -138,12 +144,12 @@ function isConfirm (state) { return Boolean(Object.keys(state.confirmTransaction.txData).length) } -function calcCustomGasPrice (customGasPriceInHex, gasPrice) { - return Number(hexWEIToDecGWEI(customGasPriceInHex || gasPrice)) +function calcCustomGasPrice (customGasPriceInHex) { + return Number(hexWEIToDecGWEI(customGasPriceInHex)) } -function calcCustomGasLimit (customGasLimitInHex, gasLimit) { - return parseInt(customGasLimitInHex || gasLimit, 16) +function calcCustomGasLimit (customGasLimitInHex) { + return parseInt(customGasLimitInHex, 16) } function getTxParams (state) { diff --git a/ui/app/components/gas-customization/gas-modal-page-container/index.scss b/ui/app/components/gas-customization/gas-modal-page-container/index.scss index f02045fe3..c49d69bf7 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/index.scss +++ b/ui/app/components/gas-customization/gas-modal-page-container/index.scss @@ -4,6 +4,57 @@ .gas-modal-page-container { .page-container { width: 391px; + + &__header { + padding: 0px; + padding-top: 16px; + + &--no-padding-bottom { + padding-bottom: 0; + } + } + + &__header-close-text { + font-size: 14px; + color: #4EADE7; + position: absolute; + top: 16px; + right: 16px; + cursor: pointer; + overflow: hidden; + } + + &__title { + color: $black; + font-size: 16px; + font-weight: 500; + line-height: 16px; + display: flex; + justify-content: center; + align-items: flex-start; + } + + &__subtitle { + display: none; + } + + &__tabs { + margin-top: 0px; + } + + &__tab { + width: 100%; + font-size: 14px; + + &:last-of-type { + margin-right: 0; + } + + &--selected { + color: $curious-blue; + border-bottom: 2px solid $curious-blue; + } + } } } @@ -20,30 +71,35 @@ display: flex; flex-flow: column; color: $scorpion; + font-size: 12px; - &__total-info, &__sum-info { + &__send-info, &__transaction-info, &__total-info, &__fiat-total-info { display: flex; flex-flow: row; justify-content: space-between; } + &__fiat-total-info { + justify-content: flex-end; + } + &__total-info { - &__total-label { + &__label { font-size: 16px; } - &__total-value { + &__value { font-size: 16px; font-weight: bold; } } - &__sum-info { - &__sum-label { + &__transaction-info, &__send-info { + &__label { font-size: 12px; } - &__sum-value { + &__value { font-size: 14px; } } diff --git a/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js b/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js index fdd7709d9..714f01538 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js +++ b/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js @@ -9,7 +9,7 @@ import PageContainer from '../../../page-container' import { Tab } from '../../../tabs' const propsMethodSpies = { - hideModal: sinon.spy(), + cancelAndClose: sinon.spy(), onSubmit: sinon.spy(), } @@ -39,12 +39,16 @@ const mockGasPriceButtonGroupProps = { handleGasPriceSelection: 'mockSelectionFunction', noButtonActiveByDefault: true, showCheck: true, + newTotalFiat: 'mockNewTotalFiat', + newTotalEth: 'mockNewTotalEth', } const mockInfoRowProps = { originalTotalFiat: 'mockOriginalTotalFiat', originalTotalEth: 'mockOriginalTotalEth', newTotalFiat: 'mockNewTotalFiat', newTotalEth: 'mockNewTotalEth', + sendAmount: 'mockSendAmount', + transactionFee: 'mockTransactionFee', } const GP = GasModalPageContainer.prototype @@ -53,7 +57,7 @@ describe('GasModalPageContainer Component', function () { beforeEach(() => { wrapper = shallow(<GasModalPageContainer - hideModal={propsMethodSpies.hideModal} + cancelAndClose={propsMethodSpies.cancelAndClose} onSubmit={propsMethodSpies.onSubmit} updateCustomGasPrice={() => 'mockupdateCustomGasPrice'} updateCustomGasLimit={() => 'mockupdateCustomGasLimit'} @@ -67,7 +71,7 @@ describe('GasModalPageContainer Component', function () { }) afterEach(() => { - propsMethodSpies.hideModal.resetHistory() + propsMethodSpies.cancelAndClose.resetHistory() }) describe('render', () => { @@ -91,11 +95,11 @@ describe('GasModalPageContainer Component', function () { onCancel, onClose, } = wrapper.find(PageContainer).props() - assert.equal(propsMethodSpies.hideModal.callCount, 0) + assert.equal(propsMethodSpies.cancelAndClose.callCount, 0) onCancel() - assert.equal(propsMethodSpies.hideModal.callCount, 1) + assert.equal(propsMethodSpies.cancelAndClose.callCount, 1) onClose() - assert.equal(propsMethodSpies.hideModal.callCount, 2) + assert.equal(propsMethodSpies.cancelAndClose.callCount, 2) }) it('should pass the correct renderTabs property to PageContainer', () => { @@ -158,8 +162,8 @@ describe('GasModalPageContainer Component', function () { assert.equal(GP.renderInfoRows.callCount, 2) - assert.deepEqual(GP.renderInfoRows.getCall(0).args, ['mockOriginalTotalFiat', 'mockOriginalTotalEth', 'mockNewTotalFiat', 'mockNewTotalEth']) - assert.deepEqual(GP.renderInfoRows.getCall(1).args, ['mockOriginalTotalFiat', 'mockOriginalTotalEth', 'mockNewTotalFiat', 'mockNewTotalEth']) + assert.deepEqual(GP.renderInfoRows.getCall(0).args, ['mockNewTotalFiat', 'mockNewTotalEth', 'mockSendAmount', 'mockTransactionFee']) + assert.deepEqual(GP.renderInfoRows.getCall(1).args, ['mockNewTotalFiat', 'mockNewTotalEth', 'mockSendAmount', 'mockTransactionFee']) }) it('should not render the basic tab if hideBasic is true', () => { @@ -176,25 +180,6 @@ describe('GasModalPageContainer Component', function () { }) }) - describe('renderInfoRow', () => { - it('should render a div with the passed className and two children, each with the expected text', () => { - const renderInfoRowResult = wrapper.instance().renderInfoRow('mockClassName', 'mockLabelKey', 'mockFiatAmount', 'mockCryptoAmount') - const renderedInfoRow = shallow(renderInfoRowResult) - assert.equal(renderedInfoRow.props().className, 'mockClassName') - - const firstChild = renderedInfoRow.childAt(0) - const secondhild = renderedInfoRow.childAt(1) - - assert.equal(firstChild.props().className, 'mockClassName__total-info') - assert.equal(secondhild.props().className, 'mockClassName__sum-info') - - assert.equal(firstChild.childAt(0).text(), 'mockLabelKey:') - assert.equal(firstChild.childAt(1).text(), 'mockFiatAmount') - assert.equal(secondhild.childAt(0).text(), 'amountPlusTxFee') - assert.equal(secondhild.childAt(1).text(), 'mockCryptoAmount') - }) - }) - describe('renderBasicTabContent', () => { it('should render', () => { const renderBasicTabContentResult = wrapper.instance().renderBasicTabContent(mockGasPriceButtonGroupProps) @@ -220,8 +205,34 @@ describe('GasModalPageContainer Component', function () { assert.equal(advancedTabContentProps.updateCustomGasLimit(), 'mockConvertThenUpdateCustomGasLimit') assert.equal(advancedTabContentProps.customGasPrice, 123) assert.equal(advancedTabContentProps.customGasLimit, 456) - assert.equal(advancedTabContentProps.millisecondsRemaining, 91000) + assert.equal(advancedTabContentProps.timeRemaining, '1 min 31 sec') assert.equal(advancedTabContentProps.totalFee, '$0.30') }) }) + + describe('renderInfoRows', () => { + it('should render the info rows with the passed data', () => { + const baseClassName = 'gas-modal-content__info-row' + const renderedInfoRowsContainer = shallow(wrapper.instance().renderInfoRows( + 'mockNewTotalFiat', + ' mockNewTotalEth', + ' mockSendAmount', + ' mockTransactionFee' + )) + + assert(renderedInfoRowsContainer.childAt(0).hasClass(baseClassName)) + + const renderedInfoRows = renderedInfoRowsContainer.childAt(0).children() + assert.equal(renderedInfoRows.length, 4) + assert(renderedInfoRows.at(0).hasClass(`${baseClassName}__send-info`)) + assert(renderedInfoRows.at(1).hasClass(`${baseClassName}__transaction-info`)) + assert(renderedInfoRows.at(2).hasClass(`${baseClassName}__total-info`)) + assert(renderedInfoRows.at(3).hasClass(`${baseClassName}__fiat-total-info`)) + + assert.equal(renderedInfoRows.at(0).text(), 'Send Amount mockSendAmount') + assert.equal(renderedInfoRows.at(1).text(), 'Transaction Fee mockTransactionFee') + assert.equal(renderedInfoRows.at(2).text(), 'New Total mockNewTotalEth') + assert.equal(renderedInfoRows.at(3).text(), 'mockNewTotalFiat') + }) + }) }) diff --git a/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js b/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js index 238f27ed6..3d9fb2624 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js +++ b/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js @@ -15,6 +15,7 @@ const actionSpies = { const gasActionSpies = { setCustomGasPrice: sinon.spy(), setCustomGasLimit: sinon.spy(), + resetCustomData: sinon.spy(), } const confirmTransactionActionSpies = { @@ -37,7 +38,7 @@ proxyquire('../gas-modal-page-container.container.js', { '../../../selectors/custom-gas': { getBasicGasEstimateLoadingStatus: (s) => `mockBasicGasEstimateLoadingStatus:${Object.keys(s).length}`, getRenderableBasicEstimateData: (s) => `mockRenderableBasicEstimateData:${Object.keys(s).length}`, - getDefaultActiveButtonIndex: (a, b, c) => a + b + c, + getDefaultActiveButtonIndex: (a, b) => a + b, }, '../../../actions': actionSpies, '../../../ducks/gas.duck': gasActionSpies, @@ -89,15 +90,14 @@ describe('gas-modal-page-container container', () => { assert.deepEqual(result2, { isConfirm: true, - customGasPriceInHex: 'ffffffff', - customGasLimitInHex: 'aaaaaaaa', customGasPrice: 4.294967295, customGasLimit: 2863311530, newTotalFiat: '637.41', - gasPriceButtonGroupProps: - { + customModalGasLimitInHex: 'aaaaaaaa', + customModalGasPriceInHex: 'ffffffff', + gasPriceButtonGroupProps: { buttonDataLoading: 'mockBasicGasEstimateLoadingStatus:4', - defaultActiveButtonIndex: 'mockRenderableBasicEstimateData:4ffffffff0x3200000', + defaultActiveButtonIndex: 'mockRenderableBasicEstimateData:4ffffffff', gasButtonInfo: 'mockRenderableBasicEstimateData:4', }, hideBasic: true, @@ -106,6 +106,8 @@ describe('gas-modal-page-container container', () => { originalTotalEth: '0.451569 ETH', newTotalFiat: '637.41', newTotalEth: '12.748189 ETH', + sendAmount: '0.45036 ETH', + transactionFee: '12.297829 ETH', }, }) }) @@ -135,11 +137,12 @@ describe('gas-modal-page-container container', () => { }) }) - describe('hideModal()', () => { + describe('cancelAndClose()', () => { it('should dispatch a hideModal action', () => { - mapDispatchToPropsObject.hideModal() - assert(dispatchSpy.calledOnce) + mapDispatchToPropsObject.cancelAndClose() + assert(dispatchSpy.calledTwice) assert(actionSpies.hideModal.calledOnce) + assert(gasActionSpies.resetCustomData.calledOnce) }) }) diff --git a/ui/app/components/gas-customization/gas-price-chart/gas-price-chart.component.js b/ui/app/components/gas-customization/gas-price-chart/gas-price-chart.component.js new file mode 100644 index 000000000..7c32058b7 --- /dev/null +++ b/ui/app/components/gas-customization/gas-price-chart/gas-price-chart.component.js @@ -0,0 +1,16 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' + +export default class GasPriceChart extends Component { + static contextTypes = { + t: PropTypes.func, + } + + render () { + return ( + <div className="gas-price-chart"> + <div className="gas-price-chart__container" id="chart"></div> + </div> + ) + } +} diff --git a/ui/app/components/gas-customization/gas-price-chart/index.js b/ui/app/components/gas-customization/gas-price-chart/index.js new file mode 100644 index 000000000..9895acb62 --- /dev/null +++ b/ui/app/components/gas-customization/gas-price-chart/index.js @@ -0,0 +1 @@ +export { default } from './gas-price-chart.component' diff --git a/ui/app/components/gas-customization/gas-price-chart/index.scss b/ui/app/components/gas-customization/gas-price-chart/index.scss new file mode 100644 index 000000000..14e7a12a8 --- /dev/null +++ b/ui/app/components/gas-customization/gas-price-chart/index.scss @@ -0,0 +1,6 @@ +.gas-price-chart { + &__container { + display: flex; + position: relative; + } +} diff --git a/ui/app/components/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js b/ui/app/components/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js new file mode 100644 index 000000000..474b7b7b6 --- /dev/null +++ b/ui/app/components/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js @@ -0,0 +1,25 @@ +import React from 'react' +import assert from 'assert' +import shallow from '../../../../../lib/shallow-with-context' +import GasPriceChart from '../gas-price-chart.component.js' + +describe('GasPriceChart Component', function () { + let wrapper + + beforeEach(() => { + wrapper = shallow(<GasPriceChart />) + }) + + describe('render()', () => { + it('should render', () => { + console.log('wrapper', wrapper.html()) + assert(wrapper.hasClass('gas-price-chart')) + }) + + it('should render the chart div', () => { + assert(wrapper.childAt(0).hasClass('gas-price-chart__container')) + assert.equal(wrapper.childAt(0).props().id, 'chart') + }) + }) + +}) diff --git a/ui/app/components/gas-customization/index.scss b/ui/app/components/gas-customization/index.scss index 91ca5004e..e99d4e57f 100644 --- a/ui/app/components/gas-customization/index.scss +++ b/ui/app/components/gas-customization/index.scss @@ -1,3 +1,5 @@ @import './gas-slider/index'; @import './gas-modal-page-container/index'; + +@import './gas-price-chart/index'; diff --git a/ui/app/components/page-container/page-container-footer/page-container-footer.component.js b/ui/app/components/page-container/page-container-footer/page-container-footer.component.js index 773fe1f56..5725c22ac 100644 --- a/ui/app/components/page-container/page-container-footer/page-container-footer.component.js +++ b/ui/app/components/page-container/page-container-footer/page-container-footer.component.js @@ -12,6 +12,7 @@ export default class PageContainerFooter extends Component { submitText: PropTypes.string, disabled: PropTypes.bool, submitButtonType: PropTypes.string, + hideCancel: PropTypes.func, } static contextTypes = { @@ -27,20 +28,21 @@ export default class PageContainerFooter extends Component { submitText, disabled, submitButtonType, + hideCancel, } = this.props return ( <div className="page-container__footer"> <header> - <Button + {!hideCancel && <Button type="default" large className="page-container__footer-button" onClick={e => onCancel(e)} > { cancelText || this.context.t('cancel') } - </Button> + </Button>} <Button type={submitButtonType || 'primary'} diff --git a/ui/app/components/page-container/page-container-header/page-container-header.component.js b/ui/app/components/page-container/page-container-header/page-container-header.component.js index a8458604e..08f9c7544 100644 --- a/ui/app/components/page-container/page-container-header/page-container-header.component.js +++ b/ui/app/components/page-container/page-container-header/page-container-header.component.js @@ -12,6 +12,7 @@ export default class PageContainerHeader extends Component { backButtonStyles: PropTypes.object, backButtonString: PropTypes.string, tabs: PropTypes.node, + headerCloseText: PropTypes.string, } renderTabs () { @@ -41,7 +42,7 @@ export default class PageContainerHeader extends Component { } render () { - const { title, subtitle, onClose, tabs } = this.props + const { title, subtitle, onClose, tabs, headerCloseText } = this.props return ( <div className={ @@ -66,10 +67,12 @@ export default class PageContainerHeader extends Component { } { - onClose && <div - className="page-container__header-close" - onClick={() => onClose()} - /> + onClose && headerCloseText + ? <div className="page-container__header-close-text" onClick={() => onClose()}>{ headerCloseText }</div> + : onClose && <div + className="page-container__header-close" + onClick={() => onClose()} + /> } { this.renderTabs() } diff --git a/ui/app/components/page-container/page-container.component.js b/ui/app/components/page-container/page-container.component.js index 672255e27..27daf4c04 100644 --- a/ui/app/components/page-container/page-container.component.js +++ b/ui/app/components/page-container/page-container.component.js @@ -9,6 +9,7 @@ export default class PageContainer extends PureComponent { // PageContainerHeader props backButtonString: PropTypes.string, backButtonStyles: PropTypes.object, + headerCloseText: PropTypes.string, onBackButtonClick: PropTypes.func, onClose: PropTypes.func, showBackButton: PropTypes.bool, @@ -22,6 +23,7 @@ export default class PageContainer extends PureComponent { // PageContainerFooter props cancelText: PropTypes.string, disabled: PropTypes.bool, + hideCancel: PropTypes.string, onCancel: PropTypes.func, onSubmit: PropTypes.func, submitText: PropTypes.string, @@ -93,6 +95,8 @@ export default class PageContainer extends PureComponent { onSubmit, submitText, disabled, + headerCloseText, + hideCancel, } = this.props return ( @@ -106,6 +110,7 @@ export default class PageContainer extends PureComponent { backButtonStyles={backButtonStyles} backButtonString={backButtonString} tabs={this.renderTabs()} + headerCloseText={headerCloseText} /> <div className="page-container__content"> { this.renderContent() } @@ -113,6 +118,7 @@ export default class PageContainer extends PureComponent { <PageContainerFooter onCancel={onCancel} cancelText={cancelText} + hideCancel={hideCancel} onSubmit={onSubmit} submitText={submitText} disabled={disabled} diff --git a/ui/app/ducks/gas.duck.js b/ui/app/ducks/gas.duck.js index 7f18b2272..558047cf7 100644 --- a/ui/app/ducks/gas.duck.js +++ b/ui/app/ducks/gas.duck.js @@ -4,6 +4,7 @@ import { clone } from 'ramda' const BASIC_GAS_ESTIMATE_LOADING_FINISHED = 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_FINISHED' const BASIC_GAS_ESTIMATE_LOADING_STARTED = 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_STARTED' const RESET_CUSTOM_GAS_STATE = 'metamask/gas/RESET_CUSTOM_GAS_STATE' +const RESET_CUSTOM_DATA = 'metamask/gas/RESET_CUSTOM_DATA' const SET_BASIC_GAS_ESTIMATE_DATA = 'metamask/gas/SET_BASIC_GAS_ESTIMATE_DATA' const SET_CUSTOM_GAS_ERRORS = 'metamask/gas/SET_CUSTOM_GAS_ERRORS' const SET_CUSTOM_GAS_LIMIT = 'metamask/gas/SET_CUSTOM_GAS_LIMIT' @@ -85,6 +86,11 @@ export default function reducer ({ gas: gasState = initState }, action = {}) { ...action.value, }, } + case RESET_CUSTOM_DATA: + return { + ...newState, + customData: clone(initState.customData), + } case RESET_CUSTOM_GAS_STATE: return clone(initState) default: @@ -187,3 +193,7 @@ export function setCustomGasErrors (newErrors) { export function resetCustomGasState () { return { type: RESET_CUSTOM_GAS_STATE } } + +export function resetCustomData () { + return { type: RESET_CUSTOM_DATA } +} |