mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-22 17:33:23 +01:00
Add more tracking for MetaMask (#15462)
This commit is contained in:
parent
86f02e4fd5
commit
2eb0fe6978
@ -22,6 +22,9 @@ import { SECOND } from '../../shared/constants/time';
|
||||
import {
|
||||
REJECT_NOTFICIATION_CLOSE,
|
||||
REJECT_NOTFICIATION_CLOSE_SIG,
|
||||
EVENT,
|
||||
EVENT_NAMES,
|
||||
TRAITS,
|
||||
} from '../../shared/constants/metametrics';
|
||||
import { isManifestV3 } from '../../shared/modules/mv3.utils';
|
||||
import { maskObject } from '../../shared/modules/object.utils';
|
||||
@ -69,6 +72,7 @@ let notificationIsOpen = false;
|
||||
let uiIsTriggering = false;
|
||||
const openMetamaskTabsIDs = {};
|
||||
const requestAccountTabIds = {};
|
||||
let controller;
|
||||
|
||||
// state persistence
|
||||
const inTest = process.env.IN_TEST;
|
||||
@ -314,7 +318,7 @@ function setupController(initState, initLangCode, remoteSourcePort) {
|
||||
// MetaMask Controller
|
||||
//
|
||||
|
||||
const controller = new MetamaskController({
|
||||
controller = new MetamaskController({
|
||||
infuraProjectId: process.env.INFURA_PROJECT_ID,
|
||||
// User confirmation callbacks:
|
||||
showUserConfirmation: triggerUi,
|
||||
@ -751,12 +755,32 @@ async function openPopup() {
|
||||
});
|
||||
}
|
||||
|
||||
// It adds the "App Installed" event into a queue of events, which will be tracked only after a user opts into metrics.
|
||||
const addAppInstalledEvent = () => {
|
||||
if (controller) {
|
||||
controller.metaMetricsController.updateTraits({
|
||||
[TRAITS.INSTALL_DATE_EXT]: new Date().toISOString().split('T')[0], // yyyy-mm-dd
|
||||
});
|
||||
controller.metaMetricsController.addEventBeforeMetricsOptIn({
|
||||
category: EVENT.CATEGORIES.APP,
|
||||
event: EVENT_NAMES.APP_INSTALLED,
|
||||
properties: {},
|
||||
});
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
// If the controller is not set yet, we wait and try to add the "App Installed" event again.
|
||||
addAppInstalledEvent();
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// On first install, open a new tab with MetaMask
|
||||
browser.runtime.onInstalled.addListener(({ reason }) => {
|
||||
if (
|
||||
reason === 'install' &&
|
||||
!(process.env.METAMASK_DEBUG || process.env.IN_TEST)
|
||||
) {
|
||||
addAppInstalledEvent();
|
||||
platform.openExtensionInBrowser();
|
||||
}
|
||||
});
|
||||
|
@ -19,6 +19,8 @@ import {
|
||||
} from '../../../shared/constants/metametrics';
|
||||
import { SECOND } from '../../../shared/constants/time';
|
||||
|
||||
const EXTENSION_UNINSTALL_URL = 'https://metamask.io/uninstalled';
|
||||
|
||||
const defaultCaptureException = (err) => {
|
||||
// throw error on clean stack so its captured by platform integrations (eg sentry)
|
||||
// but does not interrupt the call stack
|
||||
@ -52,6 +54,9 @@ const exceptionsToFilter = {
|
||||
* whether or not events are tracked
|
||||
* @property {{[string]: MetaMetricsEventFragment}} [fragments] - Object keyed
|
||||
* by UUID with stored fragments as values.
|
||||
* @property {Array} [eventsBeforeMetricsOptIn] - Array of queued events added before
|
||||
* a user opts into metrics.
|
||||
* @property {object} [traits] - Traits that are not derived from other state keys.
|
||||
*/
|
||||
|
||||
export default class MetaMetricsController {
|
||||
@ -69,6 +74,7 @@ export default class MetaMetricsController {
|
||||
* identifier from the network controller
|
||||
* @param {string} options.version - The version of the extension
|
||||
* @param {string} options.environment - The environment the extension is running in
|
||||
* @param {string} options.extension - webextension-polyfill
|
||||
* @param {MetaMetricsControllerState} options.initState - State to initialized with
|
||||
* @param options.captureException
|
||||
*/
|
||||
@ -81,6 +87,7 @@ export default class MetaMetricsController {
|
||||
version,
|
||||
environment,
|
||||
initState,
|
||||
extension,
|
||||
captureException = defaultCaptureException,
|
||||
}) {
|
||||
this._captureException = (err) => {
|
||||
@ -96,12 +103,16 @@ export default class MetaMetricsController {
|
||||
this.locale = prefState.currentLocale.replace('_', '-');
|
||||
this.version =
|
||||
environment === 'production' ? version : `${version}-${environment}`;
|
||||
this.extension = extension;
|
||||
this.environment = environment;
|
||||
|
||||
const abandonedFragments = omitBy(initState?.fragments, 'persist');
|
||||
|
||||
this.store = new ObservableStore({
|
||||
participateInMetaMetrics: null,
|
||||
metaMetricsId: null,
|
||||
eventsBeforeMetricsOptIn: [],
|
||||
traits: {},
|
||||
...initState,
|
||||
fragments: {
|
||||
...initState?.fragments,
|
||||
@ -315,6 +326,24 @@ export default class MetaMetricsController {
|
||||
this._identify(allValidTraits);
|
||||
}
|
||||
|
||||
// It sets an uninstall URL ("Sorry to see you go!" page),
|
||||
// which is opened if a user uninstalls the extension.
|
||||
updateExtensionUninstallUrl(participateInMetaMetrics, metaMetricsId) {
|
||||
// TODO: Change it to the right URL once it's available.
|
||||
|
||||
const query = {};
|
||||
if (participateInMetaMetrics) {
|
||||
// We only want to track these things if a user opted into metrics.
|
||||
query.id = metaMetricsId;
|
||||
query.env = this.environment;
|
||||
query.av = this.version;
|
||||
}
|
||||
const queryString = new URLSearchParams(query);
|
||||
this.extension.runtime.setUninstallURL(
|
||||
`${EXTENSION_UNINSTALL_URL}?${queryString}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the `participateInMetaMetrics` property
|
||||
*
|
||||
@ -331,6 +360,12 @@ export default class MetaMetricsController {
|
||||
metaMetricsId = null;
|
||||
}
|
||||
this.store.updateState({ participateInMetaMetrics, metaMetricsId });
|
||||
if (participateInMetaMetrics) {
|
||||
this.trackEventsAfterMetricsOptIn();
|
||||
this.clearEventsAfterMetricsOptIn();
|
||||
}
|
||||
// TODO: Uncomment the line below once we have a "Sorry to see you go" page ready.
|
||||
// this.updateExtensionUninstallUrl(participateInMetaMetrics, metaMetricsId);
|
||||
return metaMetricsId;
|
||||
}
|
||||
|
||||
@ -472,6 +507,37 @@ export default class MetaMetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
// Track all queued events after a user opted into metrics.
|
||||
trackEventsAfterMetricsOptIn() {
|
||||
const { eventsBeforeMetricsOptIn } = this.store.getState();
|
||||
eventsBeforeMetricsOptIn.forEach((eventBeforeMetricsOptIn) => {
|
||||
this.trackEvent(eventBeforeMetricsOptIn);
|
||||
});
|
||||
}
|
||||
|
||||
// Once we track queued events after a user opts into metrics, we want to clear the event queue.
|
||||
clearEventsAfterMetricsOptIn() {
|
||||
this.store.updateState({
|
||||
eventsBeforeMetricsOptIn: [],
|
||||
});
|
||||
}
|
||||
|
||||
// It adds an event into a queue, which is only tracked if a user opts into metrics.
|
||||
addEventBeforeMetricsOptIn(event) {
|
||||
const prevState = this.store.getState().eventsBeforeMetricsOptIn;
|
||||
this.store.updateState({
|
||||
eventsBeforeMetricsOptIn: [...prevState, event],
|
||||
});
|
||||
}
|
||||
|
||||
// Add or update traits for tracking.
|
||||
updateTraits(newTraits) {
|
||||
const { traits } = this.store.getState();
|
||||
this.store.updateState({
|
||||
traits: { ...traits, ...newTraits },
|
||||
});
|
||||
}
|
||||
|
||||
/** PRIVATE METHODS */
|
||||
|
||||
/**
|
||||
@ -549,11 +615,13 @@ export default class MetaMetricsController {
|
||||
* @returns {MetaMetricsTraits | null} traits that have changed since last update
|
||||
*/
|
||||
_buildUserTraitsObject(metamaskState) {
|
||||
const { traits } = this.store.getState();
|
||||
/** @type {MetaMetricsTraits} */
|
||||
const currentTraits = {
|
||||
[TRAITS.ADDRESS_BOOK_ENTRIES]: sum(
|
||||
Object.values(metamaskState.addressBook).map(size),
|
||||
),
|
||||
[TRAITS.INSTALL_DATE_EXT]: traits[TRAITS.INSTALL_DATE_EXT] || '',
|
||||
[TRAITS.LEDGER_CONNECTION_TYPE]: metamaskState.ledgerTransportType,
|
||||
[TRAITS.NETWORKS_ADDED]: metamaskState.frequentRpcListDetail.map(
|
||||
(rpc) => rpc.chainId,
|
||||
|
@ -688,6 +688,7 @@ describe('MetaMetricsController', function () {
|
||||
|
||||
assert.deepEqual(traits, {
|
||||
[TRAITS.ADDRESS_BOOK_ENTRIES]: 3,
|
||||
[TRAITS.INSTALL_DATE_EXT]: '',
|
||||
[TRAITS.LEDGER_CONNECTION_TYPE]: 'web-hid',
|
||||
[TRAITS.NETWORKS_ADDED]: [MAINNET_CHAIN_ID, ROPSTEN_CHAIN_ID, '0xaf'],
|
||||
[TRAITS.NETWORKS_WITHOUT_TICKER]: ['0xaf'],
|
||||
|
@ -394,6 +394,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
),
|
||||
version: this.platform.getVersion(),
|
||||
environment: process.env.METAMASK_ENVIRONMENT,
|
||||
extension: this.extension,
|
||||
initState: initState.MetaMetricsController,
|
||||
captureException,
|
||||
});
|
||||
|
@ -183,6 +183,7 @@
|
||||
* @property {'theme'} THEME - when the user's theme changes we identify the theme trait
|
||||
* @property {'token_detection_enabled'} TOKEN_DETECTION_ENABLED - when token detection feature is toggled we
|
||||
* identify the token_detection_enabled trait
|
||||
* @property {'install_date_ext'} INSTALL_DATE_EXT - when the user installed the extension
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -192,6 +193,7 @@
|
||||
|
||||
export const TRAITS = {
|
||||
ADDRESS_BOOK_ENTRIES: 'address_book_entries',
|
||||
INSTALL_DATE_EXT: 'install_date_ext',
|
||||
LEDGER_CONNECTION_TYPE: 'ledger_connection_type',
|
||||
NETWORKS_ADDED: 'networks_added',
|
||||
NETWORKS_WITHOUT_TICKER: 'networks_without_ticker',
|
||||
@ -201,8 +203,8 @@ export const TRAITS = {
|
||||
NUMBER_OF_NFTS: 'number_of_nfts',
|
||||
NUMBER_OF_TOKENS: 'number_of_tokens',
|
||||
OPENSEA_API_ENABLED: 'opensea_api_enabled',
|
||||
THREE_BOX_ENABLED: 'three_box_enabled',
|
||||
THEME: 'theme',
|
||||
THREE_BOX_ENABLED: 'three_box_enabled',
|
||||
TOKEN_DETECTION_ENABLED: 'token_detection_enabled',
|
||||
};
|
||||
|
||||
@ -276,12 +278,16 @@ export const REJECT_NOTFICIATION_CLOSE_SIG =
|
||||
*/
|
||||
|
||||
export const EVENT_NAMES = {
|
||||
ENCRYPTION_PUBLIC_KEY_APPROVED: 'Encryption Public Key Approved',
|
||||
ENCRYPTION_PUBLIC_KEY_REJECTED: 'Encryption Public Key Rejected',
|
||||
ENCRYPTION_PUBLIC_KEY_REQUESTED: 'Encryption Public Key Requested',
|
||||
APP_INSTALLED: 'App Installed',
|
||||
DECRYPTION_APPROVED: 'Decryption Approved',
|
||||
DECRYPTION_REJECTED: 'Decryption Rejected',
|
||||
DECRYPTION_REQUESTED: 'Decryption Requested',
|
||||
ENCRYPTION_PUBLIC_KEY_APPROVED: 'Encryption Public Key Approved',
|
||||
ENCRYPTION_PUBLIC_KEY_REJECTED: 'Encryption Public Key Rejected',
|
||||
ENCRYPTION_PUBLIC_KEY_REQUESTED: 'Encryption Public Key Requested',
|
||||
NEW_WALLET_CREATED: 'New Wallet Created',
|
||||
NEW_WALLET_IMPORTED: 'New Wallet Imported',
|
||||
NFT_ADDED: 'NFT Added',
|
||||
PERMISSIONS_APPROVED: 'Permissions Approved',
|
||||
PERMISSIONS_REJECTED: 'Permissions Rejected',
|
||||
PERMISSIONS_REQUESTED: 'Permissions Requested',
|
||||
@ -289,10 +295,10 @@ export const EVENT_NAMES = {
|
||||
SIGNATURE_APPROVED: 'Signature Approved',
|
||||
SIGNATURE_REJECTED: 'Signature Rejected',
|
||||
SIGNATURE_REQUESTED: 'Signature Requested',
|
||||
SUPPORT_LINK_CLICKED: 'Support Link Clicked',
|
||||
TOKEN_ADDED: 'Token Added',
|
||||
TOKEN_DETECTED: 'Token Detected',
|
||||
TOKEN_HIDDEN: 'Token Hidden',
|
||||
NFT_ADDED: 'NFT Added',
|
||||
TOKEN_IMPORT_CANCELED: 'Token Import Canceled',
|
||||
TOKEN_IMPORT_CLICKED: 'Token Import Clicked',
|
||||
};
|
||||
@ -300,8 +306,12 @@ export const EVENT_NAMES = {
|
||||
export const EVENT = {
|
||||
CATEGORIES: {
|
||||
ACCOUNTS: 'Accounts',
|
||||
APP: 'App',
|
||||
AUTH: 'Auth',
|
||||
BACKGROUND: 'Background',
|
||||
ERROR: 'Error',
|
||||
FOOTER: 'Footer',
|
||||
HOME: 'Home',
|
||||
INPAGE_PROVIDER: 'inpage_provider',
|
||||
MESSAGES: 'Messages',
|
||||
NAVIGATION: 'Navigation',
|
||||
@ -314,29 +324,35 @@ export const EVENT = {
|
||||
TRANSACTIONS: 'Transactions',
|
||||
WALLET: 'Wallet',
|
||||
},
|
||||
LOCATION: {
|
||||
TOKEN_DETAILS: 'token_details',
|
||||
TOKEN_DETECTION: 'token_detection',
|
||||
TOKEN_MENU: 'token_menu',
|
||||
},
|
||||
SOURCE: {
|
||||
NETWORK: {
|
||||
POPULAR_NETWORK_LIST: 'popular_network_list',
|
||||
CUSTOM_NETWORK_FORM: 'custom_network_form',
|
||||
POPULAR_NETWORK_LIST: 'popular_network_list',
|
||||
},
|
||||
SWAPS: {
|
||||
MAIN_VIEW: 'Main View',
|
||||
TOKEN_VIEW: 'Token View',
|
||||
},
|
||||
TRANSACTION: {
|
||||
USER: 'user',
|
||||
DAPP: 'dapp',
|
||||
},
|
||||
TOKEN: {
|
||||
CUSTOM: 'custom',
|
||||
DETECTED: 'detected',
|
||||
DAPP: 'dapp',
|
||||
DETECTED: 'detected',
|
||||
LIST: 'list',
|
||||
},
|
||||
},
|
||||
LOCATION: {
|
||||
TOKEN_DETECTION: 'token_detection',
|
||||
TOKEN_MENU: 'token_menu',
|
||||
TOKEN_DETAILS: 'token_details',
|
||||
TRANSACTION: {
|
||||
DAPP: 'dapp',
|
||||
USER: 'user',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Values below (e.g. 'location') can be used in the "properties"
|
||||
// tracking object as keys, e.g. { location: 'Home' }
|
||||
export const CONTEXT_PROPS = {
|
||||
PAGE_TITLE: 'location',
|
||||
};
|
||||
|
@ -5,7 +5,11 @@ import Fuse from 'fuse.js';
|
||||
import InputAdornment from '@material-ui/core/InputAdornment';
|
||||
import classnames from 'classnames';
|
||||
import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import {
|
||||
EVENT,
|
||||
EVENT_NAMES,
|
||||
CONTEXT_PROPS,
|
||||
} from '../../../../shared/constants/metametrics';
|
||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
|
||||
import Identicon from '../../ui/identicon';
|
||||
import SiteIcon from '../../ui/site-icon';
|
||||
@ -442,6 +446,18 @@ export default class AccountMenu extends Component {
|
||||
}
|
||||
<AccountMenuItem
|
||||
onClick={() => {
|
||||
trackEvent(
|
||||
{
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: EVENT_NAMES.SUPPORT_LINK_CLICKED,
|
||||
properties: {
|
||||
url: supportLink,
|
||||
},
|
||||
},
|
||||
{
|
||||
contextPropsIntoEventProperties: [CONTEXT_PROPS.PAGE_TITLE],
|
||||
},
|
||||
);
|
||||
global.platform.openTab({ url: supportLink });
|
||||
}}
|
||||
icon={
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import MetaFoxLogo from '../../../ui/metafox-logo';
|
||||
import PageContainerFooter from '../../../ui/page-container/page-container-footer';
|
||||
import { EVENT } from '../../../../../shared/constants/metametrics';
|
||||
|
@ -17,6 +17,7 @@ import { captureException, captureMessage } from '@sentry/browser';
|
||||
import { omit } from 'lodash';
|
||||
import { getEnvironmentType } from '../../app/scripts/lib/util';
|
||||
import { PATH_NAME_MAP } from '../helpers/constants/routes';
|
||||
import { CONTEXT_PROPS } from '../../shared/constants/metametrics';
|
||||
import { useSegmentContext } from '../hooks/useSegmentContext';
|
||||
|
||||
import { trackMetaMetricsEvent, trackMetaMetricsPage } from '../store/actions';
|
||||
@ -57,11 +58,26 @@ export function MetaMetricsProvider({ children }) {
|
||||
const location = useLocation();
|
||||
const context = useSegmentContext();
|
||||
|
||||
// Sometimes we want to track context properties inside the event's "properties" object.
|
||||
const addContextPropsIntoEventProperties = (payload, options) => {
|
||||
const fields = options?.contextPropsIntoEventProperties;
|
||||
if (!fields || fields.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (!payload.properties) {
|
||||
payload.properties = {};
|
||||
}
|
||||
if (fields.includes(CONTEXT_PROPS.PAGE_TITLE)) {
|
||||
payload.properties[CONTEXT_PROPS.PAGE_TITLE] = context.page?.title;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {UITrackEventMethod}
|
||||
*/
|
||||
const trackEvent = useCallback(
|
||||
(payload, options) => {
|
||||
addContextPropsIntoEventProperties(payload, options);
|
||||
trackMetaMetricsEvent(
|
||||
{
|
||||
...payload,
|
||||
|
@ -30,7 +30,8 @@ export function getRenderableTokenData(
|
||||
if (isSwapsDefaultTokenSymbol(symbol, chainId)) {
|
||||
contractExchangeRate = 1;
|
||||
} else if (string && conversionRate > 0) {
|
||||
// This condition improves performance significantly.
|
||||
// This condition improves performance significantly, because it only gets a contract exchange rate
|
||||
// if a token amount is truthy and conversion rate is higher than 0.
|
||||
contractExchangeRate = contractExchangeRates[toChecksumHexAddress(address)];
|
||||
}
|
||||
const formattedFiat =
|
||||
|
@ -3,10 +3,16 @@ import PropTypes from 'prop-types';
|
||||
import { getEnvironmentType } from '../../../app/scripts/lib/util';
|
||||
import { ENVIRONMENT_TYPE_POPUP } from '../../../shared/constants/app';
|
||||
import { SUPPORT_REQUEST_LINK } from '../../helpers/constants/common';
|
||||
import {
|
||||
EVENT,
|
||||
EVENT_NAMES,
|
||||
CONTEXT_PROPS,
|
||||
} from '../../../shared/constants/metametrics';
|
||||
|
||||
class ErrorPage extends PureComponent {
|
||||
static contextTypes = {
|
||||
t: PropTypes.func.isRequired,
|
||||
trackEvent: PropTypes.func,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
@ -41,6 +47,20 @@ class ErrorPage extends PureComponent {
|
||||
key="metamaskSupportLink"
|
||||
rel="noopener noreferrer"
|
||||
href={SUPPORT_REQUEST_LINK}
|
||||
onClick={() => {
|
||||
this.context.trackEvent(
|
||||
{
|
||||
category: EVENT.CATEGORIES.ERROR,
|
||||
event: EVENT_NAMES.SUPPORT_LINK_CLICKED,
|
||||
properties: {
|
||||
url: SUPPORT_REQUEST_LINK,
|
||||
},
|
||||
},
|
||||
{
|
||||
contextPropsIntoEventProperties: [CONTEXT_PROPS.PAGE_TITLE],
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
<span className="error-page__link-text">{this.context.t('here')}</span>
|
||||
</a>
|
||||
|
@ -6,7 +6,11 @@ import MetaFoxLogo from '../../../components/ui/metafox-logo';
|
||||
import { SUPPORT_REQUEST_LINK } from '../../../helpers/constants/common';
|
||||
import { DEFAULT_ROUTE } from '../../../helpers/constants/routes';
|
||||
import { returnToOnboardingInitiatorTab } from '../onboarding-initiator-util';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import {
|
||||
EVENT,
|
||||
EVENT_NAMES,
|
||||
CONTEXT_PROPS,
|
||||
} from '../../../../shared/constants/metametrics';
|
||||
|
||||
export default class EndOfFlowScreen extends PureComponent {
|
||||
static contextTypes = {
|
||||
@ -99,6 +103,20 @@ export default class EndOfFlowScreen extends PureComponent {
|
||||
key="metamaskSupportLink"
|
||||
rel="noopener noreferrer"
|
||||
href={SUPPORT_REQUEST_LINK}
|
||||
onClick={() => {
|
||||
this.context.trackEvent(
|
||||
{
|
||||
category: EVENT.CATEGORIES.ONBOARDING,
|
||||
event: EVENT_NAMES.SUPPORT_LINK_CLICKED,
|
||||
properties: {
|
||||
url: SUPPORT_REQUEST_LINK,
|
||||
},
|
||||
},
|
||||
{
|
||||
contextPropsIntoEventProperties: [CONTEXT_PROPS.PAGE_TITLE],
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
<span className="first-time-flow__link-text">
|
||||
{this.context.t('here')}
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { getOnboardingInitiator } from '../../../selectors';
|
||||
import { setCompletedOnboarding } from '../../../store/actions';
|
||||
import { EVENT_NAMES } from '../../../../shared/constants/metametrics';
|
||||
import EndOfFlow from './end-of-flow.component';
|
||||
|
||||
const firstTimeFlowTypeNameMap = {
|
||||
create: 'New Wallet Created',
|
||||
import: 'New Wallet Imported',
|
||||
create: EVENT_NAMES.NEW_WALLET_CREATED,
|
||||
import: EVENT_NAMES.NEW_WALLET_IMPORTED,
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
|
@ -10,7 +10,10 @@ import {
|
||||
DEFAULT_ROUTE,
|
||||
INITIALIZE_SEED_PHRASE_INTRO_ROUTE,
|
||||
} from '../../../../helpers/constants/routes';
|
||||
import { EVENT } from '../../../../../shared/constants/metametrics';
|
||||
import {
|
||||
EVENT,
|
||||
EVENT_NAMES,
|
||||
} from '../../../../../shared/constants/metametrics';
|
||||
import { returnToOnboardingInitiatorTab } from '../../onboarding-initiator-util';
|
||||
import { exportAsFile } from '../../../../../shared/modules/export-utils';
|
||||
|
||||
@ -78,6 +81,15 @@ export default class RevealSeedPhrase extends PureComponent {
|
||||
|
||||
await Promise.all([setCompletedOnboarding(), setSeedPhraseBackedUp(false)]);
|
||||
|
||||
this.context.trackEvent({
|
||||
category: EVENT.CATEGORIES.ONBOARDING,
|
||||
event: EVENT_NAMES.NEW_WALLET_CREATED,
|
||||
properties: {
|
||||
action: 'Onboarding Complete',
|
||||
legacy_event: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (onboardingInitiator) {
|
||||
await returnToOnboardingInitiatorTab(onboardingInitiator);
|
||||
}
|
||||
|
@ -1,13 +1,39 @@
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
|
||||
import { SUPPORT_REQUEST_LINK } from '../../../helpers/constants/common';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import {
|
||||
EVENT,
|
||||
EVENT_NAMES,
|
||||
CONTEXT_PROPS,
|
||||
} from '../../../../shared/constants/metametrics';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
|
||||
const BetaHomeFooter = () => {
|
||||
const t = useI18nContext();
|
||||
const trackEvent = useContext(MetaMetricsContext);
|
||||
|
||||
return (
|
||||
<>
|
||||
<a href={SUPPORT_REQUEST_LINK} target="_blank" rel="noopener noreferrer">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={SUPPORT_REQUEST_LINK}
|
||||
onClick={() => {
|
||||
trackEvent(
|
||||
{
|
||||
category: EVENT.CATEGORIES.FOOTER,
|
||||
event: EVENT_NAMES.SUPPORT_LINK_CLICKED,
|
||||
properties: {
|
||||
url: SUPPORT_REQUEST_LINK,
|
||||
},
|
||||
},
|
||||
{
|
||||
contextPropsIntoEventProperties: [CONTEXT_PROPS.PAGE_TITLE],
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t('needHelpSubmitTicket')}
|
||||
</a>{' '}
|
||||
|{' '}
|
||||
|
@ -1,13 +1,39 @@
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
|
||||
import { SUPPORT_REQUEST_LINK } from '../../../helpers/constants/common';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import {
|
||||
EVENT,
|
||||
EVENT_NAMES,
|
||||
CONTEXT_PROPS,
|
||||
} from '../../../../shared/constants/metametrics';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
|
||||
const FlaskHomeFooter = () => {
|
||||
const t = useI18nContext();
|
||||
const trackEvent = useContext(MetaMetricsContext);
|
||||
|
||||
return (
|
||||
<>
|
||||
<a href={SUPPORT_REQUEST_LINK} target="_blank" rel="noopener noreferrer">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={SUPPORT_REQUEST_LINK}
|
||||
onClick={() => {
|
||||
trackEvent(
|
||||
{
|
||||
category: EVENT.CATEGORIES.FOOTER,
|
||||
event: EVENT_NAMES.SUPPORT_LINK_CLICKED,
|
||||
properties: {
|
||||
url: SUPPORT_REQUEST_LINK,
|
||||
},
|
||||
},
|
||||
{
|
||||
contextPropsIntoEventProperties: [CONTEXT_PROPS.PAGE_TITLE],
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t('needHelpSubmitTicket')}
|
||||
</a>{' '}
|
||||
|{' '}
|
||||
|
@ -3,6 +3,11 @@ import PropTypes from 'prop-types';
|
||||
import { Redirect, Route } from 'react-router-dom';
|
||||
///: BEGIN:ONLY_INCLUDE_IN(main)
|
||||
import { SUPPORT_LINK } from '../../helpers/constants/common';
|
||||
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';
|
||||
@ -73,6 +78,7 @@ function shouldCloseNotificationPopup({
|
||||
export default class Home extends PureComponent {
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
trackEvent: PropTypes.func,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
@ -608,6 +614,7 @@ export default class Home extends PureComponent {
|
||||
!completedOnboarding) &&
|
||||
announcementsToShow &&
|
||||
showWhatsNewPopup;
|
||||
|
||||
return (
|
||||
<div className="main-container">
|
||||
<Route path={CONNECTED_ROUTE} component={ConnectedSites} exact />
|
||||
@ -681,6 +688,22 @@ export default class Home extends PureComponent {
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="need-help-link"
|
||||
onClick={() => {
|
||||
this.context.trackEvent(
|
||||
{
|
||||
category: EVENT.CATEGORIES.HOME,
|
||||
event: EVENT_NAMES.SUPPORT_LINK_CLICKED,
|
||||
properties: {
|
||||
url: SUPPORT_LINK,
|
||||
},
|
||||
},
|
||||
{
|
||||
contextPropsIntoEventProperties: [
|
||||
CONTEXT_PROPS.PAGE_TITLE,
|
||||
],
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t('needHelpLinkText')}
|
||||
</a>,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import Box from '../../../components/ui/box';
|
||||
import Typography from '../../../components/ui/typography';
|
||||
import Button from '../../../components/ui/button';
|
||||
@ -18,12 +19,12 @@ import {
|
||||
import { setCompletedOnboarding } from '../../../store/actions';
|
||||
import { getFirstTimeFlowType } from '../../../selectors';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics';
|
||||
|
||||
export default function CreationSuccessful() {
|
||||
const firstTimeFlowTypeNameMap = {
|
||||
create: 'New Wallet Created',
|
||||
import: 'New Wallet Imported',
|
||||
create: EVENT_NAMES.NEW_WALLET_CREATED,
|
||||
import: EVENT_NAMES.NEW_WALLET_IMPORTED,
|
||||
};
|
||||
const history = useHistory();
|
||||
const t = useI18nContext();
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Button from '../../../components/ui/button';
|
||||
import {
|
||||
SUPPORT_LINK,
|
||||
@ -10,6 +11,11 @@ import {
|
||||
getNumberOfSettingsInSection,
|
||||
handleSettingsRefs,
|
||||
} from '../../../helpers/utils/settings-search';
|
||||
import {
|
||||
EVENT,
|
||||
EVENT_NAMES,
|
||||
CONTEXT_PROPS,
|
||||
} from '../../../../shared/constants/metametrics';
|
||||
|
||||
export default class InfoTab extends PureComponent {
|
||||
state = {
|
||||
@ -18,6 +24,7 @@ export default class InfoTab extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
trackEvent: PropTypes.func,
|
||||
};
|
||||
|
||||
settingsRefs = Array(
|
||||
@ -87,6 +94,20 @@ export default class InfoTab extends PureComponent {
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="info-tab__link-text"
|
||||
onClick={() => {
|
||||
this.context.trackEvent(
|
||||
{
|
||||
category: EVENT.CATEGORIES.SETTINGS,
|
||||
event: EVENT_NAMES.SUPPORT_LINK_CLICKED,
|
||||
properties: {
|
||||
url: SUPPORT_LINK,
|
||||
},
|
||||
},
|
||||
{
|
||||
contextPropsIntoEventProperties: [CONTEXT_PROPS.PAGE_TITLE],
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t('supportCenter')}
|
||||
</Button>
|
||||
@ -109,6 +130,20 @@ export default class InfoTab extends PureComponent {
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="info-tab__link-text"
|
||||
onClick={() => {
|
||||
this.context.trackEvent(
|
||||
{
|
||||
category: EVENT.CATEGORIES.SETTINGS,
|
||||
event: EVENT_NAMES.SUPPORT_LINK_CLICKED,
|
||||
properties: {
|
||||
url: SUPPORT_REQUEST_LINK,
|
||||
},
|
||||
},
|
||||
{
|
||||
contextPropsIntoEventProperties: [CONTEXT_PROPS.PAGE_TITLE],
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t('contactUs')}
|
||||
</Button>
|
||||
|
@ -8,7 +8,11 @@ import { getBlockExplorerLink } from '@metamask/etherscan-link';
|
||||
import { I18nContext } from '../../../contexts/i18n';
|
||||
import { SUPPORT_LINK } from '../../../helpers/constants/common';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import {
|
||||
EVENT,
|
||||
EVENT_NAMES,
|
||||
CONTEXT_PROPS,
|
||||
} from '../../../../shared/constants/metametrics';
|
||||
|
||||
import {
|
||||
getCurrentChainId,
|
||||
@ -156,6 +160,20 @@ export default function AwaitingSwap({
|
||||
href={SUPPORT_LINK}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={() => {
|
||||
trackEvent(
|
||||
{
|
||||
category: EVENT.CATEGORIES.SWAPS,
|
||||
event: EVENT_NAMES.SUPPORT_LINK_CLICKED,
|
||||
properties: {
|
||||
url: SUPPORT_LINK,
|
||||
},
|
||||
},
|
||||
{
|
||||
contextPropsIntoEventProperties: [CONTEXT_PROPS.PAGE_TITLE],
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{new URL(SUPPORT_LINK).hostname}
|
||||
</a>,
|
||||
|
@ -7,7 +7,11 @@ import TextField from '../../components/ui/text-field';
|
||||
import Mascot from '../../components/ui/mascot';
|
||||
import { SUPPORT_LINK } from '../../helpers/constants/common';
|
||||
import { DEFAULT_ROUTE } from '../../helpers/constants/routes';
|
||||
import { EVENT } from '../../../shared/constants/metametrics';
|
||||
import {
|
||||
EVENT,
|
||||
EVENT_NAMES,
|
||||
CONTEXT_PROPS,
|
||||
} from '../../../shared/constants/metametrics';
|
||||
|
||||
export default class UnlockPage extends Component {
|
||||
static contextTypes = {
|
||||
@ -205,6 +209,22 @@ export default class UnlockPage extends Component {
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key="need-help-link"
|
||||
onClick={() => {
|
||||
this.context.trackEvent(
|
||||
{
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: EVENT_NAMES.SUPPORT_LINK_CLICKED,
|
||||
properties: {
|
||||
url: SUPPORT_LINK,
|
||||
},
|
||||
},
|
||||
{
|
||||
contextPropsIntoEventProperties: [
|
||||
CONTEXT_PROPS.PAGE_TITLE,
|
||||
],
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t('needHelpLinkText')}
|
||||
</a>,
|
||||
|
Loading…
Reference in New Issue
Block a user