aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorDan Miller <danjm.com@gmail.com>2018-08-10 00:14:03 +0800
committerDan Miller <danjm.com@gmail.com>2018-12-04 11:36:04 +0800
commit112d18e316df312a648b8c8ac17c201314fc9ed6 (patch)
tree32f9e37bb174bc4246e46442afd0609f7c074673 /ui
parent57cd721800aff67cd18e9e530d92eb94ff75d473 (diff)
downloadtangerine-wallet-browser-112d18e316df312a648b8c8ac17c201314fc9ed6.tar.gz
tangerine-wallet-browser-112d18e316df312a648b8c8ac17c201314fc9ed6.tar.zst
tangerine-wallet-browser-112d18e316df312a648b8c8ac17c201314fc9ed6.zip
Adds basic tab content to gas customizer, with styled button group (static, for now).
Diffstat (limited to 'ui')
-rw-r--r--ui/app/components/button/button.component.js6
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js22
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/index.js1
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/index.scss11
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/tests/basic-tab-content-component.test.js71
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js10
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js29
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/index.scss7
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js47
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js39
-rw-r--r--ui/app/components/gas-customization/gas-price-button-group/gas-price-button-group.component.js85
-rw-r--r--ui/app/components/gas-customization/gas-price-button-group/index.js1
-rw-r--r--ui/app/components/gas-customization/gas-price-button-group/index.scss60
-rw-r--r--ui/app/components/gas-customization/gas-price-button-group/tests/gas-price-button-group-component.test.js238
-rw-r--r--ui/app/components/index.scss2
-rw-r--r--ui/app/css/itcss/settings/variables.scss1
16 files changed, 615 insertions, 15 deletions
diff --git a/ui/app/components/button/button.component.js b/ui/app/components/button/button.component.js
index 4a06333e7..5c617585d 100644
--- a/ui/app/components/button/button.component.js
+++ b/ui/app/components/button/button.component.js
@@ -22,7 +22,11 @@ export default class Button extends Component {
type: PropTypes.string,
large: PropTypes.bool,
className: PropTypes.string,
- children: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
+ children: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.array,
+ PropTypes.element,
+ ]),
}
render () {
diff --git a/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js b/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js
new file mode 100644
index 000000000..751042871
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/basic-tab-content.component.js
@@ -0,0 +1,22 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import GasPriceButtonGroup from '../../gas-price-button-group'
+
+export default class BasicTabContent extends Component {
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ gasPriceButtonGroupProps: PropTypes.object,
+ }
+
+ render () {
+ return (
+ <div className="basic-tab-content">
+ <div className="basic-tab-content__title">Suggest gas fee increases</div>
+ <GasPriceButtonGroup {...this.props.gasPriceButtonGroupProps} />
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/index.js b/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/index.js
new file mode 100644
index 000000000..078d50fce
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/index.js
@@ -0,0 +1 @@
+export { default } from './basic-tab-content.component'
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
new file mode 100644
index 000000000..ba665716c
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/index.scss
@@ -0,0 +1,11 @@
+.basic-tab-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ &__title {
+ margin-top: 19px;
+ font-size: 20px;
+ color: $scorpion;
+ }
+}
diff --git a/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/tests/basic-tab-content-component.test.js b/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/tests/basic-tab-content-component.test.js
new file mode 100644
index 000000000..0c9c6ac63
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-modal-page-container/basic-tab-content/tests/basic-tab-content-component.test.js
@@ -0,0 +1,71 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow } from 'enzyme'
+import BasicTabContent from '../basic-tab-content.component'
+
+import GasPriceButtonGroup from '../../../gas-price-button-group/'
+
+const mockGasPriceButtonGroupProps = {
+ buttonDataLoading: false,
+ className: 'gas-price-button-group',
+ gasButtonInfo: [
+ {
+ feeInPrimaryCurrency: '$0.52',
+ feeInSecondaryCurrency: '0.0048 ETH',
+ timeEstimate: '~ 1 min 0 sec',
+ priceInHexWei: '0xa1b2c3f',
+ },
+ {
+ feeInPrimaryCurrency: '$0.39',
+ feeInSecondaryCurrency: '0.004 ETH',
+ timeEstimate: '~ 1 min 30 sec',
+ priceInHexWei: '0xa1b2c39',
+ },
+ {
+ feeInPrimaryCurrency: '$0.30',
+ feeInSecondaryCurrency: '0.00354 ETH',
+ timeEstimate: '~ 2 min 1 sec',
+ priceInHexWei: '0xa1b2c30',
+ },
+ ],
+ handleGasPriceSelection: newPrice => console.log('NewPrice: ', newPrice),
+ noButtonActiveByDefault: true,
+ showCheck: true,
+}
+
+describe('BasicTabContent Component', function () {
+ let wrapper
+
+ beforeEach(() => {
+ wrapper = shallow(<BasicTabContent
+ gasPriceButtonGroupProps={mockGasPriceButtonGroupProps}
+ />)
+ })
+
+ describe('render', () => {
+ it('should have a title', () => {
+ assert(wrapper.find('.basic-tab-content').childAt(0).hasClass('basic-tab-content__title'))
+ })
+
+ it('should render a GasPriceButtonGroup compenent', () => {
+ assert.equal(wrapper.find(GasPriceButtonGroup).length, 1)
+ })
+
+ it('should pass correct props to GasPriceButtonGroup', () => {
+ const {
+ buttonDataLoading,
+ className,
+ gasButtonInfo,
+ handleGasPriceSelection,
+ noButtonActiveByDefault,
+ showCheck,
+ } = wrapper.find(GasPriceButtonGroup).props()
+ assert.equal(buttonDataLoading, mockGasPriceButtonGroupProps.buttonDataLoading)
+ assert.equal(className, mockGasPriceButtonGroupProps.className)
+ assert.equal(noButtonActiveByDefault, mockGasPriceButtonGroupProps.noButtonActiveByDefault)
+ assert.equal(showCheck, mockGasPriceButtonGroupProps.showCheck)
+ assert.deepEqual(gasButtonInfo, mockGasPriceButtonGroupProps.gasButtonInfo)
+ assert.equal(JSON.stringify(handleGasPriceSelection), JSON.stringify(mockGasPriceButtonGroupProps.handleGasPriceSelection))
+ })
+ })
+})
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 e47ebaf65..9a0070b2a 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
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
import PageContainer from '../../page-container'
import { Tabs, Tab } from '../../tabs'
import AdvancedTabContent from './advanced-tab-content'
+import BasicTabContent from './basic-tab-content'
export default class GasModalPageContainer extends Component {
static contextTypes = {
@@ -15,13 +16,14 @@ export default class GasModalPageContainer extends Component {
updateCustomGasLimit: PropTypes.func,
customGasPrice: PropTypes.number,
customGasLimit: PropTypes.number,
+ gasPriceButtonGroupProps: PropTypes.object,
}
state = {}
renderBasicTabContent () {
return (
- <div className="gas-modal-content__basic-tab"/>
+ <BasicTabContent gasPriceButtonGroupProps={this.props.gasPriceButtonGroupProps} />
)
}
@@ -63,7 +65,7 @@ export default class GasModalPageContainer extends Component {
renderTabContent (mainTabContent) {
return (
<div className="gas-modal-content">
- { mainTabContent() }
+ { mainTabContent }
{ this.renderInfoRow('gas-modal-content__info-row--fade', 'originalTotal', '$20.02 USD', '0.06685 ETH') }
{ this.renderInfoRow('gas-modal-content__info-row', 'newTotal', '$20.02 USD', '0.06685 ETH') }
</div>
@@ -74,10 +76,10 @@ export default class GasModalPageContainer extends Component {
return (
<Tabs>
<Tab name={this.context.t('basic')}>
- { this.renderTabContent(this.renderBasicTabContent) }
+ { this.renderTabContent(this.renderBasicTabContent()) }
</Tab>
<Tab name={this.context.t('advanced')}>
- { this.renderTabContent(this.renderAdvancedTabContent) }
+ { this.renderTabContent(this.renderAdvancedTabContent()) }
</Tab>
</Tabs>
)
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 f7ac91a38..2354d578c 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
@@ -10,10 +10,39 @@ import {
getCustomGasLimit,
} from '../../../selectors/custom-gas'
+const mockGasPriceButtonGroupProps = {
+ buttonDataLoading: false,
+ className: 'gas-price-button-group',
+ gasButtonInfo: [
+ {
+ feeInPrimaryCurrency: '$0.52',
+ feeInSecondaryCurrency: '0.0048 ETH',
+ timeEstimate: '~ 1 min 0 sec',
+ priceInHexWei: '0xa1b2c3f',
+ },
+ {
+ feeInPrimaryCurrency: '$0.39',
+ feeInSecondaryCurrency: '0.004 ETH',
+ timeEstimate: '~ 1 min 30 sec',
+ priceInHexWei: '0xa1b2c39',
+ },
+ {
+ feeInPrimaryCurrency: '$0.30',
+ feeInSecondaryCurrency: '0.00354 ETH',
+ timeEstimate: '~ 2 min 1 sec',
+ priceInHexWei: '0xa1b2c30',
+ },
+ ],
+ handleGasPriceSelection: newPrice => console.log('NewPrice: ', newPrice),
+ noButtonActiveByDefault: true,
+ showCheck: true,
+}
+
const mapStateToProps = state => {
return {
customGasPrice: getCustomGasPrice(state),
customGasLimit: getCustomGasLimit(state),
+ gasPriceButtonGroupProps: mockGasPriceButtonGroupProps,
}
}
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 ff512537e..427b58888 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
@@ -1,4 +1,5 @@
@import './advanced-tab-content/index';
+@import './basic-tab-content/index';
.gas-modal-page-container {
.page-container {
@@ -12,7 +13,7 @@
}
- .info-row, .info-row--fade {
+ &__info-row, &__info-row--fade {
width: 100%;
background: $polar;
padding: 15px 21px;
@@ -51,5 +52,7 @@
&__info-row--fade {
background: white;
color: $dusty-gray;
+ border-top: 1px solid $mischka;
+ margin-top: 22px;
}
-} \ 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
index 8bf72647a..86286b615 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
@@ -5,12 +5,43 @@ import sinon from 'sinon'
import GasModalPageContainer from '../gas-modal-page-container.component.js'
import PageContainer from '../../../page-container'
+import BasicTabContent from '../basic-tab-content'
+import AdvancedTabContent from '../advanced-tab-content'
+
import { Tab } from '../../../tabs'
const propsMethodSpies = {
hideModal: sinon.spy(),
}
+const mockGasPriceButtonGroupProps = {
+ buttonDataLoading: false,
+ className: 'gas-price-button-group',
+ gasButtonInfo: [
+ {
+ feeInPrimaryCurrency: '$0.52',
+ feeInSecondaryCurrency: '0.0048 ETH',
+ timeEstimate: '~ 1 min 0 sec',
+ priceInHexWei: '0xa1b2c3f',
+ },
+ {
+ feeInPrimaryCurrency: '$0.39',
+ feeInSecondaryCurrency: '0.004 ETH',
+ timeEstimate: '~ 1 min 30 sec',
+ priceInHexWei: '0xa1b2c39',
+ },
+ {
+ feeInPrimaryCurrency: '$0.30',
+ feeInSecondaryCurrency: '0.00354 ETH',
+ timeEstimate: '~ 2 min 1 sec',
+ priceInHexWei: '0xa1b2c30',
+ },
+ ],
+ handleGasPriceSelection: 'mockSelectionFunction',
+ noButtonActiveByDefault: true,
+ showCheck: true,
+}
+
describe('GasModalPageContainer Component', function () {
let wrapper
@@ -21,6 +52,7 @@ describe('GasModalPageContainer Component', function () {
updateCustomGasLimit={() => 'mockupdateCustomGasLimit'}
customGasPrice={21}
customGasLimit={54321}
+ gasPriceButtonGroupProps={mockGasPriceButtonGroupProps}
/>, { context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } })
})
@@ -90,8 +122,8 @@ describe('GasModalPageContainer Component', function () {
assert.equal(GP.renderTabContent.callCount, 2)
- assert.deepEqual(GP.renderTabContent.firstCall.args, [wrapper.instance().renderBasicTabContent])
- assert.deepEqual(GP.renderTabContent.secondCall.args, [wrapper.instance().renderAdvancedTabContent])
+ assert.equal(GP.renderTabContent.firstCall.args.type, BasicTabContent.type)
+ assert.equal(GP.renderTabContent.secondCall.args.type, AdvancedTabContent.type)
GP.renderTabContent.restore()
})
@@ -104,8 +136,8 @@ describe('GasModalPageContainer Component', function () {
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(() => <span>Mock content</span>)
+ it('should render the passed element as its first child', () => {
+ const renderTabContentResult = wrapper.instance().renderTabContent(<span>Mock content</span>)
const renderedTabContent = shallow(renderTabContentResult)
assert(renderedTabContent.childAt(0).equals(<span>Mock content</span>))
})
@@ -145,8 +177,11 @@ describe('GasModalPageContainer Component', function () {
describe('renderBasicTabContent', () => {
it('should render', () => {
const renderBasicTabContentResult = wrapper.instance().renderBasicTabContent()
- const renderedBasicTabContent = shallow(renderBasicTabContentResult)
- assert.equal(renderedBasicTabContent.props().className, 'gas-modal-content__basic-tab')
+
+ assert.deepEqual(
+ renderBasicTabContentResult.props.gasPriceButtonGroupProps,
+ mockGasPriceButtonGroupProps
+ )
})
})
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 5b133fbe2..119ae640b 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
@@ -2,26 +2,45 @@ import assert from 'assert'
import proxyquire from 'proxyquire'
import sinon from 'sinon'
-// let mapStateToProps
+let mapStateToProps
let mapDispatchToProps
const actionSpies = {
hideModal: sinon.spy(),
}
+const customGasActionSpies = {
+ setCustomGasPrice: sinon.spy(),
+ setCustomGasLimit: sinon.spy(),
+}
+
proxyquire('../gas-modal-page-container.container.js', {
'react-redux': {
connect: (ms, md) => {
- // mapStateToProps = ms
+ mapStateToProps = ms
mapDispatchToProps = md
return () => ({})
},
},
+ '../../../selectors/custom-gas': {
+ getCustomGasPrice: (s) => `mockGasPrice:${s}`,
+ getCustomGasLimit: (s) => `mockGasLimit:${s}`,
+ },
'../../../actions': actionSpies,
+ '../../../ducks/custom-gas': customGasActionSpies,
})
describe('gas-modal-page-container container', () => {
+ describe('mapStateToProps()', () => {
+
+ it('should map the correct properties to props', () => {
+ assert.equal(mapStateToProps('mockState').customGasPrice, 'mockGasPrice:mockState')
+ assert.equal(mapStateToProps('mockState').customGasLimit, 'mockGasLimit:mockState')
+ })
+
+ })
+
describe('mapDispatchToProps()', () => {
let dispatchSpy
let mapDispatchToPropsObject
@@ -39,6 +58,22 @@ describe('gas-modal-page-container container', () => {
})
})
+ describe('updateCustomGasPrice()', () => {
+ it('should dispatch a setCustomGasPrice action', () => {
+ mapDispatchToPropsObject.updateCustomGasPrice()
+ assert(dispatchSpy.calledOnce)
+ assert(customGasActionSpies.setCustomGasPrice.calledOnce)
+ })
+ })
+
+ describe('updateCustomGasLimit()', () => {
+ it('should dispatch a setCustomGasLimit action', () => {
+ mapDispatchToPropsObject.updateCustomGasLimit()
+ assert(dispatchSpy.calledOnce)
+ assert(customGasActionSpies.setCustomGasLimit.calledOnce)
+ })
+ })
+
})
})
diff --git a/ui/app/components/gas-customization/gas-price-button-group/gas-price-button-group.component.js b/ui/app/components/gas-customization/gas-price-button-group/gas-price-button-group.component.js
new file mode 100644
index 000000000..3873f54bc
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-price-button-group/gas-price-button-group.component.js
@@ -0,0 +1,85 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import ButtonGroup from '../../button-group'
+import Button from '../../button'
+
+const GAS_OBJECT_PROPTYPES_SHAPE = {
+ label: PropTypes.string,
+ feeInPrimaryCurrency: PropTypes.string,
+ feeInSecondaryCurrency: PropTypes.string,
+ timeEstimate: PropTypes.string,
+ priceInHexWei: PropTypes.string,
+}
+
+export default class GasPriceButtonGroup extends Component {
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ buttonDataLoading: PropTypes.bool,
+ className: PropTypes.string,
+ defaultActiveButtonIndex: PropTypes.number,
+ gasButtonInfo: PropTypes.arrayOf(PropTypes.shape(GAS_OBJECT_PROPTYPES_SHAPE)),
+ handleGasPriceSelection: PropTypes.func,
+ noButtonActiveByDefault: PropTypes.bool,
+ showCheck: PropTypes.bool,
+ }
+
+ renderButtonContent ({
+ label,
+ feeInPrimaryCurrency,
+ feeInSecondaryCurrency,
+ timeEstimate,
+ }, {
+ className,
+ showCheck,
+ }) {
+ return (<div>
+ { label && <div className={`${className}__label`}>{ label }</div> }
+ { feeInPrimaryCurrency && <div className={`${className}__primary-currency`}>{ feeInPrimaryCurrency }</div> }
+ { feeInSecondaryCurrency && <div className={`${className}__secondary-currency`}>{ feeInSecondaryCurrency }</div> }
+ { timeEstimate && <div className={`${className}__time-estimate`}>{ timeEstimate }</div> }
+ { showCheck && <i className="fa fa-check fa-2x" /> }
+ </div>)
+ }
+
+ renderButton ({
+ priceInHexWei,
+ ...renderableGasInfo
+ }, {
+ buttonDataLoading,
+ handleGasPriceSelection,
+ ...buttonContentPropsAndFlags
+ }, index) {
+ return (
+ <Button
+ onClick={() => handleGasPriceSelection(priceInHexWei)}
+ key={`gas-price-button-${index}`}
+ >
+ {buttonDataLoading
+ ? 'Loading...'
+ : this.renderButtonContent(renderableGasInfo, buttonContentPropsAndFlags)}
+ </Button>
+ )
+ }
+
+ render () {
+ const {
+ gasButtonInfo,
+ defaultActiveButtonIndex = 1,
+ noButtonActiveByDefault = false,
+ ...buttonPropsAndFlags
+ } = this.props
+
+ return (
+ <ButtonGroup
+ className={buttonPropsAndFlags.className}
+ defaultActiveButtonIndex={defaultActiveButtonIndex}
+ noButtonActiveByDefault={noButtonActiveByDefault}
+ >
+ { gasButtonInfo.map((obj, index) => this.renderButton(obj, buttonPropsAndFlags, index)) }
+ </ButtonGroup>
+ )
+ }
+}
diff --git a/ui/app/components/gas-customization/gas-price-button-group/index.js b/ui/app/components/gas-customization/gas-price-button-group/index.js
new file mode 100644
index 000000000..775648330
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-price-button-group/index.js
@@ -0,0 +1 @@
+export { default } from './gas-price-button-group.component'
diff --git a/ui/app/components/gas-customization/gas-price-button-group/index.scss b/ui/app/components/gas-customization/gas-price-button-group/index.scss
new file mode 100644
index 000000000..e2670edd5
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-price-button-group/index.scss
@@ -0,0 +1,60 @@
+.gas-price-button-group {
+ margin-top: 22px;
+ display: flex;
+ justify-content: space-evenly;
+ width: 100%;
+ padding-left: 20px;
+ padding-right: 20px;
+
+ &__primary-currency {
+ font-size: 18px;
+ height: 20.5px;
+ margin-bottom: 7.5px;
+ }
+
+ &__time-estimate {
+ margin-top: 5.5px;
+ color: $silver-chalice;
+ height: 15.4px;
+ }
+
+
+ .button-group__button, .button-group__button--active {
+ height: 130px;
+ max-width: 108px;
+ font-size: 12px;
+ flex-direction: column;
+ align-items: center;
+ display: flex;
+ padding-top: 17px;
+ border-radius: 4px;
+ border: 2px solid $spindle;
+ background: $white;
+ color: $scorpion;
+
+ div {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+
+ i {
+ &:last-child {
+ display: none;
+ }
+ }
+ }
+
+ .button-group__button--active {
+ border: 2px solid $curious-blue;
+ color: $scorpion;
+
+ i {
+ &:last-child {
+ display: flex;
+ color: $curious-blue;
+ margin-top: 8px
+ }
+ }
+ }
+}
diff --git a/ui/app/components/gas-customization/gas-price-button-group/tests/gas-price-button-group-component.test.js b/ui/app/components/gas-customization/gas-price-button-group/tests/gas-price-button-group-component.test.js
new file mode 100644
index 000000000..e1458188d
--- /dev/null
+++ b/ui/app/components/gas-customization/gas-price-button-group/tests/gas-price-button-group-component.test.js
@@ -0,0 +1,238 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow } from 'enzyme'
+import sinon from 'sinon'
+import GasPriceButtonGroup from '../gas-price-button-group.component'
+
+import ButtonGroup from '../../../button-group/'
+
+const mockGasPriceButtonGroupProps = {
+ buttonDataLoading: false,
+ className: 'gas-price-button-group',
+ gasButtonInfo: [
+ {
+ feeInPrimaryCurrency: '$0.52',
+ feeInSecondaryCurrency: '0.0048 ETH',
+ timeEstimate: '~ 1 min 0 sec',
+ priceInHexWei: '0xa1b2c3f',
+ },
+ {
+ feeInPrimaryCurrency: '$0.39',
+ feeInSecondaryCurrency: '0.004 ETH',
+ timeEstimate: '~ 1 min 30 sec',
+ priceInHexWei: '0xa1b2c39',
+ },
+ {
+ feeInPrimaryCurrency: '$0.30',
+ feeInSecondaryCurrency: '0.00354 ETH',
+ timeEstimate: '~ 2 min 1 sec',
+ priceInHexWei: '0xa1b2c30',
+ },
+ ],
+ handleGasPriceSelection: sinon.spy(),
+ noButtonActiveByDefault: true,
+ defaultActiveButtonIndex: 2,
+ showCheck: true,
+}
+
+const mockButtonPropsAndFlags = Object.assign({}, {
+ buttonDataLoading: mockGasPriceButtonGroupProps.buttonDataLoading,
+ className: mockGasPriceButtonGroupProps.className,
+ handleGasPriceSelection: mockGasPriceButtonGroupProps.handleGasPriceSelection,
+ showCheck: mockGasPriceButtonGroupProps.showCheck,
+})
+
+sinon.spy(GasPriceButtonGroup.prototype, 'renderButton')
+sinon.spy(GasPriceButtonGroup.prototype, 'renderButtonContent')
+
+describe('GasPriceButtonGroup Component', function () {
+ let wrapper
+
+ beforeEach(() => {
+ wrapper = shallow(<GasPriceButtonGroup
+ {...mockGasPriceButtonGroupProps}
+ />)
+ })
+
+ afterEach(() => {
+ GasPriceButtonGroup.prototype.renderButton.resetHistory()
+ GasPriceButtonGroup.prototype.renderButtonContent.resetHistory()
+ mockGasPriceButtonGroupProps.handleGasPriceSelection.resetHistory()
+ })
+
+ describe('render', () => {
+ it('should render a ButtonGroup', () => {
+ assert(wrapper.is(ButtonGroup))
+ })
+
+ it('should render the correct props on the ButtonGroup', () => {
+ const {
+ className,
+ defaultActiveButtonIndex,
+ noButtonActiveByDefault,
+ } = wrapper.props()
+ assert.equal(className, 'gas-price-button-group')
+ assert.equal(defaultActiveButtonIndex, 2)
+ assert.equal(noButtonActiveByDefault, true)
+ })
+
+ function renderButtonArgsTest (i, mockButtonPropsAndFlags) {
+ assert.deepEqual(
+ GasPriceButtonGroup.prototype.renderButton.getCall(i).args,
+ [
+ Object.assign({}, mockGasPriceButtonGroupProps.gasButtonInfo[i]),
+ mockButtonPropsAndFlags,
+ i,
+ ]
+ )
+ }
+
+ it('should called this.renderButton 3 times, with the correct args', () => {
+ assert.equal(GasPriceButtonGroup.prototype.renderButton.callCount, 3)
+ renderButtonArgsTest(0, mockButtonPropsAndFlags)
+ renderButtonArgsTest(1, mockButtonPropsAndFlags)
+ renderButtonArgsTest(2, mockButtonPropsAndFlags)
+ })
+ })
+
+ describe('renderButton', () => {
+ let wrappedRenderButtonResult
+
+ beforeEach(() => {
+ GasPriceButtonGroup.prototype.renderButtonContent.resetHistory()
+ const renderButtonResult = GasPriceButtonGroup.prototype.renderButton(
+ Object.assign({}, mockGasPriceButtonGroupProps.gasButtonInfo[0]),
+ mockButtonPropsAndFlags
+ )
+ wrappedRenderButtonResult = shallow(renderButtonResult)
+ })
+
+ it('should render a button', () => {
+ assert.equal(wrappedRenderButtonResult.type(), 'button')
+ })
+
+ it('should call the correct method when clicked', () => {
+ assert.equal(mockGasPriceButtonGroupProps.handleGasPriceSelection.callCount, 0)
+ wrappedRenderButtonResult.props().onClick()
+ assert.equal(mockGasPriceButtonGroupProps.handleGasPriceSelection.callCount, 1)
+ assert.deepEqual(
+ mockGasPriceButtonGroupProps.handleGasPriceSelection.getCall(0).args,
+ [mockGasPriceButtonGroupProps.gasButtonInfo[0].priceInHexWei]
+ )
+ })
+
+ it('should call this.renderButtonContent with the correct args', () => {
+ assert.equal(GasPriceButtonGroup.prototype.renderButtonContent.callCount, 1)
+ const {
+ feeInPrimaryCurrency,
+ feeInSecondaryCurrency,
+ timeEstimate,
+ } = mockGasPriceButtonGroupProps.gasButtonInfo[0]
+ const {
+ showCheck,
+ className,
+ } = mockGasPriceButtonGroupProps
+ assert.deepEqual(
+ GasPriceButtonGroup.prototype.renderButtonContent.getCall(0).args,
+ [
+ {
+ feeInPrimaryCurrency,
+ feeInSecondaryCurrency,
+ timeEstimate,
+ },
+ {
+ showCheck,
+ className,
+ },
+ ]
+ )
+ })
+
+ it('should not call renderButtonContent if buttonDataLoading is true and should show a loading indicator', () => {
+ GasPriceButtonGroup.prototype.renderButtonContent.resetHistory()
+ const renderButtonResult = GasPriceButtonGroup.prototype.renderButton(
+ Object.assign({}, mockGasPriceButtonGroupProps.gasButtonInfo[0]),
+ Object.assign({}, mockButtonPropsAndFlags, {buttonDataLoading: true})
+ )
+ wrappedRenderButtonResult = shallow(renderButtonResult)
+ assert.equal(GasPriceButtonGroup.prototype.renderButtonContent.callCount, 0)
+ assert.equal(wrappedRenderButtonResult.childAt(0).text(), 'Loading...')
+ })
+ })
+
+ describe('renderButtonContent', () => {
+ it('should render a label if passed a label', () => {
+ const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({
+ label: 'mockLabel',
+ }, {
+ className: 'someClass',
+ })
+ const wrappedRenderButtonContentResult = shallow(renderButtonContentResult)
+ assert.equal(wrappedRenderButtonContentResult.childAt(0).children().length, 1)
+ assert.equal(wrappedRenderButtonContentResult.find('.someClass__label').text(), 'mockLabel')
+ })
+
+ it('should render a feeInPrimaryCurrency if passed a feeInPrimaryCurrency', () => {
+ const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({
+ feeInPrimaryCurrency: 'mockFeeInPrimaryCurrency',
+ }, {
+ className: 'someClass',
+ })
+ const wrappedRenderButtonContentResult = shallow(renderButtonContentResult)
+ assert.equal(wrappedRenderButtonContentResult.childAt(0).children().length, 1)
+ assert.equal(wrappedRenderButtonContentResult.find('.someClass__primary-currency').text(), 'mockFeeInPrimaryCurrency')
+ })
+
+ it('should render a feeInSecondaryCurrency if passed a feeInSecondaryCurrency', () => {
+ const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({
+ feeInSecondaryCurrency: 'mockFeeInSecondaryCurrency',
+ }, {
+ className: 'someClass',
+ })
+ const wrappedRenderButtonContentResult = shallow(renderButtonContentResult)
+ assert.equal(wrappedRenderButtonContentResult.childAt(0).children().length, 1)
+ assert.equal(wrappedRenderButtonContentResult.find('.someClass__secondary-currency').text(), 'mockFeeInSecondaryCurrency')
+ })
+
+ it('should render a timeEstimate if passed a timeEstimate', () => {
+ const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({
+ timeEstimate: 'mockTimeEstimate',
+ }, {
+ className: 'someClass',
+ })
+ const wrappedRenderButtonContentResult = shallow(renderButtonContentResult)
+ assert.equal(wrappedRenderButtonContentResult.childAt(0).children().length, 1)
+ assert.equal(wrappedRenderButtonContentResult.find('.someClass__time-estimate').text(), 'mockTimeEstimate')
+ })
+
+ it('should render a check if showCheck is true', () => {
+ const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({}, {
+ className: 'someClass',
+ showCheck: true,
+ })
+ const wrappedRenderButtonContentResult = shallow(renderButtonContentResult)
+ assert.equal(wrappedRenderButtonContentResult.find('.fa-check').length, 1)
+ })
+
+ it('should render all elements if all args passed', () => {
+ const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({
+ label: 'mockLabel',
+ feeInPrimaryCurrency: 'mockFeeInPrimaryCurrency',
+ feeInSecondaryCurrency: 'mockFeeInSecondaryCurrency',
+ timeEstimate: 'mockTimeEstimate',
+ }, {
+ className: 'someClass',
+ showCheck: true,
+ })
+ const wrappedRenderButtonContentResult = shallow(renderButtonContentResult)
+ assert.equal(wrappedRenderButtonContentResult.children().length, 5)
+ })
+
+
+ it('should render no elements if all args passed', () => {
+ const renderButtonContentResult = GasPriceButtonGroup.prototype.renderButtonContent({}, {})
+ const wrappedRenderButtonContentResult = shallow(renderButtonContentResult)
+ assert.equal(wrappedRenderButtonContentResult.children().length, 0)
+ })
+ })
+})
diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss
index 156b1b9f6..78c1216f7 100644
--- a/ui/app/components/index.scss
+++ b/ui/app/components/index.scss
@@ -71,3 +71,5 @@
@import './gas-customization/gas-modal-page-container/index';
@import './gas-customization/index';
+
+@import './gas-customization/gas-price-button-group/index';
diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss
index 1c95f06a0..42a8655df 100644
--- a/ui/app/css/itcss/settings/variables.scss
+++ b/ui/app/css/itcss/settings/variables.scss
@@ -58,6 +58,7 @@ $linen: #fdf4f4;
$oslo-gray: #8C8E94;
$polar: #fafcfe;
$blizzard-blue: #bfdef3;
+$mischka: #dddee9;
/*
Z-Indicies