diff options
Diffstat (limited to 'ui/app/pages/routes/index.js')
-rw-r--r-- | ui/app/pages/routes/index.js | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/ui/app/pages/routes/index.js b/ui/app/pages/routes/index.js new file mode 100644 index 000000000..460cec958 --- /dev/null +++ b/ui/app/pages/routes/index.js @@ -0,0 +1,441 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { connect } from 'react-redux' +import { Route, Switch, withRouter, matchPath } from 'react-router-dom' +import { compose } from 'recompose' +import actions from '../../store/actions' +import log from 'loglevel' +import { getMetaMaskAccounts, getNetworkIdentifier } from '../../selectors/selectors' + +// init +import FirstTimeFlow from '../first-time-flow' +// accounts +const SendTransactionScreen = require('../../components/app/send/send.container') +const ConfirmTransaction = require('../confirm-transaction') + +// slideout menu +const Sidebar = require('../../components/app/sidebars').default +const { WALLET_VIEW_SIDEBAR } = require('../../components/app/sidebars/sidebar.constants') + +// other views +import Home from '../home' +import Settings from '../settings' +import Authenticated from '../../helpers/higher-order-components/authenticated' +import Initialized from '../../helpers/higher-order-components/initialized' +import Lock from '../lock' +import UiMigrationAnnouncement from '../../components/app/ui-migration-annoucement' +const RestoreVaultPage = require('../keychains/restore-vault').default +const RevealSeedConfirmation = require('../keychains/reveal-seed') +const MobileSyncPage = require('../mobile-sync') +const AddTokenPage = require('../add-token') +const ConfirmAddTokenPage = require('../confirm-add-token') +const ConfirmAddSuggestedTokenPage = require('../confirm-add-suggested-token') +const CreateAccountPage = require('../create-account') +const NoticeScreen = require('../notice/notice') + +const Loading = require('../../components/ui/loading-screen') +const LoadingNetwork = require('../../components/app/loading-network-screen').default +const NetworkDropdown = require('../../components/app/dropdowns/network-dropdown') +import AccountMenu from '../../components/app/account-menu' + +// Global Modals +const Modal = require('../../components/app/modals').Modal +// Global Alert +const Alert = require('../../components/ui/alert') + +import AppHeader from '../../components/app/app-header' +import UnlockPage from '../unlock-page' + +import { + submittedPendingTransactionsSelector, +} from '../../selectors/transactions' + +// Routes +import { + DEFAULT_ROUTE, + LOCK_ROUTE, + UNLOCK_ROUTE, + SETTINGS_ROUTE, + REVEAL_SEED_ROUTE, + MOBILE_SYNC_ROUTE, + RESTORE_VAULT_ROUTE, + ADD_TOKEN_ROUTE, + CONFIRM_ADD_TOKEN_ROUTE, + CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE, + NEW_ACCOUNT_ROUTE, + SEND_ROUTE, + CONFIRM_TRANSACTION_ROUTE, + INITIALIZE_ROUTE, + INITIALIZE_UNLOCK_ROUTE, + NOTICE_ROUTE, +} from '../../helpers/constants/routes' + +// enums +import { + ENVIRONMENT_TYPE_NOTIFICATION, + ENVIRONMENT_TYPE_POPUP, +} from '../../../../app/scripts/lib/enums' + +class Routes extends Component { + componentWillMount () { + const { currentCurrency, setCurrentCurrencyToUSD } = this.props + + if (!currentCurrency) { + setCurrentCurrencyToUSD() + } + + this.props.history.listen((locationObj, action) => { + if (action === 'PUSH') { + const url = `&url=${encodeURIComponent('http://www.metamask.io/metametrics' + locationObj.pathname)}` + this.context.metricsEvent({}, { + currentPath: '', + pathname: locationObj.pathname, + url, + pageOpts: { + hideDimensions: true, + }, + }) + } + }) + } + + renderRoutes () { + return ( + <Switch> + <Route path={LOCK_ROUTE} component={Lock} exact /> + <Route path={INITIALIZE_ROUTE} component={FirstTimeFlow} /> + <Initialized path={UNLOCK_ROUTE} component={UnlockPage} exact /> + <Initialized path={RESTORE_VAULT_ROUTE} component={RestoreVaultPage} exact /> + <Authenticated path={REVEAL_SEED_ROUTE} component={RevealSeedConfirmation} exact /> + <Authenticated path={MOBILE_SYNC_ROUTE} component={MobileSyncPage} exact /> + <Authenticated path={SETTINGS_ROUTE} component={Settings} /> + <Authenticated path={NOTICE_ROUTE} component={NoticeScreen} exact /> + <Authenticated path={`${CONFIRM_TRANSACTION_ROUTE}/:id?`} component={ConfirmTransaction} /> + <Authenticated path={SEND_ROUTE} component={SendTransactionScreen} exact /> + <Authenticated path={ADD_TOKEN_ROUTE} component={AddTokenPage} exact /> + <Authenticated path={CONFIRM_ADD_TOKEN_ROUTE} component={ConfirmAddTokenPage} exact /> + <Authenticated path={CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE} component={ConfirmAddSuggestedTokenPage} exact /> + <Authenticated path={NEW_ACCOUNT_ROUTE} component={CreateAccountPage} /> + <Authenticated path={DEFAULT_ROUTE} component={Home} exact /> + </Switch> + ) + } + + onInitializationUnlockPage () { + const { location } = this.props + return Boolean(matchPath(location.pathname, { path: INITIALIZE_UNLOCK_ROUTE, exact: true })) + } + + onConfirmPage () { + const { location } = this.props + return Boolean(matchPath(location.pathname, { path: CONFIRM_TRANSACTION_ROUTE, exact: false })) + } + + hasProviderRequests () { + const { providerRequests } = this.props + return Array.isArray(providerRequests) && providerRequests.length > 0 + } + + hideAppHeader () { + const { location } = this.props + + const isInitializing = Boolean(matchPath(location.pathname, { + path: INITIALIZE_ROUTE, exact: false, + })) + + if (isInitializing && !this.onInitializationUnlockPage()) { + return true + } + + if (window.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_NOTIFICATION) { + return true + } + + if (window.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_POPUP) { + return this.onConfirmPage() || this.hasProviderRequests() + } + } + + render () { + const { + isLoading, + alertMessage, + loadingMessage, + network, + provider, + frequentRpcListDetail, + currentView, + setMouseUserState, + sidebar, + submittedPendingTransactions, + } = this.props + const isLoadingNetwork = network === 'loading' && currentView.name !== 'config' + const loadMessage = loadingMessage || isLoadingNetwork ? + 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, + type: sidebarType, + props, + } = sidebar + const { transaction: sidebarTransaction } = props || {} + + return ( + <div + className="app" + onClick={() => setMouseUserState(true)} + onKeyDown={e => { + if (e.keyCode === 9) { + setMouseUserState(false) + } + }} + > + <UiMigrationAnnouncement /> + <Modal /> + <Alert + visible={this.props.alertOpen} + msg={alertMessage} + /> + { + !this.hideAppHeader() && ( + <AppHeader + hideNetworkIndicator={this.onInitializationUnlockPage()} + disabled={this.onConfirmPage()} + /> + ) + } + <Sidebar + sidebarOpen={sidebarIsOpen} + sidebarShouldClose={sidebarTransaction && !submittedPendingTransactions.find(({ id }) => id === sidebarTransaction.id)} + hideSidebar={this.props.hideSidebar} + transitionName={sidebarTransitionName} + type={sidebarType} + sidebarProps={sidebar.props} + onOverlayClose={sidebarOnOverlayClose} + /> + <NetworkDropdown + provider={provider} + frequentRpcListDetail={frequentRpcListDetail} + /> + <AccountMenu /> + <div className="main-container-wrapper"> + { isLoading && <Loading loadingMessage={loadMessage} /> } + { !isLoading && isLoadingNetwork && <LoadingNetwork /> } + { this.renderRoutes() } + </div> + </div> + ) + } + + toggleMetamaskActive () { + if (!this.props.isUnlocked) { + // currently inactive: redirect to password box + var passwordBox = document.querySelector('input[type=password]') + if (!passwordBox) return + passwordBox.focus() + } else { + // currently active: deactivate + this.props.dispatch(actions.lockMetamask(false)) + } + } + + 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 + } + + getNetworkName () { + const { provider } = this.props + const providerName = provider.type + + let name + + if (providerName === 'mainnet') { + name = this.context.t('mainnet') + } else if (providerName === 'ropsten') { + name = this.context.t('ropsten') + } else if (providerName === 'kovan') { + name = this.context.t('kovan') + } else if (providerName === 'rinkeby') { + name = this.context.t('rinkeby') + } else { + name = this.context.t('unknownNetwork') + } + + return name + } +} + +Routes.propTypes = { + currentCurrency: PropTypes.string, + setCurrentCurrencyToUSD: PropTypes.func, + isLoading: PropTypes.bool, + loadingMessage: PropTypes.string, + alertMessage: PropTypes.string, + network: PropTypes.string, + provider: PropTypes.object, + frequentRpcListDetail: PropTypes.array, + currentView: PropTypes.object, + sidebar: PropTypes.object, + alertOpen: PropTypes.bool, + hideSidebar: PropTypes.func, + isOnboarding: PropTypes.bool, + isUnlocked: PropTypes.bool, + networkDropdownOpen: PropTypes.bool, + showNetworkDropdown: PropTypes.func, + hideNetworkDropdown: PropTypes.func, + history: PropTypes.object, + location: PropTypes.object, + dispatch: PropTypes.func, + toggleAccountMenu: PropTypes.func, + selectedAddress: PropTypes.string, + noActiveNotices: PropTypes.bool, + lostAccounts: PropTypes.array, + isInitialized: PropTypes.bool, + forgottenPassword: PropTypes.bool, + activeAddress: PropTypes.string, + unapprovedTxs: PropTypes.object, + seedWords: PropTypes.string, + submittedPendingTransactions: PropTypes.array, + unapprovedMsgCount: PropTypes.number, + unapprovedPersonalMsgCount: PropTypes.number, + unapprovedTypedMessagesCount: PropTypes.number, + welcomeScreenSeen: PropTypes.bool, + isPopup: PropTypes.bool, + isMouseUser: PropTypes.bool, + setMouseUserState: PropTypes.func, + t: PropTypes.func, + providerId: PropTypes.string, + providerRequests: PropTypes.array, +} + +function mapStateToProps (state) { + const { appState, metamask } = state + const { + networkDropdownOpen, + sidebar, + alertOpen, + alertMessage, + isLoading, + loadingMessage, + } = appState + + const accounts = getMetaMaskAccounts(state) + + const { + identities, + address, + keyrings, + isInitialized, + noActiveNotices, + seedWords, + unapprovedTxs, + nextUnreadNotice, + lostAccounts, + unapprovedMsgCount, + unapprovedPersonalMsgCount, + unapprovedTypedMessagesCount, + providerRequests, + } = metamask + const selected = address || Object.keys(accounts)[0] + + return { + // state from plugin + networkDropdownOpen, + sidebar, + alertOpen, + alertMessage, + isLoading, + loadingMessage, + noActiveNotices, + isInitialized, + isUnlocked: state.metamask.isUnlocked, + selectedAddress: state.metamask.selectedAddress, + currentView: state.appState.currentView, + activeAddress: state.appState.activeAddress, + transForward: state.appState.transForward, + isOnboarding: Boolean(!noActiveNotices || seedWords || !isInitialized), + isPopup: state.metamask.isPopup, + seedWords: state.metamask.seedWords, + submittedPendingTransactions: submittedPendingTransactionsSelector(state), + unapprovedTxs, + unapprovedMsgs: state.metamask.unapprovedMsgs, + unapprovedMsgCount, + unapprovedPersonalMsgCount, + unapprovedTypedMessagesCount, + menuOpen: state.appState.menuOpen, + network: state.metamask.network, + provider: state.metamask.provider, + forgottenPassword: state.appState.forgottenPassword, + nextUnreadNotice, + lostAccounts, + frequentRpcListDetail: state.metamask.frequentRpcListDetail || [], + currentCurrency: state.metamask.currentCurrency, + isMouseUser: state.appState.isMouseUser, + 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, + selected, + keyrings, + providerRequests, + } +} + +function mapDispatchToProps (dispatch, ownProps) { + return { + dispatch, + hideSidebar: () => dispatch(actions.hideSidebar()), + showNetworkDropdown: () => dispatch(actions.showNetworkDropdown()), + hideNetworkDropdown: () => dispatch(actions.hideNetworkDropdown()), + setCurrentCurrencyToUSD: () => dispatch(actions.setCurrentCurrency('usd')), + toggleAccountMenu: () => dispatch(actions.toggleAccountMenu()), + setMouseUserState: (isMouseUser) => dispatch(actions.setMouseUserState(isMouseUser)), + } +} + +Routes.contextTypes = { + t: PropTypes.func, + metricsEvent: PropTypes.func, +} + +module.exports = compose( + withRouter, + connect(mapStateToProps, mapDispatchToProps) +)(Routes) |