1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-10-23 03:36:18 +02:00
metamask-extension/ui/pages/routes/routes.component.js

410 lines
12 KiB
JavaScript
Raw Normal View History

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,
2020-10-06 20:28:38 +02:00
SWAPS_ROUTE,
SETTINGS_ROUTE,
UNLOCK_ROUTE,
BUILD_QUOTE_ROUTE,
2021-02-22 17:20:42 +01:00
CONFIRMATION_V_NEXT_ROUTE,
} from '../../helpers/constants/routes';
2020-11-03 00:41:28 +01:00
import {
ENVIRONMENT_TYPE_NOTIFICATION,
ENVIRONMENT_TYPE_POPUP,
} from '../../../shared/constants/app';
import { getEnvironmentType } from '../../../app/scripts/lib/util';
import { TRANSACTION_STATUSES } from '../../../shared/constants/transaction';
2021-02-22 17:20:42 +01:00
import ConfirmationPage from '../confirmation';
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,
isNetworkLoading: PropTypes.bool,
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,
2020-10-06 20:28:38 +02:00
prepareToLeaveSwaps: PropTypes.func,
browserEnvironment: PropTypes.object,
};
static contextTypes = {
t: PropTypes.func,
metricsEvent: PropTypes.func,
};
2020-11-03 00:41:28 +01:00
UNSAFE_componentWillMount() {
const {
currentCurrency,
pageChanged,
setCurrentCurrencyToUSD,
Whats new popup (#10583) * Add 'What's New' notification popup * Move selectors from shared/notifications into ui/ directory * Use keys for localized message in whats new notifications objects, to ensure notifications will be translated. * Remove unused swaps intro popup locale messages * Fix keys of whats new notification locales * Remove notifications messages and descriptions from comment in shared/notifications * Move notifcationActionFunctions to shared/notifications and make it stateless * Get notification data from constants instead of state in whats-new-popup * Code cleanup * Fix build quote reference to swapsEthToken, broken during rebase * Rename notificationFilters to notificationToExclude to clarify its purpose * Documentation for getSortedNotificationsToShow * Move notification action functions from shared/ to whats-new-popup.js * Stop setting swapsWelcomeMessageHasBeenShown to state in app-state controller * Update e2e tests for whats new popup changes * Updating migration files * Addressing feedback part 1 * Addressing feedback part 2 * Remove unnecessary div in whats-new-popup * Change getNotificationsToExclude to getNotificationsToInclude for use in the getSortedNotificationsToShow selector * Delete intro-popup directory and test files * Lint fix * Add notifiction state to address-entry fixture * Use two separate functions for rendering first and subsequent notifications in the whats-new-popup * Ensure that string literals are passed to t for whats new popup text * Update import-ui fixtures to include notificaiton controller state * Remove unnecessary, accidental change confirm-approve * Remove swaps notification in favour of mobile swaps as first notifcation and TBD 3rd notification * Update whats-new-popup to use intersection observer api to detect if notification has been seen * Add notifications to send-edit and threebox e2e test fixtures * Update ui/app/selectors/selectors.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * Update ui/app/selectors/selectors.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * Clean up locale code for whats-new-popup notifications * Disconnect observers in whats-new-popup when their callback is first called * Add test case for migration 58 for when the AppStateController does not exist * Rename popover components containerRef to popoverWrapRef * Fix messages.json * Update notification messages and images * Rename popoverWrapRef -> popoverRef in whats-new-popup and popover.component * Only create one observer, and only after images have loaded, in whats-new-popup * Set width and height on whats-new-popup image, instead of setting state on img load * Update ui/app/components/app/whats-new-popup/whats-new-popup.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * Code clean up in whats new popup re: notification rendering and action functions * Code cleanup in render notification functions of whats-new-popup * Update ui/app/components/app/whats-new-popup/whats-new-popup.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * lint fix * Update and localize notification dates * Clean up date code in shred/notifications/index.js Co-authored-by: ryanml <ryanlanese@gmail.com> Co-authored-by: Mark Stacey <markjstacey@gmail.com>
2021-04-28 18:51:41 +02:00
history,
} = this.props;
if (!currentCurrency) {
setCurrentCurrencyToUSD();
}
Whats new popup (#10583) * Add 'What's New' notification popup * Move selectors from shared/notifications into ui/ directory * Use keys for localized message in whats new notifications objects, to ensure notifications will be translated. * Remove unused swaps intro popup locale messages * Fix keys of whats new notification locales * Remove notifications messages and descriptions from comment in shared/notifications * Move notifcationActionFunctions to shared/notifications and make it stateless * Get notification data from constants instead of state in whats-new-popup * Code cleanup * Fix build quote reference to swapsEthToken, broken during rebase * Rename notificationFilters to notificationToExclude to clarify its purpose * Documentation for getSortedNotificationsToShow * Move notification action functions from shared/ to whats-new-popup.js * Stop setting swapsWelcomeMessageHasBeenShown to state in app-state controller * Update e2e tests for whats new popup changes * Updating migration files * Addressing feedback part 1 * Addressing feedback part 2 * Remove unnecessary div in whats-new-popup * Change getNotificationsToExclude to getNotificationsToInclude for use in the getSortedNotificationsToShow selector * Delete intro-popup directory and test files * Lint fix * Add notifiction state to address-entry fixture * Use two separate functions for rendering first and subsequent notifications in the whats-new-popup * Ensure that string literals are passed to t for whats new popup text * Update import-ui fixtures to include notificaiton controller state * Remove unnecessary, accidental change confirm-approve * Remove swaps notification in favour of mobile swaps as first notifcation and TBD 3rd notification * Update whats-new-popup to use intersection observer api to detect if notification has been seen * Add notifications to send-edit and threebox e2e test fixtures * Update ui/app/selectors/selectors.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * Update ui/app/selectors/selectors.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * Clean up locale code for whats-new-popup notifications * Disconnect observers in whats-new-popup when their callback is first called * Add test case for migration 58 for when the AppStateController does not exist * Rename popover components containerRef to popoverWrapRef * Fix messages.json * Update notification messages and images * Rename popoverWrapRef -> popoverRef in whats-new-popup and popover.component * Only create one observer, and only after images have loaded, in whats-new-popup * Set width and height on whats-new-popup image, instead of setting state on img load * Update ui/app/components/app/whats-new-popup/whats-new-popup.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * Code clean up in whats new popup re: notification rendering and action functions * Code cleanup in render notification functions of whats-new-popup * Update ui/app/components/app/whats-new-popup/whats-new-popup.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> * lint fix * Update and localize notification dates * Clean up date code in shred/notifications/index.js Co-authored-by: ryanml <ryanlanese@gmail.com> Co-authored-by: Mark Stacey <markjstacey@gmail.com>
2021-04-28 18:51:41 +02:00
history.listen((locationObj, action) => {
if (action === 'PUSH') {
pageChanged(locationObj.pathname);
}
});
}
2020-11-03 00:41:28 +01:00
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 />
2020-11-03 00:41:28 +01:00
<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} />
2020-11-03 00:41:28 +01:00
<Authenticated
path={`${CONFIRM_TRANSACTION_ROUTE}/:id?`}
component={ConfirmTransaction}
/>
<Authenticated
path={SEND_ROUTE}
component={SendTransactionScreen}
exact
/>
2020-10-06 20:28:38 +02:00
<Authenticated path={SWAPS_ROUTE} component={Swaps} />
<Authenticated path={ADD_TOKEN_ROUTE} component={AddTokenPage} exact />
2020-11-03 00:41:28 +01:00
<Authenticated
path={CONFIRM_ADD_TOKEN_ROUTE}
component={ConfirmAddTokenPage}
exact
/>
<Authenticated
path={CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE}
component={ConfirmAddSuggestedTokenPage}
exact
/>
2021-02-22 17:20:42 +01:00
<Authenticated
path={CONFIRMATION_V_NEXT_ROUTE}
component={ConfirmationPage}
/>
<Authenticated path={NEW_ACCOUNT_ROUTE} component={CreateAccountPage} />
2020-11-03 00:41:28 +01:00
<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;
}
2020-11-03 00:41:28 +01:00
onInitializationUnlockPage() {
const { location } = this.props;
2020-11-03 00:41:28 +01:00
return Boolean(
matchPath(location.pathname, {
path: INITIALIZE_UNLOCK_ROUTE,
exact: true,
}),
);
}
2020-11-03 00:41:28 +01:00
onConfirmPage() {
const { location } = this.props;
2020-11-03 00:41:28 +01:00
return Boolean(
matchPath(location.pathname, {
path: CONFIRM_TRANSACTION_ROUTE,
exact: false,
}),
);
}
2020-11-03 00:41:28 +01:00
onSwapsPage() {
const { location } = this.props;
2020-11-03 00:41:28 +01:00
return Boolean(
matchPath(location.pathname, { path: SWAPS_ROUTE, exact: false }),
);
2020-10-06 20:28:38 +02:00
}
2020-11-03 00:41:28 +01:00
onSwapsBuildQuotePage() {
const { location } = this.props;
2020-11-03 00:41:28 +01:00
return Boolean(
matchPath(location.pathname, { path: BUILD_QUOTE_ROUTE, exact: false }),
);
}
2020-11-03 00:41:28 +01:00
hideAppHeader() {
const { location } = this.props;
2020-11-03 00:41:28 +01:00
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;
}
2020-06-11 02:27:47 +02:00
if (windowType === ENVIRONMENT_TYPE_POPUP && this.onConfirmPage()) {
return true;
}
2020-11-03 00:41:28 +01:00
const isHandlingPermissionsRequest = Boolean(
matchPath(location.pathname, {
path: CONNECT_ROUTE,
exact: false,
}),
);
2021-02-22 17:20:42 +01:00
const isHandlingAddEthereumChainRequest = Boolean(
matchPath(location.pathname, {
path: CONFIRMATION_V_NEXT_ROUTE,
exact: false,
}),
);
return isHandlingPermissionsRequest || isHandlingAddEthereumChainRequest;
}
2020-11-03 00:41:28 +01:00
render() {
const {
isLoading,
isUnlocked,
alertMessage,
textDirection,
loadingMessage,
isNetworkLoading,
provider,
frequentRpcListDetail,
setMouseUserState,
sidebar,
submittedPendingTransactions,
isMouseUser,
2020-10-06 20:28:38 +02:00
prepareToLeaveSwaps,
browserEnvironment,
} = this.props;
2020-11-03 00:41:28 +01:00
const loadMessage =
loadingMessage || isNetworkLoading
2020-11-03 00:41:28 +01:00
? this.getConnectingLabel(loadingMessage)
: null;
const {
isOpen: sidebarIsOpen,
transitionName: sidebarTransitionName,
type: sidebarType,
props,
} = sidebar;
const { transaction: sidebarTransaction } = props || {};
2020-11-03 00:41:28 +01:00
const sidebarShouldClose =
sidebarTransaction &&
!sidebarTransaction.status === TRANSACTION_STATUSES.FAILED &&
2020-11-03 00:41:28 +01:00
!submittedPendingTransactions.find(
({ id }) => id === sidebarTransaction.id,
);
const { os, browser } = browserEnvironment;
return (
<div
className={classnames('app', {
[`os-${os}`]: os,
[`browser-${browser}`]: browser,
'mouse-user-styles': isMouseUser,
})}
dir={textDirection}
onClick={() => setMouseUserState(true)}
onKeyDown={(e) => {
if (e.keyCode === 9) {
setMouseUserState(false);
}
}}
>
<Modal />
2020-11-03 00:41:28 +01:00
<Alert visible={this.props.alertOpen} msg={alertMessage} />
{!this.hideAppHeader() && (
<AppHeader
hideNetworkIndicator={this.onInitializationUnlockPage()}
2020-10-06 20:28:38 +02:00
disableNetworkIndicator={this.onSwapsPage()}
onClick={async () => {
if (this.onSwapsPage()) {
await prepareToLeaveSwaps();
2020-10-06 20:28:38 +02:00
}
}}
2020-11-03 00:41:28 +01:00
disabled={
this.onConfirmPage() ||
(this.onSwapsPage() && !this.onSwapsBuildQuotePage())
}
/>
2020-11-03 00:41:28 +01:00
)}
<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">
2020-11-03 00:41:28 +01:00
{isLoading && <Loading loadingMessage={loadMessage} />}
{!isLoading && isNetworkLoading && <LoadingNetwork />}
2020-11-03 00:41:28 +01:00
{this.renderRoutes()}
</div>
2020-11-03 00:41:28 +01:00
{isUnlocked ? <Alerts history={this.props.history} /> : null}
</div>
);
}
2020-11-03 00:41:28 +01:00
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();
}
}
2020-11-03 00:41:28 +01:00
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]);
}
}
2020-11-03 00:41:28 +01:00
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');
}
}
}