From 6dd6384c01c11377192162324965080e46166e2e Mon Sep 17 00:00:00 2001 From: Nicolas MASSART Date: Tue, 27 Feb 2024 14:53:23 +0100 Subject: [PATCH] update remaining files and remove legacy analytics --- app/components/Nav/App/index.js | 8 +- app/components/UI/Navbar/index.js | 5 +- app/components/UI/OptinMetrics/index.js | 7 +- app/components/Views/Quiz/SRPQuiz/SRPQuiz.tsx | 4 +- .../SecuritySettings/SecuritySettings.tsx | 12 +- app/core/Analytics/Analytics.js | 502 ------------------ app/core/Analytics/MetaMetrics.events.ts | 5 +- app/core/Analytics/index.ts | 2 - app/core/SecureKeychain.js | 19 +- app/util/analyticsV2.js | 96 ---- app/util/termsOfUse/termsOfUse.ts | 7 +- 11 files changed, 32 insertions(+), 635 deletions(-) delete mode 100644 app/core/Analytics/Analytics.js delete mode 100644 app/util/analyticsV2.js diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index 8a5e876e7aef..39d487ba9b4d 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -31,7 +31,6 @@ import branch from 'react-native-branch'; import AppConstants from '../../../core/AppConstants'; import Logger from '../../../util/Logger'; import { routingInstrumentation } from '../../../util/sentry/utils'; -import Analytics from '../../../core/Analytics/Analytics'; import { connect, useDispatch } from 'react-redux'; import { CURRENT_APP_VERSION, @@ -370,13 +369,12 @@ const App = ({ userLoggedIn }) => { }, [dispatch, handleDeeplink, navigator, queueOfHandleDeeplinkFunctions]); useEffect(() => { - const initAnalytics = async () => { + const initMetrics = async () => { await MetaMetrics.getInstance().configure(); - await Analytics.init(); }; - initAnalytics().catch((err) => { - Logger.error(err, 'Error initializing analytics'); + initMetrics().catch((err) => { + Logger.error(err, 'Error initializing MetaMetrics'); }); }, []); diff --git a/app/components/UI/Navbar/index.js b/app/components/UI/Navbar/index.js index 322a0947fc98..c37b87d75fe1 100644 --- a/app/components/UI/Navbar/index.js +++ b/app/components/UI/Navbar/index.js @@ -169,6 +169,9 @@ export function getTransactionsNavbarOptions( * * @param {string} title - Title in string format * @param {Object} navigation - Navigation object required to push new views + * @param isFullScreenModal + * @param themeColors + * @param {IMetaMetricsEvent} navigationPopEvent * @returns {Object} - Corresponding navbar options containing title and headerTitleStyle */ export function getNavigationOptionsTitle( @@ -176,7 +179,7 @@ export function getNavigationOptionsTitle( navigation, isFullScreenModal, themeColors, - navigationPopEvent = undefined, + navigationPopEvent = null, ) { const innerStyles = StyleSheet.create({ headerStyle: { diff --git a/app/components/UI/OptinMetrics/index.js b/app/components/UI/OptinMetrics/index.js index 666f50c094aa..525c9babc6b0 100644 --- a/app/components/UI/OptinMetrics/index.js +++ b/app/components/UI/OptinMetrics/index.js @@ -20,8 +20,10 @@ import { connect } from 'react-redux'; import { clearOnboardingEvents } from '../../../actions/onboarding'; import { ONBOARDING_WIZARD } from '../../../constants/storage'; import AppConstants from '../../../core/AppConstants'; -import { Analytics, MetaMetricsEvents } from '../../../core/Analytics'; -import { withMetricsAwareness } from '../../hooks/useMetrics'; +import { + MetaMetricsEvents, + withMetricsAwareness, +} from '../../hooks/useMetrics'; import DefaultPreference from 'react-native-default-preference'; import { ThemeContext } from '../../../util/theme'; @@ -272,7 +274,6 @@ class OptinMetrics extends PureComponent { // and disable analytics clearOnboardingEvents(); await metrics.enable(false); - Analytics.disableInstance(); }, 200); this.continue(); }; diff --git a/app/components/Views/Quiz/SRPQuiz/SRPQuiz.tsx b/app/components/Views/Quiz/SRPQuiz/SRPQuiz.tsx index d1a0816abdff..c98f937b728d 100644 --- a/app/components/Views/Quiz/SRPQuiz/SRPQuiz.tsx +++ b/app/components/Views/Quiz/SRPQuiz/SRPQuiz.tsx @@ -67,8 +67,8 @@ const SRPQuiz = () => { ); const goToRevealPrivateCredential = useCallback((): void => { - trackEvent(MetaMetricsEvents.REVEAL_SRP_INITIATED, {}); - trackEvent(MetaMetricsEvents.REVEAL_SRP_CTA, {}); + trackEvent(MetaMetricsEvents.REVEAL_SRP_INITIATED); + trackEvent(MetaMetricsEvents.REVEAL_SRP_CTA); navigation.navigate(Routes.SETTINGS.REVEAL_PRIVATE_CREDENTIAL, { credentialName: 'seed_phrase', shouldUpdateNav: true, diff --git a/app/components/Views/Settings/SecuritySettings/SecuritySettings.tsx b/app/components/Views/Settings/SecuritySettings/SecuritySettings.tsx index f65a49bb217b..e5b66c3365f5 100644 --- a/app/components/Views/Settings/SecuritySettings/SecuritySettings.tsx +++ b/app/components/Views/Settings/SecuritySettings/SecuritySettings.tsx @@ -19,7 +19,6 @@ import Logger from '../../../../util/Logger'; import { getNavigationOptionsTitle } from '../../../UI/Navbar'; import { setLockTime } from '../../../../actions/settings'; import { strings } from '../../../../../locales/i18n'; -import Analytics from '../../../../core/Analytics/Analytics'; import { passwordSet } from '../../../../actions/user'; import Engine from '../../../../core/Engine'; import AppConstants from '../../../../core/AppConstants'; @@ -119,8 +118,8 @@ import Button, { ButtonSize, ButtonWidthTypes, } from '../../../../component-library/components/Buttons/Button'; -import { trackErrorAsAnalytics } from '../../../../util/analyticsV2'; import { isBlockaidFeatureEnabled } from '../../../../util/blockaid'; +import trackErrorAsAnalytics from '../../../../util/metrics/TrackError/trackErrorAsAnalytics'; const Heading: React.FC = ({ children, first }) => { const { colors } = useTheme(); @@ -450,8 +449,6 @@ const Settings: React.FC = () => { const toggleMetricsOptIn = async (metricsEnabled: boolean) => { if (metricsEnabled) { - Analytics.enable(); - const consolidatedTraits = { ...generateDeviceAnalyticsMetaData(), ...generateUserSettingsAnalyticsMetaData(), @@ -460,21 +457,14 @@ const Settings: React.FC = () => { setAnalyticsEnabled(true); InteractionManager.runAfterInteractions(async () => { - // Segment metrics optin tracking await addTraitsToUser(consolidatedTraits); trackEvent(MetaMetricsEvents.ANALYTICS_PREFERENCE_SELECTED, { analytics_option_selected: 'Metrics Opt in', updated_after_onboarding: true, }); - // Legacy metrics optin tracking - trackEvent(MetaMetricsEvents.ANALYTICS_PREFERENCE_SELECTED, { - analytics_option_selected: 'Metrics Opt in', - updated_after_onboarding: true, - }); }); } else { await enable(false); - Analytics.disable(); setAnalyticsEnabled(false); Alert.alert( strings('app_settings.metametrics_opt_out'), diff --git a/app/core/Analytics/Analytics.js b/app/core/Analytics/Analytics.js deleted file mode 100644 index 38687e304b26..000000000000 --- a/app/core/Analytics/Analytics.js +++ /dev/null @@ -1,502 +0,0 @@ -'use strict'; - -import { Appearance, NativeModules } from 'react-native'; -import axios from 'axios'; -import AUTHENTICATION_TYPE from '../../constants/userProperties'; -import DefaultPreference from 'react-native-default-preference'; -import Logger from '../../util/Logger'; -import { MetaMetricsEvents } from '../../core/Analytics'; -import { store } from '../../store'; -import { MIXPANEL_PROXY_ENDPOINT_BASE_URL } from '../../constants/urls'; -import { - METRICS_OPT_IN, - AGREED, - DENIED, - ANALYTICS_DATA_DELETION_TASK_ID, - ANALYTICS_DATA_RECORDED, - MIXPANEL_METAMETRICS_ID, -} from '../../constants/storage'; -import { - DataDeleteResponseStatus, - DataDeleteStatus, -} from './MetaMetrics.types'; - -const RCTAnalytics = NativeModules.Analytics; - -const USER_PROFILE_PROPERTY = { - ENABLE_OPENSEA_API: 'Enable OpenSea API', - NFT_AUTODETECTION: 'NFT Autodetection', - THEME: 'Theme', - ON: 'ON', - OFF: 'OFF', - AUTHENTICATION_TYPE: 'Authentication Type', - TOKEN_DETECTION: 'token_detection_enable', - MULTI_ACCOUNT_BALANCE: 'Batch account balance requests', - SECURITY_PROVIDERS: 'security_providers', -}; - -/** - * Class to handle analytics through the app - */ -class Analytics { - /** - * Variables defined in Mixpanel - */ - remoteVariables = {}; - - /** - * Whether the manager has permission to send analytics - */ - enabled; - - /** - * ID from the deletion task - */ - dataDeletionTaskId; - - /** - * Persist current Metrics OptIn flag in user preferences datastore - */ - _storeMetricsOptInPreference = async () => { - try { - await DefaultPreference.set( - METRICS_OPT_IN, - this.enabled ? AGREED : DENIED, - ); - } catch (e) { - Logger.error(e, 'Error storing Metrics OptIn flag in user preferences'); - } - }; - - /** - * Identify current user to mixpanel people - */ - _peopleIdentify = () => { - RCTAnalytics.peopleIdentify(); - }; - - /** - * Set the user profile state for current user to mixpanel - */ - _setUserProfileProperties = () => { - const reduxState = store.getState(); - const preferencesController = - reduxState?.engine?.backgroundState?.PreferencesController; - const appTheme = reduxState?.user?.appTheme; - // This will return either "light" or "dark" - const appThemeStyle = - appTheme === 'os' ? Appearance.getColorScheme() : appTheme; - - RCTAnalytics.setUserProfileProperty( - USER_PROFILE_PROPERTY.ENABLE_OPENSEA_API, - preferencesController?.displayNftMedia - ? USER_PROFILE_PROPERTY.ON - : USER_PROFILE_PROPERTY.OFF, - ); - RCTAnalytics.setUserProfileProperty( - USER_PROFILE_PROPERTY.NFT_AUTODETECTION, - preferencesController?.useNftDetection - ? USER_PROFILE_PROPERTY.ON - : USER_PROFILE_PROPERTY.OFF, - ); - RCTAnalytics.setUserProfileProperty( - USER_PROFILE_PROPERTY.THEME, - appThemeStyle, - ); - // Track token detection toggle - RCTAnalytics.setUserProfileProperty( - USER_PROFILE_PROPERTY.TOKEN_DETECTION, - preferencesController.useTokenDetection - ? USER_PROFILE_PROPERTY.ON - : USER_PROFILE_PROPERTY.OFF, - ); - // Track multi account balance toggle - RCTAnalytics.setUserProfileProperty( - USER_PROFILE_PROPERTY.MULTI_ACCOUNT_BALANCE, - preferencesController.isMultiAccountBalancesEnabled - ? USER_PROFILE_PROPERTY.ON - : USER_PROFILE_PROPERTY.OFF, - ); - - // Track security providers toggle - const securityProviders = preferencesController?.securityAlertsEnabled - ? 'blockaid' - : ''; - - RCTAnalytics.setUserProfileProperty( - USER_PROFILE_PROPERTY.SECURITY_PROVIDERS, - securityProviders, - ); - }; - - /** - * Track event if enabled and not DEV mode - */ - async _trackEvent( - name, - { event, params = {}, value, info, anonymously = false }, - ) { - const isAnalyticsPreferenceSelectedEvent = - MetaMetricsEvents.ANALYTICS_PREFERENCE_SELECTED === event; - if (!this.enabled && !isAnalyticsPreferenceSelectedEvent) return; - this._setUserProfileProperties(); - if (!__DEV__) { - if (!anonymously) { - RCTAnalytics.trackEvent({ - ...event, - ...params, - value, - info, - }); - } else { - RCTAnalytics.trackEventAnonymously({ - ...event, - ...params, - value, - info, - }); - } - - if (!this.isDataRecorded) { - this.isDataRecorded = true; - await DefaultPreference.set( - ANALYTICS_DATA_DELETION_TASK_ID, - this.dataDeletionTaskId, - ); - - await DefaultPreference.set(ANALYTICS_DATA_RECORDED, 'true'); - } - } else { - Logger.log(`Analytics '${name}' -`, event, params, value, info); - } - } - - /** - * Creates a Deletion Task using MixPanel GDPR API - * Reference https://developer.mixpanel.com/docs/privacy-security#create-a-deletion-task - * - * @param {string} compliance - CCPA or GDPR compliance. Default is GDPR. - * @returns Object with the response of the request - * { - * status: ResponseStatus, - * error?: string, - * DataDeleteStatus?: DataDeleteStatus - * } - */ - async _createDataDeletionTask(compliance) { - if (__DEV__) { - // Mock response for DEV env - Logger.log( - `Analytics Deletion Task Created for following ${compliance} compliance`, - ); - return { - status: DataDeleteResponseStatus.ok, - DataDeleteStatus: DataDeleteStatus.pending, - }; - } - const distinctId = await this.getDistinctId(); - const action = 'data-deletions'; - const token = process.env.MM_MIXPANEL_TOKEN; - const url = `${MIXPANEL_PROXY_ENDPOINT_BASE_URL}/${action}/v3.0/?token=${token}`; - try { - const response = await axios({ - url, - method: 'post', - headers: { - Accept: 'application/json', - }, - data: JSON.stringify({ - distinct_ids: [distinctId], - compliance_type: compliance, - }), - }); - - const result = response.data; - - if (result.status === DataDeleteResponseStatus.ok) { - this.dataDeletionTaskId = result.results.task_id; - - await DefaultPreference.set( - ANALYTICS_DATA_DELETION_TASK_ID, - this.dataDeletionTaskId, - ); - - return { - status: result.status, - DataDeleteStatus: DataDeleteResponseStatus.pending, - }; - } - Logger.log(`Analytics Deletion Task Error - ${result.error}`); - return { status: response.status, error: result.error }; - } catch (error) { - Logger.log(`Analytics Deletion Task Error - ${error}`); - return { status: DataDeleteResponseStatus.error, error }; - } - } - - /** - * Creates a Analytics instance - */ - constructor(metricsOptIn, dataDeletionTaskId) { - if (!Analytics.instance) { - this.enabled = metricsOptIn === AGREED; - this.dataDeletionTaskId = dataDeletionTaskId; - this.listeners = []; - Analytics.instance = this; - if (!__DEV__) { - RCTAnalytics.optIn(this.enabled); - this._peopleIdentify(); - } - } - return Analytics.instance; - } - - /** - * Enable analytics - */ - enable = () => { - this.enabled = true; - RCTAnalytics.optIn(this.enabled); - this._storeMetricsOptInPreference(); - }; - - /** - * Disable analytics - */ - disable = () => { - this.enabled = false; - RCTAnalytics.optIn(this.enabled); - this._storeMetricsOptInPreference(); - }; - - /** - * Disable analytics for the current class instance - * It will block sending events internally but it will keep RCTAnalytics enabled until app reload - */ - disableInstance = () => { - this.enabled = false; - this._storeMetricsOptInPreference(); - }; - - /** - * Get current tracking id - */ - getDistinctId = async () => { - const id = await RCTAnalytics.getDistinctId(); - return id; - }; - - /** - * Track event - * - * @param {object} event - Object containing event category, action and name - * @param {boolean} anonymously - Whether the tracking should be without the right distinctId - */ - trackEvent = (event, anonymously = false) => { - this._trackEvent('trackEvent', { event }); - }; - - /** - * Apply User Property - * - * @param {string} property - A string representing the login method of the user. One of biometrics, device_passcode, remember_me, password, unknown - */ - applyUserProperty = (property) => { - switch (property) { - case AUTHENTICATION_TYPE.BIOMETRIC: - RCTAnalytics.setUserProfileProperty( - USER_PROFILE_PROPERTY.AUTHENTICATION_TYPE, - AUTHENTICATION_TYPE.BIOMETRIC, - ); - break; - case AUTHENTICATION_TYPE.PASSCODE: - RCTAnalytics.setUserProfileProperty( - USER_PROFILE_PROPERTY.AUTHENTICATION_TYPE, - AUTHENTICATION_TYPE.PASSCODE, - ); - break; - case AUTHENTICATION_TYPE.REMEMBER_ME: - RCTAnalytics.setUserProfileProperty( - USER_PROFILE_PROPERTY.AUTHENTICATION_TYPE, - AUTHENTICATION_TYPE.REMEMBER_ME, - ); - break; - case AUTHENTICATION_TYPE.PASSWORD: - RCTAnalytics.setUserProfileProperty( - USER_PROFILE_PROPERTY.AUTHENTICATION_TYPE, - AUTHENTICATION_TYPE.PASSWORD, - ); - break; - default: - RCTAnalytics.setUserProfileProperty( - USER_PROFILE_PROPERTY.AUTHENTICATION_TYPE, - AUTHENTICATION_TYPE.UNKOWN, - ); - } - }; - - /** - * Track event with value - * - * @param {object} event - Object containing event category, action and name - * @param {number} value - Value number to send with event - * @param {boolean} anonymously - Whether the tracking should be without the right distinctId - */ - trackEventWithValue = (event, value, anonymously = false) => { - this._trackEvent('trackEventWithValue', { event, value, anonymously }); - }; - - /** - * Track event with information - * - * @param {object} event - Object containing event category, action and name - * @param {string} info - Information string to send with event - * @param {boolean} anonymously - Whether the tracking should be without the right distinctId - */ - trackEventWithInfo = (event, info, anonymously = false) => { - this._trackEvent('trackEventWithInfo', { event, info, anonymously }); - }; - - /** - * Track event with value and information - * - * @param {object} event - Object containing event category, action and name - * @param {number} value - Value number to send with event - * @param {string} info - Information string to send with event - * @param {boolean} anonymously - Whether the tracking should be without the right distinctId - */ - trackEventWithValueAndInfo = (event, value, info, anonymously = false) => { - this._trackEvent('trackEventWithValueAndInfo', { - event, - value, - info, - anonymously, - }); - }; - - /** - * Track event with parameters - * - * @param {object} event - Object containing event category, action and name - * @param {object} params - Object containing other params to send with event - * @param {boolean} anonymously - Whether the tracking should be without the right distinctId - */ - trackEventWithParameters = (event, params, anonymously = false) => { - this._trackEvent('trackEventWithParameters', { - event, - params, - anonymously, - }); - }; - - /** - * Track event with value and parameters - * - * @param {object} event - Object containing event category, action and name - * @param {number} value - Value number to send with event - * @param {object} params - Object containing other params to send with event - * @param {boolean} anonymously - Whether the tracking should be without the right distinctId - */ - trackEventWithValueAndParameters = ( - event, - value, - params, - anonymously = false, - ) => { - this._trackEvent('trackEventWithValueAndParameters', { - event, - value, - params, - anonymously, - }); - }; - - /** - * Track event with value and parameters - * - * @param {object} event - Object containing event category, action and name - * @param {number} value - Value number to send with event - * @param {string} info - Information string to send with event - * @param {object} params - Object containing other params to send with event - * @param {boolean} anonymously - Whether the tracking should be without the right distinctId - */ - trackEventWithValueAndInfoAndParameters = ( - event, - value, - info, - params, - anonymously = false, - ) => { - this._trackEvent('trackEventWithValueAndInfoAndParameters', { - event, - value, - info, - params, - anonymously, - }); - }; -} - -let instance; - -export default { - init: async () => { - const metricsOptIn = await DefaultPreference.get(METRICS_OPT_IN); - const deleteTaskId = await DefaultPreference.get( - ANALYTICS_DATA_DELETION_TASK_ID, - ); - const metametricsId = await DefaultPreference.get(MIXPANEL_METAMETRICS_ID); - instance = new Analytics(metricsOptIn, deleteTaskId); - // MixPanel distinctId stored for consistency purposes between - // Segment and MixPanel - if (!metametricsId) { - const distinctId = await instance.getDistinctId(); - await DefaultPreference.set(MIXPANEL_METAMETRICS_ID, distinctId); - } - try { - const vars = await RCTAnalytics.getRemoteVariables(); - instance.remoteVariables = JSON.parse(vars); - } catch (e) { - // Do nothing - } - return instance; - }, - enable() { - return instance && instance.enable(); - }, - disable() { - return instance && instance.disable(); - }, - disableInstance() { - return instance && instance.disableInstance(); - }, - checkEnabled() { - return instance && instance.enabled; - }, - getDistinctId() { - return instance && instance.getDistinctId(); - }, - trackEvent(event, anonymously) { - return instance && instance.trackEvent(event, anonymously); - }, - applyUserProperty(property) { - return instance && instance.applyUserProperty(property); - }, - trackEventWithParameters(event, parameters, anonymously) { - return ( - instance && - instance.trackEventWithParameters(event, parameters, anonymously) - ); - }, - getRemoteVariables() { - return instance.remoteVariables; - }, - refreshRemoteVariables: async () => { - try { - const vars = await RCTAnalytics.getRemoteVariables(); - instance.remoteVariables = JSON.parse(vars); - } catch (e) { - // Do nothing - } - }, -}; diff --git a/app/core/Analytics/MetaMetrics.events.ts b/app/core/Analytics/MetaMetrics.events.ts index 75ae6b91d52e..de1c1b9de12b 100644 --- a/app/core/Analytics/MetaMetrics.events.ts +++ b/app/core/Analytics/MetaMetrics.events.ts @@ -32,7 +32,7 @@ const ONBOARDING_WIZARD_STEP_DESCRIPTION = { }; /** - * V2 Analytics Tracking Events + * Analytics Tracking Events */ enum EVENT_NAME { // Error @@ -256,7 +256,6 @@ enum EVENT_NAME { RECEIVE_OPTIONS = 'Receive Options', SEND_FLOW = 'Send Flow', DAPP_INTERACTIONS = 'Dapp Interactions', - WALLET = 'Wallet', PAYMENTS = 'Payments', // Swaps @@ -355,7 +354,6 @@ enum ACTIONS { IMPORT_OR_CREATE = 'Import or Create', IMPORT_OR_SYNC = 'Import or Sync', ONBOARDING_NEXT = 'Onboarding Next', - ONBOARDING_SKIP = 'Onboarding Skip', // Navigation Drawer NAVIGATION_DRAWER = 'Navigation Drawer', // Common Navigation @@ -834,7 +832,6 @@ enum DESCRIPTION { ONBOARDING_SELECTED_WITH_SEEDPHRASE = 'Selected Import with Seedphrase', ONBOARDING_SELECTED_TAKE_THE_TOUR = `Onboarding wizard 'Take the tour'`, ONBOARDING_SELECTED_NO_THANKS = `Onboarding wizard 'No thanks'`, - ONBOARDING_SELECTED_SKIP = 'Onboarding wizard Skip', ONBOARDING_SELECTED_SKIP_TUTORIAL = 'Onboarding wizard Skip', // Navigation Drawer NAVIGATION_TAPS_ACCOUNT_NAME = 'Tapped Account Name / Profile', diff --git a/app/core/Analytics/index.ts b/app/core/Analytics/index.ts index a7a517dafc81..6933eed6ba3f 100644 --- a/app/core/Analytics/index.ts +++ b/app/core/Analytics/index.ts @@ -1,4 +1,3 @@ -import Analytics from './Analytics'; import MetaMetrics from './MetaMetrics'; import { MetaMetricsEvents, @@ -12,7 +11,6 @@ import { } from './MetaMetrics.types'; export { - Analytics, MetaMetrics, MetaMetricsEvents, DataDeleteStatus, diff --git a/app/core/SecureKeychain.js b/app/core/SecureKeychain.js index 60d17ac754a7..6fc0e90bebe1 100644 --- a/app/core/SecureKeychain.js +++ b/app/core/SecureKeychain.js @@ -24,8 +24,8 @@ const defaultOptions = { fingerprintPromptDesc: strings('authentication.fingerprint_prompt_desc'), fingerprintPromptCancel: strings('authentication.fingerprint_prompt_cancel'), }; -import Analytics from './Analytics/Analytics'; import AUTHENTICATION_TYPE from '../constants/userProperties'; +import { AUTHENTICATION_TYPE as NATIVE_AUTH_TYPE } from 'react-native-keychain'; /** * Class that wraps Keychain from react-native-keychain * abstracting metamask specific functionality and settings @@ -80,7 +80,9 @@ export default { await AsyncStorage.removeItem(BIOMETRY_CHOICE); await AsyncStorage.removeItem(PASSCODE_CHOICE); // This is called to remove other auth types and set the user back to the default password login - Analytics.applyUserProperty(AUTHENTICATION_TYPE.PASSWORD); + await MetaMetrics.getInstance().addTraitsToUser({ + [NATIVE_AUTH_TYPE]: AUTHENTICATION_TYPE.PASSWORD, + }); return Keychain.resetGenericPassword(options); }, @@ -112,14 +114,21 @@ export default { accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY, }; + const metrics = MetaMetrics.getInstance(); if (type === this.TYPES.BIOMETRICS) { authOptions.accessControl = Keychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET; - Analytics.applyUserProperty(AUTHENTICATION_TYPE.BIOMETRIC); + await metrics.addTraitsToUser({ + [NATIVE_AUTH_TYPE]: AUTHENTICATION_TYPE.BIOMETRIC, + }); } else if (type === this.TYPES.PASSCODE) { authOptions.accessControl = Keychain.ACCESS_CONTROL.DEVICE_PASSCODE; - Analytics.applyUserProperty(AUTHENTICATION_TYPE.PASSCODE); + await metrics.addTraitsToUser({ + [NATIVE_AUTH_TYPE]: AUTHENTICATION_TYPE.PASSCODE, + }); } else if (type === this.TYPES.REMEMBER_ME) { - Analytics.applyUserProperty(AUTHENTICATION_TYPE.REMEMBER_ME); + await metrics.addTraitsToUser({ + [NATIVE_AUTH_TYPE]: AUTHENTICATION_TYPE.REMEMBER_ME, + }); //Don't need to add any parameter } else { // Setting a password without a type does not save it diff --git a/app/util/analyticsV2.js b/app/util/analyticsV2.js deleted file mode 100644 index 4c588335858e..000000000000 --- a/app/util/analyticsV2.js +++ /dev/null @@ -1,96 +0,0 @@ -import { InteractionManager } from 'react-native'; -import DefaultPreference from 'react-native-default-preference'; -import Analytics from '../core/Analytics/Analytics'; -import Logger from './Logger'; -import { DENIED, METRICS_OPT_IN } from '../constants/storage'; - -const generateOpt = (name) => ({ category: name }); - -/** - * This takes params with the following structure: - * { foo : 'this is not anonymous', bar: {value: 'this is anonymous', anonymous: true} } - * @param {Object} eventName - * @param {Object} params - */ -export const trackEventV2 = (eventName, params) => { - const init = async () => { - const metricsOptIn = await DefaultPreference.get(METRICS_OPT_IN); - if (metricsOptIn === DENIED) return; - - InteractionManager.runAfterInteractions(() => { - let anonymousEvent = false; - try { - if (!params || Object.keys(params).length === 0) { - Analytics.trackEvent(eventName); - } - - const userParams = {}; - const anonymousParams = {}; - - for (const key in params) { - const property = params[key]; - - if ( - property && - typeof property === 'object' && - !Array.isArray(property) - ) { - if (property.anonymous) { - anonymousEvent = true; - // Anonymous property - add only to anonymous params - anonymousParams[key] = property.value; - } else { - // Non-anonymous property - add to both - userParams[key] = property.value; - anonymousParams[key] = property.value; - } - } else { - // Non-anonymous properties - add to both - userParams[key] = property; - anonymousParams[key] = property; - } - } - - // Log all non-anonymous properties - if (Object.keys(userParams).length) { - Analytics.trackEventWithParameters(eventName, userParams); - } - - // Log all anonymous properties - if (anonymousEvent && Object.keys(anonymousParams).length) { - Analytics.trackEventWithParameters(eventName, anonymousParams, true); - } - } catch (error) { - Logger.error(error, 'Error logging analytics'); - } - }); - }; - init(); -}; - -/** - * This functions logs errors to analytics instead of sentry. - * The objective is to log errors (that are not errors from our side) like “Invalid Password”. - * An error like this generally means a user inserted the wrong password, so logging to sentry doesn't make sense. - * But we still want to log this to analytics so that we are aware of a rapid increase which may mean it's an error from our side, for example, an error with the encryption library. - * @param {String} type - * @param {String} errorMessage - * @param {String} otherInfo - */ -export const trackErrorAsAnalytics = (type, errorMessage, otherInfo) => { - try { - Analytics.trackEventWithParameters(generateOpt('Error occurred'), { - error: true, - type, - errorMessage, - otherInfo, - }); - } catch (error) { - Logger.error(error, 'Error logging analytics - trackErrorAsAnalytics'); - } -}; - -export default { - trackEvent: trackEventV2, - trackErrorAsAnalytics, -}; diff --git a/app/util/termsOfUse/termsOfUse.ts b/app/util/termsOfUse/termsOfUse.ts index 0b278e35b81d..dac5938bcffe 100644 --- a/app/util/termsOfUse/termsOfUse.ts +++ b/app/util/termsOfUse/termsOfUse.ts @@ -1,6 +1,5 @@ import AppConstants from '../../core/AppConstants'; -import { MetaMetricsEvents } from '../../core/Analytics'; -import { trackEventV2 as trackEvent } from '../analyticsV2'; +import { MetaMetrics, MetaMetricsEvents } from '../../core/Analytics'; import { TRUE, USE_TERMS } from '../../constants/storage'; import Routes from '../../constants/navigation/Routes'; import { strings } from '../../../locales/i18n'; @@ -12,11 +11,11 @@ import AsyncStorage from '../../store/async-storage-wrapper'; const onConfirmUseTerms = async () => { await AsyncStorage.setItem(USE_TERMS, TRUE); - trackEvent(MetaMetricsEvents.USER_TERMS_ACCEPTED, {}); + MetaMetrics.getInstance().trackEvent(MetaMetricsEvents.USER_TERMS_ACCEPTED); }; const useTermsDisplayed = () => { - trackEvent(MetaMetricsEvents.USER_TERMS_SHOWN, {}); + MetaMetrics.getInstance().trackEvent(MetaMetricsEvents.USER_TERMS_SHOWN); }; export default async function navigateTermsOfUse(