mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-24 11:01:41 +01:00
d1e8f5db86
If a notification popup was opened while the user was partway through the swaps flow, the notification would display the swaps flow instead of whatever action triggered the popup (e.g. a connect request or a confirmation). This is confusing and potentially dangerous, as the user might mistakenly think the swap was triggered by a dapp. The swap redirects are now prevented in the notification UI. The user will still be redirected to an in-progress swap flow if they open the browser action popup or the fullscreen UI, but not on the notification popup that is triggered by dapp actions.
323 lines
9.9 KiB
JavaScript
323 lines
9.9 KiB
JavaScript
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,
|
|
}
|
|
|
|
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,
|
|
} = 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 ? (
|
|
<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>
|
|
)
|
|
}
|
|
}
|