diff options
author | Dan J Miller <danjm.com@gmail.com> | 2018-12-14 01:50:27 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-14 01:50:27 +0800 |
commit | c5861c88a5e8ca98e52a7acc13479dbba0341eb1 (patch) | |
tree | b11bdeff5c375b2875e2ede66a3e90bb67eadefc /ui/app | |
parent | 042845791c0d629e32fd0bdaec8b0e865cb5b22e (diff) | |
parent | 04cc98d8e4155246b1be5ffd5404440d4799736b (diff) | |
download | tangerine-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.js | 12 | ||||
-rw-r--r-- | ui/app/app.js | 12 | ||||
-rw-r--r-- | ui/app/components/dropdowns/components/network-dropdown-icon.js | 32 | ||||
-rw-r--r-- | ui/app/components/loading-network-screen/index.js | 1 | ||||
-rw-r--r-- | ui/app/components/loading-network-screen/loading-network-screen.component.js | 138 | ||||
-rw-r--r-- | ui/app/components/loading-network-screen/loading-network-screen.container.js | 41 | ||||
-rw-r--r-- | ui/app/components/modals/loading-network-error/index.js | 1 | ||||
-rw-r--r-- | ui/app/components/modals/loading-network-error/loading-network-error.component.js | 29 | ||||
-rw-r--r-- | ui/app/components/modals/loading-network-error/loading-network-error.container.js | 4 | ||||
-rw-r--r-- | ui/app/components/network.js | 53 | ||||
-rw-r--r-- | ui/app/css/itcss/components/loading-overlay.scss | 27 | ||||
-rw-r--r-- | ui/app/reducers/app.js | 9 | ||||
-rw-r--r-- | ui/app/selectors.js | 7 |
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">😞</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] |