diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index 0fe8e81cd..6e7df3aa8 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -80,12 +80,18 @@
"addAcquiredTokens": {
"message": "Add the tokens you've acquired using MetaMask"
},
+ "advanced": {
+ "message": "Advanced"
+ },
"amount": {
"message": "Amount"
},
"amountPlusGas": {
"message": "Amount + Gas"
},
+ "amountPlusTxFee": {
+ "message": "Amount + TX Fee"
+ },
"appDescription": {
"message": "Ethereum Browser Extension",
"description": "The description of the application"
@@ -127,6 +133,9 @@
"balanceIsInsufficientGas": {
"message": "Insufficient balance for current gas total"
},
+ "basic": {
+ "message": "Basic"
+ },
"beta": {
"message": "BETA"
},
@@ -303,6 +312,9 @@
"customGas": {
"message": "Customize Gas"
},
+ "customGasSubTitle": {
+ "message": "Increasing fee may decrease processing times, but it is not guaranteed."
+ },
"customToken": {
"message": "Custom Token"
},
@@ -755,6 +767,9 @@
"optionalNickname": {
"message": "Nickname (optional)"
},
+ "newTotal": {
+ "message": "New Total"
+ },
"next": {
"message": "Next"
},
@@ -820,6 +835,9 @@
"parameters": {
"message": "Parameters"
},
+ "originalTotal": {
+ "message": "Original Total"
+ },
"password": {
"message": "Password"
},
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
new file mode 100644
index 000000000..dfc011c1e
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js
@@ -0,0 +1,79 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import PageContainer from '../../page-container'
+import { Tabs, Tab } from '../../tabs'
+
+export default class GasModalPageContainer extends Component {
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ hideModal: PropTypes.func,
+ }
+
+ state = {}
+
+ renderBasicTabContent () {
+ return (
+
+ )
+ }
+
+ renderAdvancedTabContent () {
+ return (
+
+ )
+ }
+
+ renderInfoRow (className, totalLabelKey, fiatTotal, cryptoTotal) {
+ return (
+
+
+ {`${this.context.t(totalLabelKey)}:`}{fiatTotal}
+
+
+ {`${this.context.t('amountPlusTxFee')}`}{cryptoTotal}
+
+
+ )
+ }
+
+ renderTabContent (mainTabContent) {
+ return (
+
+ { mainTabContent() }
+ { this.renderInfoRow('info-row--fade', 'originalTotal', '$20.02 USD', '0.06685 ETH') }
+ { this.renderInfoRow('info-row', 'newTotal', '$20.02 USD', '0.06685 ETH') }
+
+ )
+ }
+
+ renderTabs () {
+ return (
+
+
+ { this.renderTabContent(this.renderBasicTabContent) }
+
+
+ { this.renderTabContent(this.renderAdvancedTabContent) }
+
+
+ )
+ }
+
+ render () {
+ const { hideModal } = this.props
+
+ return (
+ hideModal()}
+ onClose={() => hideModal()}
+ />
+ )
+ }
+}
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
new file mode 100644
index 000000000..71c700507
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js
@@ -0,0 +1,11 @@
+import { connect } from 'react-redux'
+import GasModalPageContainer from './gas-modal-page-container.component'
+import { hideModal } from '../../../actions'
+
+const mapDispatchToProps = dispatch => {
+ return {
+ hideModal: () => dispatch(hideModal()),
+ }
+}
+
+export default connect(null, mapDispatchToProps)(GasModalPageContainer)
diff --git a/ui/app/components/gas-customization/gas-modal-page-container/index.js b/ui/app/components/gas-customization/gas-modal-page-container/index.js
new file mode 100644
index 000000000..ec0ebad22
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-modal-page-container/index.js
@@ -0,0 +1 @@
+export { default } from './gas-modal-page-container.container'
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
new file mode 100644
index 000000000..2d2250212
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-modal-page-container/index.scss
@@ -0,0 +1,50 @@
+.gas-modal-content {
+ .basic-tab {
+ height: 219px;
+ }
+
+ .advanced-tab {
+ height: 475px;
+ }
+
+ .info-row, .info-row--fade {
+ width: 100%;
+ background: $polar;
+ padding: 15px 21px;
+ display: flex;
+ flex-flow: column;
+ color: $scorpion;
+
+ .total-info, .sum-info {
+ display: flex;
+ flex-flow: row;
+ justify-content: space-between;
+ }
+
+ .total-info {
+ .total-label {
+ font-size: 16px;
+ }
+
+ .total-value {
+ font-size: 16px;
+ font-weight: bold;
+ }
+ }
+
+ .sum-info {
+ .sum-label {
+ font-size: 12px;
+ }
+
+ .sum-value {
+ font-size: 14px;
+ }
+ }
+ }
+
+ .info-row--fade {
+ background: white;
+ color: $dusty-gray;
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 000000000..ffe242de2
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js
@@ -0,0 +1,156 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow } from 'enzyme'
+import sinon from 'sinon'
+import GasModalPageContainer from '../gas-modal-page-container.component.js'
+
+import PageContainer from '../../../page-container'
+import { Tab } from '../../../tabs'
+
+const propsMethodSpies = {
+ hideModal: sinon.spy(),
+}
+
+describe('GasModalPageContainer Component', function () {
+ let wrapper
+
+ beforeEach(() => {
+ wrapper = shallow(, { context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } })
+ })
+
+ afterEach(() => {
+ propsMethodSpies.hideModal.resetHistory()
+ })
+
+ describe('render', () => {
+ it('should render a PageContainer compenent', () => {
+ assert.equal(wrapper.find(PageContainer).length, 1)
+ })
+
+ it('should pass correct props to PageContainer', () => {
+ const {
+ title,
+ subtitle,
+ disabled,
+ } = wrapper.find(PageContainer).props()
+ assert.equal(title, 'customGas')
+ assert.equal(subtitle, 'customGasSpeedUp')
+ assert.equal(disabled, false)
+ })
+
+ it('should pass the correct onCancel and onClose methods to PageContainer', () => {
+ const {
+ onCancel,
+ onClose,
+ } = wrapper.find(PageContainer).props()
+ assert.equal(propsMethodSpies.hideModal.callCount, 0)
+ onCancel()
+ assert.equal(propsMethodSpies.hideModal.callCount, 1)
+ onClose()
+ assert.equal(propsMethodSpies.hideModal.callCount, 2)
+ })
+
+ it('should pass the correct renderTabs property to PageContainer', () => {
+ sinon.stub(GasModalPageContainer.prototype, 'renderTabs').returns('mockTabs')
+ const renderTabsWrapperTester = shallow(, { context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } })
+ const { tabsComponent } = renderTabsWrapperTester.find(PageContainer).props()
+ assert.equal(tabsComponent, 'mockTabs')
+ GasModalPageContainer.prototype.renderTabs.restore()
+ })
+ })
+
+ describe('renderTabs', () => {
+ it('should render a Tabs component with "Basic" and "Advanced" tabs', () => {
+ const renderTabsResult = wrapper.instance().renderTabs()
+ const renderedTabs = shallow(renderTabsResult)
+ assert.equal(renderedTabs.props().className, 'tabs')
+
+ const tabs = renderedTabs.find(Tab)
+ assert.equal(tabs.length, 2)
+
+ assert.equal(tabs.at(0).props().name, 'basic')
+ assert.equal(tabs.at(1).props().name, 'advanced')
+
+ assert.equal(tabs.at(0).childAt(0).props().className, 'gas-modal-content')
+ assert.equal(tabs.at(1).childAt(0).props().className, 'gas-modal-content')
+ })
+
+ it('should render the expected children of each tab', () => {
+ const GP = GasModalPageContainer.prototype
+ sinon.spy(GP, 'renderTabContent')
+ assert.equal(GP.renderTabContent.callCount, 0)
+
+ wrapper.instance().renderTabs()
+
+ assert.equal(GP.renderTabContent.callCount, 2)
+
+ assert.deepEqual(GP.renderTabContent.firstCall.args, [wrapper.instance().renderBasicTabContent])
+ assert.deepEqual(GP.renderTabContent.secondCall.args, [wrapper.instance().renderAdvancedTabContent])
+
+ GP.renderTabContent.restore()
+ })
+ })
+
+ describe('renderTabContent', () => {
+ it('should render a root gas-modal-content div', () => {
+ const renderTabContentResult = wrapper.instance().renderTabContent(() => {})
+ const renderedTabContent = shallow(renderTabContentResult)
+ assert.equal(renderedTabContent.props().className, 'gas-modal-content')
+ })
+
+ it('should render the element returned by the passed func as its first child', () => {
+ const renderTabContentResult = wrapper.instance().renderTabContent(() => Mock content)
+ const renderedTabContent = shallow(renderTabContentResult)
+ assert(renderedTabContent.childAt(0).equals(Mock content))
+ })
+
+ it('should render the element results of renderInfoRow calls as second and third childs', () => {
+ const GP = GasModalPageContainer.prototype
+ sinon.stub(GP, 'renderInfoRow').callsFake((...args) => args.join(','))
+
+ const renderTabContentResult = wrapper.instance().renderTabContent(() => Mock content)
+ const renderedTabContent = shallow(renderTabContentResult)
+ assert.equal(renderedTabContent.childAt(1).text(), 'info-row--fade,originalTotal,$20.02 USD,0.06685 ETH')
+ assert.equal(renderedTabContent.childAt(2).text(), 'info-row,newTotal,$20.02 USD,0.06685 ETH')
+
+ GP.renderInfoRow.restore()
+ })
+ })
+
+ 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, 'total-info')
+ assert.equal(secondhild.props().className, '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()
+ const renderedBasicTabContent = shallow(renderBasicTabContentResult)
+ assert.equal(renderedBasicTabContent.props().className, 'basic-tab')
+ })
+ })
+
+ describe('renderAdvancedTabContent', () => {
+ it('should render', () => {
+ const renderAdvancedTabContentResult = wrapper.instance().renderAdvancedTabContent()
+ const renderedAdvancedTabContent = shallow(renderAdvancedTabContentResult)
+ assert.equal(renderedAdvancedTabContent.props().className, 'advanced-tab')
+ })
+ })
+})
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
new file mode 100644
index 000000000..5b133fbe2
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
@@ -0,0 +1,44 @@
+import assert from 'assert'
+import proxyquire from 'proxyquire'
+import sinon from 'sinon'
+
+// let mapStateToProps
+let mapDispatchToProps
+
+const actionSpies = {
+ hideModal: sinon.spy(),
+}
+
+proxyquire('../gas-modal-page-container.container.js', {
+ 'react-redux': {
+ connect: (ms, md) => {
+ // mapStateToProps = ms
+ mapDispatchToProps = md
+ return () => ({})
+ },
+ },
+ '../../../actions': actionSpies,
+})
+
+describe('gas-modal-page-container container', () => {
+
+ describe('mapDispatchToProps()', () => {
+ let dispatchSpy
+ let mapDispatchToPropsObject
+
+ beforeEach(() => {
+ dispatchSpy = sinon.spy()
+ mapDispatchToPropsObject = mapDispatchToProps(dispatchSpy)
+ })
+
+ describe('hideModal()', () => {
+ it('should dispatch a hideModal action', () => {
+ mapDispatchToPropsObject.hideModal()
+ assert(dispatchSpy.calledOnce)
+ assert(actionSpies.hideModal.calledOnce)
+ })
+ })
+
+ })
+
+})
diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss
index f901aed7d..48c6496d9 100644
--- a/ui/app/components/index.scss
+++ b/ui/app/components/index.scss
@@ -63,3 +63,5 @@
@import './sidebars/index';
@import './unit-input/index';
+
+@import './gas-customization/gas-modal-page-container/index'
diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js
index 5aff4f5e1..46347312c 100644
--- a/ui/app/components/modals/modal.js
+++ b/ui/app/components/modals/modal.js
@@ -17,18 +17,17 @@ const ExportPrivateKeyModal = require('./export-private-key-modal')
const NewAccountModal = require('./new-account-modal')
const ShapeshiftDepositTxModal = require('./shapeshift-deposit-tx-modal.js')
const HideTokenConfirmationModal = require('./hide-token-confirmation-modal')
-const CustomizeGasModal = require('../customize-gas-modal')
const NotifcationModal = require('./notification-modal')
const QRScanner = require('./qr-scanner')
import ConfirmRemoveAccount from './confirm-remove-account'
import ConfirmResetAccount from './confirm-reset-account'
import TransactionConfirmed from './transaction-confirmed'
-import ConfirmCustomizeGasModal from './customize-gas'
import CancelTransaction from './cancel-transaction'
import WelcomeBeta from './welcome-beta'
import RejectTransactions from './reject-transactions'
import ClearApprovedOrigins from './clear-approved-origins'
+import ConfirmCustomizeGasModal from '../gas-customization/gas-modal-page-container'
const modalContainerBaseStyle = {
transform: 'translate3d(-50%, 0, 0px)',
@@ -295,7 +294,7 @@ const MODALS = {
CUSTOMIZE_GAS: {
contents: [
- h(CustomizeGasModal),
+ h(ConfirmCustomizeGasModal),
],
mobileModalStyle: {
width: '100vw',
@@ -307,35 +306,16 @@ const MODALS = {
margin: '0 auto',
},
laptopModalStyle: {
- width: '720px',
- height: '377px',
+ width: 'auto',
+ height: '0px',
top: '80px',
+ left: '0px',
transform: 'none',
- left: '0',
- right: '0',
margin: '0 auto',
+ position: 'relative',
},
- },
-
- CONFIRM_CUSTOMIZE_GAS: {
- contents: h(ConfirmCustomizeGasModal),
- mobileModalStyle: {
- width: '100vw',
- height: '100vh',
- top: '0',
- transform: 'none',
- left: '0',
- right: '0',
- margin: '0 auto',
- },
- laptopModalStyle: {
- width: '720px',
- height: '377px',
- top: '80px',
- transform: 'none',
- left: '0',
- right: '0',
- margin: '0 auto',
+ contentStyle: {
+ borderRadius: '8px',
},
},
diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
index 626143ac7..a3ec82863 100644
--- a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
+++ b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
@@ -117,7 +117,7 @@ const mapDispatchToProps = dispatch => {
return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onSubmit }))
},
showCustomizeGasModal: ({ txData, onSubmit, validate }) => {
- return dispatch(showModal({ name: 'CONFIRM_CUSTOMIZE_GAS', txData, onSubmit, validate }))
+ return dispatch(showModal({ name: 'CUSTOMIZE_GAS', txData, onSubmit, validate }))
},
updateGasAndCalculate: ({ gasLimit, gasPrice }) => {
return dispatch(updateGasAndCalculate({ gasLimit, gasPrice }))
diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss
index f90c8edc3..6c2b82f39 100644
--- a/ui/app/css/itcss/settings/variables.scss
+++ b/ui/app/css/itcss/settings/variables.scss
@@ -56,6 +56,7 @@ $zumthor: #edf7ff;
$ecstasy: #f7861c;
$linen: #fdf4f4;
$oslo-gray: #8C8E94;
+$polar: #fafcfe;
/*
Z-Indicies