mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 09:57:02 +01:00
b8b94c2c1f
* added balance-overview component * updated balance overview component to use Currency utility props * added MULTICHAIN feature flag * lint fix * lint fix * lint fix * updated ternary operators
1015 lines
34 KiB
JavaScript
1015 lines
34 KiB
JavaScript
import React, { PureComponent } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import { Redirect, Route } from 'react-router-dom';
|
|
import {
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main)
|
|
MetaMetricsContextProp,
|
|
///: END:ONLY_INCLUDE_IN
|
|
MetaMetricsEventCategory,
|
|
MetaMetricsEventName,
|
|
} from '../../../shared/constants/metametrics';
|
|
import AssetList from '../../components/app/asset-list';
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
|
import NftsTab from '../../components/app/nfts-tab';
|
|
import TermsOfUsePopup from '../../components/app/terms-of-use-popup';
|
|
import RecoveryPhraseReminder from '../../components/app/recovery-phrase-reminder';
|
|
///: END:ONLY_INCLUDE_IN
|
|
import HomeNotification from '../../components/app/home-notification';
|
|
import MultipleNotifications from '../../components/app/multiple-notifications';
|
|
import TransactionList from '../../components/app/transaction-list';
|
|
import Popover from '../../components/ui/popover';
|
|
import Button from '../../components/ui/button';
|
|
import ConnectedSites from '../connected-sites';
|
|
import ConnectedAccounts from '../connected-accounts';
|
|
import { Tabs, Tab } from '../../components/ui/tabs';
|
|
import { EthOverview } from '../../components/app/wallet-overview';
|
|
import WhatsNewPopup from '../../components/app/whats-new-popup';
|
|
|
|
import ActionableMessage from '../../components/ui/actionable-message/actionable-message';
|
|
import {
|
|
FontWeight,
|
|
Display,
|
|
TextColor,
|
|
TextVariant,
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main)
|
|
Size,
|
|
///: END:ONLY_INCLUDE_IN
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-mmi)
|
|
JustifyContent,
|
|
///: END:ONLY_INCLUDE_IN
|
|
} from '../../helpers/constants/design-system';
|
|
import { SECOND } from '../../../shared/constants/time';
|
|
import {
|
|
ButtonIcon,
|
|
ButtonIconSize,
|
|
IconName,
|
|
Box,
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main)
|
|
ButtonLink,
|
|
///: END:ONLY_INCLUDE_IN
|
|
Text,
|
|
} from '../../components/component-library';
|
|
|
|
import {
|
|
ASSET_ROUTE,
|
|
RESTORE_VAULT_ROUTE,
|
|
CONFIRM_TRANSACTION_ROUTE,
|
|
CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE,
|
|
CONFIRM_ADD_SUGGESTED_NFT_ROUTE,
|
|
CONNECT_ROUTE,
|
|
CONNECTED_ROUTE,
|
|
CONNECTED_ACCOUNTS_ROUTE,
|
|
AWAITING_SWAP_ROUTE,
|
|
BUILD_QUOTE_ROUTE,
|
|
VIEW_QUOTE_ROUTE,
|
|
CONFIRMATION_V_NEXT_ROUTE,
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
|
ONBOARDING_SECURE_YOUR_WALLET_ROUTE,
|
|
///: END:ONLY_INCLUDE_IN
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
CONFIRM_ADD_CUSTODIAN_TOKEN,
|
|
INTERACTIVE_REPLACEMENT_TOKEN_PAGE,
|
|
///: END:ONLY_INCLUDE_IN
|
|
} from '../../helpers/constants/routes';
|
|
import ZENDESK_URLS from '../../helpers/constants/zendesk-url';
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main)
|
|
import { SUPPORT_LINK } from '../../../shared/lib/ui-utils';
|
|
///: END:ONLY_INCLUDE_IN
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-beta)
|
|
import BetaHomeFooter from './beta/beta-home-footer.component';
|
|
///: END:ONLY_INCLUDE_IN
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask)
|
|
import FlaskHomeFooter from './flask/flask-home-footer.component';
|
|
///: END:ONLY_INCLUDE_IN
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
import InstitutionalHomeFooter from './institutional/institutional-home-footer';
|
|
///: END:ONLY_INCLUDE_IN
|
|
|
|
function shouldCloseNotificationPopup({
|
|
isNotification,
|
|
totalUnapprovedCount,
|
|
hasApprovalFlows,
|
|
isSigningQRHardwareTransaction,
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
waitForConfirmDeepLinkDialog,
|
|
institutionalConnectRequests,
|
|
///: END:ONLY_INCLUDE_IN
|
|
}) {
|
|
let shouldCLose =
|
|
isNotification &&
|
|
totalUnapprovedCount === 0 &&
|
|
!hasApprovalFlows &&
|
|
!isSigningQRHardwareTransaction;
|
|
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
shouldCLose &&=
|
|
// MMI User must be shown a deeplink
|
|
!waitForConfirmDeepLinkDialog &&
|
|
// MMI User is connecting to custodian
|
|
institutionalConnectRequests.length === 0;
|
|
///: END:ONLY_INCLUDE_IN
|
|
|
|
return shouldCLose;
|
|
}
|
|
|
|
export default class Home extends PureComponent {
|
|
static contextTypes = {
|
|
t: PropTypes.func,
|
|
trackEvent: PropTypes.func,
|
|
};
|
|
|
|
static propTypes = {
|
|
history: PropTypes.object,
|
|
forgottenPassword: PropTypes.bool,
|
|
hasTransactionPendingApprovals: PropTypes.bool.isRequired,
|
|
hasWatchTokenPendingApprovals: PropTypes.bool,
|
|
hasWatchNftPendingApprovals: PropTypes.bool,
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
|
shouldShowSeedPhraseReminder: PropTypes.bool.isRequired,
|
|
isPopup: PropTypes.bool,
|
|
connectedStatusPopoverHasBeenShown: PropTypes.bool,
|
|
showRecoveryPhraseReminder: PropTypes.bool.isRequired,
|
|
showTermsOfUsePopup: PropTypes.bool.isRequired,
|
|
seedPhraseBackedUp: (props) => {
|
|
if (
|
|
props.seedPhraseBackedUp !== null &&
|
|
typeof props.seedPhraseBackedUp !== 'boolean'
|
|
) {
|
|
throw new Error(
|
|
`seedPhraseBackedUp is required to be null or boolean. Received ${props.seedPhraseBackedUp}`,
|
|
);
|
|
}
|
|
},
|
|
///: END:ONLY_INCLUDE_IN
|
|
isNotification: PropTypes.bool.isRequired,
|
|
firstPermissionsRequestId: PropTypes.string,
|
|
// This prop is used in the `shouldCloseNotificationPopup` function
|
|
// eslint-disable-next-line react/no-unused-prop-types
|
|
totalUnapprovedCount: PropTypes.number.isRequired,
|
|
setConnectedStatusPopoverHasBeenShown: PropTypes.func,
|
|
defaultHomeActiveTabName: PropTypes.string,
|
|
firstTimeFlowType: PropTypes.string,
|
|
completedOnboarding: PropTypes.bool,
|
|
onTabClick: PropTypes.func.isRequired,
|
|
haveSwapsQuotes: PropTypes.bool.isRequired,
|
|
showAwaitingSwapScreen: PropTypes.bool.isRequired,
|
|
swapsFetchParams: PropTypes.object,
|
|
location: PropTypes.object,
|
|
shouldShowWeb3ShimUsageNotification: PropTypes.bool.isRequired,
|
|
setWeb3ShimUsageAlertDismissed: PropTypes.func.isRequired,
|
|
originOfCurrentTab: PropTypes.string,
|
|
disableWeb3ShimUsageAlert: PropTypes.func.isRequired,
|
|
pendingConfirmations: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
hasApprovalFlows: PropTypes.bool.isRequired,
|
|
infuraBlocked: PropTypes.bool.isRequired,
|
|
showWhatsNewPopup: PropTypes.bool.isRequired,
|
|
hideWhatsNewPopup: PropTypes.func.isRequired,
|
|
announcementsToShow: PropTypes.bool.isRequired,
|
|
///: BEGIN:ONLY_INCLUDE_IN(snaps)
|
|
errorsToShow: PropTypes.object.isRequired,
|
|
shouldShowErrors: PropTypes.bool.isRequired,
|
|
removeSnapError: PropTypes.func.isRequired,
|
|
///: END:ONLY_INCLUDE_IN
|
|
setRecoveryPhraseReminderHasBeenShown: PropTypes.func.isRequired,
|
|
setRecoveryPhraseReminderLastShown: PropTypes.func.isRequired,
|
|
setTermsOfUseLastAgreed: PropTypes.func.isRequired,
|
|
showOutdatedBrowserWarning: PropTypes.bool.isRequired,
|
|
setOutdatedBrowserWarningLastShown: PropTypes.func.isRequired,
|
|
newNetworkAddedName: PropTypes.string,
|
|
// This prop is used in the `shouldCloseNotificationPopup` function
|
|
// eslint-disable-next-line react/no-unused-prop-types
|
|
isSigningQRHardwareTransaction: PropTypes.bool.isRequired,
|
|
newNftAddedMessage: PropTypes.string,
|
|
setNewNftAddedMessage: PropTypes.func.isRequired,
|
|
removeNftMessage: PropTypes.string,
|
|
setRemoveNftMessage: PropTypes.func.isRequired,
|
|
closeNotificationPopup: PropTypes.func.isRequired,
|
|
newTokensImported: PropTypes.string,
|
|
setNewTokensImported: PropTypes.func.isRequired,
|
|
newNetworkAddedConfigurationId: PropTypes.string,
|
|
clearNewNetworkAdded: PropTypes.func,
|
|
setActiveNetwork: PropTypes.func,
|
|
onboardedInThisUISession: PropTypes.bool,
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
institutionalConnectRequests: PropTypes.arrayOf(PropTypes.object),
|
|
mmiPortfolioEnabled: PropTypes.bool,
|
|
mmiPortfolioUrl: PropTypes.string,
|
|
modalOpen: PropTypes.bool,
|
|
setWaitForConfirmDeepLinkDialog: PropTypes.func,
|
|
waitForConfirmDeepLinkDialog: PropTypes.bool,
|
|
///: END:ONLY_INCLUDE_IN
|
|
};
|
|
|
|
state = {
|
|
canShowBlockageNotification: true,
|
|
notificationClosing: false,
|
|
redirecting: false,
|
|
};
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
const {
|
|
closeNotificationPopup,
|
|
firstPermissionsRequestId,
|
|
haveSwapsQuotes,
|
|
isNotification,
|
|
showAwaitingSwapScreen,
|
|
hasWatchTokenPendingApprovals,
|
|
hasWatchNftPendingApprovals,
|
|
swapsFetchParams,
|
|
hasTransactionPendingApprovals,
|
|
location,
|
|
} = this.props;
|
|
const stayOnHomePage = Boolean(location?.state?.stayOnHomePage);
|
|
|
|
if (shouldCloseNotificationPopup(props)) {
|
|
this.state.notificationClosing = true;
|
|
closeNotificationPopup();
|
|
} else if (
|
|
firstPermissionsRequestId ||
|
|
hasTransactionPendingApprovals ||
|
|
hasWatchTokenPendingApprovals ||
|
|
hasWatchNftPendingApprovals ||
|
|
(!isNotification &&
|
|
!stayOnHomePage &&
|
|
(showAwaitingSwapScreen || haveSwapsQuotes || swapsFetchParams))
|
|
) {
|
|
this.state.redirecting = true;
|
|
}
|
|
}
|
|
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
checkInstitutionalConnectRequest() {
|
|
const { history, institutionalConnectRequests } = this.props;
|
|
if (
|
|
institutionalConnectRequests &&
|
|
institutionalConnectRequests.length > 0 &&
|
|
institutionalConnectRequests[0].feature === 'custodian'
|
|
) {
|
|
if (
|
|
institutionalConnectRequests[0].method ===
|
|
'metamaskinstitutional_reauthenticate'
|
|
) {
|
|
history.push(INTERACTIVE_REPLACEMENT_TOKEN_PAGE);
|
|
} else if (
|
|
institutionalConnectRequests[0].method ===
|
|
'metamaskinstitutional_authenticate'
|
|
) {
|
|
history.push(CONFIRM_ADD_CUSTODIAN_TOKEN);
|
|
}
|
|
}
|
|
}
|
|
|
|
shouldCloseCurrentWindow() {
|
|
const {
|
|
isNotification,
|
|
modalOpen,
|
|
totalUnapprovedCount,
|
|
institutionalConnectRequests,
|
|
waitForConfirmDeepLinkDialog,
|
|
} = this.props;
|
|
|
|
if (
|
|
isNotification &&
|
|
totalUnapprovedCount === 0 &&
|
|
institutionalConnectRequests.length === 0 &&
|
|
!waitForConfirmDeepLinkDialog &&
|
|
!modalOpen
|
|
) {
|
|
global.platform.closeCurrentWindow();
|
|
}
|
|
}
|
|
///: END:ONLY_INCLUDE_IN
|
|
|
|
checkStatusAndNavigate() {
|
|
const {
|
|
firstPermissionsRequestId,
|
|
history,
|
|
isNotification,
|
|
hasTransactionPendingApprovals,
|
|
hasWatchTokenPendingApprovals,
|
|
hasWatchNftPendingApprovals,
|
|
haveSwapsQuotes,
|
|
showAwaitingSwapScreen,
|
|
swapsFetchParams,
|
|
location,
|
|
pendingConfirmations,
|
|
hasApprovalFlows,
|
|
} = this.props;
|
|
const stayOnHomePage = Boolean(location?.state?.stayOnHomePage);
|
|
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
this.shouldCloseCurrentWindow();
|
|
///: END:ONLY_INCLUDE_IN
|
|
|
|
const canRedirect = !isNotification && !stayOnHomePage;
|
|
if (canRedirect && showAwaitingSwapScreen) {
|
|
history.push(AWAITING_SWAP_ROUTE);
|
|
} else if (canRedirect && haveSwapsQuotes) {
|
|
history.push(VIEW_QUOTE_ROUTE);
|
|
} else if (canRedirect && swapsFetchParams) {
|
|
history.push(BUILD_QUOTE_ROUTE);
|
|
} else if (firstPermissionsRequestId) {
|
|
history.push(`${CONNECT_ROUTE}/${firstPermissionsRequestId}`);
|
|
} else if (hasTransactionPendingApprovals) {
|
|
history.push(CONFIRM_TRANSACTION_ROUTE);
|
|
} else if (hasWatchTokenPendingApprovals) {
|
|
history.push(CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE);
|
|
} else if (hasWatchNftPendingApprovals) {
|
|
history.push(CONFIRM_ADD_SUGGESTED_NFT_ROUTE);
|
|
} else if (pendingConfirmations.length > 0 || hasApprovalFlows) {
|
|
history.push(CONFIRMATION_V_NEXT_ROUTE);
|
|
}
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
this.checkInstitutionalConnectRequest();
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.checkStatusAndNavigate();
|
|
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
const { setWaitForConfirmDeepLinkDialog } = this.props;
|
|
|
|
window.addEventListener('beforeunload', () => {
|
|
// If user closes notification window manually, change waitForConfirmDeepLinkDialog to false
|
|
setWaitForConfirmDeepLinkDialog(false);
|
|
});
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
|
|
static getDerivedStateFromProps(props) {
|
|
if (shouldCloseNotificationPopup(props)) {
|
|
return { notificationClosing: true };
|
|
}
|
|
return null;
|
|
}
|
|
|
|
componentDidUpdate(_prevProps, prevState) {
|
|
const { closeNotificationPopup, isNotification } = this.props;
|
|
const { notificationClosing } = this.state;
|
|
|
|
if (notificationClosing && !prevState.notificationClosing) {
|
|
closeNotificationPopup();
|
|
} else if (isNotification) {
|
|
this.checkStatusAndNavigate();
|
|
}
|
|
}
|
|
|
|
onRecoveryPhraseReminderClose = () => {
|
|
const {
|
|
setRecoveryPhraseReminderHasBeenShown,
|
|
setRecoveryPhraseReminderLastShown,
|
|
} = this.props;
|
|
setRecoveryPhraseReminderHasBeenShown(true);
|
|
setRecoveryPhraseReminderLastShown(new Date().getTime());
|
|
};
|
|
|
|
onAcceptTermsOfUse = () => {
|
|
const { setTermsOfUseLastAgreed } = this.props;
|
|
setTermsOfUseLastAgreed(new Date().getTime());
|
|
this.context.trackEvent({
|
|
category: MetaMetricsEventCategory.Onboarding,
|
|
event: MetaMetricsEventName.TermsOfUseAccepted,
|
|
properties: {
|
|
location: 'Terms Of Use Popover',
|
|
},
|
|
});
|
|
};
|
|
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main)
|
|
onSupportLinkClick = () => {
|
|
this.context.trackEvent(
|
|
{
|
|
category: MetaMetricsEventCategory.Home,
|
|
event: MetaMetricsEventName.SupportLinkClicked,
|
|
properties: {
|
|
url: SUPPORT_LINK,
|
|
},
|
|
},
|
|
{
|
|
contextPropsIntoEventProperties: [MetaMetricsContextProp.PageTitle],
|
|
},
|
|
);
|
|
};
|
|
///: END:ONLY_INCLUDE_IN
|
|
|
|
onOutdatedBrowserWarningClose = () => {
|
|
const { setOutdatedBrowserWarningLastShown } = this.props;
|
|
setOutdatedBrowserWarningLastShown(new Date().getTime());
|
|
};
|
|
|
|
renderNotifications() {
|
|
const { t } = this.context;
|
|
|
|
const {
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
|
history,
|
|
shouldShowSeedPhraseReminder,
|
|
isPopup,
|
|
///: END:ONLY_INCLUDE_IN
|
|
shouldShowWeb3ShimUsageNotification,
|
|
setWeb3ShimUsageAlertDismissed,
|
|
originOfCurrentTab,
|
|
disableWeb3ShimUsageAlert,
|
|
///: BEGIN:ONLY_INCLUDE_IN(snaps)
|
|
removeSnapError,
|
|
errorsToShow,
|
|
shouldShowErrors,
|
|
///: END:ONLY_INCLUDE_IN
|
|
infuraBlocked,
|
|
showOutdatedBrowserWarning,
|
|
newNftAddedMessage,
|
|
setNewNftAddedMessage,
|
|
newNetworkAddedName,
|
|
removeNftMessage,
|
|
setRemoveNftMessage,
|
|
newTokensImported,
|
|
setNewTokensImported,
|
|
newNetworkAddedConfigurationId,
|
|
clearNewNetworkAdded,
|
|
setActiveNetwork,
|
|
} = this.props;
|
|
|
|
const onAutoHide = () => {
|
|
setNewNftAddedMessage('');
|
|
setRemoveNftMessage('');
|
|
};
|
|
|
|
const autoHideDelay = 5 * SECOND;
|
|
|
|
return (
|
|
<MultipleNotifications>
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(snaps)
|
|
shouldShowErrors
|
|
? Object.entries(errorsToShow).map(([errorId, error]) => {
|
|
return (
|
|
<HomeNotification
|
|
classNames={['home__error-message']}
|
|
infoText={error.data.snapId}
|
|
descriptionText={
|
|
<>
|
|
<Text
|
|
variant={TextVariant.bodyMd}
|
|
as="h5"
|
|
color={TextColor.textAlternative}
|
|
>
|
|
{t('somethingWentWrong')}
|
|
</Text>
|
|
<Text
|
|
color={TextColor.textAlternative}
|
|
variant={TextVariant.bodySm}
|
|
as="h6"
|
|
>
|
|
{t('snapError', [error.message, error.code])}
|
|
</Text>
|
|
</>
|
|
}
|
|
onIgnore={async () => {
|
|
await removeSnapError(errorId);
|
|
}}
|
|
ignoreText="Dismiss"
|
|
key="home-error-message"
|
|
/>
|
|
);
|
|
})
|
|
: null
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
{newNftAddedMessage === 'success' ? (
|
|
<ActionableMessage
|
|
type="success"
|
|
className="home__new-network-notification"
|
|
autoHideTime={autoHideDelay}
|
|
onAutoHide={onAutoHide}
|
|
message={
|
|
<Box display={Display.InlineFlex}>
|
|
<i className="fa fa-check-circle home__new-nft-notification-icon" />
|
|
<Text variant={TextVariant.bodySm} as="h6">
|
|
{t('newNftAddedMessage')}
|
|
</Text>
|
|
<ButtonIcon
|
|
iconName={IconName.Close}
|
|
size={ButtonIconSize.Sm}
|
|
ariaLabel={t('close')}
|
|
onClick={onAutoHide}
|
|
/>
|
|
</Box>
|
|
}
|
|
/>
|
|
) : null}
|
|
{removeNftMessage === 'success' ? (
|
|
<ActionableMessage
|
|
type="danger"
|
|
className="home__new-network-notification"
|
|
autoHideTime={autoHideDelay}
|
|
onAutoHide={onAutoHide}
|
|
message={
|
|
<Box display={Display.InlineFlex}>
|
|
<i className="fa fa-check-circle home__new-nft-notification-icon" />
|
|
<Text variant={TextVariant.bodySm} as="h6">
|
|
{t('removeNftMessage')}
|
|
</Text>
|
|
<ButtonIcon
|
|
iconName={IconName.Close}
|
|
size={ButtonIconSize.Sm}
|
|
ariaLabel={t('close')}
|
|
onClick={onAutoHide}
|
|
/>
|
|
</Box>
|
|
}
|
|
/>
|
|
) : null}
|
|
{newNetworkAddedName ? (
|
|
<ActionableMessage
|
|
type="success"
|
|
className="home__new-network-notification"
|
|
message={
|
|
<Box display={Display.InlineFlex}>
|
|
<i className="fa fa-check-circle home__new-network-notification-icon" />
|
|
<Text variant={TextVariant.bodySm} as="h6">
|
|
{t('newNetworkAdded', [newNetworkAddedName])}
|
|
</Text>
|
|
<ButtonIcon
|
|
iconName={IconName.Close}
|
|
size={ButtonIconSize.Sm}
|
|
ariaLabel={t('close')}
|
|
onClick={() => clearNewNetworkAdded()}
|
|
className="home__new-network-notification-close"
|
|
/>
|
|
</Box>
|
|
}
|
|
/>
|
|
) : null}
|
|
{newTokensImported ? (
|
|
<ActionableMessage
|
|
type="success"
|
|
className="home__new-tokens-imported-notification"
|
|
message={
|
|
<Box display={Display.InlineFlex}>
|
|
<i className="fa fa-check-circle home__new-tokens-imported-notification-icon" />
|
|
<Box>
|
|
<Text
|
|
className="home__new-tokens-imported-notification-title"
|
|
variant={TextVariant.bodySmBold}
|
|
as="h6"
|
|
>
|
|
{t('newTokensImportedTitle')}
|
|
</Text>
|
|
<Text
|
|
className="home__new-tokens-imported-notification-message"
|
|
variant={TextVariant.bodySm}
|
|
as="h6"
|
|
>
|
|
{t('newTokensImportedMessage', [newTokensImported])}
|
|
</Text>
|
|
</Box>
|
|
|
|
<ButtonIcon
|
|
iconName={IconName.Close}
|
|
size={ButtonIconSize.Sm}
|
|
ariaLabel={t('close')}
|
|
onClick={() => setNewTokensImported('')}
|
|
className="home__new-tokens-imported-notification-close"
|
|
/>
|
|
</Box>
|
|
}
|
|
/>
|
|
) : null}
|
|
{shouldShowWeb3ShimUsageNotification ? (
|
|
<HomeNotification
|
|
descriptionText={t('web3ShimUsageNotification', [
|
|
<span
|
|
key="web3ShimUsageNotificationLink"
|
|
className="home-notification__text-link"
|
|
onClick={() =>
|
|
global.platform.openTab({ url: ZENDESK_URLS.LEGACY_WEB3 })
|
|
}
|
|
>
|
|
{t('here')}
|
|
</span>,
|
|
])}
|
|
ignoreText={t('dismiss')}
|
|
onIgnore={(disable) => {
|
|
setWeb3ShimUsageAlertDismissed(originOfCurrentTab);
|
|
if (disable) {
|
|
disableWeb3ShimUsageAlert();
|
|
}
|
|
}}
|
|
checkboxText={t('dontShowThisAgain')}
|
|
checkboxTooltipText={t('canToggleInSettings')}
|
|
key="home-web3ShimUsageNotification"
|
|
/>
|
|
) : null}
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
|
shouldShowSeedPhraseReminder ? (
|
|
<HomeNotification
|
|
descriptionText={t('backupApprovalNotice')}
|
|
acceptText={t('backupNow')}
|
|
onAccept={() => {
|
|
const backUpSRPRoute = `${ONBOARDING_SECURE_YOUR_WALLET_ROUTE}/?isFromReminder=true`;
|
|
if (isPopup) {
|
|
global.platform.openExtensionInBrowser(backUpSRPRoute);
|
|
} else {
|
|
history.push(backUpSRPRoute);
|
|
}
|
|
}}
|
|
infoText={t('backupApprovalInfo')}
|
|
key="home-backupApprovalNotice"
|
|
/>
|
|
) : null
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
{infuraBlocked && this.state.canShowBlockageNotification ? (
|
|
<HomeNotification
|
|
descriptionText={t('infuraBlockedNotification', [
|
|
<span
|
|
key="infuraBlockedNotificationLink"
|
|
className="home-notification__text-link"
|
|
onClick={() =>
|
|
global.platform.openTab({ url: ZENDESK_URLS.INFURA_BLOCKAGE })
|
|
}
|
|
>
|
|
{t('here')}
|
|
</span>,
|
|
])}
|
|
ignoreText={t('dismiss')}
|
|
onIgnore={() => {
|
|
this.setState({
|
|
canShowBlockageNotification: false,
|
|
});
|
|
}}
|
|
key="home-infuraBlockedNotification"
|
|
/>
|
|
) : null}
|
|
{showOutdatedBrowserWarning ? (
|
|
<HomeNotification
|
|
descriptionText={t('outdatedBrowserNotification')}
|
|
acceptText={t('gotIt')}
|
|
onAccept={this.onOutdatedBrowserWarningClose}
|
|
key="home-outdatedBrowserNotification"
|
|
/>
|
|
) : null}
|
|
{newNetworkAddedConfigurationId && (
|
|
<Popover
|
|
className="home__new-network-added"
|
|
onClose={() => clearNewNetworkAdded()}
|
|
>
|
|
<i className="fa fa-check-circle fa-2x home__new-network-added__check-circle" />
|
|
<Text
|
|
variant={TextVariant.headingSm}
|
|
as="h4"
|
|
marginTop={5}
|
|
marginRight={9}
|
|
marginLeft={9}
|
|
marginBottom={0}
|
|
fontWeight={FontWeight.Bold}
|
|
>
|
|
{t('networkAddedSuccessfully')}
|
|
</Text>
|
|
<Box marginTop={8} marginRight={8} marginLeft={8} marginBottom={5}>
|
|
<Button
|
|
type="primary"
|
|
className="home__new-network-added__switch-to-button"
|
|
onClick={() => {
|
|
setActiveNetwork(newNetworkAddedConfigurationId);
|
|
clearNewNetworkAdded();
|
|
}}
|
|
>
|
|
<Text
|
|
variant={TextVariant.bodySm}
|
|
as="h6"
|
|
color={TextColor.primaryInverse}
|
|
>
|
|
{t('switchToNetwork', [newNetworkAddedName])}
|
|
</Text>
|
|
</Button>
|
|
<Button type="secondary" onClick={() => clearNewNetworkAdded()}>
|
|
<Text
|
|
variant={TextVariant.bodySm}
|
|
as="h6"
|
|
color={TextColor.primaryDefault}
|
|
>
|
|
{t('dismiss')}
|
|
</Text>
|
|
</Button>
|
|
</Box>
|
|
</Popover>
|
|
)}
|
|
</MultipleNotifications>
|
|
);
|
|
}
|
|
|
|
renderPopover = () => {
|
|
const { setConnectedStatusPopoverHasBeenShown } = this.props;
|
|
const { t } = this.context;
|
|
return (
|
|
<Popover
|
|
title={t('whatsThis')}
|
|
onClose={setConnectedStatusPopoverHasBeenShown}
|
|
className="home__connected-status-popover"
|
|
showArrow
|
|
CustomBackground={({ onClose }) => {
|
|
return (
|
|
<div
|
|
className="home__connected-status-popover-bg-container"
|
|
onClick={onClose}
|
|
>
|
|
<div className="home__connected-status-popover-bg" />
|
|
</div>
|
|
);
|
|
}}
|
|
footer={
|
|
<>
|
|
<a
|
|
href={ZENDESK_URLS.USER_GUIDE_DAPPS}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
{t('learnMoreUpperCase')}
|
|
</a>
|
|
<Button
|
|
type="primary"
|
|
onClick={setConnectedStatusPopoverHasBeenShown}
|
|
>
|
|
{t('dismiss')}
|
|
</Button>
|
|
</>
|
|
}
|
|
>
|
|
<main className="home__connect-status-text">
|
|
<div>{t('metaMaskConnectStatusParagraphOne')}</div>
|
|
<div>{t('metaMaskConnectStatusParagraphTwo')}</div>
|
|
<div>{t('metaMaskConnectStatusParagraphThree')}</div>
|
|
</main>
|
|
</Popover>
|
|
);
|
|
};
|
|
|
|
render() {
|
|
const { t } = this.context;
|
|
const {
|
|
defaultHomeActiveTabName,
|
|
onTabClick,
|
|
forgottenPassword,
|
|
history,
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
|
connectedStatusPopoverHasBeenShown,
|
|
isPopup,
|
|
seedPhraseBackedUp,
|
|
showRecoveryPhraseReminder,
|
|
showTermsOfUsePopup,
|
|
///: END:ONLY_INCLUDE_IN
|
|
announcementsToShow,
|
|
showWhatsNewPopup,
|
|
hideWhatsNewPopup,
|
|
firstTimeFlowType,
|
|
completedOnboarding,
|
|
onboardedInThisUISession,
|
|
newNetworkAddedConfigurationId,
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
mmiPortfolioEnabled,
|
|
mmiPortfolioUrl,
|
|
///: END:ONLY_INCLUDE_IN
|
|
} = this.props;
|
|
|
|
if (forgottenPassword) {
|
|
return <Redirect to={{ pathname: RESTORE_VAULT_ROUTE }} />;
|
|
} else if (this.state.notificationClosing || this.state.redirecting) {
|
|
return null;
|
|
}
|
|
const tabPadding = process.env.MULTICHAIN ? 4 : 0; // TODO: Remove tabPadding and add paddingTop={4} to parent container Box of Tabs
|
|
|
|
const showWhatsNew =
|
|
completedOnboarding &&
|
|
(!onboardedInThisUISession || firstTimeFlowType === 'import') &&
|
|
announcementsToShow &&
|
|
showWhatsNewPopup &&
|
|
!process.env.IN_TEST &&
|
|
!newNetworkAddedConfigurationId;
|
|
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
|
const showTermsOfUse =
|
|
completedOnboarding && !onboardedInThisUISession && showTermsOfUsePopup;
|
|
///: END:ONLY_INCLUDE_IN
|
|
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
// The style in activity screen for support is different
|
|
const activitySupportDisplayStyle =
|
|
defaultHomeActiveTabName === 'activity'
|
|
? {
|
|
justifyContent: JustifyContent.center,
|
|
paddingLeft: 0,
|
|
marginTop: 4,
|
|
marginBottom: 4,
|
|
}
|
|
: {
|
|
justifyContent: JustifyContent.flexStart,
|
|
paddingLeft: 4,
|
|
marginTop: 0,
|
|
marginBottom: 4,
|
|
};
|
|
///: END:ONLY_INCLUDE_IN
|
|
return (
|
|
<div className="main-container">
|
|
<Route path={CONNECTED_ROUTE} component={ConnectedSites} exact />
|
|
<Route
|
|
path={CONNECTED_ACCOUNTS_ROUTE}
|
|
component={ConnectedAccounts}
|
|
exact
|
|
/>
|
|
<div className="home__container">
|
|
{showWhatsNew ? (
|
|
<WhatsNewPopup
|
|
onClose={hideWhatsNewPopup}
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
mmiPortfolioUrl={mmiPortfolioUrl}
|
|
///: END:ONLY_INCLUDE_IN
|
|
/>
|
|
) : null}
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
|
}
|
|
{!showWhatsNew && showRecoveryPhraseReminder ? (
|
|
<RecoveryPhraseReminder
|
|
hasBackedUp={seedPhraseBackedUp}
|
|
onConfirm={this.onRecoveryPhraseReminderClose}
|
|
/>
|
|
) : null}
|
|
{showTermsOfUse ? (
|
|
<TermsOfUsePopup onAccept={this.onAcceptTermsOfUse} />
|
|
) : null}
|
|
{isPopup && !connectedStatusPopoverHasBeenShown
|
|
? this.renderPopover()
|
|
: null}
|
|
{
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
<div className="home__main-view">
|
|
{process.env.MULTICHAIN ? null : (
|
|
<div className="home__balance-wrapper">
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
|
<EthOverview showAddress />
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
<EthOverview
|
|
showAddress
|
|
mmiPortfolioEnabled={mmiPortfolioEnabled}
|
|
mmiPortfolioUrl={mmiPortfolioUrl}
|
|
/>
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
</div>
|
|
)}
|
|
<Box style={{ flexGrow: '1' }} paddingTop={tabPadding}>
|
|
<Tabs
|
|
t={this.context.t}
|
|
defaultActiveTabKey={defaultHomeActiveTabName}
|
|
onTabClick={(tabName) => {
|
|
onTabClick(tabName);
|
|
let event;
|
|
switch (tabName) {
|
|
case 'nfts':
|
|
event = MetaMetricsEventName.NftScreenOpened;
|
|
break;
|
|
case 'activity':
|
|
event = MetaMetricsEventName.ActivityScreenOpened;
|
|
break;
|
|
default:
|
|
event = MetaMetricsEventName.TokenScreenOpened;
|
|
}
|
|
this.context.trackEvent({
|
|
category: MetaMetricsEventCategory.Home,
|
|
event,
|
|
});
|
|
}}
|
|
tabsClassName="home__tabs"
|
|
>
|
|
<Tab
|
|
activeClassName="home__tab--active"
|
|
className="home__tab"
|
|
data-testid="home__asset-tab"
|
|
name={this.context.t('tokens')}
|
|
tabKey="tokens"
|
|
>
|
|
<Box marginTop={2}>
|
|
<AssetList
|
|
onClickAsset={(asset) =>
|
|
history.push(`${ASSET_ROUTE}/${asset}`)
|
|
}
|
|
/>
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main)
|
|
<ButtonLink
|
|
size={Size.MD}
|
|
startIconName={IconName.MessageQuestion}
|
|
data-testid="need-help-link"
|
|
href={SUPPORT_LINK}
|
|
display={Display.Flex}
|
|
justifyContent={JustifyContent.flexStart}
|
|
paddingLeft={4}
|
|
marginBottom={4}
|
|
onClick={this.onSupportLinkClick}
|
|
externalLink
|
|
>
|
|
{t('needHelpLinkText')}
|
|
</ButtonLink>
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
</Box>
|
|
</Tab>
|
|
<Tab
|
|
activeClassName="home__tab--active"
|
|
className="home__tab"
|
|
data-testid="home__nfts-tab"
|
|
name={this.context.t('nfts')}
|
|
tabKey="nfts"
|
|
>
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
|
|
<NftsTab />
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main)
|
|
<ButtonLink
|
|
size={Size.MD}
|
|
startIconName={IconName.MessageQuestion}
|
|
data-testid="need-help-link"
|
|
href={SUPPORT_LINK}
|
|
display={Display.Flex}
|
|
justifyContent={JustifyContent.flexStart}
|
|
paddingLeft={4}
|
|
marginBottom={4}
|
|
onClick={this.onSupportLinkClick}
|
|
externalLink
|
|
>
|
|
{t('needHelpLinkText')}
|
|
</ButtonLink>
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
</Tab>
|
|
<Tab
|
|
activeClassName="home__tab--active"
|
|
className="home__tab"
|
|
data-testid="home__activity-tab"
|
|
name={t('activity')}
|
|
tabKey="activity"
|
|
>
|
|
<TransactionList />
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-main)
|
|
<ButtonLink
|
|
size={Size.MD}
|
|
startIconName={IconName.MessageQuestion}
|
|
data-testid="need-help-link"
|
|
href={SUPPORT_LINK}
|
|
display={Display.Flex}
|
|
justifyContent={JustifyContent.center}
|
|
marginBottom={4}
|
|
marginTop={4}
|
|
onClick={this.onSupportLinkClick}
|
|
externalLink
|
|
>
|
|
{t('needHelpLinkText')}
|
|
</ButtonLink>
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
</Tab>
|
|
</Tabs>
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
|
|
<InstitutionalHomeFooter
|
|
activitySupportDisplayStyle={activitySupportDisplayStyle}
|
|
/>
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
</Box>
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-beta)
|
|
<div className="home__support">
|
|
<BetaHomeFooter />
|
|
</div>
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
{
|
|
///: BEGIN:ONLY_INCLUDE_IN(build-flask)
|
|
<div className="home__support">
|
|
<FlaskHomeFooter />
|
|
</div>
|
|
///: END:ONLY_INCLUDE_IN
|
|
}
|
|
</div>
|
|
{this.renderNotifications()}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|