mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
A new page has been created for viewing assets. This replaces the old `selectedToken` state, which previously would augment the home page to show token-specific information. The new asset page shows the standard token overview as seen previously on the home page, plus a history filtered to show just transactions relevant to that token. The actions that were available in the old token list menu have been moved to a "Token Options" menu that mirrors the "Account Options" menu. The `selectedTokenAddress` state has been removed, as it is no longer being used for anything. `getMetaMetricState` has been renamed to `getBackgroundMetaMetricState` because its sole purpose is extracting data from the background state to send metrics from the background. It's not really a selector, but it was convenient for it to use the same selectors the UI uses to extract background data, so I left it there for now. A new Redux store has been added to track state related to browser history. The most recent "overview" page (i.e. the home page or the asset page) is currently being tracked, so that actions taken from the asset page can return the user back to the asset page when the action has finished.
329 lines
10 KiB
JavaScript
329 lines
10 KiB
JavaScript
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 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,
|
|
SETTINGS_ROUTE,
|
|
UNLOCK_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,
|
|
hasPermissionsRequests: PropTypes.bool,
|
|
autoLockTimeLimit: PropTypes.number,
|
|
pageChanged: PropTypes.func.isRequired,
|
|
}
|
|
|
|
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)
|
|
const url = `&url=${encodeURIComponent('http://www.metamask.io/metametrics' + locationObj.pathname)}`
|
|
this.context.metricsEvent({}, {
|
|
currentPath: '',
|
|
pathname: locationObj.pathname,
|
|
url,
|
|
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={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 }))
|
|
}
|
|
|
|
hideAppHeader () {
|
|
const { location, hasPermissionsRequests } = 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) {
|
|
return this.onConfirmPage() || hasPermissionsRequests
|
|
}
|
|
|
|
const isHandlingPermissionsRequest = Boolean(matchPath(location.pathname, {
|
|
path: CONNECT_ROUTE, exact: false,
|
|
}))
|
|
|
|
if (hasPermissionsRequests || isHandlingPermissionsRequest) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
render () {
|
|
const {
|
|
isLoading,
|
|
isUnlocked,
|
|
alertMessage,
|
|
textDirection,
|
|
loadingMessage,
|
|
network,
|
|
provider,
|
|
frequentRpcListDetail,
|
|
setMouseUserState,
|
|
sidebar,
|
|
submittedPendingTransactions,
|
|
isMouseUser,
|
|
} = 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()}
|
|
disabled={this.onConfirmPage()}
|
|
/>
|
|
) }
|
|
<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 />
|
|
)
|
|
: null
|
|
}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
toggleMetamaskActive () {
|
|
if (!this.props.isUnlocked) {
|
|
// currently inactive: redirect to password box
|
|
const passwordBox = document.querySelector('input[type=password]')
|
|
if (!passwordBox) {
|
|
return
|
|
}
|
|
passwordBox.focus()
|
|
} else {
|
|
// currently active: deactivate
|
|
this.props.lockMetaMask()
|
|
}
|
|
}
|
|
|
|
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 'localhost':
|
|
return this.context.t('connectingToLocalhost')
|
|
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 'localhost':
|
|
return this.context.t('localhost')
|
|
case 'goerli':
|
|
return this.context.t('goerli')
|
|
default:
|
|
return this.context.t('unknownNetwork')
|
|
}
|
|
}
|
|
}
|