Skip to content

Commit

Permalink
Merge pull request #5893 from MetaMask/loading-network-screen
Browse files Browse the repository at this point in the history
Loading network screen
  • Loading branch information
danjm authored Dec 13, 2018
2 parents 0428457 + 04cc98d commit c5861c8
Show file tree
Hide file tree
Showing 15 changed files with 341 additions and 38 deletions.
9 changes: 9 additions & 0 deletions app/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@
"connecting": {
"message": "Connecting..."
},
"connectingTo": {
"message": "Connecting to $1"
},
"connectingToKovan": {
"message": "Connecting to Kovan Test Network"
},
Expand Down Expand Up @@ -1198,6 +1201,9 @@
"sigRequested": {
"message": "Signature Requested"
},
"somethingWentWrong": {
"message": "Oops! Something went wrong."
},
"spaceBetween": {
"message": "there can only be a space between words"
},
Expand All @@ -1216,6 +1222,9 @@
"speedUpTransaction": {
"message": "Speed up this transaction"
},
"switchNetworks": {
"message": "Switch Networks"
},
"status": {
"message": "Status"
},
Expand Down
4 changes: 2 additions & 2 deletions test/unit/ui/app/actions.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1079,8 +1079,10 @@ describe('Actions', () => {

describe('#setProviderType', () => {
let setProviderTypeSpy
let store

beforeEach(() => {
store = mockStore({ metamask: { provider: {} } })
setProviderTypeSpy = sinon.stub(background, 'setProviderType')
})

Expand All @@ -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!' },
]
Expand Down
12 changes: 11 additions & 1 deletion ui/app/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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())
})
Expand All @@ -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}`)
Expand Down
12 changes: 8 additions & 4 deletions ui/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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')

Expand Down Expand Up @@ -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(),
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -279,6 +281,7 @@ App.propTypes = {
isMouseUser: PropTypes.bool,
setMouseUserState: PropTypes.func,
t: PropTypes.func,
providerId: PropTypes.string,
}

function mapStateToProps (state) {
Expand Down Expand Up @@ -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,
Expand Down
32 changes: 24 additions & 8 deletions ui/app/components/dropdowns/components/network-dropdown-icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
},
})
)
}
1 change: 1 addition & 0 deletions ui/app/components/loading-network-screen/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './loading-network-screen.container'
Original file line number Diff line number Diff line change
@@ -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>
)
}
}
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions ui/app/components/modals/loading-network-error/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './loading-network-error.container'
Loading

0 comments on commit c5861c8

Please sign in to comment.