1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 01:47:00 +01:00

Add entry point for metalabs dapp into metamask home page (#15407)

Co-authored-by: Dan Miller <danjm.com@gmail.com>
This commit is contained in:
Matthew Epps 2022-09-13 06:41:58 -07:00 committed by GitHub
parent 0b1744d4eb
commit dcfe80c255
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 281 additions and 20 deletions

View File

@ -8,6 +8,7 @@ COLLECTIBLES_V1=
PUBNUB_PUB_KEY=
PUBNUB_SUB_KEY=
TOKEN_ALLOWANCE_IMPROVEMENTS=
PORTFOLIO_URL=
; Set this to '1' to enable support for Sign-In with Ethereum [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361)
SIWE_V1=

View File

@ -451,6 +451,9 @@
"betaMetamaskVersion": {
"message": "MetaMask Beta Version"
},
"betaPortfolioSite": {
"message": "beta portfolio site"
},
"betaWelcome": {
"message": "Welcome to MetaMask Beta"
},
@ -1779,6 +1782,9 @@
"message": "JSON File",
"description": "format for importing an account"
},
"keepTapsOnTokens": {
"message": "to keep tabs on your tokens and NFTs across accounts and networks."
},
"keystone": {
"message": "Keystone"
},
@ -2165,6 +2171,9 @@
"nevermind": {
"message": "Nevermind"
},
"new": {
"message": "New!"
},
"newAccount": {
"message": "New account"
},
@ -2660,6 +2669,9 @@
"popularCustomNetworks": {
"message": "Popular custom networks"
},
"portfolioSite": {
"message": "Portfolio site"
},
"preferredLedgerConnectionType": {
"message": "Preferred Ledger connection type",
"description": "A header for a dropdown in Settings > Advanced. Appears above the ledgerConnectionPreferenceDescription message"
@ -4075,6 +4087,9 @@
"tryAgain": {
"message": "Try again"
},
"tryOur": {
"message": "Try our"
},
"turnOnTokenDetection": {
"message": "Turn on enhanced token detection"
},

View File

@ -33,6 +33,7 @@ export default class AppStateController extends EventEmitter {
collectiblesDetectionNoticeDismissed: false,
enableEIP1559V2NoticeDismissed: false,
showTestnetMessageInDropdown: true,
showPortfolioTooltip: true,
trezorModel: null,
...initState,
qrHardware: {},
@ -259,6 +260,15 @@ export default class AppStateController extends EventEmitter {
this.store.updateState({ showTestnetMessageInDropdown });
}
/**
* Sets whether the portfolio site tooltip should be shown on the home page
*
* @param showPortfolioTooltip
*/
setShowPortfolioTooltip(showPortfolioTooltip) {
this.store.updateState({ showPortfolioTooltip });
}
/**
* Sets a property indicating the model of the user's Trezor hardware wallet
*

View File

@ -1727,6 +1727,8 @@ export default class MetamaskController extends EventEmitter {
appStateController.setShowTestnetMessageInDropdown.bind(
appStateController,
),
setShowPortfolioTooltip:
appStateController.setShowPortfolioTooltip.bind(appStateController),
setCollectiblesDetectionNoticeDismissed:
appStateController.setCollectiblesDetectionNoticeDismissed.bind(
appStateController,

View File

@ -1023,6 +1023,7 @@ async function getEnvironmentVariables({ buildTarget, buildType, version }) {
environment,
testing,
}),
PORTFOLIO_URL: ENVIRONMENT.PORTFOLIO_URL || 'https://portfolio.metamask.io',
METAMASK_DEBUG: devMode,
METAMASK_ENVIRONMENT: environment,
METAMASK_VERSION: version,

View File

@ -323,6 +323,7 @@ export const EVENT_NAMES = {
PERMISSIONS_APPROVED: 'Permissions Approved',
PERMISSIONS_REJECTED: 'Permissions Rejected',
PERMISSIONS_REQUESTED: 'Permissions Requested',
PORTFOLIO_LINK_CLICKED: 'Portfolio Link Clicked',
PUBLIC_ADDRESS_COPIED: 'Public Address Copied',
PROVIDER_METHOD_CALLED: 'Provider Method Called',
SIGNATURE_APPROVED: 'Signature Approved',

View File

@ -15,7 +15,8 @@
},
"AppStateController": {
"mkrMigrationReminderTimestamp": null,
"swapsWelcomeMessageHasBeenShown": true
"swapsWelcomeMessageHasBeenShown": true,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -1,7 +1,8 @@
{
"data": {
"AppStateController": {
"connectedStatusPopoverHasBeenShown": false
"connectedStatusPopoverHasBeenShown": false,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -1,7 +1,8 @@
{
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null
"mkrMigrationReminderTimestamp": null,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -12,7 +12,8 @@
"connectedStatusPopoverHasBeenShown": true,
"defaultHomeActiveTabName": null,
"recoveryPhraseReminderHasBeenShown": true,
"recoveryPhraseReminderLastShown": "__FIXTURE_SUBSTITUTION__currentDateInMilliseconds"
"recoveryPhraseReminderLastShown": "__FIXTURE_SUBSTITUTION__currentDateInMilliseconds",
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -2,7 +2,8 @@
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null,
"swapsWelcomeMessageHasBeenShown": true
"swapsWelcomeMessageHasBeenShown": true,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -2,7 +2,8 @@
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null,
"swapsWelcomeMessageHasBeenShown": true
"swapsWelcomeMessageHasBeenShown": true,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -259,7 +259,8 @@
"AppStateController": {
"connectedStatusPopoverHasBeenShown": true,
"swapsWelcomeMessageHasBeenShown": false,
"defaultHomeActiveTabName": "Activity"
"defaultHomeActiveTabName": "Activity",
"showPortfolioTooltip": false
}
},
"meta": {

View File

@ -1,7 +1,8 @@
{
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null
"mkrMigrationReminderTimestamp": null,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -1,7 +1,8 @@
{
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null
"mkrMigrationReminderTimestamp": null,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -1,7 +1,8 @@
{
"data": {
"AppStateController": {
"connectedStatusPopoverHasBeenShown": false
"connectedStatusPopoverHasBeenShown": false,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -1,7 +1,8 @@
{
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null
"mkrMigrationReminderTimestamp": null,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -2,7 +2,8 @@
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null,
"swapsWelcomeMessageHasBeenShown": true
"swapsWelcomeMessageHasBeenShown": true,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -2,7 +2,8 @@
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null,
"swapsWelcomeMessageHasBeenShown": true
"swapsWelcomeMessageHasBeenShown": true,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -1,7 +1,8 @@
{
"data": {
"AppStateController": {
"mkrMigrationReminderTimestamp": null
"mkrMigrationReminderTimestamp": null,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -2,7 +2,8 @@
"data": {
"AppStateController": {
"swapsWelcomeMessageHasBeenShown": true,
"connectedStatusPopoverHasBeenShown": false
"connectedStatusPopoverHasBeenShown": false,
"showPortfolioTooltip": false
},
"CachedBalancesController": {
"cachedBalances": {

View File

@ -0,0 +1,45 @@
import React from 'react';
import PropTypes from 'prop-types';
const IconChart = ({
size = 12,
color = 'var(--color-primary-default)',
className,
ariaLabel,
}) => (
<svg
width={size}
height={size}
viewBox="0 0 12 12"
fill="none"
className={className}
aria-label={ariaLabel}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.5 9.375C1.5 9.58125 1.66781 9.75 1.875 9.75H11.25C11.6648 9.75 12 10.0852 12 10.5C12 10.9148 11.6648 11.25 11.25 11.25H1.875C0.839531 11.25 0 10.4109 0 9.375V1.5C0 1.08586 0.335859 0.75 0.75 0.75C1.16414 0.75 1.5 1.08586 1.5 1.5V9.375ZM8.02969 6.52969C7.73672 6.82266 7.26328 6.82266 6.97031 6.52969L5.625 5.18672L3.52969 7.27969C3.23672 7.57266 2.76328 7.57266 2.47031 7.27969C2.17688 6.98672 2.17688 6.51328 2.47031 6.22031L5.09531 3.59531C5.38828 3.30234 5.86172 3.30234 6.15469 3.59531L7.5 4.93828L9.97031 2.47031C10.2633 2.17687 10.7367 2.17687 11.0297 2.47031C11.3227 2.76328 11.3227 3.23672 11.0297 3.52969L8.02969 6.52969Z"
fill={color}
/>
</svg>
);
IconChart.propTypes = {
/**
* The size of the Icon follows an 8px grid 2 = 16px, 3 = 24px etc
*/
size: PropTypes.number,
/**
* The color of the icon accepts design token css variables
*/
color: PropTypes.string,
/**
* An additional className to assign the Icon
*/
className: PropTypes.string,
/**
* The aria-label of the icon for accessibility purposes
*/
ariaLabel: PropTypes.string,
};
export default IconChart;

View File

@ -7,6 +7,7 @@ export default class Tabs extends Component {
defaultActiveTabName: null,
onTabClick: null,
tabsClassName: undefined,
subHeader: null,
};
static propTypes = {
@ -14,6 +15,7 @@ export default class Tabs extends Component {
onTabClick: PropTypes.func,
children: PropTypes.node.isRequired,
tabsClassName: PropTypes.string,
subHeader: PropTypes.node,
};
state = {
@ -74,12 +76,13 @@ export default class Tabs extends Component {
}
render() {
const { tabsClassName } = this.props;
const { tabsClassName, subHeader } = this.props;
return (
<div className="tabs">
<ul className={classnames('tabs__list', tabsClassName)}>
{this.renderTabs()}
</ul>
{subHeader}
<div className="tabs__content">{this.renderActiveTabContent()}</div>
</div>
);

View File

@ -12,6 +12,7 @@ export default class Tooltip extends PureComponent {
onHidden: null,
position: 'left',
offset: 0,
open: undefined,
size: 'small',
title: null,
trigger: 'mouseenter focus',
@ -29,6 +30,7 @@ export default class Tooltip extends PureComponent {
interactive: PropTypes.bool,
offset: PropTypes.number,
onHidden: PropTypes.func,
open: PropTypes.bool,
position: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
size: PropTypes.oneOf(['small', 'regular', 'big']),
title: PropTypes.string,
@ -54,6 +56,7 @@ export default class Tooltip extends PureComponent {
trigger,
onHidden,
offset,
open,
wrapperClassName,
style,
theme,
@ -82,6 +85,7 @@ export default class Tooltip extends PureComponent {
style={style}
title={disabled ? '' : title}
trigger={trigger}
open={open}
theme={`tippy-tooltip--mm-custom ${theme}`} // Required for correct theming
tabIndex={tabIndex || 0}
tag={tag}

View File

@ -58,6 +58,7 @@ export default function reduceApp(state = {}, action) {
ledgerTransportStatus: TRANSPORT_STATES.NONE,
newNetworkAdded: '',
newCollectibleAddedMessage: '',
portfolioTooltipWasShownInThisSession: false,
sendInputCurrencySwitched: false,
newTokensImported: '',
newCustomNetworkAdded: {},
@ -321,6 +322,12 @@ export default function reduceApp(state = {}, action) {
newCollectibleAddedMessage: action.value,
};
case actionConstants.PORTFOLIO_TOOLTIP_WAS_SHOWN_IN_THIS_SESSION:
return {
...appState,
portfolioTooltipWasShownInThisSession: true,
};
case actionConstants.LOADING_METHOD_DATA_STARTED:
return {
...appState,
@ -418,6 +425,12 @@ export function hideWhatsNewPopup() {
};
}
export function setPortfolioTooltipWasShownInThisSession() {
return {
type: actionConstants.PORTFOLIO_TOOLTIP_WAS_SHOWN_IN_THIS_SESSION,
};
}
export function toggleGasLoadingAnimation(value) {
return { type: actionConstants.TOGGLE_GAS_LOADING_ANIMATION, value };
}
@ -447,6 +460,10 @@ export function getLedgerTransportStatus(state) {
return state.appState.ledgerTransportStatus;
}
export function getPortfolioTooltipWasShownInThisSession(state) {
return state.appState.portfolioTooltipWasShownInThisSession;
}
export function toggleCurrencySwitch() {
return { type: actionConstants.TOGGLE_CURRENCY_INPUT_SWITCH };
}

View File

@ -3,12 +3,12 @@ import PropTypes from 'prop-types';
import { Redirect, Route } from 'react-router-dom';
///: BEGIN:ONLY_INCLUDE_IN(main)
import { SUPPORT_LINK } from '../../helpers/constants/common';
///: END:ONLY_INCLUDE_IN
import {
EVENT,
EVENT_NAMES,
CONTEXT_PROPS,
} from '../../../shared/constants/metametrics';
///: END:ONLY_INCLUDE_IN
import { formatDate } from '../../helpers/utils/util';
import AssetList from '../../components/app/asset-list';
import CollectiblesTab from '../../components/app/collectibles-tab';
@ -27,6 +27,7 @@ import WhatsNewPopup from '../../components/app/whats-new-popup';
import RecoveryPhraseReminder from '../../components/app/recovery-phrase-reminder';
import ActionableMessage from '../../components/ui/actionable-message/actionable-message';
import Typography from '../../components/ui/typography/typography';
import IconChart from '../../components/ui/icon/icon-chart';
import {
TYPOGRAPHY,
FONT_WEIGHT,
@ -50,6 +51,7 @@ import {
ADD_COLLECTIBLE_ROUTE,
} from '../../helpers/constants/routes';
import ZENDESK_URLS from '../../helpers/constants/zendesk-url';
import Tooltip from '../../components/ui/tooltip';
///: BEGIN:ONLY_INCLUDE_IN(beta)
import BetaHomeFooter from './beta/beta-home-footer.component';
///: END:ONLY_INCLUDE_IN
@ -115,6 +117,10 @@ export default class Home extends PureComponent {
infuraBlocked: PropTypes.bool.isRequired,
showWhatsNewPopup: PropTypes.bool.isRequired,
hideWhatsNewPopup: PropTypes.func.isRequired,
showPortfolioTooltip: PropTypes.bool.isRequired,
hidePortfolioTooltip: PropTypes.func.isRequired,
portfolioTooltipWasShownInThisSession: PropTypes.bool.isRequired,
setPortfolioTooltipWasShownInThisSession: PropTypes.func.isRequired,
announcementsToShow: PropTypes.bool.isRequired,
///: BEGIN:ONLY_INCLUDE_IN(flask)
errorsToShow: PropTypes.object.isRequired,
@ -213,7 +219,12 @@ export default class Home extends PureComponent {
}
componentDidMount() {
const { setPortfolioTooltipWasShownInThisSession, showPortfolioTooltip } =
this.props;
this.checkStatusAndNavigate();
if (showPortfolioTooltip) {
setPortfolioTooltipWasShownInThisSession();
}
}
static getDerivedStateFromProps(props) {
@ -594,6 +605,9 @@ export default class Home extends PureComponent {
announcementsToShow,
showWhatsNewPopup,
hideWhatsNewPopup,
showPortfolioTooltip,
hidePortfolioTooltip,
portfolioTooltipWasShownInThisSession,
seedPhraseBackedUp,
showRecoveryPhraseReminder,
firstTimeFlowType,
@ -610,8 +624,9 @@ export default class Home extends PureComponent {
((completedOnboarding && firstTimeFlowType === 'import') ||
!completedOnboarding) &&
announcementsToShow &&
showWhatsNewPopup;
showWhatsNewPopup &&
!showPortfolioTooltip &&
!portfolioTooltipWasShownInThisSession;
return (
<div className="main-container">
<Route path={CONNECTED_ROUTE} component={ConnectedSites} exact />
@ -640,6 +655,67 @@ export default class Home extends PureComponent {
defaultActiveTabName={defaultHomeActiveTabName}
onTabClick={onTabClick}
tabsClassName="home__tabs"
subHeader={
<Tooltip
position="bottom"
open={!process.env.IN_TEST && showPortfolioTooltip}
interactive
theme="home__subheader-link--tooltip"
html={
<div>
<div className="home__subheader-link--tooltip-content-header">
<div className="home__subheader-link--tooltip-content-header-text">
{t('new')}
</div>
<button
className="home__subheader-link--tooltip-content-header-button"
onClick={() => {
hidePortfolioTooltip();
}}
>
<i className="fa fa-times" />
</button>
</div>
<div>
{t('tryOur')}&nbsp;
<span className="home__subheader-link--tooltip-content-text-bold">
{t('betaPortfolioSite')}
</span>
&nbsp;{t('keepTapsOnTokens')}
</div>
</div>
}
>
<div
className="home__subheader-link"
onClick={async () => {
const portfolioUrl = process.env.PORTFOLIO_URL;
global.platform.openTab({
url: `${portfolioUrl}?metamaskEntry=ext`,
});
this.context.trackEvent(
{
category: EVENT.CATEGORIES.HOME,
event: EVENT_NAMES.PORTFOLIO_LINK_CLICKED,
properties: {
url: portfolioUrl,
},
},
{
contextPropsIntoEventProperties: [
CONTEXT_PROPS.PAGE_TITLE,
],
},
);
}}
>
<IconChart />
<div className="home__subheader-link--text">
{t('portfolioSite')}
</div>
</div>
</Tooltip>
}
>
<Tab
activeClassName="home__tab--active"

View File

@ -23,6 +23,7 @@ import {
hasUnsignedQRHardwareMessage,
getNewCollectibleAddedMessage,
getNewTokensImported,
getShowPortfolioTooltip,
} from '../../selectors';
import {
@ -30,6 +31,7 @@ import {
restoreFromThreeBox,
turnThreeBoxSyncingOn,
getThreeBoxLastUpdated,
hidePortfolioTooltip,
setShowRestorePromptToFalse,
setConnectedStatusPopoverHasBeenShown,
setDefaultHomeActiveTabName,
@ -49,6 +51,8 @@ import {
setThreeBoxLastUpdated,
hideWhatsNewPopup,
setNewCustomNetworkAdded,
getPortfolioTooltipWasShownInThisSession,
setPortfolioTooltipWasShownInThisSession,
} from '../../ducks/app/app';
import { getWeb3ShimUsageAlertEnabledness } from '../../ducks/metamask/metamask';
import { getSwapsFeatureIsLive } from '../../ducks/swaps/swaps';
@ -149,6 +153,9 @@ const mapStateToProps = (state) => {
shouldShowErrors: Object.entries(metamask.snapErrors || []).length > 0,
///: END:ONLY_INCLUDE_IN
showWhatsNewPopup: getShowWhatsNewPopup(state),
showPortfolioTooltip: getShowPortfolioTooltip(state),
portfolioTooltipWasShownInThisSession:
getPortfolioTooltipWasShownInThisSession(state),
showRecoveryPhraseReminder: getShowRecoveryPhraseReminder(state),
seedPhraseBackedUp,
newNetworkAdded: getNewNetworkAdded(state),
@ -185,6 +192,7 @@ const mapDispatchToProps = (dispatch) => ({
disableWeb3ShimUsageAlert: () =>
setAlertEnabledness(ALERT_TYPES.web3ShimUsage, false),
hideWhatsNewPopup: () => dispatch(hideWhatsNewPopup()),
hidePortfolioTooltip,
setRecoveryPhraseReminderHasBeenShown: () =>
dispatch(setRecoveryPhraseReminderHasBeenShown()),
setRecoveryPhraseReminderLastShown: (lastShown) =>
@ -204,6 +212,8 @@ const mapDispatchToProps = (dispatch) => ({
setRpcTarget: (rpcUrl, chainId, ticker, nickname) => {
dispatch(setRpcTarget(rpcUrl, chainId, ticker, nickname));
},
setPortfolioTooltipWasShownInThisSession: () =>
dispatch(setPortfolioTooltipWasShownInThisSession()),
});
export default compose(

View File

@ -221,4 +221,56 @@
margin-bottom: 16px;
}
}
&__subheader-link {
display: flex;
padding: 12px 0;
justify-content: center;
color: var(--color-primary-default);
align-items: center;
cursor: pointer;
&--tooltip-content {
&-header {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
&-text {
font-size: 18px;
line-height: 22.82px;
font-weight: 700;
}
&-button {
background-color: var(--color-primary-default);
color: var(--color-primary-inverse);
border: 0;
}
}
&-text-bold {
font-weight: 700;
}
}
&--tooltip-theme {
background-color: var(--color-primary-default) !important;
& .tippy-tooltip-content {
color: var(--color-primary-inverse) !important;
}
& .arrow-regular {
border-bottom-color: var(--color-primary-default) !important;
}
}
&--text {
margin-left: 8px;
font-weight: 400;
font-size: 12px;
line-height: 140.62%;
}
}
}

View File

@ -878,6 +878,10 @@ export function getShowRecoveryPhraseReminder(state) {
return currentTime - recoveryPhraseReminderLastShown >= frequency;
}
export function getShowPortfolioTooltip(state) {
return state.metamask.showPortfolioTooltip;
}
/**
* To get the useTokenDetection flag which determines whether a static or dynamic token list is used
*

View File

@ -106,7 +106,8 @@ export const SET_OPEN_METAMASK_TAB_IDS = 'SET_OPEN_METAMASK_TAB_IDS';
// Home Screen
export const HIDE_WHATS_NEW_POPUP = 'HIDE_WHATS_NEW_POPUP';
export const PORTFOLIO_TOOLTIP_WAS_SHOWN_IN_THIS_SESSION =
'PORTFOLIO_TOOLTIP_WAS_SHOWN_IN_THIS_SESSION';
export const TOGGLE_GAS_LOADING_ANIMATION = 'TOGGLE_GAS_LOADING_ANIMATION';
// Smart Transactions

View File

@ -3854,6 +3854,10 @@ export function hideTestNetMessage() {
return submitRequestToBackground('setShowTestnetMessageInDropdown', [false]);
}
export function hidePortfolioTooltip() {
return submitRequestToBackground('setShowPortfolioTooltip', [false]);
}
export function setCollectiblesDetectionNoticeDismissed() {
return submitRequestToBackground('setCollectiblesDetectionNoticeDismissed', [
true,