aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app
diff options
context:
space:
mode:
authorDan J Miller <danjm.com@gmail.com>2018-12-14 01:50:27 +0800
committerGitHub <noreply@github.com>2018-12-14 01:50:27 +0800
commitc5861c88a5e8ca98e52a7acc13479dbba0341eb1 (patch)
treeb11bdeff5c375b2875e2ede66a3e90bb67eadefc /ui/app
parent042845791c0d629e32fd0bdaec8b0e865cb5b22e (diff)
parent04cc98d8e4155246b1be5ffd5404440d4799736b (diff)
downloadtangerine-wallet-browser-c5861c88a5e8ca98e52a7acc13479dbba0341eb1.tar
tangerine-wallet-browser-c5861c88a5e8ca98e52a7acc13479dbba0341eb1.tar.gz
tangerine-wallet-browser-c5861c88a5e8ca98e52a7acc13479dbba0341eb1.tar.bz2
tangerine-wallet-browser-c5861c88a5e8ca98e52a7acc13479dbba0341eb1.tar.lz
tangerine-wallet-browser-c5861c88a5e8ca98e52a7acc13479dbba0341eb1.tar.xz
tangerine-wallet-browser-c5861c88a5e8ca98e52a7acc13479dbba0341eb1.tar.zst
tangerine-wallet-browser-c5861c88a5e8ca98e52a7acc13479dbba0341eb1.zip
Merge pull request #5893 from MetaMask/loading-network-screen
Loading network screen
Diffstat (limited to 'ui/app')
-rw-r--r--ui/app/actions.js12
-rw-r--r--ui/app/app.js12
-rw-r--r--ui/app/components/dropdowns/components/network-dropdown-icon.js32
-rw-r--r--ui/app/components/loading-network-screen/index.js1
-rw-r--r--ui/app/components/loading-network-screen/loading-network-screen.component.js138
-rw-r--r--ui/app/components/loading-network-screen/loading-network-screen.container.js41
-rw-r--r--ui/app/components/modals/loading-network-error/index.js1
-rw-r--r--ui/app/components/modals/loading-network-error/loading-network-error.component.js29
-rw-r--r--ui/app/components/modals/loading-network-error/loading-network-error.container.js4
-rw-r--r--ui/app/components/network.js53
-rw-r--r--ui/app/css/itcss/components/loading-overlay.scss27
-rw-r--r--ui/app/reducers/app.js9
-rw-r--r--ui/app/selectors.js7
13 files changed, 330 insertions, 36 deletions
diff --git a/ui/app/actions.js b/ui/app/actions.js
index fa175177e..e1bb6dc2d 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -226,6 +226,7 @@ var actions = {
SET_RPC_TARGET: 'SET_RPC_TARGET',
SET_DEFAULT_RPC_TARGET: 'SET_DEFAULT_RPC_TARGET',
SET_PROVIDER_TYPE: 'SET_PROVIDER_TYPE',
+ SET_PREVIOUS_PROVIDER: 'SET_PREVIOUS_PROVIDER',
showConfigPage,
SHOW_ADD_TOKEN_PAGE: 'SHOW_ADD_TOKEN_PAGE',
SHOW_ADD_SUGGESTED_TOKEN_PAGE: 'SHOW_ADD_SUGGESTED_TOKEN_PAGE',
@@ -1866,13 +1867,15 @@ function createSpeedUpTransaction (txId, customGasPrice) {
//
function setProviderType (type) {
- return (dispatch) => {
+ return (dispatch, getState) => {
+ const { type: currentProviderType } = getState().metamask.provider
log.debug(`background.setProviderType`, type)
background.setProviderType(type, (err, result) => {
if (err) {
log.error(err)
return dispatch(actions.displayWarning('Had a problem changing networks!'))
}
+ dispatch(setPreviousProvider(currentProviderType))
dispatch(actions.updateProviderType(type))
dispatch(actions.setSelectedToken())
})
@@ -1887,6 +1890,13 @@ function updateProviderType (type) {
}
}
+function setPreviousProvider (type) {
+ return {
+ type: actions.SET_PREVIOUS_PROVIDER,
+ value: type,
+ }
+}
+
function setRpcTarget (newRpc, chainId, ticker = 'ETH', nickname = '') {
return (dispatch) => {
log.debug(`background.setRpcTarget: ${newRpc} ${chainId} ${ticker} ${nickname}`)
diff --git a/ui/app/app.js b/ui/app/app.js
index 7669a5db9..14b199b8e 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -7,7 +7,7 @@ const h = require('react-hyperscript')
const actions = require('./actions')
const classnames = require('classnames')
const log = require('loglevel')
-const { getMetaMaskAccounts } = require('./selectors')
+const { getMetaMaskAccounts, getNetworkIdentifier } = require('./selectors')
// init
const InitializeScreen = require('../../mascara/src/app/first-time').default
@@ -32,6 +32,7 @@ const CreateAccountPage = require('./components/pages/create-account')
const NoticeScreen = require('./components/pages/notice')
const Loading = require('./components/loading-screen')
+const LoadingNetwork = require('./components/loading-network-screen').default
const NetworkDropdown = require('./components/dropdowns/network-dropdown')
const AccountMenu = require('./components/account-menu')
@@ -169,9 +170,10 @@ class App extends Component {
h(AccountMenu),
h('div.main-container-wrapper', [
- (isLoading || isLoadingNetwork) && h(Loading, {
+ isLoading && h(Loading, {
loadingMessage: loadMessage,
}),
+ !isLoading && isLoadingNetwork && h(LoadingNetwork),
// content
this.renderRoutes(),
@@ -196,7 +198,7 @@ class App extends Component {
if (loadingMessage) {
return loadingMessage
}
- const { provider } = this.props
+ const { provider, providerId } = this.props
const providerName = provider.type
let name
@@ -210,7 +212,7 @@ class App extends Component {
} else if (providerName === 'rinkeby') {
name = this.context.t('connectingToRinkeby')
} else {
- name = this.context.t('connectingToUnknown')
+ name = this.context.t('connectingTo', [providerId])
}
return name
@@ -279,6 +281,7 @@ App.propTypes = {
isMouseUser: PropTypes.bool,
setMouseUserState: PropTypes.func,
t: PropTypes.func,
+ providerId: PropTypes.string,
}
function mapStateToProps (state) {
@@ -348,6 +351,7 @@ function mapStateToProps (state) {
isRevealingSeedWords: state.metamask.isRevealingSeedWords,
Qr: state.appState.Qr,
welcomeScreenSeen: state.metamask.welcomeScreenSeen,
+ providerId: getNetworkIdentifier(state),
// state needed to get account dropdown temporarily rendering from app bar
identities,
diff --git a/ui/app/components/dropdowns/components/network-dropdown-icon.js b/ui/app/components/dropdowns/components/network-dropdown-icon.js
index a45da4c10..d4a2c2ff7 100644
--- a/ui/app/components/dropdowns/components/network-dropdown-icon.js
+++ b/ui/app/components/dropdowns/components/network-dropdown-icon.js
@@ -16,16 +16,32 @@ NetworkDropdownIcon.prototype.render = function () {
isSelected,
innerBorder = 'none',
diameter = '12',
+ loading,
} = this.props
- return h(`.menu-icon-circle${isSelected ? '--active' : ''}`, {},
- h('div', {
+ return loading
+ ? h('span.pointer.network-indicator', {
style: {
- background: backgroundColor,
- border: innerBorder,
- height: `${diameter}px`,
- width: `${diameter}px`,
+ display: 'flex',
+ alignItems: 'center',
+ flexDirection: 'row',
},
- })
- )
+ }, [
+ h('img', {
+ style: {
+ width: '27px',
+ },
+ src: 'images/loading.svg',
+ }),
+ ])
+ : h(`.menu-icon-circle${isSelected ? '--active' : ''}`, {},
+ h('div', {
+ style: {
+ background: backgroundColor,
+ border: innerBorder,
+ height: `${diameter}px`,
+ width: `${diameter}px`,
+ },
+ })
+ )
}
diff --git a/ui/app/components/loading-network-screen/index.js b/ui/app/components/loading-network-screen/index.js
new file mode 100644
index 000000000..726b4b530
--- /dev/null
+++ b/ui/app/components/loading-network-screen/index.js
@@ -0,0 +1 @@
+export { default } from './loading-network-screen.container'
diff --git a/ui/app/components/loading-network-screen/loading-network-screen.component.js b/ui/app/components/loading-network-screen/loading-network-screen.component.js
new file mode 100644
index 000000000..bf1c141e0
--- /dev/null
+++ b/ui/app/components/loading-network-screen/loading-network-screen.component.js
@@ -0,0 +1,138 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import Spinner from '../spinner'
+import Button from '../button'
+
+export default class LoadingNetworkScreen extends PureComponent {
+ state = {
+ showErrorScreen: false,
+ }
+
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ loadingMessage: PropTypes.string,
+ cancelTime: PropTypes.number,
+ provider: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
+ providerId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ showNetworkDropdown: PropTypes.func,
+ setProviderArgs: PropTypes.array,
+ lastSelectedProvider: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
+ setProviderType: PropTypes.func,
+ isLoadingNetwork: PropTypes.bool,
+ }
+
+ componentDidMount = () => {
+ this.cancelCallTimeout = setTimeout(this.cancelCall, this.props.cancelTime || 15000)
+ }
+
+ getConnectingLabel = function (loadingMessage) {
+ if (loadingMessage) {
+ return loadingMessage
+ }
+ const { provider, providerId } = this.props
+ const providerName = provider.type
+
+ let name
+
+ if (providerName === 'mainnet') {
+ name = this.context.t('connectingToMainnet')
+ } else if (providerName === 'ropsten') {
+ name = this.context.t('connectingToRopsten')
+ } else if (providerName === 'kovan') {
+ name = this.context.t('connectingToKovan')
+ } else if (providerName === 'rinkeby') {
+ name = this.context.t('connectingToRinkeby')
+ } else {
+ name = this.context.t('connectingTo', [providerId])
+ }
+
+ return name
+ }
+
+ renderMessage = () => {
+ return <span>{ this.getConnectingLabel(this.props.loadingMessage) }</span>
+ }
+
+ renderLoadingScreenContent = () => {
+ return <div className="loading-overlay__screen-content">
+ <Spinner color="#F7C06C" />
+ {this.renderMessage()}
+ </div>
+ }
+
+ renderErrorScreenContent = () => {
+ const { showNetworkDropdown, setProviderArgs, setProviderType } = this.props
+
+ return <div className="loading-overlay__error-screen">
+ <span className="loading-overlay__emoji">&#128542;</span>
+ <span>{ this.context.t('somethingWentWrong') }</span>
+ <div className="loading-overlay__error-buttons">
+ <Button
+ type="default"
+ onClick={() => {
+ window.clearTimeout(this.cancelCallTimeout)
+ showNetworkDropdown()
+ }}
+ >
+ { this.context.t('switchNetworks') }
+ </Button>
+
+ <Button
+ type="primary"
+ onClick={() => {
+ this.setState({ showErrorScreen: false })
+ setProviderType(...setProviderArgs)
+ window.clearTimeout(this.cancelCallTimeout)
+ this.cancelCallTimeout = setTimeout(this.cancelCall, this.props.cancelTime || 15000)
+ }}
+ >
+ { this.context.t('tryAgain') }
+ </Button>
+ </div>
+ </div>
+ }
+
+ cancelCall = () => {
+ const { isLoadingNetwork } = this.props
+
+ if (isLoadingNetwork) {
+ this.setState({ showErrorScreen: true })
+ }
+ }
+
+ componentDidUpdate = (prevProps) => {
+ const { provider } = this.props
+ const { provider: prevProvider } = prevProps
+ if (provider.type !== prevProvider.type) {
+ window.clearTimeout(this.cancelCallTimeout)
+ this.setState({ showErrorScreen: false })
+ this.cancelCallTimeout = setTimeout(this.cancelCall, this.props.cancelTime || 15000)
+ }
+ }
+
+ componentWillUnmount = () => {
+ window.clearTimeout(this.cancelCallTimeout)
+ }
+
+ render () {
+ const { lastSelectedProvider, setProviderType } = this.props
+
+ return (
+ <div className="loading-overlay">
+ <div
+ className="page-container__header-close"
+ onClick={() => setProviderType(lastSelectedProvider || 'ropsten')}
+ />
+ <div className="loading-overlay__container">
+ { this.state.showErrorScreen
+ ? this.renderErrorScreenContent()
+ : this.renderLoadingScreenContent()
+ }
+ </div>
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/loading-network-screen/loading-network-screen.container.js b/ui/app/components/loading-network-screen/loading-network-screen.container.js
new file mode 100644
index 000000000..d0623e574
--- /dev/null
+++ b/ui/app/components/loading-network-screen/loading-network-screen.container.js
@@ -0,0 +1,41 @@
+import { connect } from 'react-redux'
+import LoadingNetworkScreen from './loading-network-screen.component'
+import actions from '../../actions'
+import { getNetworkIdentifier } from '../../selectors'
+
+const mapStateToProps = state => {
+ const {
+ loadingMessage,
+ currentView,
+ } = state.appState
+ const {
+ provider,
+ lastSelectedProvider,
+ network,
+ } = state.metamask
+ const { rpcTarget, chainId, ticker, nickname, type } = provider
+
+ const setProviderArgs = type === 'rpc'
+ ? [rpcTarget, chainId, ticker, nickname]
+ : [provider.type]
+
+ return {
+ isLoadingNetwork: network === 'loading' && currentView.name !== 'config',
+ loadingMessage,
+ lastSelectedProvider,
+ setProviderArgs,
+ provider,
+ providerId: getNetworkIdentifier(state),
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ setProviderType: (type) => {
+ dispatch(actions.setProviderType(type))
+ },
+ showNetworkDropdown: () => dispatch(actions.showNetworkDropdown()),
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(LoadingNetworkScreen)
diff --git a/ui/app/components/modals/loading-network-error/index.js b/ui/app/components/modals/loading-network-error/index.js
new file mode 100644
index 000000000..b3737458a
--- /dev/null
+++ b/ui/app/components/modals/loading-network-error/index.js
@@ -0,0 +1 @@
+export { default } from './loading-network-error.container'
diff --git a/ui/app/components/modals/loading-network-error/loading-network-error.component.js b/ui/app/components/modals/loading-network-error/loading-network-error.component.js
new file mode 100644
index 000000000..44f71e4b2
--- /dev/null
+++ b/ui/app/components/modals/loading-network-error/loading-network-error.component.js
@@ -0,0 +1,29 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import Modal, { ModalContent } from '../../modal'
+
+const LoadingNetworkError = (props, context) => {
+ const { t } = context
+ const { hideModal } = props
+
+ return (
+ <Modal
+ onSubmit={() => hideModal()}
+ submitText={t('tryAgain')}
+ >
+ <ModalContent
+ description={'Oops! Something went wrong.'}
+ />
+ </Modal>
+ )
+}
+
+LoadingNetworkError.contextTypes = {
+ t: PropTypes.func,
+}
+
+LoadingNetworkError.propTypes = {
+ hideModal: PropTypes.func,
+}
+
+export default LoadingNetworkError
diff --git a/ui/app/components/modals/loading-network-error/loading-network-error.container.js b/ui/app/components/modals/loading-network-error/loading-network-error.container.js
new file mode 100644
index 000000000..3fcba20aa
--- /dev/null
+++ b/ui/app/components/modals/loading-network-error/loading-network-error.container.js
@@ -0,0 +1,4 @@
+import LoadingNetworkError from './loading-network-error.component'
+import withModalProps from '../../../higher-order-components/with-modal-props'
+
+export default withModalProps(LoadingNetworkError)
diff --git a/ui/app/components/network.js b/ui/app/components/network.js
index 611aadb7b..e18404f42 100644
--- a/ui/app/components/network.js
+++ b/ui/app/components/network.js
@@ -23,33 +23,19 @@ Network.prototype.render = function () {
const props = this.props
const context = this.context
const networkNumber = props.network
- let providerName, providerNick
+ let providerName, providerNick, providerUrl
try {
providerName = props.provider.type
providerNick = props.provider.nickname || ''
+ providerUrl = props.provider.rpcTarget
} catch (e) {
providerName = null
}
- let iconName, hoverText
+ const providerId = providerNick || providerName || providerUrl || null
+ let iconName
+ let hoverText
- if (networkNumber === 'loading') {
- return h('span.pointer.network-indicator', {
- style: {
- display: 'flex',
- alignItems: 'center',
- flexDirection: 'row',
- },
- onClick: (event) => this.props.onClick(event),
- }, [
- h('img', {
- title: context.t('attemptingConnect'),
- style: {
- width: '27px',
- },
- src: 'images/loading.svg',
- }),
- ])
- } else if (providerName === 'mainnet') {
+ if (providerName === 'mainnet') {
hoverText = context.t('mainnet')
iconName = 'ethereum-network'
} else if (providerName === 'ropsten') {
@@ -65,8 +51,8 @@ Network.prototype.render = function () {
hoverText = context.t('rinkeby')
iconName = 'rinkeby-test-network'
} else {
- hoverText = context.t('unknownNetwork')
- iconName = 'unknown-private-network'
+ hoverText = providerId
+ iconName = 'private-network'
}
return (
@@ -92,6 +78,7 @@ Network.prototype.render = function () {
h(NetworkDropdownIcon, {
backgroundColor: '#038789', // $blue-lagoon
nonSelectBackgroundColor: '#15afb2',
+ loading: networkNumber === 'loading',
}),
h('.network-name', context.t('mainnet')),
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
@@ -101,6 +88,7 @@ Network.prototype.render = function () {
h(NetworkDropdownIcon, {
backgroundColor: '#e91550', // $crimson
nonSelectBackgroundColor: '#ec2c50',
+ loading: networkNumber === 'loading',
}),
h('.network-name', context.t('ropsten')),
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
@@ -110,6 +98,7 @@ Network.prototype.render = function () {
h(NetworkDropdownIcon, {
backgroundColor: '#690496', // $purple
nonSelectBackgroundColor: '#b039f3',
+ loading: networkNumber === 'loading',
}),
h('.network-name', context.t('kovan')),
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
@@ -119,13 +108,31 @@ Network.prototype.render = function () {
h(NetworkDropdownIcon, {
backgroundColor: '#ebb33f', // $tulip-tree
nonSelectBackgroundColor: '#ecb23e',
+ loading: networkNumber === 'loading',
}),
h('.network-name', context.t('rinkeby')),
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
])
default:
return h('.network-indicator', [
- h('i.fa.fa-question-circle.fa-lg', {
+ networkNumber === 'loading'
+ ? h('span.pointer.network-indicator', {
+ style: {
+ display: 'flex',
+ alignItems: 'center',
+ flexDirection: 'row',
+ },
+ onClick: (event) => this.props.onClick(event),
+ }, [
+ h('img', {
+ title: context.t('attemptingConnect'),
+ style: {
+ width: '27px',
+ },
+ src: 'images/loading.svg',
+ }),
+ ])
+ : h('i.fa.fa-question-circle.fa-lg', {
style: {
margin: '10px',
color: 'rgb(125, 128, 130)',
diff --git a/ui/app/css/itcss/components/loading-overlay.scss b/ui/app/css/itcss/components/loading-overlay.scss
index b023c8423..d7ff0b8ed 100644
--- a/ui/app/css/itcss/components/loading-overlay.scss
+++ b/ui/app/css/itcss/components/loading-overlay.scss
@@ -11,6 +11,12 @@
height: 100%;
background: rgba(255, 255, 255, .8);
+ &__screen-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+
&__container {
position: absolute;
top: 33%;
@@ -26,6 +32,27 @@
font-size: 20px;
color: $manatee;
}
+
+ &__error-screen {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ height: 160px;
+ justify-content: space-evenly;
+ }
+
+ &__error-buttons {
+ display: flex;
+ flex-direction: row;
+
+ button {
+ margin: 5px;
+ }
+ }
+
+ &__emoji {
+ font-size: 32px;
+ }
}
.spinner {
diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js
index ea25b8693..22cfe7f8d 100644
--- a/ui/app/reducers/app.js
+++ b/ui/app/reducers/app.js
@@ -76,6 +76,7 @@ function reduceApp (state, action) {
trezor: `m/44'/60'/0'/0`,
ledger: `m/44'/60'/0'/0/0`,
},
+ lastSelectedProvider: null,
}, state.appState)
switch (action.type) {
@@ -748,6 +749,14 @@ function reduceApp (state, action) {
networkNonce: action.value,
})
+ case actions.SET_PREVIOUS_PROVIDER:
+ if (action.value === 'loading') {
+ return appState
+ }
+ return extend(appState, {
+ lastSelectedProvider: action.value,
+ })
+
default:
return appState
}
diff --git a/ui/app/selectors.js b/ui/app/selectors.js
index 8259bb052..f1ef41f28 100644
--- a/ui/app/selectors.js
+++ b/ui/app/selectors.js
@@ -36,10 +36,17 @@ const selectors = {
preferencesSelector,
getMetaMaskAccounts,
getCurrentEthBalance,
+ getNetworkIdentifier,
}
module.exports = selectors
+function getNetworkIdentifier (state) {
+ const { metamask: { provider: { type, nickname, rpcTarget } } } = state
+
+ return nickname || rpcTarget || type
+}
+
function getSelectedAddress (state) {
const selectedAddress = state.metamask.selectedAddress || Object.keys(getMetaMaskAccounts(state))[0]