diff options
Diffstat (limited to 'ui/app')
35 files changed, 630 insertions, 458 deletions
diff --git a/ui/app/components/app/app-header/app-header.component.js b/ui/app/components/app/app-header/app-header.component.js index 171a3499f..7bf7a39bd 100644 --- a/ui/app/components/app/app-header/app-header.component.js +++ b/ui/app/components/app/app-header/app-header.component.js @@ -2,6 +2,7 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import Identicon from '../../ui/identicon' +import MetaFoxLogo from '../../ui/metafox-logo' import { DEFAULT_ROUTE } from '../../../helpers/constants/routes' const NetworkIndicator = require('../network') @@ -70,6 +71,7 @@ export default class AppHeader extends PureComponent { <Identicon address={selectedAddress} diameter={32} + addBorder={true} /> </div> ) @@ -89,20 +91,10 @@ export default class AppHeader extends PureComponent { <div className={classnames('app-header', { 'app-header--back-drop': isUnlocked })}> <div className="app-header__contents"> - <div - className="app-header__logo-container" + <MetaFoxLogo + unsetIconHeight={true} onClick={() => history.push(DEFAULT_ROUTE)} - > - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - /> - </div> + /> <div className="app-header__account-menu-container"> { !hideNetworkIndicator && ( diff --git a/ui/app/components/app/index.scss b/ui/app/components/app/index.scss index c8516c91c..1236f0c38 100644 --- a/ui/app/components/app/index.scss +++ b/ui/app/components/app/index.scss @@ -77,3 +77,5 @@ @import 'gas-customization/index'; @import 'gas-customization/gas-price-button-group/index'; + +@import '../ui/toggle-button/index'; diff --git a/ui/app/components/app/menu-droppo.js b/ui/app/components/app/menu-droppo.js index c80bee2be..a88cad4b4 100644 --- a/ui/app/components/app/menu-droppo.js +++ b/ui/app/components/app/menu-droppo.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const findDOMNode = require('react-dom').findDOMNode -const ReactCSSTransitionGroup = require('react-addons-css-transition-group') +const ReactCSSTransitionGroup = require('react-transition-group/CSSTransitionGroup') module.exports = MenuDroppoComponent diff --git a/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js b/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js index 0335991fc..1bf7c21b5 100644 --- a/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js +++ b/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js @@ -1,5 +1,6 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' +import MetaFoxLogo from '../../../ui/metafox-logo' import PageContainerFooter from '../../../ui/page-container/page-container-footer' export default class MetaMetricsOptInModal extends Component { @@ -20,19 +21,7 @@ export default class MetaMetricsOptInModal extends Component { <div className="metametrics-opt-in metametrics-opt-in-modal"> <div className="metametrics-opt-in__main"> <div className="metametrics-opt-in__content"> - <div className="app-header__logo-container"> - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - height={42} - width={42} - /> - </div> + <MetaFoxLogo /> <div className="metametrics-opt-in__body-graphic"> <img src="images/metrics-chart.svg" /> </div> diff --git a/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js b/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js index a83ba8f8e..cb8b07ff1 100644 --- a/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js +++ b/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js @@ -1,7 +1,7 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { BrowserQRCodeReader } from '@zxing/library' -import adapter from 'webrtc-adapter' // eslint-disable-line import/no-nodejs-modules, no-unused-vars +import 'webrtc-adapter' import Spinner from '../../../ui/spinner' import WebcamUtils from '../../../../../lib/webcam-utils' import PageContainerFooter from '../../../ui/page-container/page-container-footer/page-container-footer.component' diff --git a/ui/app/components/app/sidebars/sidebar.component.js b/ui/app/components/app/sidebars/sidebar.component.js index b9e0f9e81..657982a21 100644 --- a/ui/app/components/app/sidebars/sidebar.component.js +++ b/ui/app/components/app/sidebars/sidebar.component.js @@ -1,6 +1,6 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import ReactCSSTransitionGroup from 'react-addons-css-transition-group' +import ReactCSSTransitionGroup from 'react-transition-group/CSSTransitionGroup' import WalletView from '../wallet-view' import { WALLET_VIEW_SIDEBAR } from './sidebar.constants' import CustomizeGas from '../gas-customization/gas-modal-page-container/' diff --git a/ui/app/components/app/sidebars/tests/sidebars-component.test.js b/ui/app/components/app/sidebars/tests/sidebars-component.test.js index cee22aca8..e2daea9b6 100644 --- a/ui/app/components/app/sidebars/tests/sidebars-component.test.js +++ b/ui/app/components/app/sidebars/tests/sidebars-component.test.js @@ -2,7 +2,7 @@ import React from 'react' import assert from 'assert' import { shallow } from 'enzyme' import sinon from 'sinon' -import ReactCSSTransitionGroup from 'react-addons-css-transition-group' +import ReactCSSTransitionGroup from 'react-transition-group/CSSTransitionGroup' import Sidebar from '../sidebar.component.js' import WalletView from '../../wallet-view' diff --git a/ui/app/components/app/transaction-status/index.scss b/ui/app/components/app/transaction-status/index.scss index 024cbf2a1..99884d28c 100644 --- a/ui/app/components/app/transaction-status/index.scss +++ b/ui/app/components/app/transaction-status/index.scss @@ -43,4 +43,10 @@ border: 1px solid $monzo; } } + + &__pending-spinner { + height: 16px; + width: 16px; + margin-right: 6px; + } } diff --git a/ui/app/components/app/transaction-status/transaction-status.component.js b/ui/app/components/app/transaction-status/transaction-status.component.js index d3a239539..a97b79bde 100644 --- a/ui/app/components/app/transaction-status/transaction-status.component.js +++ b/ui/app/components/app/transaction-status/transaction-status.component.js @@ -2,6 +2,8 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import Tooltip from '../../ui/tooltip-v2' +import Spinner from '../../ui/spinner' + import { UNAPPROVED_STATUS, REJECTED_STATUS, @@ -51,6 +53,7 @@ export default class TransactionStatus extends PureComponent { return ( <div className={classnames('transaction-status', className, statusToClassNameHash[statusKey])}> + { statusToTextHash[statusKey] === 'pending' ? <Spinner className="transaction-status__pending-spinner" /> : null } <Tooltip position="top" title={title} diff --git a/ui/app/components/ui/identicon/identicon.component.js b/ui/app/components/ui/identicon/identicon.component.js index 88521247c..5582c7d12 100644 --- a/ui/app/components/ui/identicon/identicon.component.js +++ b/ui/app/components/ui/identicon/identicon.component.js @@ -16,6 +16,7 @@ const getStyles = diameter => ( export default class Identicon extends PureComponent { static propTypes = { + addBorder: PropTypes.bool, address: PropTypes.string, className: PropTypes.string, diameter: PropTypes.number, @@ -70,7 +71,7 @@ export default class Identicon extends PureComponent { } render () { - const { className, address, image, diameter, useBlockie } = this.props + const { className, address, image, diameter, useBlockie, addBorder } = this.props if (image) { return this.renderImage() @@ -83,9 +84,11 @@ export default class Identicon extends PureComponent { return this.renderJazzicon() } - return useBlockie - ? this.renderBlockie() - : this.renderJazzicon() + return ( + <div className={classnames({ 'identicon__address-wrapper': addBorder })}> + { useBlockie ? this.renderBlockie() : this.renderJazzicon() } + </div> + ) } return ( diff --git a/ui/app/components/ui/identicon/index.scss b/ui/app/components/ui/identicon/index.scss index 657afc48f..4c8213f01 100644 --- a/ui/app/components/ui/identicon/index.scss +++ b/ui/app/components/ui/identicon/index.scss @@ -4,4 +4,17 @@ align-items: center; justify-content: center; overflow: hidden; + + &__address-wrapper { + height: 40px; + width: 40px; + border-radius: 18px; + display: flex; + justify-content: center; + align-items: center; + border-style: solid; + border-radius: 50%; + border-width: 2px; + border-color: $curious-blue; + } } diff --git a/ui/app/components/ui/metafox-logo/index.js b/ui/app/components/ui/metafox-logo/index.js new file mode 100644 index 000000000..0aeaed743 --- /dev/null +++ b/ui/app/components/ui/metafox-logo/index.js @@ -0,0 +1 @@ +export { default } from './metafox-logo.component' diff --git a/ui/app/components/ui/metafox-logo/metafox-logo.component.js b/ui/app/components/ui/metafox-logo/metafox-logo.component.js new file mode 100644 index 000000000..041e354ef --- /dev/null +++ b/ui/app/components/ui/metafox-logo/metafox-logo.component.js @@ -0,0 +1,31 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' + +export default class MetaFoxLogo extends PureComponent { + static propTypes = { + onClick: PropTypes.func, + unsetIconHeight: PropTypes.bool, + } + + render () { + const iconProps = this.props.unsetIconHeight ? {} : { height: 42, width: 42 } + + return ( + <div + onClick={this.props.onClick} + className="app-header__logo-container" + > + <img + height={30} + src="/images/logo/metamask-logo-horizontal.svg" + className="app-header__metafox-logo app-header__metafox-logo--horizontal" + /> + <img + {...iconProps} + src="/images/logo/metamask-fox.svg" + className="app-header__metafox-logo app-header__metafox-logo--icon" + /> + </div> + ) + } +} diff --git a/ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js b/ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js new file mode 100644 index 000000000..c794a004f --- /dev/null +++ b/ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js @@ -0,0 +1,25 @@ +import React from 'react' +import assert from 'assert' +import { mount } from 'enzyme' +import MetaFoxLogo from '../' + +describe('MetaFoxLogo', () => { + + it('sets icon height and width to 42 by default', () => { + const wrapper = mount( + <MetaFoxLogo /> + ) + + assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('width'), 42) + assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('height'), 42) + }) + + it('does not set icon height and width when unsetIconHeight is true', () => { + const wrapper = mount( + <MetaFoxLogo unsetIconHeight={true} /> + ) + + assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('width'), null) + assert.equal(wrapper.find('img.app-header__metafox-logo--icon').prop('height'), null) + }) +}) diff --git a/ui/app/components/ui/toggle-button/index.js b/ui/app/components/ui/toggle-button/index.js new file mode 100644 index 000000000..7948d3ca1 --- /dev/null +++ b/ui/app/components/ui/toggle-button/index.js @@ -0,0 +1,2 @@ +import ToggleButton from './toggle-button.component' +module.exports = ToggleButton diff --git a/ui/app/components/ui/toggle-button/index.scss b/ui/app/components/ui/toggle-button/index.scss new file mode 100644 index 000000000..868d416c8 --- /dev/null +++ b/ui/app/components/ui/toggle-button/index.scss @@ -0,0 +1,14 @@ +.toggle-button { + display: flex; + + &__status-label { + font-family: Roboto; + font-style: normal; + font-weight: normal; + font-size: 16px; + line-height: 23px; + display: flex; + align-items: center; + text-transform: uppercase; + } +}
\ No newline at end of file diff --git a/ui/app/components/ui/toggle-button/toggle-button.component.js b/ui/app/components/ui/toggle-button/toggle-button.component.js new file mode 100644 index 000000000..3f13203a5 --- /dev/null +++ b/ui/app/components/ui/toggle-button/toggle-button.component.js @@ -0,0 +1,75 @@ +import React from 'react' +import PropTypes from 'prop-types' +import ReactToggleButton from 'react-toggle-button' + +const trackStyle = { + width: '40px', + height: '24px', + padding: '0px', + borderRadius: '26px', + border: '2px solid rgb(3, 125, 214)', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', +} + +const offTrackStyle = { + ...trackStyle, + border: '2px solid #8E8E8E', +} + +const thumbStyle = { + width: '18px', + height: '18px', + display: 'flex', + boxShadow: 'none', + alignSelf: 'center', + borderRadius: '50%', + position: 'relative', +} + +const colors = { + activeThumb: { + base: '#037DD6', + }, + inactiveThumb: { + base: '#037DD6', + }, + active: { + base: '#ffffff', + hover: '#ffffff', + }, + inactive: { + base: '#DADADA', + hover: '#DADADA', + }, +} + +const ToggleButton = props => { + const { value, onToggle, offLabel, onLabel } = props + + return ( + <div className="toggle-button"> + <ReactToggleButton + value={value} + onToggle={onToggle} + activeLabel="" + inactiveLabel="" + trackStyle={value ? trackStyle : offTrackStyle} + thumbStyle={thumbStyle} + thumbAnimateRange={[3, 18]} + colors={colors} + /> + <div className="toggle-button__status-label">{ value ? onLabel : offLabel }</div> + </div> + ) +} + +ToggleButton.propTypes = { + value: PropTypes.bool, + onToggle: PropTypes.func, + offLabel: PropTypes.string, + onLabel: PropTypes.string, +} + +export default ToggleButton diff --git a/ui/app/css/itcss/components/new-account.scss b/ui/app/css/itcss/components/new-account.scss index b3aae8eec..162aac38f 100644 --- a/ui/app/css/itcss/components/new-account.scss +++ b/ui/app/css/itcss/components/new-account.scss @@ -3,7 +3,11 @@ background-color: #FFFFFF; box-shadow: 0 0 7px 0 rgba(0,0,0,0.08); z-index: 25; - height: 100%; + height: unset; + + @media screen and (min-width: 576px) { + position: absolute; + } &__header { display: flex; diff --git a/ui/app/ducks/gas/gas-duck.test.js b/ui/app/ducks/gas/gas-duck.test.js index b7e83a81c..e97ef2d9f 100644 --- a/ui/app/ducks/gas/gas-duck.test.js +++ b/ui/app/ducks/gas/gas-duck.test.js @@ -2,12 +2,10 @@ import assert from 'assert' import sinon from 'sinon' import proxyquire from 'proxyquire' +const fakeLocalStorage = {} const GasDuck = proxyquire('./gas.duck.js', { - '../../../lib/local-storage-helpers': { - loadLocalStorageData: sinon.spy(), - saveLocalStorageData: sinon.spy(), - }, + '../../../lib/local-storage-helpers': fakeLocalStorage, }) const { @@ -68,24 +66,28 @@ describe('Gas Duck', () => { { expectedTime: 1.1, expectedWait: 0.6, gasprice: 19.9, somethingElse: 'foobar' }, { expectedTime: 1, expectedWait: 0.5, gasprice: 20, somethingElse: 'foobar' }, ] - const fetchStub = sinon.stub().callsFake((url) => new Promise(resolve => { + const fakeFetch = (url) => new Promise(resolve => { const dataToResolve = url.match(/ethgasAPI|gasexpress/) ? mockEthGasApiResponse : mockPredictTableResponse resolve({ json: () => new Promise(resolve => resolve(dataToResolve)), }) - })) + }) beforeEach(() => { tempFetch = global.fetch tempDateNow = global.Date.now - global.fetch = fetchStub + + fakeLocalStorage.loadLocalStorageData = sinon.stub() + fakeLocalStorage.saveLocalStorageData = sinon.spy() + global.fetch = sinon.stub().callsFake(fakeFetch) global.Date.now = () => 2000000 }) afterEach(() => { - fetchStub.resetHistory() + sinon.restore() + global.fetch = tempFetch global.Date.now = tempDateNow }) @@ -118,7 +120,6 @@ describe('Gas Duck', () => { gasEstimatesLoading: true, priceAndTimeEstimates: [], priceAndTimeEstimatesLastRetrieved: 0, - basicPriceAndTimeEstimates: [], basicPriceAndTimeEstimatesLastRetrieved: 0, basicPriceEstimatesLastRetrieved: 0, } @@ -305,8 +306,9 @@ describe('Gas Duck', () => { }) describe('fetchBasicGasEstimates', () => { - const mockDistpatch = sinon.spy() it('should call fetch with the expected params', async () => { + const mockDistpatch = sinon.spy() + await fetchBasicGasEstimates()(mockDistpatch, () => ({ gas: Object.assign( {}, initState, @@ -330,12 +332,109 @@ describe('Gas Duck', () => { }, ] ) - assert.deepEqual( mockDistpatch.getCall(1).args, [{ type: SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED, value: 2000000 } ] ) + assert.deepEqual( + mockDistpatch.getCall(2).args, + [{ + type: SET_BASIC_GAS_ESTIMATE_DATA, + value: { + average: 20, + blockTime: 'mockBlock_time', + blockNum: 'mockBlockNum', + fast: 30, + fastest: 40, + safeLow: 10, + }, + }] + ) + assert.deepEqual( + mockDistpatch.getCall(3).args, + [{ type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }] + ) + }) + + it('should fetch recently retrieved estimates from local storage', async () => { + const mockDistpatch = sinon.spy() + fakeLocalStorage.loadLocalStorageData + .withArgs('BASIC_PRICE_ESTIMATES_LAST_RETRIEVED') + .returns(2000000 - 1) // one second ago from "now" + fakeLocalStorage.loadLocalStorageData + .withArgs('BASIC_PRICE_ESTIMATES') + .returns({ + average: 25, + blockTime: 'mockBlock_time', + blockNum: 'mockBlockNum', + fast: 35, + fastest: 45, + safeLow: 15, + }) + await fetchBasicGasEstimates()(mockDistpatch, () => ({ gas: Object.assign( + {}, + initState, + {} + ) })) + assert.deepEqual( + mockDistpatch.getCall(0).args, + [{ type: BASIC_GAS_ESTIMATE_LOADING_STARTED} ] + ) + assert.ok(global.fetch.notCalled) + assert.deepEqual( + mockDistpatch.getCall(1).args, + [{ + type: SET_BASIC_GAS_ESTIMATE_DATA, + value: { + average: 25, + blockTime: 'mockBlock_time', + blockNum: 'mockBlockNum', + fast: 35, + fastest: 45, + safeLow: 15, + }, + }] + ) + assert.deepEqual( + mockDistpatch.getCall(2).args, + [{ type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }] + ) + }) + + it('should fallback to network if retrieving estimates from local storage fails', async () => { + const mockDistpatch = sinon.spy() + fakeLocalStorage.loadLocalStorageData + .withArgs('BASIC_PRICE_ESTIMATES_LAST_RETRIEVED') + .returns(2000000 - 1) // one second ago from "now" + + await fetchBasicGasEstimates()(mockDistpatch, () => ({ gas: Object.assign( + {}, + initState, + {} + ) })) + assert.deepEqual( + mockDistpatch.getCall(0).args, + [{ type: BASIC_GAS_ESTIMATE_LOADING_STARTED} ] + ) + assert.deepEqual( + global.fetch.getCall(0).args, + [ + 'https://dev.blockscale.net/api/gasexpress.json', + { + 'headers': {}, + 'referrer': 'https://dev.blockscale.net/api/', + 'referrerPolicy': 'no-referrer-when-downgrade', + 'body': null, + 'method': 'GET', + 'mode': 'cors', + }, + ] + ) + assert.deepEqual( + mockDistpatch.getCall(1).args, + [{ type: SET_BASIC_PRICE_ESTIMATES_LAST_RETRIEVED, value: 2000000 } ] + ) assert.deepEqual( mockDistpatch.getCall(2).args, [{ @@ -358,8 +457,9 @@ describe('Gas Duck', () => { }) describe('fetchBasicGasAndTimeEstimates', () => { - const mockDistpatch = sinon.spy() it('should call fetch with the expected params', async () => { + const mockDistpatch = sinon.spy() + await fetchBasicGasAndTimeEstimates()(mockDistpatch, () => ({ gas: Object.assign( {}, initState, @@ -415,17 +515,133 @@ describe('Gas Duck', () => { [{ type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }] ) }) - }) - describe('fetchGasEstimates', () => { - const mockDistpatch = sinon.spy() + it('should fetch recently retrieved estimates from local storage', async () => { + const mockDistpatch = sinon.spy() + fakeLocalStorage.loadLocalStorageData + .withArgs('BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED') + .returns(2000000 - 1) // one second ago from "now" + fakeLocalStorage.loadLocalStorageData + .withArgs('BASIC_GAS_AND_TIME_API_ESTIMATES') + .returns({ + average: 5, + avgWait: 'mockAvgWait', + blockTime: 'mockBlock_time', + blockNum: 'mockBlockNum', + fast: 6, + fastest: 7, + fastestWait: 'mockFastestWait', + fastWait: 'mockFastWait', + safeLow: 1, + safeLowWait: 'mockSafeLowWait', + speed: 'mockSpeed', + }) + + await fetchBasicGasAndTimeEstimates()(mockDistpatch, () => ({ gas: Object.assign( + {}, + initState, + {} + ), + metamask: { provider: { type: 'ropsten' } }, + })) + assert.deepEqual( + mockDistpatch.getCall(0).args, + [{ type: BASIC_GAS_ESTIMATE_LOADING_STARTED} ] + ) + assert.ok(global.fetch.notCalled) - beforeEach(() => { - mockDistpatch.resetHistory() + assert.deepEqual( + mockDistpatch.getCall(1).args, + [{ + type: SET_BASIC_GAS_ESTIMATE_DATA, + value: { + average: 5, + avgWait: 'mockAvgWait', + blockTime: 'mockBlock_time', + blockNum: 'mockBlockNum', + fast: 6, + fastest: 7, + fastestWait: 'mockFastestWait', + fastWait: 'mockFastWait', + safeLow: 1, + safeLowWait: 'mockSafeLowWait', + speed: 'mockSpeed', + }, + }] + ) + assert.deepEqual( + mockDistpatch.getCall(2).args, + [{ type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }] + ) }) + it('should fallback to network if retrieving estimates from local storage fails', async () => { + const mockDistpatch = sinon.spy() + fakeLocalStorage.loadLocalStorageData + .withArgs('BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED') + .returns(2000000 - 1) // one second ago from "now" + + await fetchBasicGasAndTimeEstimates()(mockDistpatch, () => ({ gas: Object.assign( + {}, + initState, + {} + ), + metamask: { provider: { type: 'ropsten' } }, + })) + assert.deepEqual( + mockDistpatch.getCall(0).args, + [{ type: BASIC_GAS_ESTIMATE_LOADING_STARTED} ] + ) + assert.deepEqual( + global.fetch.getCall(0).args, + [ + 'https://ethgasstation.info/json/ethgasAPI.json', + { + 'headers': {}, + 'referrer': 'http://ethgasstation.info/json/', + 'referrerPolicy': 'no-referrer-when-downgrade', + 'body': null, + 'method': 'GET', + 'mode': 'cors', + }, + ] + ) + + assert.deepEqual( + mockDistpatch.getCall(1).args, + [{ type: SET_BASIC_API_ESTIMATES_LAST_RETRIEVED, value: 2000000 } ] + ) + + assert.deepEqual( + mockDistpatch.getCall(2).args, + [{ + type: SET_BASIC_GAS_ESTIMATE_DATA, + value: { + average: 2, + avgWait: 'mockAvgWait', + blockTime: 'mockBlock_time', + blockNum: 'mockBlockNum', + fast: 3, + fastest: 4, + fastestWait: 'mockFastestWait', + fastWait: 'mockFastWait', + safeLow: 1, + safeLowWait: 'mockSafeLowWait', + speed: 'mockSpeed', + }, + }] + ) + assert.deepEqual( + mockDistpatch.getCall(3).args, + [{ type: BASIC_GAS_ESTIMATE_LOADING_FINISHED }] + ) + }) + }) + + describe('fetchGasEstimates', () => { it('should call fetch with the expected params', async () => { - global.fetch.resetHistory() + const mockDistpatch = sinon.spy() + await fetchGasEstimates(5)(mockDistpatch, () => ({ gas: Object.assign( {}, initState, @@ -471,7 +687,8 @@ describe('Gas Duck', () => { }) it('should not call fetch if the estimates were retrieved < 75000 ms ago', async () => { - global.fetch.resetHistory() + const mockDistpatch = sinon.spy() + await fetchGasEstimates(5)(mockDistpatch, () => ({ gas: Object.assign( {}, initState, diff --git a/ui/app/ducks/gas/gas.duck.js b/ui/app/ducks/gas/gas.duck.js index 5a0a236e6..d57e825c4 100644 --- a/ui/app/ducks/gas/gas.duck.js +++ b/ui/app/ducks/gas/gas.duck.js @@ -50,7 +50,6 @@ const initState = { basicEstimateIsLoading: true, gasEstimatesLoading: true, priceAndTimeEstimates: [], - basicPriceAndTimeEstimates: [], priceAndTimeEstimatesLastRetrieved: 0, basicPriceAndTimeEstimatesLastRetrieved: 0, basicPriceEstimatesLastRetrieved: 0, @@ -177,134 +176,132 @@ export function gasEstimatesLoadingFinished () { } export function fetchBasicGasEstimates () { - return (dispatch, getState) => { - const { - basicPriceEstimatesLastRetrieved, - basicPriceAndTimeEstimates, - } = getState().gas + return async (dispatch, getState) => { + const { basicPriceEstimatesLastRetrieved } = getState().gas const timeLastRetrieved = basicPriceEstimatesLastRetrieved || loadLocalStorageData('BASIC_PRICE_ESTIMATES_LAST_RETRIEVED') || 0 dispatch(basicGasEstimatesLoadingStarted()) - const promiseToFetch = Date.now() - timeLastRetrieved > 75000 - ? fetch('https://dev.blockscale.net/api/gasexpress.json', { - 'headers': {}, - 'referrer': 'https://dev.blockscale.net/api/', - 'referrerPolicy': 'no-referrer-when-downgrade', - 'body': null, - 'method': 'GET', - 'mode': 'cors'} - ) - .then(r => r.json()) - .then(({ - safeLow, - standard: average, - fast, - fastest, - block_time: blockTime, - blockNum, - }) => { - const basicEstimates = { - safeLow, - average, - fast, - fastest, - blockTime, - blockNum, - } - - const timeRetrieved = Date.now() - dispatch(setBasicPriceEstimatesLastRetrieved(timeRetrieved)) - saveLocalStorageData(timeRetrieved, 'BASIC_PRICE_ESTIMATES_LAST_RETRIEVED') - saveLocalStorageData(basicEstimates, 'BASIC_PRICE_ESTIMATES') - - return basicEstimates - }) - : Promise.resolve(basicPriceAndTimeEstimates.length - ? basicPriceAndTimeEstimates - : loadLocalStorageData('BASIC_PRICE_ESTIMATES') - ) - - return promiseToFetch.then(basicEstimates => { - dispatch(setBasicGasEstimateData(basicEstimates)) - dispatch(basicGasEstimatesLoadingFinished()) - return basicEstimates - }) + let basicEstimates + if (Date.now() - timeLastRetrieved > 75000) { + basicEstimates = await fetchExternalBasicGasEstimates(dispatch) + } else { + const cachedBasicEstimates = loadLocalStorageData('BASIC_PRICE_ESTIMATES') + basicEstimates = cachedBasicEstimates || await fetchExternalBasicGasEstimates(dispatch) + } + + dispatch(setBasicGasEstimateData(basicEstimates)) + dispatch(basicGasEstimatesLoadingFinished()) + + return basicEstimates } } +async function fetchExternalBasicGasEstimates (dispatch) { + const response = await fetch('https://dev.blockscale.net/api/gasexpress.json', { + 'headers': {}, + 'referrer': 'https://dev.blockscale.net/api/', + 'referrerPolicy': 'no-referrer-when-downgrade', + 'body': null, + 'method': 'GET', + 'mode': 'cors'} + ) + const { + safeLow, + standard: average, + fast, + fastest, + block_time: blockTime, + blockNum, + } = await response.json() + + const basicEstimates = { + safeLow, + average, + fast, + fastest, + blockTime, + blockNum, + } + + const timeRetrieved = Date.now() + saveLocalStorageData(basicEstimates, 'BASIC_PRICE_ESTIMATES') + saveLocalStorageData(timeRetrieved, 'BASIC_PRICE_ESTIMATES_LAST_RETRIEVED') + dispatch(setBasicPriceEstimatesLastRetrieved(timeRetrieved)) + + return basicEstimates +} + export function fetchBasicGasAndTimeEstimates () { - return (dispatch, getState) => { - const { - basicPriceAndTimeEstimatesLastRetrieved, - basicPriceAndTimeEstimates, - } = getState().gas + return async (dispatch, getState) => { + const { basicPriceAndTimeEstimatesLastRetrieved } = getState().gas const timeLastRetrieved = basicPriceAndTimeEstimatesLastRetrieved || loadLocalStorageData('BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED') || 0 dispatch(basicGasEstimatesLoadingStarted()) - const promiseToFetch = Date.now() - timeLastRetrieved > 75000 - ? fetch('https://ethgasstation.info/json/ethgasAPI.json', { - 'headers': {}, - 'referrer': 'http://ethgasstation.info/json/', - 'referrerPolicy': 'no-referrer-when-downgrade', - 'body': null, - 'method': 'GET', - 'mode': 'cors'} - ) - .then(r => r.json()) - .then(({ - average: averageTimes10, - avgWait, - block_time: blockTime, - blockNum, - fast: fastTimes10, - fastest: fastestTimes10, - fastestWait, - fastWait, - safeLow: safeLowTimes10, - safeLowWait, - speed, - }) => { - const [average, fast, fastest, safeLow] = [ - averageTimes10, - fastTimes10, - fastestTimes10, - safeLowTimes10, - ].map(price => (new BigNumber(price)).div(10).toNumber()) - - const basicEstimates = { - average, - avgWait, - blockTime, - blockNum, - fast, - fastest, - fastestWait, - fastWait, - safeLow, - safeLowWait, - speed, - } - - const timeRetrieved = Date.now() - dispatch(setBasicApiEstimatesLastRetrieved(timeRetrieved)) - saveLocalStorageData(timeRetrieved, 'BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED') - saveLocalStorageData(basicEstimates, 'BASIC_GAS_AND_TIME_API_ESTIMATES') + let basicEstimates + if (Date.now() - timeLastRetrieved > 75000) { + basicEstimates = await fetchExternalBasicGasAndTimeEstimates(dispatch) + } else { + const cachedBasicEstimates = loadLocalStorageData('BASIC_GAS_AND_TIME_API_ESTIMATES') + basicEstimates = cachedBasicEstimates || await fetchExternalBasicGasAndTimeEstimates(dispatch) + } - return basicEstimates - }) - : Promise.resolve(basicPriceAndTimeEstimates.length - ? basicPriceAndTimeEstimates - : loadLocalStorageData('BASIC_GAS_AND_TIME_API_ESTIMATES') - ) + dispatch(setBasicGasEstimateData(basicEstimates)) + dispatch(basicGasEstimatesLoadingFinished()) + return basicEstimates + } +} - return promiseToFetch.then(basicEstimates => { - dispatch(setBasicGasEstimateData(basicEstimates)) - dispatch(basicGasEstimatesLoadingFinished()) - return basicEstimates - }) +async function fetchExternalBasicGasAndTimeEstimates (dispatch) { + const response = await fetch('https://ethgasstation.info/json/ethgasAPI.json', { + 'headers': {}, + 'referrer': 'http://ethgasstation.info/json/', + 'referrerPolicy': 'no-referrer-when-downgrade', + 'body': null, + 'method': 'GET', + 'mode': 'cors'} + ) + const { + average: averageTimes10, + avgWait, + block_time: blockTime, + blockNum, + fast: fastTimes10, + fastest: fastestTimes10, + fastestWait, + fastWait, + safeLow: safeLowTimes10, + safeLowWait, + speed, + } = await response.json() + const [average, fast, fastest, safeLow] = [ + averageTimes10, + fastTimes10, + fastestTimes10, + safeLowTimes10, + ].map(price => (new BigNumber(price)).div(10).toNumber()) + + const basicEstimates = { + average, + avgWait, + blockTime, + blockNum, + fast, + fastest, + fastestWait, + fastWait, + safeLow, + safeLowWait, + speed, } + + const timeRetrieved = Date.now() + saveLocalStorageData(basicEstimates, 'BASIC_GAS_AND_TIME_API_ESTIMATES') + saveLocalStorageData(timeRetrieved, 'BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED') + dispatch(setBasicApiEstimatesLastRetrieved(timeRetrieved)) + + return basicEstimates } function extrapolateY ({ higherY, lowerY, higherX, lowerX, xForExtrapolation }) { diff --git a/ui/app/helpers/utils/conversion-util.js b/ui/app/helpers/utils/conversion-util.js index affddade7..46bcfe47b 100644 --- a/ui/app/helpers/utils/conversion-util.js +++ b/ui/app/helpers/utils/conversion-util.js @@ -37,13 +37,6 @@ const BIG_NUMBER_WEI_MULTIPLIER = new BigNumber('1000000000000000000') const BIG_NUMBER_GWEI_MULTIPLIER = new BigNumber('1000000000') const BIG_NUMBER_ETH_MULTIPLIER = new BigNumber('1') -// Individual Setters -const convert = R.invoker(1, 'times') -const round = R.invoker(2, 'round')(R.__, BigNumber.ROUND_HALF_DOWN) -const roundDown = R.invoker(2, 'round')(R.__, BigNumber.ROUND_DOWN) -const invertConversionRate = conversionRate => () => new BigNumber(1.0).div(conversionRate) -const decToBigNumberViaString = () => R.pipe(String, toBigNumber['dec']) - // Setter Maps const toBigNumber = { hex: n => new BigNumber(stripHexPrefix(n), 16), @@ -66,6 +59,13 @@ const baseChange = { BN: n => new BN(n.toString(16)), } +// Individual Setters +const convert = R.invoker(1, 'times') +const round = R.invoker(2, 'round')(R.__, BigNumber.ROUND_HALF_DOWN) +const roundDown = R.invoker(2, 'round')(R.__, BigNumber.ROUND_DOWN) +const invertConversionRate = conversionRate => () => new BigNumber(1.0).div(conversionRate) +const decToBigNumberViaString = () => R.pipe(String, toBigNumber['dec']) + // Predicates const fromAndToCurrencyPropsNotEqual = R.compose( R.not, diff --git a/ui/app/pages/first-time-flow/create-password/create-password.component.js b/ui/app/pages/first-time-flow/create-password/create-password.component.js index 5e67a2244..fbeb34d77 100644 --- a/ui/app/pages/first-time-flow/create-password/create-password.component.js +++ b/ui/app/pages/first-time-flow/create-password/create-password.component.js @@ -2,6 +2,7 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import { Switch, Route } from 'react-router-dom' import NewAccount from './new-account' +import MetaFoxLogo from '../../../components/ui/metafox-logo' import ImportWithSeedPhrase from './import-with-seed-phrase' import { INITIALIZE_CREATE_PASSWORD_ROUTE, @@ -30,19 +31,7 @@ export default class CreatePassword extends PureComponent { return ( <div className="first-time-flow__wrapper"> - <div className="app-header__logo-container"> - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - height={42} - width={42} - /> - </div> + <MetaFoxLogo /> <Switch> <Route exact diff --git a/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.component.js b/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.component.js index 83b0e7fc6..e410ebc3c 100644 --- a/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.component.js +++ b/ui/app/pages/first-time-flow/end-of-flow/end-of-flow.component.js @@ -1,6 +1,7 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import Button from '../../../components/ui/button' +import MetaFoxLogo from '../../../components/ui/metafox-logo' import { DEFAULT_ROUTE } from '../../../helpers/constants/routes' export default class EndOfFlowScreen extends PureComponent { @@ -21,19 +22,7 @@ export default class EndOfFlowScreen extends PureComponent { return ( <div className="end-of-flow"> - <div className="app-header__logo-container"> - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - height={42} - width={42} - /> - </div> + <MetaFoxLogo /> <div className="end-of-flow__emoji">🎉</div> <div className="first-time-flow__header"> { t('congratulations') } diff --git a/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js b/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js index 6b9d06cf9..e4d6afb76 100644 --- a/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js +++ b/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js @@ -1,5 +1,6 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' +import MetaFoxLogo from '../../../components/ui/metafox-logo' import PageContainerFooter from '../../../components/ui/page-container/page-container-footer' export default class MetaMetricsOptIn extends Component { @@ -28,19 +29,7 @@ export default class MetaMetricsOptIn extends Component { return ( <div className="metametrics-opt-in"> <div className="metametrics-opt-in__main"> - <div className="app-header__logo-container"> - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - height={42} - width={42} - /> - </div> + <MetaFoxLogo /> <div className="metametrics-opt-in__body-graphic"> <img src="images/metrics-chart.svg" /> </div> diff --git a/ui/app/pages/first-time-flow/seed-phrase/seed-phrase.component.js b/ui/app/pages/first-time-flow/seed-phrase/seed-phrase.component.js index 0b19af18c..f4557115a 100644 --- a/ui/app/pages/first-time-flow/seed-phrase/seed-phrase.component.js +++ b/ui/app/pages/first-time-flow/seed-phrase/seed-phrase.component.js @@ -10,6 +10,7 @@ import { } from '../../../helpers/constants/routes' import HTML5Backend from 'react-dnd-html5-backend' import {DragDropContextProvider} from 'react-dnd' +import MetaFoxLogo from '../../../components/ui/metafox-logo' export default class SeedPhrase extends PureComponent { static propTypes = { @@ -32,19 +33,7 @@ export default class SeedPhrase extends PureComponent { return ( <DragDropContextProvider backend={HTML5Backend}> <div className="first-time-flow__wrapper"> - <div className="app-header__logo-container"> - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - height={42} - width={42} - /> - </div> + <MetaFoxLogo /> <Switch> <Route exact diff --git a/ui/app/pages/first-time-flow/select-action/select-action.component.js b/ui/app/pages/first-time-flow/select-action/select-action.component.js index 5af29a505..9e7b84e93 100644 --- a/ui/app/pages/first-time-flow/select-action/select-action.component.js +++ b/ui/app/pages/first-time-flow/select-action/select-action.component.js @@ -1,6 +1,7 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import Button from '../../../components/ui/button' +import MetaFoxLogo from '../../../components/ui/metafox-logo' import { INITIALIZE_METAMETRICS_OPT_IN_ROUTE, } from '../../../helpers/constants/routes' @@ -40,19 +41,7 @@ export default class SelectAction extends PureComponent { return ( <div className="select-action"> - <div className="app-header__logo-container"> - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - height={42} - width={42} - /> - </div> + <MetaFoxLogo /> <div className="select-action__wrapper"> diff --git a/ui/app/pages/home/home.container.js b/ui/app/pages/home/home.container.js index d0a5d7b47..7508654dc 100644 --- a/ui/app/pages/home/home.container.js +++ b/ui/app/pages/home/home.container.js @@ -3,7 +3,7 @@ import { compose } from 'recompose' import { connect } from 'react-redux' import { withRouter } from 'react-router-dom' import { unconfirmedTransactionsCountSelector } from '../../selectors/confirm-transaction' -`` + const mapStateToProps = state => { const { metamask, appState } = state const { diff --git a/ui/app/pages/routes/index.js b/ui/app/pages/routes/index.js index afef0692e..c292fd9c7 100644 --- a/ui/app/pages/routes/index.js +++ b/ui/app/pages/routes/index.js @@ -183,18 +183,6 @@ class Routes extends Component { this.getConnectingLabel(loadingMessage) : null log.debug('Main ui render function') - const sidebarOnOverlayClose = sidebarType === WALLET_VIEW_SIDEBAR - ? () => { - this.context.metricsEvent({ - eventOpts: { - category: 'Navigation', - action: 'Wallet Sidebar', - name: 'Closed Sidebare Via Overlay', - }, - }) - } - : null - const { isOpen: sidebarIsOpen, transitionName: sidebarTransitionName, @@ -203,6 +191,18 @@ class Routes extends Component { } = sidebar const { transaction: sidebarTransaction } = props || {} + const sidebarOnOverlayClose = sidebarType === WALLET_VIEW_SIDEBAR + ? () => { + this.context.metricsEvent({ + eventOpts: { + category: 'Navigation', + action: 'Wallet Sidebar', + name: 'Closed Sidebare Via Overlay', + }, + }) + } + : null + return ( <div className="app" diff --git a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js index 3d27fe349..105cd89f9 100644 --- a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js +++ b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js @@ -1,8 +1,7 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' -import validUrl from 'valid-url' import { exportAsFile } from '../../../helpers/utils/util' -import ToggleButton from 'react-toggle-button' +import ToggleButton from '../../../components/ui/toggle-button' import TextField from '../../../components/ui/text-field' import Button from '../../../components/ui/button' import { MOBILE_SYNC_ROUTE } from '../../../helpers/constants/routes' @@ -29,155 +28,7 @@ export default class AdvancedTab extends PureComponent { setShowFiatConversionOnTestnetsPreference: PropTypes.func.isRequired, } - state = { - newRpc: '', - chainId: '', - showOptions: false, - ticker: '', - nickname: '', - } - - renderNewRpcUrl () { - const { t } = this.context - const { newRpc, chainId, ticker, nickname } = this.state - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('newNetwork') }</span> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <TextField - type="text" - id="new-rpc" - placeholder={t('rpcUrl')} - value={newRpc} - onChange={e => this.setState({ newRpc: e.target.value })} - onKeyPress={e => { - if (e.key === 'Enter') { - this.validateRpc(newRpc, chainId, ticker, nickname) - } - }} - fullWidth - margin="dense" - /> - <TextField - type="text" - id="chainid" - placeholder={t('optionalChainId')} - value={chainId} - onChange={e => this.setState({ chainId: e.target.value })} - onKeyPress={e => { - if (e.key === 'Enter') { - this.validateRpc(newRpc, chainId, ticker, nickname) - } - }} - style={{ - display: this.state.showOptions ? null : 'none', - }} - fullWidth - margin="dense" - /> - <TextField - type="text" - id="ticker" - placeholder={t('optionalSymbol')} - value={ticker} - onChange={e => this.setState({ ticker: e.target.value })} - onKeyPress={e => { - if (e.key === 'Enter') { - this.validateRpc(newRpc, chainId, ticker, nickname) - } - }} - style={{ - display: this.state.showOptions ? null : 'none', - }} - fullWidth - margin="dense" - /> - <TextField - type="text" - id="nickname" - placeholder={t('optionalNickname')} - value={nickname} - onChange={e => this.setState({ nickname: e.target.value })} - onKeyPress={e => { - if (e.key === 'Enter') { - this.validateRpc(newRpc, chainId, ticker, nickname) - } - }} - style={{ - display: this.state.showOptions ? null : 'none', - }} - fullWidth - margin="dense" - /> - <div className="flex-row flex-align-center space-between"> - <span className="settings-tab__advanced-link" - onClick={e => { - e.preventDefault() - this.setState({ showOptions: !this.state.showOptions }) - }} - > - { t(this.state.showOptions ? 'hideAdvancedOptions' : 'showAdvancedOptions') } - </span> - <button - className="button btn-primary settings-tab__rpc-save-button" - onClick={e => { - e.preventDefault() - this.validateRpc(newRpc, chainId, ticker, nickname) - }} - > - { t('save') } - </button> - </div> - </div> - </div> - </div> - ) - } - - validateRpc (newRpc, chainId, ticker = 'ETH', nickname) { - const { setRpcTarget, displayWarning } = this.props - if (validUrl.isWebUri(newRpc)) { - this.context.metricsEvent({ - eventOpts: { - category: 'Settings', - action: 'Custom RPC', - name: 'Success', - }, - customVariables: { - networkId: newRpc, - chainId, - }, - }) - if (!!chainId && Number.isNaN(parseInt(chainId))) { - return displayWarning(`${this.context.t('invalidInput')} chainId`) - } - - setRpcTarget(newRpc, chainId, ticker, nickname) - } else { - this.context.metricsEvent({ - eventOpts: { - category: 'Settings', - action: 'Custom RPC', - name: 'Error', - }, - customVariables: { - networkId: newRpc, - chainId, - }, - }) - const appendedRpc = `http://${newRpc}` - - if (validUrl.isWebUri(appendedRpc)) { - displayWarning(this.context.t('uriErrorMsg')) - } else { - displayWarning(this.context.t('invalidRPC')) - } - } - } + state = { autoLogoutTimeLimit: this.props.autoLogoutTimeLimit } renderMobileSync () { const { t } = this.context @@ -293,8 +144,8 @@ export default class AdvancedTab extends PureComponent { <ToggleButton value={sendHexData} onToggle={value => setHexDataFeatureFlag(!value)} - activeLabel="" - inactiveLabel="" + offLabel={t('off')} + onLabel={t('on')} /> </div> </div> @@ -319,8 +170,8 @@ export default class AdvancedTab extends PureComponent { <ToggleButton value={advancedInlineGas} onToggle={value => setAdvancedInlineGasFeatureFlag(!value)} - activeLabel="" - inactiveLabel="" + offLabel={t('off')} + onLabel={t('on')} /> </div> </div> @@ -348,8 +199,8 @@ export default class AdvancedTab extends PureComponent { <ToggleButton value={showFiatInTestnets} onToggle={value => setShowFiatConversionOnTestnetsPreference(!value)} - activeLabel="" - inactiveLabel="" + offLabel={t('off')} + onLabel={t('on')} /> </div> </div> @@ -407,7 +258,6 @@ export default class AdvancedTab extends PureComponent { { warning && <div className="settings-tab__error">{ warning }</div> } { this.renderStateLogs() } { this.renderMobileSync() } - { this.renderNewRpcUrl() } { this.renderResetAccount() } { this.renderAdvancedGasInputInline() } { this.renderHexDataOptIn() } diff --git a/ui/app/pages/settings/advanced-tab/tests/advanced-tab-component.test.js b/ui/app/pages/settings/advanced-tab/tests/advanced-tab-component.test.js index f81329533..31cdd747c 100644 --- a/ui/app/pages/settings/advanced-tab/tests/advanced-tab-component.test.js +++ b/ui/app/pages/settings/advanced-tab/tests/advanced-tab-component.test.js @@ -16,7 +16,7 @@ describe('AdvancedTab Component', () => { } ) - assert.equal(root.find('.settings-page__content-row').length, 8) + assert.equal(root.find('.settings-page__content-row').length, 7) }) it('should update autoLogoutTimeLimit', () => { diff --git a/ui/app/pages/settings/index.scss b/ui/app/pages/settings/index.scss index c516a84bb..d98a48c2f 100644 --- a/ui/app/pages/settings/index.scss +++ b/ui/app/pages/settings/index.scss @@ -142,7 +142,7 @@ min-width: 0; display: flex; flex-direction: column; - min-height: 71px; + margin-bottom: 20px; @media screen and (max-width: 575px) { height: initial; diff --git a/ui/app/pages/settings/security-tab/security-tab.component.js b/ui/app/pages/settings/security-tab/security-tab.component.js index 01a28bac7..0d367abfb 100644 --- a/ui/app/pages/settings/security-tab/security-tab.component.js +++ b/ui/app/pages/settings/security-tab/security-tab.component.js @@ -1,7 +1,7 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import { exportAsFile } from '../../../helpers/utils/util' -import ToggleButton from 'react-toggle-button' +import ToggleButton from '../../../components/ui/toggle-button' import { REVEAL_SEED_ROUTE } from '../../../helpers/constants/routes' import Button from '../../../components/ui/button' @@ -140,8 +140,8 @@ export default class SecurityTab extends PureComponent { <ToggleButton value={privacyMode} onToggle={value => setPrivacyMode(!value)} - activeLabel="" - inactiveLabel="" + offLabel={t('off')} + onLabel={t('on')} /> </div> </div> @@ -166,8 +166,8 @@ export default class SecurityTab extends PureComponent { <ToggleButton value={participateInMetaMetrics} onToggle={value => setParticipateInMetaMetrics(!value)} - activeLabel="" - inactiveLabel="" + offLabel={t('off')} + onLabel={t('on')} /> </div> </div> diff --git a/ui/app/pages/settings/settings-tab/settings-tab.component.js b/ui/app/pages/settings/settings-tab/settings-tab.component.js index 57e80be0d..f8daa98f9 100644 --- a/ui/app/pages/settings/settings-tab/settings-tab.component.js +++ b/ui/app/pages/settings/settings-tab/settings-tab.component.js @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import infuraCurrencies from '../../../helpers/constants/infura-conversion.json' import SimpleDropdown from '../../../components/app/dropdowns/simple-dropdown' -import ToggleButton from 'react-toggle-button' +import ToggleButton from '../../../components/ui/toggle-button' import locales from '../../../../../app/_locales/index.json' const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { @@ -105,6 +105,7 @@ export default class SettingsTab extends PureComponent { renderBlockieOptIn () { + const { t } = this.context const { useBlockie, setUseBlockie } = this.props return ( @@ -117,8 +118,8 @@ export default class SettingsTab extends PureComponent { <ToggleButton value={useBlockie} onToggle={value => setUseBlockie(!value)} - activeLabel="" - inactiveLabel="" + offLabel={t('off')} + onLabel={t('on')} /> </div> </div> diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index 389a47d46..634e6c058 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -1210,6 +1210,20 @@ function signTokenTx (tokenAddress, toAddress, amount, txData) { } } +const updateMetamaskStateFromBackground = () => { + log.debug(`background.getState`) + + return new Promise((resolve, reject) => { + background.getState((error, newState) => { + if (error) { + return reject(error) + } + + resolve(newState) + }) + }) +} + function updateTransaction (txData) { log.info('actions: updateTx: ' + JSON.stringify(txData)) return dispatch => { @@ -1462,7 +1476,9 @@ function cancelAllTx (txsData) { txsData.forEach((txData, i) => { background.cancelTransaction(txData.id, () => { dispatch(actions.completedTx(txData.id)) - i === txsData.length - 1 ? dispatch(actions.goHome()) : null + if (i === txsData.length - 1) { + dispatch(actions.goHome()) + } }) }) } @@ -1618,20 +1634,6 @@ const backgroundSetLocked = () => { }) } -const updateMetamaskStateFromBackground = () => { - log.debug(`background.getState`) - - return new Promise((resolve, reject) => { - background.getState((error, newState) => { - if (error) { - return reject(error) - } - - resolve(newState) - }) - }) -} - function lockMetamask () { log.debug(`background.setLocked`) @@ -2394,18 +2396,21 @@ function reshowQrCode (data, coin) { } } -function shapeShiftRequest (query, options, cb) { +function shapeShiftRequest (query, options = {}, cb) { var queryResponse, method - !options ? options = {} : null options.method ? method = options.method : method = 'GET' var requestListner = function () { try { queryResponse = JSON.parse(this.responseText) - cb ? cb(queryResponse) : null + if (cb) { + cb(queryResponse) + } return queryResponse } catch (e) { - cb ? cb({error: e}) : null + if (cb) { + cb({error: e}) + } return e } } diff --git a/ui/app/store/store.js b/ui/app/store/store.js index 9f12f469e..2edb6a7d3 100644 --- a/ui/app/store/store.js +++ b/ui/app/store/store.js @@ -1,21 +1,18 @@ -const createStore = require('redux').createStore -const applyMiddleware = require('redux').applyMiddleware -const thunkMiddleware = require('redux-thunk').default +const { createStore, applyMiddleware } = require('redux') +const { default: thunkMiddleware } = require('redux-thunk') +const { composeWithDevTools } = require('remote-redux-devtools') const rootReducer = require('../ducks') -const createLogger = require('redux-logger').createLogger -global.METAMASK_DEBUG = process.env.METAMASK_DEBUG - -module.exports = configureStore - -const loggerMiddleware = createLogger({ - predicate: () => global.METAMASK_DEBUG, -}) - -const middlewares = [thunkMiddleware, loggerMiddleware] - -const createStoreWithMiddleware = applyMiddleware(...middlewares)(createStore) - -function configureStore (initialState) { - return createStoreWithMiddleware(rootReducer, initialState) +module.exports = function configureStore (initialState) { + const composeEnhancers = composeWithDevTools({ + name: 'MetaMask', + hostname: 'localhost', + port: 8000, + realtime: Boolean(process.env.METAMASK_DEBUG), + }) + return createStore(rootReducer, initialState, composeEnhancers( + applyMiddleware( + thunkMiddleware, + ), + )) } |