mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 18:00:18 +01:00
Adds redesign for the customize gas advanced tab.
This commit is contained in:
parent
5354325fab
commit
b95eb30ec6
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 22px;
|
||||
height: 291px;
|
||||
|
||||
&__title {
|
||||
margin-top: 19px;
|
||||
|
@ -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>
|
||||
)
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { default } from './gas-price-chart.component'
|
@ -0,0 +1,6 @@
|
||||
.gas-price-chart {
|
||||
&__container {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
}
|
@ -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')
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@ -1,3 +1,5 @@
|
||||
@import './gas-slider/index';
|
||||
|
||||
@import './gas-modal-page-container/index';
|
||||
|
||||
@import './gas-price-chart/index';
|
||||
|
@ -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'}
|
||||
|
@ -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() }
|
||||
|
@ -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}
|
||||
|
@ -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 }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user