import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import { Redirect, Route } from 'react-router-dom' import { formatDate } from '../../helpers/utils/util' import AssetList from '../../components/app/asset-list' import HomeNotification from '../../components/app/home-notification' import MultipleNotifications from '../../components/app/multiple-notifications' import TransactionList from '../../components/app/transaction-list' import MenuBar from '../../components/app/menu-bar' 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 SwapsIntroPopup from '../swaps/intro-popup' import { ASSET_ROUTE, RESTORE_VAULT_ROUTE, CONFIRM_TRANSACTION_ROUTE, CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE, INITIALIZE_BACKUP_SEED_PHRASE_ROUTE, CONNECT_ROUTE, CONNECTED_ROUTE, CONNECTED_ACCOUNTS_ROUTE, AWAITING_SWAP_ROUTE, BUILD_QUOTE_ROUTE, VIEW_QUOTE_ROUTE, } from '../../helpers/constants/routes' const LEARN_MORE_URL = 'https://metamask.zendesk.com/hc/en-us/articles/360045129011-Intro-to-MetaMask-v8-extension' export default class Home extends PureComponent { static contextTypes = { t: PropTypes.func, } static propTypes = { history: PropTypes.object, forgottenPassword: PropTypes.bool, suggestedTokens: PropTypes.object, unconfirmedTransactionsCount: PropTypes.number, shouldShowSeedPhraseReminder: PropTypes.bool, isPopup: PropTypes.bool, isNotification: PropTypes.bool.isRequired, threeBoxSynced: PropTypes.bool, setupThreeBox: PropTypes.func, turnThreeBoxSyncingOn: PropTypes.func, showRestorePrompt: PropTypes.bool, selectedAddress: PropTypes.string, restoreFromThreeBox: PropTypes.func, setShowRestorePromptToFalse: PropTypes.func, threeBoxLastUpdated: PropTypes.number, firstPermissionsRequestId: PropTypes.string, totalUnapprovedCount: PropTypes.number.isRequired, setConnectedStatusPopoverHasBeenShown: PropTypes.func, connectedStatusPopoverHasBeenShown: PropTypes.bool, defaultHomeActiveTabName: PropTypes.string, onTabClick: PropTypes.func.isRequired, setSwapsWelcomeMessageHasBeenShown: PropTypes.func.isRequired, swapsWelcomeMessageHasBeenShown: PropTypes.bool.isRequired, haveSwapsQuotes: PropTypes.bool.isRequired, showAwaitingSwapScreen: PropTypes.bool.isRequired, swapsFetchParams: PropTypes.object, swapsEnabled: PropTypes.bool, isMainnet: PropTypes.bool, } state = { mounted: false, } componentDidMount() { const { firstPermissionsRequestId, history, isNotification, suggestedTokens = {}, totalUnapprovedCount, unconfirmedTransactionsCount, haveSwapsQuotes, showAwaitingSwapScreen, swapsFetchParams, } = this.props this.setState({ mounted: true }) if (isNotification && totalUnapprovedCount === 0) { global.platform.closeCurrentWindow() } else 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 (unconfirmedTransactionsCount > 0) { history.push(CONFIRM_TRANSACTION_ROUTE) } else if (Object.keys(suggestedTokens).length > 0) { history.push(CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE) } } static getDerivedStateFromProps( { firstPermissionsRequestId, isNotification, suggestedTokens, totalUnapprovedCount, unconfirmedTransactionsCount, haveSwapsQuotes, showAwaitingSwapScreen, swapsFetchParams, }, { mounted }, ) { if (!mounted) { if (isNotification && totalUnapprovedCount === 0) { return { closing: true } } else if ( firstPermissionsRequestId || unconfirmedTransactionsCount > 0 || Object.keys(suggestedTokens).length > 0 || (!isNotification && (showAwaitingSwapScreen || haveSwapsQuotes || swapsFetchParams)) ) { return { redirecting: true } } } return null } componentDidUpdate(_, prevState) { const { setupThreeBox, showRestorePrompt, threeBoxLastUpdated, threeBoxSynced, } = this.props if (!prevState.closing && this.state.closing) { global.platform.closeCurrentWindow() } if (threeBoxSynced && showRestorePrompt && threeBoxLastUpdated === null) { setupThreeBox() } } renderNotifications() { const { t } = this.context const { history, shouldShowSeedPhraseReminder, isPopup, selectedAddress, restoreFromThreeBox, turnThreeBoxSyncingOn, setShowRestorePromptToFalse, showRestorePrompt, threeBoxLastUpdated, } = this.props return ( <MultipleNotifications> {shouldShowSeedPhraseReminder ? ( <HomeNotification descriptionText={t('backupApprovalNotice')} acceptText={t('backupNow')} onAccept={() => { if (isPopup) { global.platform.openExtensionInBrowser( INITIALIZE_BACKUP_SEED_PHRASE_ROUTE, ) } else { history.push(INITIALIZE_BACKUP_SEED_PHRASE_ROUTE) } }} infoText={t('backupApprovalInfo')} key="home-backupApprovalNotice" /> ) : null} {threeBoxLastUpdated && showRestorePrompt ? ( <HomeNotification descriptionText={t('restoreWalletPreferences', [ formatDate(threeBoxLastUpdated, 'M/d/y'), ])} acceptText={t('restore')} ignoreText={t('noThanks')} infoText={t('dataBackupFoundInfo')} onAccept={() => { restoreFromThreeBox(selectedAddress).then(() => { turnThreeBoxSyncingOn() }) }} onIgnore={() => { setShowRestorePromptToFalse() }} key="home-privacyModeDefault" /> ) : null} </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={LEARN_MORE_URL} target="_blank" rel="noopener noreferrer"> {t('learnMore')} </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, connectedStatusPopoverHasBeenShown, isPopup, swapsWelcomeMessageHasBeenShown, setSwapsWelcomeMessageHasBeenShown, swapsEnabled, isMainnet, } = this.props if (forgottenPassword) { return <Redirect to={{ pathname: RESTORE_VAULT_ROUTE }} /> } else if (this.state.closing || this.state.redirecting) { return null } return ( <div className="main-container"> <Route path={CONNECTED_ROUTE} component={ConnectedSites} exact /> <Route path={CONNECTED_ACCOUNTS_ROUTE} component={ConnectedAccounts} exact /> <div className="home__container"> {!swapsWelcomeMessageHasBeenShown && swapsEnabled && isMainnet ? ( <SwapsIntroPopup onClose={setSwapsWelcomeMessageHasBeenShown} /> ) : null} {isPopup && !connectedStatusPopoverHasBeenShown ? this.renderPopover() : null} <div className="home__main-view"> <MenuBar /> <div className="home__balance-wrapper"> <EthOverview /> </div> <Tabs defaultActiveTabName={defaultHomeActiveTabName} onTabClick={onTabClick} tabsClassName="home__tabs" > <Tab activeClassName="home__tab--active" className="home__tab" data-testid="home__asset-tab" name={t('assets')} > <AssetList onClickAsset={(asset) => history.push(`${ASSET_ROUTE}/${asset}`) } /> </Tab> <Tab activeClassName="home__tab--active" className="home__tab" data-testid="home__activity-tab" name={t('activity')} > <TransactionList /> </Tab> </Tabs> </div> {this.renderNotifications()} </div> </div> ) } }