From 1c9764a6a2e86962831d4d795c540b48d2911b99 Mon Sep 17 00:00:00 2001 From: John Brennan <211638+worldlyjohn@users.noreply.github.com> Date: Thu, 18 Aug 2022 14:31:07 -0700 Subject: [PATCH] Fix onboarding events (#15608) --- app/scripts/controllers/metametrics.js | 18 +++--- shared/constants/metametrics.js | 11 +++- .../app/create-new-vault/create-new-vault.js | 16 +----- .../metametrics-opt-in-modal.component.js | 9 ++- .../import-with-seed-phrase.component.js | 28 +++++---- .../end-of-flow/end-of-flow.component.js | 11 +--- .../end-of-flow/end-of-flow.container.js | 11 ---- .../metametrics-opt-in.component.js | 4 +- .../confirm-seed-phrase-component.test.js | 6 +- .../confirm-seed-phrase.component.js | 33 +++++++---- .../reveal-seed-phrase.component.js | 57 +++++++++---------- .../select-action/select-action.component.js | 12 ++-- .../creation-successful.js | 22 +------ .../metametrics/metametrics.js | 21 +++---- 14 files changed, 114 insertions(+), 145 deletions(-) diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index 0412def31..56d757a7c 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -329,19 +329,21 @@ export default class MetaMetricsController { // 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.mmi = Buffer.from(metaMetricsId).toString('base64'); query.env = this.environment; query.av = this.version; } const queryString = new URLSearchParams(query); - this.extension.runtime.setUninstallURL( - `${EXTENSION_UNINSTALL_URL}?${queryString}`, - ); + + // this.extension not currently defined in tests + if (this.extension && this.extension.runtime) { + this.extension.runtime.setUninstallURL( + `${EXTENSION_UNINSTALL_URL}?${queryString}`, + ); + } } /** @@ -364,8 +366,8 @@ export default class MetaMetricsController { this.trackEventsAfterMetricsOptIn(); this.clearEventsAfterMetricsOptIn(); } - // TODO: Uncomment the line below once we have a "Sorry to see you go" page ready. - // this.updateExtensionUninstallUrl(participateInMetaMetrics, metaMetricsId); + + this.updateExtensionUninstallUrl(participateInMetaMetrics, metaMetricsId); return metaMetricsId; } diff --git a/shared/constants/metametrics.js b/shared/constants/metametrics.js index 5d53e060b..a994ec357 100644 --- a/shared/constants/metametrics.js +++ b/shared/constants/metametrics.js @@ -281,7 +281,7 @@ export const EVENT_NAMES = { ACCOUNT_ADDED: 'Account Added', ACCOUNT_ADD_SELECTED: 'Account Add Selected', ACCOUNT_ADD_FAILED: 'Account Add Failed', - ACCOUNT_PASSWORD_CREATED: 'Account Password Created', + ACCOUNT_PASSWORD_CREATED: 'Wallet Password Created', ACCOUNT_RESET: 'Account Reset', APP_INSTALLED: 'App Installed', APP_UNLOCKED: 'App Unlocked', @@ -300,6 +300,8 @@ export const EVENT_NAMES = { KEY_EXPORT_CANCELED: 'Key Export Canceled', KEY_EXPORT_REVEALED: 'Key Material Revealed', KEY_EXPORT_COPIED: 'Key Material Copied', + METRICS_OPT_IN: 'Metrics Opt In', + METRICS_OPT_OUT: 'Metrics Opt Out', NAV_ACCOUNT_MENU_OPENED: 'Account Menu Opened', NAV_ACCOUNT_DETAILS_OPENED: 'Account Details Opened', NAV_CONNECTED_SITES_OPENED: 'Connected Sites Opened', @@ -311,8 +313,11 @@ export const EVENT_NAMES = { NAV_BUY_BUTTON_CLICKED: 'Buy Button Clicked', NAV_SEND_BUTTON_CLICKED: 'Send Button Clicked', NAV_SWAP_BUTTON_CLICKED: 'Swap Button Clicked', - NEW_WALLET_CREATED: 'New Wallet Created', - NEW_WALLET_IMPORTED: 'New Wallet Imported', + SRP_TO_CONFIRM_BACKUP: 'SRP Backup Confirm Displayed', + WALLET_SETUP_STARTED: 'Wallet Setup Selected', + WALLET_SETUP_CANCELED: 'Wallet Setup Canceled', + WALLET_SETUP_FAILED: 'Wallet Setup Failed', + WALLET_CREATED: 'Wallet Created', NFT_ADDED: 'NFT Added', ONRAMP_PROVIDER_SELECTED: 'On-ramp Provider Selected', PERMISSIONS_APPROVED: 'Permissions Approved', diff --git a/ui/components/app/create-new-vault/create-new-vault.js b/ui/components/app/create-new-vault/create-new-vault.js index 054279328..f27e1a6e8 100644 --- a/ui/components/app/create-new-vault/create-new-vault.js +++ b/ui/components/app/create-new-vault/create-new-vault.js @@ -1,8 +1,6 @@ -import React, { useCallback, useContext, useState } from 'react'; +import React, { useCallback, useState } from 'react'; import PropTypes from 'prop-types'; -import { EVENT } from '../../../../shared/constants/metametrics'; import { useI18nContext } from '../../../hooks/useI18nContext'; -import { MetaMetricsContext } from '../../../contexts/metametrics'; import TextField from '../../ui/text-field'; import Button from '../../ui/button'; import CheckBox from '../../ui/check-box'; @@ -23,7 +21,6 @@ export default function CreateNewVault({ const [termsChecked, setTermsChecked] = useState(false); const t = useI18nContext(); - const trackEvent = useContext(MetaMetricsContext); const onPasswordChange = useCallback( (newPassword) => { @@ -83,17 +80,8 @@ export default function CreateNewVault({ ); const toggleTermsCheck = useCallback(() => { - trackEvent({ - category: EVENT.CATEGORIES.ONBOARDING, - event: 'Check ToS', - properties: { - action: 'Import Seed Phrase', - legacy_event: true, - }, - }); - setTermsChecked((currentTermsChecked) => !currentTermsChecked); - }, [trackEvent]); + }, []); const termsOfUse = t('acceptTermsOfUse', [ this.context.trackEvent({ category: EVENT.CATEGORIES.ONBOARDING, - event: 'Close window on import screen', + event: EVENT_NAMES.WALLET_SETUP_FAILED, properties: { - action: 'Import Seed Phrase', - legacy_event: true, - errorLabel: 'Seed Phrase Error', - errorMessage: this.state.seedPhraseError, + account_type: EVENT.ACCOUNT_TYPES.IMPORTED, + account_import_type: EVENT.ACCOUNT_IMPORT_TYPES.SRP, + reason: 'Seed Phrase Error', + error: this.state.seedPhraseError, }, }); window.addEventListener('beforeunload', this._onBeforeUnload); @@ -46,10 +49,10 @@ export default class ImportWithSeedPhrase extends PureComponent { await onSubmit(password, seedPhrase); this.context.trackEvent({ category: EVENT.CATEGORIES.ONBOARDING, - event: 'Import Complete', + event: EVENT_NAMES.WALLET_CREATED, properties: { - action: 'Import Seed Phrase', - legacy_event: true, + account_type: EVENT.ACCOUNT_TYPES.IMPORTED, + account_import_type: EVENT.ACCOUNT_IMPORT_TYPES.SRP, }, }); @@ -69,10 +72,11 @@ export default class ImportWithSeedPhrase extends PureComponent { e.preventDefault(); this.context.trackEvent({ category: EVENT.CATEGORIES.ONBOARDING, - event: 'Go Back from Onboarding Import', + event: EVENT_NAMES.WALLET_SETUP_CANCELED, properties: { - action: 'Import Seed Phrase', - legacy_event: true, + account_type: EVENT.ACCOUNT_TYPES.IMPORTED, + account_import_type: EVENT.ACCOUNT_IMPORT_TYPES.SRP, + text: 'Back', }, }); this.props.history.push(INITIALIZE_SELECT_ACTION_ROUTE); diff --git a/ui/pages/first-time-flow/end-of-flow/end-of-flow.component.js b/ui/pages/first-time-flow/end-of-flow/end-of-flow.component.js index ef541c65d..a8c8b3b62 100644 --- a/ui/pages/first-time-flow/end-of-flow/end-of-flow.component.js +++ b/ui/pages/first-time-flow/end-of-flow/end-of-flow.component.js @@ -20,7 +20,6 @@ export default class EndOfFlowScreen extends PureComponent { static propTypes = { history: PropTypes.object, - completionMetaMetricsName: PropTypes.string, setCompletedOnboarding: PropTypes.func, onboardingInitiator: PropTypes.exact({ location: PropTypes.string, @@ -37,16 +36,8 @@ export default class EndOfFlowScreen extends PureComponent { } async _onOnboardingComplete() { - const { setCompletedOnboarding, completionMetaMetricsName } = this.props; + const { setCompletedOnboarding } = this.props; await setCompletedOnboarding(); - this.context.trackEvent({ - category: EVENT.CATEGORIES.ONBOARDING, - event: completionMetaMetricsName, - properties: { - action: 'Onboarding Complete', - legacy_event: true, - }, - }); } onComplete = async () => { diff --git a/ui/pages/first-time-flow/end-of-flow/end-of-flow.container.js b/ui/pages/first-time-flow/end-of-flow/end-of-flow.container.js index 64eef95a7..6df628ee9 100644 --- a/ui/pages/first-time-flow/end-of-flow/end-of-flow.container.js +++ b/ui/pages/first-time-flow/end-of-flow/end-of-flow.container.js @@ -2,21 +2,10 @@ 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: EVENT_NAMES.NEW_WALLET_CREATED, - import: EVENT_NAMES.NEW_WALLET_IMPORTED, -}; - const mapStateToProps = (state) => { - const { - metamask: { firstTimeFlowType }, - } = state; - return { - completionMetaMetricsName: firstTimeFlowTypeNameMap[firstTimeFlowType], onboardingInitiator: getOnboardingInitiator(state), }; }; diff --git a/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js b/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js index 648922b48..397307233 100644 --- a/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js +++ b/ui/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import MetaFoxLogo from '../../../components/ui/metafox-logo'; import PageContainerFooter from '../../../components/ui/page-container/page-container-footer'; -import { EVENT } from '../../../../shared/constants/metametrics'; +import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics'; import { INITIALIZE_SELECT_ACTION_ROUTE } from '../../../helpers/constants/routes'; export default class MetaMetricsOptIn extends Component { @@ -113,7 +113,7 @@ export default class MetaMetricsOptIn extends Component { await trackEvent( { category: EVENT.CATEGORIES.ONBOARDING, - event: 'Metrics Opt In', + event: EVENT_NAMES.METRICS_OPT_IN, properties: { action: 'Metrics Option', legacy_event: true, diff --git a/ui/pages/first-time-flow/seed-phrase/confirm-seed-phrase-component.test.js b/ui/pages/first-time-flow/seed-phrase/confirm-seed-phrase-component.test.js index b47bb9532..bf889b6a7 100644 --- a/ui/pages/first-time-flow/seed-phrase/confirm-seed-phrase-component.test.js +++ b/ui/pages/first-time-flow/seed-phrase/confirm-seed-phrase-component.test.js @@ -168,10 +168,10 @@ describe('ConfirmSeedPhrase Component', () => { expect(trackEventSpy.args[0][0]).toStrictEqual({ category: 'Onboarding', - event: 'Verify Complete', + event: 'Wallet Created', properties: { - action: 'Seed Phrase Setup', - legacy_event: true, + account_type: 'metamask', + is_backup_skipped: false, }, }); expect(initialize3BoxSpy.calledOnce).toStrictEqual(true); diff --git a/ui/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.component.js b/ui/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.component.js index 45ea77a2f..4e73efc72 100644 --- a/ui/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.component.js +++ b/ui/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.component.js @@ -6,7 +6,10 @@ import { INITIALIZE_END_OF_FLOW_ROUTE, INITIALIZE_SEED_PHRASE_ROUTE, } from '../../../../helpers/constants/routes'; -import { EVENT } from '../../../../../shared/constants/metametrics'; +import { + EVENT, + EVENT_NAMES, +} from '../../../../../shared/constants/metametrics'; import { exportAsFile } from '../../../../../shared/modules/export-utils'; import DraggableSeed from './draggable-seed.component'; @@ -78,21 +81,31 @@ export default class ConfirmSeedPhrase extends PureComponent { } try { - this.context.trackEvent({ - category: EVENT.CATEGORIES.ONBOARDING, - event: 'Verify Complete', - properties: { - action: 'Seed Phrase Setup', - legacy_event: true, - }, - }); - setSeedPhraseBackedUp(true).then(async () => { + this.context.trackEvent({ + category: EVENT.CATEGORIES.ONBOARDING, + event: EVENT_NAMES.WALLET_CREATED, + properties: { + account_type: EVENT.ACCOUNT_TYPES.DEFAULT, + is_backup_skipped: false, + }, + }); + initializeThreeBox(); history.replace(INITIALIZE_END_OF_FLOW_ROUTE); }); } catch (error) { console.error(error.message); + this.context.trackEvent({ + category: EVENT.CATEGORIES.ONBOARDING, + event: EVENT_NAMES.WALLET_SETUP_FAILED, + properties: { + account_type: EVENT.ACCOUNT_TYPES.DEFAULT, + is_backup_skipped: false, + reason: 'Seed Phrase Creation Error', + error: error.message, + }, + }); } }; diff --git a/ui/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.component.js b/ui/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.component.js index 3c78ac41c..795aadf01 100644 --- a/ui/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.component.js +++ b/ui/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.component.js @@ -48,11 +48,8 @@ export default class RevealSeedPhrase extends PureComponent { this.context.trackEvent({ category: EVENT.CATEGORIES.ONBOARDING, - event: 'Advance to Verify', - properties: { - action: 'Seed Phrase Setup', - legacy_event: true, - }, + event: EVENT_NAMES.SRP_TO_CONFIRM_BACKUP, + properties: {}, }); if (!isShowingSeedPhrase) { @@ -70,25 +67,30 @@ export default class RevealSeedPhrase extends PureComponent { onboardingInitiator, } = this.props; - this.context.trackEvent({ - category: EVENT.CATEGORIES.ONBOARDING, - event: 'Remind me later', - properties: { - action: 'Seed Phrase Setup', - legacy_event: true, - }, - }); - - 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, - }, - }); + await Promise.all([setCompletedOnboarding(), setSeedPhraseBackedUp(false)]) + .then(() => { + this.context.trackEvent({ + category: EVENT.CATEGORIES.ONBOARDING, + event: EVENT_NAMES.WALLET_CREATED, + properties: { + account_type: EVENT.ACCOUNT_TYPES.DEFAULT, + is_backup_skipped: true, + }, + }); + }) + .catch((error) => { + console.error(error.message); + this.context.trackEvent({ + category: EVENT.CATEGORIES.ONBOARDING, + event: EVENT_NAMES.WALLET_SETUP_FAILED, + properties: { + account_type: EVENT.ACCOUNT_TYPES.DEFAULT, + is_backup_skipped: true, + reason: 'Seed Phrase Creation Error', + error: error.message, + }, + }); + }); if (onboardingInitiator) { await returnToOnboardingInitiatorTab(onboardingInitiator); @@ -119,11 +121,8 @@ export default class RevealSeedPhrase extends PureComponent { onClick={() => { this.context.trackEvent({ category: EVENT.CATEGORIES.ONBOARDING, - event: 'Revealed Words', - properties: { - action: 'Seed Phrase Setup', - legacy_event: true, - }, + event: EVENT_NAMES.KEY_EXPORT_REVEALED, + properties: {}, }); this.setState({ isShowingSeedPhrase: true }); }} diff --git a/ui/pages/first-time-flow/select-action/select-action.component.js b/ui/pages/first-time-flow/select-action/select-action.component.js index 9125587c6..0a581aeb9 100644 --- a/ui/pages/first-time-flow/select-action/select-action.component.js +++ b/ui/pages/first-time-flow/select-action/select-action.component.js @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import Button from '../../../components/ui/button'; import MetaFoxLogo from '../../../components/ui/metafox-logo'; -import { EVENT } from '../../../../shared/constants/metametrics'; +import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics'; import { INITIALIZE_CREATE_PASSWORD_ROUTE, INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE, @@ -37,10 +37,9 @@ export default class SelectAction extends PureComponent { trackEvent( { category: EVENT.CATEGORIES.ONBOARDING, - event: 'Selected Create New Wallet', + event: EVENT_NAMES.WALLET_SETUP_STARTED, properties: { - action: 'Import or Create', - legacy_event: true, + account_type: EVENT.ACCOUNT_TYPES.DEFAULT, }, }, { @@ -59,10 +58,9 @@ export default class SelectAction extends PureComponent { trackEvent( { category: EVENT.CATEGORIES.ONBOARDING, - event: 'Selected Import Wallet', + event: EVENT_NAMES.WALLET_SETUP_STARTED, properties: { - action: 'Import or Create', - legacy_event: true, + account_type: EVENT.ACCOUNT_TYPES.IMPORTED, }, }, { diff --git a/ui/pages/onboarding-flow/creation-successful/creation-successful.js b/ui/pages/onboarding-flow/creation-successful/creation-successful.js index 452b9246c..1b7c12a72 100644 --- a/ui/pages/onboarding-flow/creation-successful/creation-successful.js +++ b/ui/pages/onboarding-flow/creation-successful/creation-successful.js @@ -1,6 +1,6 @@ -import React, { useContext } from 'react'; +import React from 'react'; import { useHistory } from 'react-router-dom'; -import { useDispatch, useSelector } from 'react-redux'; +import { useDispatch } from 'react-redux'; import Box from '../../../components/ui/box'; import Typography from '../../../components/ui/typography'; @@ -17,32 +17,14 @@ import { ONBOARDING_PRIVACY_SETTINGS_ROUTE, } from '../../../helpers/constants/routes'; import { setCompletedOnboarding } from '../../../store/actions'; -import { getFirstTimeFlowType } from '../../../selectors'; -import { MetaMetricsContext } from '../../../contexts/metametrics'; -import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics'; export default function CreationSuccessful() { - const firstTimeFlowTypeNameMap = { - create: EVENT_NAMES.NEW_WALLET_CREATED, - import: EVENT_NAMES.NEW_WALLET_IMPORTED, - }; const history = useHistory(); const t = useI18nContext(); const dispatch = useDispatch(); - const firstTimeFlowType = useSelector(getFirstTimeFlowType); - - const trackEvent = useContext(MetaMetricsContext); const onComplete = async () => { await dispatch(setCompletedOnboarding()); - trackEvent({ - event: firstTimeFlowTypeNameMap[firstTimeFlowType], - category: EVENT.CATEGORIES.ONBOARDING, - properties: { - action: 'Onboarding Complete', - legacy_event: true, - }, - }); history.push(ONBOARDING_PIN_EXTENSION_ROUTE); }; return ( diff --git a/ui/pages/onboarding-flow/metametrics/metametrics.js b/ui/pages/onboarding-flow/metametrics/metametrics.js index e9928577c..1fdc96527 100644 --- a/ui/pages/onboarding-flow/metametrics/metametrics.js +++ b/ui/pages/onboarding-flow/metametrics/metametrics.js @@ -17,15 +17,10 @@ import { getParticipateInMetaMetrics, } from '../../../selectors'; -import { EVENT } from '../../../../shared/constants/metametrics'; +import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics'; import { MetaMetricsContext } from '../../../contexts/metametrics'; -const firstTimeFlowTypeNameMap = { - create: 'Selected Create New Wallet', - import: 'Selected Import Wallet', -}; - export default function OnboardingMetametrics() { const t = useI18nContext(); const dispatch = useDispatch(); @@ -35,8 +30,6 @@ export default function OnboardingMetametrics() { const firstTimeFlowType = useSelector(getFirstTimeFlowType); const participateInMetaMetrics = useSelector(getParticipateInMetaMetrics); - const firstTimeSelectionMetaMetricsName = - firstTimeFlowTypeNameMap[firstTimeFlowType]; const trackEvent = useContext(MetaMetricsContext); @@ -50,7 +43,7 @@ export default function OnboardingMetametrics() { trackEvent( { category: EVENT.CATEGORIES.ONBOARDING, - event: 'Metrics Opt In', + event: EVENT_NAMES.METRICS_OPT_IN, properties: { action: 'Metrics Option', legacy_event: true, @@ -65,10 +58,12 @@ export default function OnboardingMetametrics() { trackEvent( { category: EVENT.CATEGORIES.ONBOARDING, - event: firstTimeSelectionMetaMetricsName, + event: EVENT_NAMES.WALLET_SETUP_STARTED, properties: { - action: 'Import or Create', - legacy_event: true, + account_type: + firstTimeFlowType === 'create' + ? EVENT.ACCOUNT_TYPES.DEFAULT + : EVENT.ACCOUNT_TYPES.IMPORTED, }, }, { @@ -93,7 +88,7 @@ export default function OnboardingMetametrics() { trackEvent( { category: EVENT.CATEGORIES.ONBOARDING, - event: 'Metrics Opt Out', + event: EVENT_NAMES.METRICS_OPT_OUT, properties: { action: 'Metrics Option', legacy_event: true,