mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Adds network loading retry / error screen.
This commit is contained in:
parent
0e5e51b8ff
commit
20dbebae9f
@ -1079,8 +1079,10 @@ describe('Actions', () => {
|
||||
|
||||
describe('#setProviderType', () => {
|
||||
let setProviderTypeSpy
|
||||
let store
|
||||
|
||||
beforeEach(() => {
|
||||
store = mockStore({ metamask: { provider: {} } })
|
||||
setProviderTypeSpy = sinon.stub(background, 'setProviderType')
|
||||
})
|
||||
|
||||
@ -1089,13 +1091,11 @@ describe('Actions', () => {
|
||||
})
|
||||
|
||||
it('', () => {
|
||||
const store = mockStore()
|
||||
store.dispatch(actions.setProviderType())
|
||||
assert(setProviderTypeSpy.calledOnce)
|
||||
})
|
||||
|
||||
it('', () => {
|
||||
const store = mockStore()
|
||||
const expectedActions = [
|
||||
{ type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' },
|
||||
]
|
||||
|
@ -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}`)
|
||||
|
@ -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(),
|
||||
|
2
ui/app/components/loading-network-screen/index.js
Normal file
2
ui/app/components/loading-network-screen/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
const LoadingNetworksScreen = require('./loading-network-screen.container')
|
||||
module.exports = LoadingNetworksScreen
|
@ -0,0 +1,145 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Spinner from '../spinner'
|
||||
import Button from '../button'
|
||||
|
||||
class LoadingNetworkScreen extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
showErrorScreen: false,
|
||||
}
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
componentWillMount = () => {
|
||||
this.cancelCallTimeout = setTimeout(this.cancelCall, this.props.cancelTime || 3000)
|
||||
}
|
||||
|
||||
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">😞</span>
|
||||
<span>Oops! Something went wrong.</span>
|
||||
<div className="loading-overlay__error-buttons">
|
||||
<Button
|
||||
type="default"
|
||||
onClick={() => {
|
||||
window.clearTimeout(this.cancelCallTimeout)
|
||||
showNetworkDropdown()
|
||||
}}
|
||||
>
|
||||
{ 'Switch Networks' }
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
this.setState({ showErrorScreen: false })
|
||||
setProviderType(...setProviderArgs)
|
||||
window.clearTimeout(this.cancelCallTimeout)
|
||||
this.cancelCallTimeout = setTimeout(this.cancelCall, this.props.cancelTime || 3000)
|
||||
}}
|
||||
>
|
||||
{ 'Try Again' }
|
||||
</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 || 3000)
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LoadingNetworkScreen.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,
|
||||
|
||||
}
|
||||
|
||||
module.exports = LoadingNetworkScreen
|
@ -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)
|
1
ui/app/components/modals/loading-network-error/index.js
Normal file
1
ui/app/components/modals/loading-network-error/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './loading-network-error.container'
|
@ -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
|
@ -0,0 +1,4 @@
|
||||
import LoadingNetworkError from './loading-network-error.component'
|
||||
import withModalProps from '../../../higher-order-components/with-modal-props'
|
||||
|
||||
export default withModalProps(LoadingNetworkError)
|
@ -26,6 +26,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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user