import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { Redirect, Route } from 'react-router-dom'; import AssetList from '../../components/app/asset-list'; import NftsTab from '../../components/app/nfts-tab'; 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 TermsOfUsePopup from '../../components/app/terms-of-use-popup'; import ActionableMessage from '../../components/ui/actionable-message/actionable-message'; import { FONT_WEIGHT, DISPLAY, TextColor, TextVariant, } from '../../helpers/constants/design-system'; import { SECOND } from '../../../shared/constants/time'; import { ButtonIcon, ButtonIconSize, IconName, Text, Box, } 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, ADD_NFT_ROUTE, } from '../../helpers/constants/routes'; import ZENDESK_URLS from '../../helpers/constants/zendesk-url'; 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 or compliance 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, isPopup: PropTypes.bool, 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, connectedStatusPopoverHasBeenShown: PropTypes.bool, defaultHomeActiveTabName: PropTypes.string, firstTimeFlowType: PropTypes.string, completedOnboarding: PropTypes.bool, onTabClick: PropTypes.func.isRequired, haveSwapsQuotes: PropTypes.bool.isRequired, showAwaitingSwapScreen: PropTypes.bool.isRequired, swapsFetchParams: 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, showTermsOfUsePopup: PropTypes.bool.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 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, }; state = { canShowBlockageNotification: true, notificationClosing: false, redirecting: false, }; constructor(props) { super(props); const { closeNotificationPopup, firstPermissionsRequestId, haveSwapsQuotes, isNotification, showAwaitingSwapScreen, hasWatchTokenPendingApprovals, hasWatchNftPendingApprovals, swapsFetchParams, hasTransactionPendingApprovals, } = this.props; if (shouldCloseNotificationPopup(props)) { this.state.notificationClosing = true; closeNotificationPopup(); } else if ( firstPermissionsRequestId || hasTransactionPendingApprovals || hasWatchTokenPendingApprovals || hasWatchNftPendingApprovals || (!isNotification && (showAwaitingSwapScreen || haveSwapsQuotes || swapsFetchParams)) ) { this.state.redirecting = true; } } checkStatusAndNavigate() { const { firstPermissionsRequestId, history, isNotification, hasTransactionPendingApprovals, hasWatchTokenPendingApprovals, hasWatchNftPendingApprovals, haveSwapsQuotes, showAwaitingSwapScreen, swapsFetchParams, pendingConfirmations, hasApprovalFlows, } = this.props; ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) this.shouldCloseCurrentWindow(); ///: END:ONLY_INCLUDE_IN if (!isNotification && showAwaitingSwapScreen) { history.push(AWAITING_SWAP_ROUTE); } else if (!isNotification && haveSwapsQuotes) { history.push(VIEW_QUOTE_ROUTE); } else if (!isNotification && 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(); } 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(); } } onAcceptTermsOfUse = () => { const { setTermsOfUseLastAgreed } = this.props; setTermsOfUseLastAgreed(new Date().getTime()); }; onOutdatedBrowserWarningClose = () => { const { setOutdatedBrowserWarningLastShown } = this.props; setOutdatedBrowserWarningLastShown(new Date().getTime()); }; renderNotifications() { const { t } = this.context; const { 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 ( { ///: BEGIN:ONLY_INCLUDE_IN(snaps) shouldShowErrors ? Object.entries(errorsToShow).map(([errorId, error]) => { return ( {t('somethingWentWrong')} {t('snapError', [error.message, error.code])} } onIgnore={async () => { await removeSnapError(errorId); }} ignoreText="Dismiss" key="home-error-message" /> ); }) : null ///: END:ONLY_INCLUDE_IN } {newNftAddedMessage === 'success' ? ( {t('newNftAddedMessage')} } /> ) : null} {removeNftMessage === 'success' ? ( {t('removeNftMessage')} } /> ) : null} {newNetworkAddedName ? ( {t('newNetworkAdded', [newNetworkAddedName])} clearNewNetworkAdded()} className="home__new-network-notification-close" /> } /> ) : null} {newTokensImported ? ( {t('newTokensImportedTitle')} {t('newTokensImportedMessage', [newTokensImported])} setNewTokensImported('')} className="home__new-tokens-imported-notification-close" /> } /> ) : null} {shouldShowWeb3ShimUsageNotification ? ( global.platform.openTab({ url: ZENDESK_URLS.LEGACY_WEB3 }) } > {t('here')} , ])} ignoreText={t('dismiss')} onIgnore={(disable) => { setWeb3ShimUsageAlertDismissed(originOfCurrentTab); if (disable) { disableWeb3ShimUsageAlert(); } }} checkboxText={t('dontShowThisAgain')} checkboxTooltipText={t('canToggleInSettings')} key="home-web3ShimUsageNotification" /> ) : null} {infuraBlocked && this.state.canShowBlockageNotification ? ( global.platform.openTab({ url: ZENDESK_URLS.INFURA_BLOCKAGE }) } > {t('here')} , ])} ignoreText={t('dismiss')} onIgnore={() => { this.setState({ canShowBlockageNotification: false, }); }} key="home-infuraBlockedNotification" /> ) : null} {showOutdatedBrowserWarning ? ( ) : null} {newNetworkAddedConfigurationId && ( {t('networkAddedSuccessfully')} )} ); } renderPopover = () => { const { setConnectedStatusPopoverHasBeenShown } = this.props; const { t } = this.context; return ( { return (
); }} footer={ <> {t('learnMoreUpperCase')} } >
{t('metaMaskConnectStatusParagraphOne')}
{t('metaMaskConnectStatusParagraphTwo')}
{t('metaMaskConnectStatusParagraphThree')}
); }; render() { const { t } = this.context; const { defaultHomeActiveTabName, onTabClick, forgottenPassword, history, connectedStatusPopoverHasBeenShown, isPopup, announcementsToShow, showWhatsNewPopup, hideWhatsNewPopup, showTermsOfUsePopup, firstTimeFlowType, completedOnboarding, onboardedInThisUISession, newNetworkAddedConfigurationId, } = this.props; if (forgottenPassword) { return ; } else if (this.state.notificationClosing || this.state.redirecting) { return null; } const showWhatsNew = completedOnboarding && (!onboardedInThisUISession || firstTimeFlowType === 'import') && announcementsToShow && showWhatsNewPopup && !process.env.IN_TEST && !newNetworkAddedConfigurationId; const showTermsOfUse = completedOnboarding && !onboardedInThisUISession && showTermsOfUsePopup; return (
{showWhatsNew ? : null} { ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) } {showTermsOfUse ? ( ) : null} {isPopup && !connectedStatusPopoverHasBeenShown ? this.renderPopover() : null} { ///: END:ONLY_INCLUDE_IN }
{ ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) ///: END:ONLY_INCLUDE_IN }
{ onTabClick(tabName); }} tabsClassName="home__tabs" > history.push(`${ASSET_ROUTE}/${asset}`) } /> { ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) { history.push(ADD_NFT_ROUTE); }} /> ///: END:ONLY_INCLUDE_IN }
{this.renderNotifications()}
); } }