|
|
|
import classnames from 'classnames'
|
|
|
|
import PropTypes from 'prop-types'
|
|
|
|
import React, { Component } from 'react'
|
|
|
|
import { matchPath, Route, Switch } from 'react-router-dom'
|
|
|
|
import IdleTimer from 'react-idle-timer'
|
|
|
|
|
|
|
|
import FirstTimeFlow from '../first-time-flow'
|
|
|
|
import SendTransactionScreen from '../send'
|
|
|
|
import Swaps from '../swaps'
|
|
|
|
import ConfirmTransaction from '../confirm-transaction'
|
|
|
|
import Sidebar from '../../components/app/sidebars'
|
|
|
|
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 PermissionsConnect from '../permissions-connect'
|
|
|
|
import RestoreVaultPage from '../keychains/restore-vault'
|
|
|
|
import RevealSeedConfirmation from '../keychains/reveal-seed'
|
|
|
|
import MobileSyncPage from '../mobile-sync'
|
|
|
|
import AddTokenPage from '../add-token'
|
|
|
|
import ConfirmAddTokenPage from '../confirm-add-token'
|
|
|
|
import ConfirmAddSuggestedTokenPage from '../confirm-add-suggested-token'
|
|
|
|
import CreateAccountPage from '../create-account'
|
|
|
|
import Loading from '../../components/ui/loading-screen'
|
|
|
|
import LoadingNetwork from '../../components/app/loading-network-screen'
|
|
|
|
import NetworkDropdown from '../../components/app/dropdowns/network-dropdown'
|
|
|
|
import AccountMenu from '../../components/app/account-menu'
|
|
|
|
import { Modal } from '../../components/app/modals'
|
|
|
|
import Alert from '../../components/ui/alert'
|
|
|
|
import AppHeader from '../../components/app/app-header'
|
|
|
|
import UnlockPage from '../unlock-page'
|
|
|
|
import Alerts from '../../components/app/alerts'
|
|
|
|
import Asset from '../asset'
|
|
|
|
|
|
|
|
import {
|
|
|
|
ADD_TOKEN_ROUTE,
|
|
|
|
ASSET_ROUTE,
|
|
|
|
CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE,
|
|
|
|
CONFIRM_ADD_TOKEN_ROUTE,
|
|
|
|
CONFIRM_TRANSACTION_ROUTE,
|
|
|
|
CONNECT_ROUTE,
|
|
|
|
DEFAULT_ROUTE,
|
|
|
|
INITIALIZE_ROUTE,
|
|
|
|
INITIALIZE_UNLOCK_ROUTE,
|
|
|
|
LOCK_ROUTE,
|
|
|
|
MOBILE_SYNC_ROUTE,
|
|
|
|
NEW_ACCOUNT_ROUTE,
|
|
|
|
RESTORE_VAULT_ROUTE,
|
|
|
|
REVEAL_SEED_ROUTE,
|
|
|
|
SEND_ROUTE,
|
|
|
|
SWAPS_ROUTE,
|
|
|
|
SETTINGS_ROUTE,
|
|
|
|
UNLOCK_ROUTE,
|
|
|
|
BUILD_QUOTE_ROUTE,
|
|
|
|
} from '../../helpers/constants/routes'
|
|
|
|
|
|
|
|
import { ENVIRONMENT_TYPE_NOTIFICATION, ENVIRONMENT_TYPE_POPUP } from '../../../../app/scripts/lib/enums'
|
|
|
|
import { getEnvironmentType } from '../../../../app/scripts/lib/util'
|
|
|
|
|
|
|
|
export default class Routes extends Component {
|
|
|
|
static propTypes = {
|
|
|
|
currentCurrency: PropTypes.string,
|
|
|
|
setCurrentCurrencyToUSD: PropTypes.func,
|
|
|
|
isLoading: PropTypes.bool,
|
|
|
|
loadingMessage: PropTypes.string,
|
|
|
|
alertMessage: PropTypes.string,
|
|
|
|
textDirection: PropTypes.string,
|
|
|
|
network: PropTypes.string,
|
|
|
|
provider: PropTypes.object,
|
|
|
|
frequentRpcListDetail: PropTypes.array,
|
|
|
|
sidebar: PropTypes.object,
|
|
|
|
alertOpen: PropTypes.bool,
|
|
|
|
hideSidebar: PropTypes.func,
|
|
|
|
isUnlocked: PropTypes.bool,
|
|
|
|
setLastActiveTime: PropTypes.func,
|
|
|
|
history: PropTypes.object,
|
|
|
|
location: PropTypes.object,
|
|
|
|
lockMetaMask: PropTypes.func,
|
|
|
|
submittedPendingTransactions: PropTypes.array,
|
|
|
|
isMouseUser: PropTypes.bool,
|
|
|
|
setMouseUserState: PropTypes.func,
|
|
|
|
providerId: PropTypes.string,
|
|
|
|
autoLockTimeLimit: PropTypes.number,
|
|
|
|
pageChanged: PropTypes.func.isRequired,
|
|
|
|
prepareToLeaveSwaps: PropTypes.func,
|
|
|
|
}
|
|
|
|
|
|
|
|
static contextTypes = {
|
|
|
|
t: PropTypes.func,
|
|
|
|
metricsEvent: PropTypes.func,
|
|
|
|
}
|
|
|
|
|
|
|
|
UNSAFE_componentWillMount () {
|
|
|
|
const { currentCurrency, pageChanged, setCurrentCurrencyToUSD } = this.props
|
|
|
|
|
|
|
|
if (!currentCurrency) {
|
|
|
|
setCurrentCurrencyToUSD()
|
|
|
|
}
|
|
|
|
|
|
|
|
this.props.history.listen((locationObj, action) => {
|
|
|
|
if (action === 'PUSH') {
|
|
|
|
pageChanged(locationObj.pathname)
|
|
|
|
this.context.metricsEvent({}, {
|
Use `pathname` instead of URL for `currentPath` metrics parameter (#9158)
The `currentPath` parameter passed to our metrics utility had been
passed the full URL rather than just the path, contrary to what the
name would imply. We only used the path portion, so passing the full
URL did lead to complications.
Now just the `pathname` is passed in, rather than the full URL. This
simplifies the metrics logic, and it incidentally fixes two bugs.
The main bug fixed is regarding Firefox metrics. Previously we had
assumed the `currentPath` would start with `chrome-extension://`, which
of course was not true on Firefox. This lead to us incorrectly parsing
the `currentPath`, so path tracking was broken for Firefox events.
This broken parsing is now bypassed entirely, so metrics should now
work the same on Firefox as on Chrome.
The second bug was that we were incorrectly setting the tracking URL
for background events during tests. As a result, we were incorrectly
detecting ourselves as an internal site that had referred the user to
us. But this was not of major concern, since it only affected test
metrics (which get sent to the development Matomo project).
Lastly, this change let us discard the `pathname` parameter used in
the `overrides` parameter of the `metricsEvent` function. Now that
`currentPath` is equivalent to `pathname`, the `pathname` parameter is
redundant.
4 years ago
|
|
|
currentPath: locationObj.pathname,
|
|
|
|
pageOpts: {
|
|
|
|
hideDimensions: true,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
renderRoutes () {
|
|
|
|
const { autoLockTimeLimit, setLastActiveTime } = this.props
|
|
|
|
|
|
|
|
const routes = (
|
|
|
|
<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={`${CONFIRM_TRANSACTION_ROUTE}/:id?`} component={ConfirmTransaction} />
|
|
|
|
<Authenticated path={SEND_ROUTE} component={SendTransactionScreen} exact />
|
|
|
|
<Authenticated path={SWAPS_ROUTE} component={Swaps} />
|
|
|
|
<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={`${CONNECT_ROUTE}/:id`} component={PermissionsConnect} />
|
|
|
|
<Authenticated path={`${ASSET_ROUTE}/:asset`} component={Asset} />
|
|
|
|
<Authenticated path={DEFAULT_ROUTE} component={Home} />
|
|
|
|
</Switch>
|
|
|
|
)
|
|
|
|
|
|
|
|
if (autoLockTimeLimit > 0) {
|
|
|
|
return (
|
|
|
|
<IdleTimer onAction={setLastActiveTime} throttle={1000}>
|
|
|
|
{routes}
|
|
|
|
</IdleTimer>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return routes
|
|
|
|
}
|
|
|
|
|
|
|
|
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 }))
|
|
|
|
}
|
|
|
|
|
|
|
|
onSwapsPage () {
|
|
|
|
const { location } = this.props
|
|
|
|
return Boolean(matchPath(location.pathname, { path: SWAPS_ROUTE, exact: false }))
|
|
|
|
}
|
|
|
|
|
|
|
|
onSwapsBuildQuotePage () {
|
|
|
|
const { location } = this.props
|
|
|
|
return Boolean(matchPath(location.pathname, { path: BUILD_QUOTE_ROUTE, exact: false }))
|
|
|
|
}
|
|
|
|
|
|
|
|
hideAppHeader () {
|
|
|
|
const { location } = this.props
|
|
|
|
|
|
|
|
const isInitializing = Boolean(matchPath(location.pathname, {
|
|
|
|
path: INITIALIZE_ROUTE, exact: false,
|
|
|
|
}))
|
|
|
|
|
|
|
|
if (isInitializing && !this.onInitializationUnlockPage()) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
const windowType = getEnvironmentType()
|
|
|
|
|
|
|
|
if (windowType === ENVIRONMENT_TYPE_NOTIFICATION) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if (windowType === ENVIRONMENT_TYPE_POPUP && this.onConfirmPage()) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
const isHandlingPermissionsRequest = Boolean(matchPath(location.pathname, {
|
|
|
|
path: CONNECT_ROUTE, exact: false,
|
|
|
|
}))
|
|
|
|
|
|
|
|
return isHandlingPermissionsRequest
|
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
|
|
|
const {
|
|
|
|
isLoading,
|
|
|
|
isUnlocked,
|
|
|
|
alertMessage,
|
|
|
|
textDirection,
|
|
|
|
loadingMessage,
|
|
|
|
network,
|
|
|
|
provider,
|
|
|
|
frequentRpcListDetail,
|
|
|
|
setMouseUserState,
|
|
|
|
sidebar,
|
|
|
|
submittedPendingTransactions,
|
|
|
|
isMouseUser,
|
|
|
|
prepareToLeaveSwaps,
|
|
|
|
} = this.props
|
|
|
|
const isLoadingNetwork = network === 'loading'
|
|
|
|
const loadMessage = (loadingMessage || isLoadingNetwork)
|
|
|
|
? this.getConnectingLabel(loadingMessage)
|
|
|
|
: null
|
|
|
|
|
|
|
|
const {
|
|
|
|
isOpen: sidebarIsOpen,
|
|
|
|
transitionName: sidebarTransitionName,
|
|
|
|
type: sidebarType,
|
|
|
|
props,
|
|
|
|
} = sidebar
|
|
|
|
const { transaction: sidebarTransaction } = props || {}
|
|
|
|
|
|
|
|
const sidebarShouldClose = sidebarTransaction &&
|
|
|
|
!sidebarTransaction.status === 'failed' &&
|
|
|
|
!submittedPendingTransactions.find(({ id }) => id === sidebarTransaction.id)
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className={classnames('app', { 'mouse-user-styles': isMouseUser })}
|
|
|
|
dir={textDirection}
|
|
|
|
onClick={() => setMouseUserState(true)}
|
|
|
|
onKeyDown={(e) => {
|
|
|
|
if (e.keyCode === 9) {
|
|
|
|
setMouseUserState(false)
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Modal />
|
|
|
|
<Alert
|
|
|
|
visible={this.props.alertOpen}
|
|
|
|
msg={alertMessage}
|
|
|
|
/>
|
|
|
|
{ !this.hideAppHeader() && (
|
|
|
|
<AppHeader
|
|
|
|
hideNetworkIndicator={this.onInitializationUnlockPage()}
|
|
|
|
disableNetworkIndicator={this.onSwapsPage()}
|
|
|
|
onClick={async () => {
|
|
|
|
if (this.onSwapsPage()) {
|
|
|
|
await prepareToLeaveSwaps()
|
|
|
|
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
disabled={this.onConfirmPage() || (this.onSwapsPage() && !this.onSwapsBuildQuotePage())}
|
|
|
|
/>
|
|
|
|
) }
|
|
|
|
<Sidebar
|
|
|
|
sidebarOpen={sidebarIsOpen}
|
|
|
|
sidebarShouldClose={sidebarShouldClose}
|
|
|
|
hideSidebar={this.props.hideSidebar}
|
|
|
|
transitionName={sidebarTransitionName}
|
|
|
|
type={sidebarType}
|
|
|
|
sidebarProps={sidebar.props}
|
|
|
|
/>
|
|
|
|
<NetworkDropdown
|
|
|
|
provider={provider}
|
|
|
|
frequentRpcListDetail={frequentRpcListDetail}
|
|
|
|
/>
|
|
|
|
<AccountMenu />
|
|
|
|
<div className="main-container-wrapper">
|
|
|
|
{ isLoading && <Loading loadingMessage={loadMessage} /> }
|
|
|
|
{ !isLoading && isLoadingNetwork && <LoadingNetwork /> }
|
|
|
|
{ this.renderRoutes() }
|
|
|
|
</div>
|
|
|
|
{
|
|
|
|
isUnlocked
|
|
|
|
? (
|
|
|
|
<Alerts history={this.props.history} />
|
|
|
|
)
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
toggleMetamaskActive () {
|
|
|
|
if (this.props.isUnlocked) {
|
|
|
|
// currently active: deactivate
|
|
|
|
this.props.lockMetaMask()
|
|
|
|
} else {
|
|
|
|
// currently inactive: redirect to password box
|
|
|
|
const passwordBox = document.querySelector('input[type=password]')
|
|
|
|
if (!passwordBox) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
passwordBox.focus()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getConnectingLabel (loadingMessage) {
|
|
|
|
if (loadingMessage) {
|
|
|
|
return loadingMessage
|
|
|
|
}
|
|
|
|
const { provider, providerId } = this.props
|
|
|
|
|
|
|
|
switch (provider.type) {
|
|
|
|
case 'mainnet':
|
|
|
|
return this.context.t('connectingToMainnet')
|
|
|
|
case 'ropsten':
|
|
|
|
return this.context.t('connectingToRopsten')
|
|
|
|
case 'kovan':
|
|
|
|
return this.context.t('connectingToKovan')
|
|
|
|
case 'rinkeby':
|
|
|
|
return this.context.t('connectingToRinkeby')
|
|
|
|
case 'goerli':
|
|
|
|
return this.context.t('connectingToGoerli')
|
|
|
|
default:
|
|
|
|
return this.context.t('connectingTo', [providerId])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getNetworkName () {
|
|
|
|
switch (this.props.provider.type) {
|
|
|
|
case 'mainnet':
|
|
|
|
return this.context.t('mainnet')
|
|
|
|
case 'ropsten':
|
|
|
|
return this.context.t('ropsten')
|
|
|
|
case 'kovan':
|
|
|
|
return this.context.t('kovan')
|
|
|
|
case 'rinkeby':
|
|
|
|
return this.context.t('rinkeby')
|
|
|
|
case 'goerli':
|
|
|
|
return this.context.t('goerli')
|
|
|
|
default:
|
|
|
|
return this.context.t('unknownNetwork')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|