Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use Segment (batch 1) #8067

Merged
merged 43 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
c047917
feat: create Segment analytics implementation + use geo-localization …
NicolasMassart Dec 6, 2023
886a8b1
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Dec 6, 2023
e6dcad4
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Dec 6, 2023
e457b27
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Dec 8, 2023
726fd80
feat: Use new Segment implementation in onboarding steps (Batch 3 of …
NicolasMassart Dec 8, 2023
92c5dc9
fix: rename Segment env vars and add in example file (#8059)
NicolasMassart Dec 11, 2023
6cac642
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Dec 11, 2023
c2af79a
Merge branch 'feat/batch_1129_segment' of github.com:MetaMask/metamas…
NicolasMassart Dec 11, 2023
265d1a9
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Dec 12, 2023
e34d62e
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Dec 12, 2023
9197580
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Dec 14, 2023
b43425f
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Dec 14, 2023
ad1022d
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Jan 3, 2024
da3f72d
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Jan 8, 2024
054b3b6
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Jan 9, 2024
df791dd
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Jan 10, 2024
8e795c6
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Jan 16, 2024
88dfddd
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Jan 22, 2024
f199acc
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Jan 22, 2024
8419e09
feat: segment data deletion (4/4) (#8090)
NicolasMassart Jan 23, 2024
723ff5d
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Jan 23, 2024
5e871ce
feat: Segment instance error handling (#8218)
NicolasMassart Jan 24, 2024
ad72be1
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Jan 24, 2024
23b4675
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Jan 29, 2024
e2440c3
update lockfile
NicolasMassart Jan 29, 2024
06a526e
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Jan 30, 2024
f6be241
feat: a hook to use Segment metrics (#8471)
NicolasMassart Feb 2, 2024
99194b0
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Feb 2, 2024
6b5cc4c
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Feb 13, 2024
80b9408
feat: migrate Segment core mechanism [split of 8387] (#8573)
NicolasMassart Feb 14, 2024
18106c2
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Feb 16, 2024
c9e1667
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Feb 16, 2024
780e6aa
fix import and getInstance call
NicolasMassart Feb 16, 2024
ed3dc7a
remove await
NicolasMassart Feb 16, 2024
f3feb39
use hook
NicolasMassart Feb 16, 2024
0ff5c5a
Merge branch 'main' into feat/batch_1129_segment
NicolasMassart Feb 16, 2024
729cbfa
use env var for endpoint
NicolasMassart Feb 19, 2024
8629533
add test env for metametrics
NicolasMassart Feb 19, 2024
61bbe56
make type for track consistent between class and hook
NicolasMassart Feb 19, 2024
bfaa528
fix configure
NicolasMassart Feb 20, 2024
00b0f3a
fix test
NicolasMassart Feb 20, 2024
af34152
fix type
NicolasMassart Feb 20, 2024
502a9ff
optimise metrics settings
NicolasMassart Feb 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .js.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,9 @@ export WATCHER_PORT=8081
export METAMASK_ENVIRONMENT=""

# Build type: "main" or "flask"
export METAMASK_BUILD_TYPE=""
export METAMASK_BUILD_TYPE=""

# Segment SDK proxy endpoint and write key
export SEGMENT_WRITE_KEY=""
export SEGMENT_PROXY_URL=""
export SEGMENT_DELETE_API_SOURCE_ID=""
2 changes: 2 additions & 0 deletions app/components/Nav/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ import AsyncStorage from '../../../store/async-storage-wrapper';
import ShowIpfsGatewaySheet from '../../Views/ShowIpfsGatewaySheet/ShowIpfsGatewaySheet';
import ShowDisplayNftMediaSheet from '../../Views/ShowDisplayMediaNFTSheet/ShowDisplayNFTMediaSheet';
import AmbiguousAddressSheet from '../../../../app/components/Views/Settings/Contacts/AmbiguousAddressSheet/AmbiguousAddressSheet';
import MetaMetrics from '../../../core/Analytics/MetaMetrics';

const clearStackNavigatorOptions = {
headerShown: false,
Expand Down Expand Up @@ -354,6 +355,7 @@ const App = ({ userLoggedIn }) => {

useEffect(() => {
const initAnalytics = async () => {
await MetaMetrics.getInstance();
await Analytics.init();
};

Expand Down
88 changes: 52 additions & 36 deletions app/components/UI/OptinMetrics/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,14 @@ import { getOptinMetricsNavbarOptions } from '../Navbar';
import { strings } from '../../../../locales/i18n';
import setOnboardingWizardStep from '../../../actions/wizard';
import { connect } from 'react-redux';
import Analytics from '../../../core/Analytics/Analytics';
import { clearOnboardingEvents } from '../../../actions/onboarding';
import {
ONBOARDING_WIZARD,
METRICS_OPT_IN,
DENIED,
AGREED,
} from '../../../constants/storage';
import { ONBOARDING_WIZARD } from '../../../constants/storage';
import AppConstants from '../../../core/AppConstants';
import { MetaMetricsEvents } from '../../../core/Analytics';
import AnalyticsV2 from '../../../util/analyticsV2';
import {
Analytics,
MetaMetrics,
MetaMetricsEvents,
} from '../../../core/Analytics';

import DefaultPreference from 'react-native-default-preference';
import { ThemeContext } from '../../../util/theme';
Expand All @@ -45,6 +42,9 @@ import Button, {
} from '../../../component-library/components/Buttons/Button';
import { MAINNET } from '../../../constants/network';
import Routes from '../../../constants/navigation/Routes';
import generateDeviceAnalyticsMetaData, {
UserSettingsAnalyticsMetaData as generateUserSettingsAnalyticsMetaData,
} from '../../../util/metrics';

const createStyles = ({ colors }) =>
StyleSheet.create({
Expand Down Expand Up @@ -260,32 +260,17 @@ class OptinMetrics extends PureComponent {
);
};

/**
* Track the event of opt in or opt out.
* @param AnalyticsOptionSelected - User selected option regarding the tracking of events
*/
trackOptInEvent = (AnalyticsOptionSelected) => {
InteractionManager.runAfterInteractions(async () => {
AnalyticsV2.trackEvent(MetaMetricsEvents.ANALYTICS_PREFERENCE_SELECTED, {
analytics_option_selected: AnalyticsOptionSelected,
updated_after_onboarding: false,
});
});
};

/**
* Callback on press cancel
*/
onCancel = async () => {
const { events } = this.props;
const metricsOptionSelected = 'Metrics Opt Out';
setTimeout(async () => {
if (events && events.length) {
events.forEach((eventArgs) => AnalyticsV2.trackEvent(...eventArgs));
}
this.trackOptInEvent(metricsOptionSelected);
const metrics = await MetaMetrics.getInstance();
// if users refuses tracking, get rid of the stored events
// and never send them to Segment
// and disable analytics
this.props.clearOnboardingEvents();
await DefaultPreference.set(METRICS_OPT_IN, DENIED);
await metrics.enable(false);
Analytics.disableInstance();
}, 200);
this.continue();
Expand All @@ -296,16 +281,47 @@ class OptinMetrics extends PureComponent {
*/
onConfirm = async () => {
const { events } = this.props;
const metricsOptionSelected = 'Metrics Opt In';
Analytics.enable();
setTimeout(async () => {
const metrics = await MetaMetrics.getInstance();
await metrics.enable();
InteractionManager.runAfterInteractions(async () => {
// add traits to user for identification
// consolidate device and user settings traits
const consolidatedTraits = {
...generateDeviceAnalyticsMetaData(),
...generateUserSettingsAnalyticsMetaData(),
};
await metrics.addTraitsToUser(consolidatedTraits);

// track onboarding events that were stored before user opted in
// only if the user eventually opts in.
if (events && events.length) {
events.forEach((eventArgs) => AnalyticsV2.trackEvent(...eventArgs));
let delay = 0; // Initialize delay
const eventTrackingDelay = 200; // ms delay between each event
events.forEach((eventArgs) => {
// delay each event to prevent them from
// being tracked with the same timestamp
// which would cause them to be grouped together
// by sentAt time in the Segment dashboard
// as precision is only to the milisecond
// and loop seems to runs faster than that
setTimeout(() => {
metrics.trackEvent(...eventArgs);
}, delay);
delay += eventTrackingDelay;
});
}
this.trackOptInEvent(metricsOptionSelected);

this.props.clearOnboardingEvents();
await DefaultPreference.set(METRICS_OPT_IN, AGREED);
}, 200);

// track event for user opting in
metrics.trackEvent(
MetaMetricsEvents.ANALYTICS_PREFERENCE_SELECTED.category,
{
analytics_option_selected: 'Metrics Opt In',
updated_after_onboarding: false,
},
);
});
this.continue();
};

Expand Down
23 changes: 11 additions & 12 deletions app/components/Views/AccountBackupStep1/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
SafeAreaView,
StyleSheet,
BackHandler,
InteractionManager,
} from 'react-native';
import PropTypes from 'prop-types';
import { fontStyles } from '../../../styles/common';
Expand All @@ -27,12 +26,12 @@ import SeedPhraseVideo from '../../UI/SeedPhraseVideo';
import { connect } from 'react-redux';
import setOnboardingWizardStep from '../../../actions/wizard';
import { MetaMetricsEvents } from '../../../core/Analytics';
import AnalyticsV2 from '../../../util/analyticsV2';

import DefaultPreference from 'react-native-default-preference';
import { useTheme } from '../../../util/theme';
import trackAfterInteractions from '../../../util/metrics/TrackAfterInteraction/trackAfterInteractions';
import Logger from '../../../util/Logger';
import { ManualBackUpStepsSelectorsIDs } from '../../../../e2e/selectors/Onboarding/ManualBackUpSteps.selectors';

const createStyles = (colors) =>
StyleSheet.create({
mainWrapper: {
Expand Down Expand Up @@ -128,6 +127,12 @@ const AccountBackupStep1 = (props) => {
const { colors } = useTheme();
const styles = createStyles(colors);

const track = (event, properties) => {
trackAfterInteractions(event, properties).catch(() => {
Logger.log('AccountBackupStep1', `Failed to track ${event}`);
});
};

useEffect(() => {
navigation.setOptions({
...getOnboardingNavbarOptions(
Expand Down Expand Up @@ -161,18 +166,14 @@ const AccountBackupStep1 = (props) => {

const goNext = () => {
props.navigation.navigate('AccountBackupStep1B', { ...props.route.params });
InteractionManager.runAfterInteractions(() => {
AnalyticsV2.trackEvent(MetaMetricsEvents.WALLET_SECURITY_STARTED);
});
track(MetaMetricsEvents.WALLET_SECURITY_STARTED);
};

const showRemindLater = () => {
if (hasFunds) return;

setRemindLaterModal(true);
InteractionManager.runAfterInteractions(() => {
AnalyticsV2.trackEvent(MetaMetricsEvents.WALLET_SECURITY_SKIP_INITIATED);
});
track(MetaMetricsEvents.WALLET_SECURITY_SKIP_INITIATED);
};

const toggleSkipCheckbox = () =>
Expand All @@ -190,9 +191,7 @@ const AccountBackupStep1 = (props) => {

const skip = async () => {
hideRemindLaterModal();
InteractionManager.runAfterInteractions(() => {
AnalyticsV2.trackEvent(MetaMetricsEvents.WALLET_SECURITY_SKIP_CONFIRMED);
});
track(MetaMetricsEvents.WALLET_SECURITY_SKIP_CONFIRMED);
// Get onboarding wizard state
const onboardingWizard = await DefaultPreference.get(ONBOARDING_WIZARD);
if (onboardingWizard) {
Expand Down
16 changes: 9 additions & 7 deletions app/components/Views/AccountBackupStep1B/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
StyleSheet,
Image,
Dimensions,
InteractionManager,
} from 'react-native';
import PropTypes from 'prop-types';
import Icon from 'react-native-vector-icons/FontAwesome';
Expand All @@ -23,9 +22,10 @@ import SeedphraseModal from '../../UI/SeedphraseModal';
import { getOnboardingNavbarOptions } from '../../UI/Navbar';
import { CHOOSE_PASSWORD_STEPS } from '../../../constants/onboarding';
import { MetaMetricsEvents } from '../../../core/Analytics';
import AnalyticsV2 from '../../../util/analyticsV2';

import { useTheme } from '../../../util/theme';
import trackAfterInteractions from '../../../util/metrics/TrackAfterInteraction/trackAfterInteractions';
import Logger from '../../../util/Logger';
import { ManualBackUpStepsSelectorsIDs } from '../../../../e2e/selectors/Onboarding/ManualBackUpSteps.selectors';

const explain_backup_seedphrase = require('../../../images/explain-backup-seedphrase.png'); // eslint-disable-line
Expand Down Expand Up @@ -206,17 +206,19 @@ const AccountBackupStep1B = (props) => {
const { colors } = useTheme();
const styles = createStyles(colors);

const track = (event, properties) => {
trackAfterInteractions(event, properties).catch(() => {
Logger.log('AccountBackupStep1B', `Failed to track ${event}`);
});
};

useEffect(() => {
navigation.setOptions(getOnboardingNavbarOptions(route, {}, colors));
}, [navigation, route, colors]);

const goNext = () => {
props.navigation.navigate('ManualBackupStep1', { ...props.route.params });
InteractionManager.runAfterInteractions(() => {
AnalyticsV2.trackEvent(
MetaMetricsEvents.WALLET_SECURITY_MANUAL_BACKUP_INITIATED,
);
});
track(MetaMetricsEvents.WALLET_SECURITY_MANUAL_BACKUP_INITIATED);
};

const learnMore = () => {
Expand Down
35 changes: 17 additions & 18 deletions app/components/Views/ChoosePassword/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
SafeAreaView,
StyleSheet,
Image,
InteractionManager,
} from 'react-native';
import CheckBox from '@react-native-community/checkbox';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
Expand Down Expand Up @@ -55,7 +54,6 @@ import {

import { CHOOSE_PASSWORD_STEPS } from '../../../constants/onboarding';
import { MetaMetricsEvents } from '../../../core/Analytics';
import AnalyticsV2 from '../../../util/analyticsV2';
import { Authentication } from '../../../core';
import AUTHENTICATION_TYPE from '../../../constants/userProperties';
import { ThemeContext, mockTheme } from '../../../util/theme';
Expand All @@ -64,6 +62,7 @@ import AnimatedFox from 'react-native-animated-fox';
import { LoginOptionsSwitch } from '../../UI/LoginOptionsSwitch';
import navigateTermsOfUse from '../../../util/termsOfUse/termsOfUse';
import { ChoosePasswordSelectorsIDs } from '../../../../e2e/selectors/Onboarding/ChoosePassword.selectors';
import trackAfterInteractions from '../../../util/metrics/TrackAfterInteraction/trackAfterInteractions';

const createStyles = (colors) =>
StyleSheet.create({
Expand Down Expand Up @@ -260,6 +259,12 @@ class ChoosePassword extends PureComponent {
// Flag to know if password in keyring was set or not
keyringControllerPasswordSet = false;

track = (event, properties) => {
trackAfterInteractions(event, properties).catch(() => {
Logger.log('ChoosePassword', `Failed to track ${event}`);
});
};

updateNavBar = () => {
const { route, navigation } = this.props;
const colors = this.context.colors || mockTheme.colors;
Expand Down Expand Up @@ -338,9 +343,7 @@ class ChoosePassword extends PureComponent {
Alert.alert('Error', strings('choose_password.password_dont_match'));
return;
}
InteractionManager.runAfterInteractions(() => {
AnalyticsV2.trackEvent(MetaMetricsEvents.WALLET_CREATION_ATTEMPTED);
});
this.track(MetaMetricsEvents.WALLET_CREATION_ATTEMPTED);

try {
this.setState({ loading: true });
Expand All @@ -367,14 +370,12 @@ class ChoosePassword extends PureComponent {
this.props.setLockTime(AppConstants.DEFAULT_LOCK_TIMEOUT);
this.setState({ loading: false });
this.props.navigation.replace('AccountBackupStep1');
InteractionManager.runAfterInteractions(() => {
AnalyticsV2.trackEvent(MetaMetricsEvents.WALLET_CREATED, {
biometrics_enabled: Boolean(this.state.biometryType),
});
AnalyticsV2.trackEvent(MetaMetricsEvents.WALLET_SETUP_COMPLETED, {
wallet_setup_type: 'new',
new_wallet: true,
});
this.track(MetaMetricsEvents.WALLET_CREATED, {
biometrics_enabled: Boolean(this.state.biometryType),
});
this.track(MetaMetricsEvents.WALLET_SETUP_COMPLETED, {
wallet_setup_type: 'new',
new_wallet: true,
});
} catch (error) {
try {
Expand All @@ -397,11 +398,9 @@ class ChoosePassword extends PureComponent {
} else {
this.setState({ loading: false, error: error.toString() });
}
InteractionManager.runAfterInteractions(() => {
AnalyticsV2.trackEvent(MetaMetricsEvents.WALLET_SETUP_FAILURE, {
wallet_setup_type: 'new',
error_type: error.toString(),
});
this.track(MetaMetricsEvents.WALLET_SETUP_FAILURE, {
wallet_setup_type: 'new',
error_type: error.toString(),
});
}
};
Expand Down
Loading
Loading