aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app')
-rw-r--r--ui/app/components/app/app-header/app-header.component.js18
-rw-r--r--ui/app/components/app/index.scss2
-rw-r--r--ui/app/components/app/menu-droppo.js2
-rw-r--r--ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.component.js15
-rw-r--r--ui/app/components/app/modals/qr-scanner/qr-scanner.component.js2
-rw-r--r--ui/app/components/app/sidebars/sidebar.component.js2
-rw-r--r--ui/app/components/app/sidebars/tests/sidebars-component.test.js2
-rw-r--r--ui/app/components/app/transaction-status/index.scss6
-rw-r--r--ui/app/components/app/transaction-status/transaction-status.component.js3
-rw-r--r--ui/app/components/ui/identicon/identicon.component.js11
-rw-r--r--ui/app/components/ui/identicon/index.scss13
-rw-r--r--ui/app/components/ui/metafox-logo/index.js1
-rw-r--r--ui/app/components/ui/metafox-logo/metafox-logo.component.js31
-rw-r--r--ui/app/components/ui/metafox-logo/tests/metafox-logo.component.test.js25
-rw-r--r--ui/app/components/ui/toggle-button/index.js2
-rw-r--r--ui/app/components/ui/toggle-button/index.scss14
-rw-r--r--ui/app/components/ui/toggle-button/toggle-button.component.js75
-rw-r--r--ui/app/css/itcss/components/new-account.scss6
-rw-r--r--ui/app/ducks/gas/gas-duck.test.js255
-rw-r--r--ui/app/ducks/gas/gas.duck.js225
-rw-r--r--ui/app/helpers/utils/conversion-util.js14
-rw-r--r--ui/app/pages/first-time-flow/create-password/create-password.component.js15
-rw-r--r--ui/app/pages/first-time-flow/end-of-flow/end-of-flow.component.js15
-rw-r--r--ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js15
-rw-r--r--ui/app/pages/first-time-flow/seed-phrase/seed-phrase.component.js15
-rw-r--r--ui/app/pages/first-time-flow/select-action/select-action.component.js15
-rw-r--r--ui/app/pages/home/home.container.js2
-rw-r--r--ui/app/pages/routes/index.js24
-rw-r--r--ui/app/pages/settings/advanced-tab/advanced-tab.component.js166
-rw-r--r--ui/app/pages/settings/advanced-tab/tests/advanced-tab-component.test.js2
-rw-r--r--ui/app/pages/settings/index.scss2
-rw-r--r--ui/app/pages/settings/security-tab/security-tab.component.js10
-rw-r--r--ui/app/pages/settings/settings-tab/settings-tab.component.js7
-rw-r--r--ui/app/store/actions.js43
-rw-r--r--ui/app/store/store.js33
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,
+ ),
+ ))
}