Skip to content

Commit

Permalink
chore: Capture currency change in MetaMetrics (#11011)
Browse files Browse the repository at this point in the history
## **Description**

Mobile companion to:
MetaMask/metamask-extension#26876

In order to figure out which currencies we should support 24hr % change,
we need to know which currencies are the most popular.

This adds telemetry to the settings page to capture this.

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MMASSETS-344

## **Manual testing steps**

## **Screenshots/Recordings**

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

---------

Co-authored-by: Nico MASSART <NicolasMassart@users.noreply.github.com>
  • Loading branch information
gambinish and NicolasMassart authored Sep 11, 2024
1 parent fbd9692 commit e2994bb
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 10 deletions.
41 changes: 32 additions & 9 deletions app/components/Views/Settings/GeneralSettings/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ import { toDataUrl } from '../../../../util/blockies.js';
import Jazzicon from 'react-native-jazzicon';
import { ThemeContext, mockTheme } from '../../../../util/theme';
import { selectCurrentCurrency } from '../../../../selectors/currencyRateController';
import { withMetricsAwareness } from '../../../../components/hooks/useMetrics';
import { selectSelectedInternalAccountChecksummedAddress } from '../../../../selectors/accountsController';
import Text, {
TextVariant,
TextColor,
} from '../../../../component-library/components/Texts/Text';
import { MetaMetrics, MetaMetricsEvents } from '../../../../core/Analytics';
import { MetaMetricsEvents } from '../../../../core/Analytics';
import { UserProfileProperty } from '../../../../util/metrics/UserSettingsAnalyticsMetaData/UserProfileAnalyticsMetaData.types';

const diameter = 40;
Expand All @@ -55,6 +56,26 @@ const infuraCurrencyOptions = sortedCurrencies.map(
}),
);

export const updateUserTraitsWithCurrentCurrency = (currency, metrics) => {
// track event and add selected currency to user profile for analytics
const traits = { [UserProfileProperty.CURRENT_CURRENCY]: currency };
metrics.addTraitsToUser(traits);
metrics.trackEvent(MetaMetricsEvents.CURRENCY_CHANGED, {
...traits,
location: 'app_settings',
});
};

export const updateUserTraitsWithCurrencyType = (primaryCurrency, metrics) => {
// track event and add primary currency preference (fiat/crypto) to user profile for analytics
const traits = { [UserProfileProperty.PRIMARY_CURRENCY]: primaryCurrency };
metrics.addTraitsToUser(traits);
metrics.trackEvent(MetaMetricsEvents.PRIMARY_CURRENCY_TOGGLE, {
...traits,
location: 'app_settings',
});
};

const createStyles = (colors) =>
StyleSheet.create({
wrapper: {
Expand Down Expand Up @@ -180,6 +201,10 @@ class Settings extends PureComponent {
* App theme
*/
// appTheme: PropTypes.string,
/**
* Metrics injected by withMetricsAwareness HOC
*/
metrics: PropTypes.object,
};

state = {
Expand All @@ -190,6 +215,7 @@ class Settings extends PureComponent {
selectCurrency = async (currency) => {
const { CurrencyRateController } = Engine.context;
CurrencyRateController.setCurrentCurrency(currency);
updateUserTraitsWithCurrentCurrency(currency, this.props.metrics);
};

selectLanguage = (language) => {
Expand All @@ -206,13 +232,7 @@ class Settings extends PureComponent {
selectPrimaryCurrency = (primaryCurrency) => {
this.props.setPrimaryCurrency(primaryCurrency);

const metrics = MetaMetrics.getInstance();
const traits = { [UserProfileProperty.PRIMARY_CURRENCY]: primaryCurrency };
metrics.addTraitsToUser(traits);
metrics.trackEvent(MetaMetricsEvents.PRIMARY_CURRENCY_TOGGLE, {
...traits,
location: 'app_settings',
});
updateUserTraitsWithCurrencyType(primaryCurrency, this.props.metrics);
};

toggleHideZeroBalanceTokens = (toggleHideZeroBalanceTokens) => {
Expand Down Expand Up @@ -506,4 +526,7 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(setHideZeroBalanceTokens(hideZeroBalanceTokens)),
});

export default connect(mapStateToProps, mapDispatchToProps)(Settings);
export default connect(
mapStateToProps,
mapDispatchToProps,
)(withMetricsAwareness(Settings));
109 changes: 108 additions & 1 deletion app/components/Views/Settings/GeneralSettings/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import React from 'react';
import { shallow } from 'enzyme';
import GeneralSettings from './';
import GeneralSettings, {
updateUserTraitsWithCurrentCurrency,
updateUserTraitsWithCurrencyType,
} from './';
import configureMockStore from 'redux-mock-store';
import { Provider } from 'react-redux';
import { AppThemeKey } from '../../../../util/theme/models';
import { backgroundState } from '../../../../util/test/initial-root-state';
import { MetaMetricsEvents } from '../../../../core/Analytics';
import { UserProfileProperty } from '../../../../util/metrics/UserSettingsAnalyticsMetaData/UserProfileAnalyticsMetaData.types';

jest.mock('../../../../core/Analytics');

const mockStore = configureMockStore();
const initialState = {
Expand Down Expand Up @@ -32,3 +39,103 @@ describe('GeneralSettings', () => {
expect(wrapper).toMatchSnapshot();
});
});

describe('updateUserTraitsWithCurrentCurrency', () => {
let mockMetrics: { addTraitsToUser: () => void; trackEvent: () => void };

beforeEach(() => {
// Create a mock for the metrics object with spies on the required methods
mockMetrics = {
addTraitsToUser: jest.fn(),
trackEvent: jest.fn(),
};
});

afterEach(() => {
jest.clearAllMocks(); // Clear mocks after each test to avoid interference
});

it('adds selected currency trait', () => {
const mockCurrency = 'USD';

updateUserTraitsWithCurrentCurrency(mockCurrency, mockMetrics);

// Check if addTraitsToUser was called with the correct argument
expect(mockMetrics.addTraitsToUser).toHaveBeenCalledWith({
[UserProfileProperty.CURRENT_CURRENCY]: mockCurrency,
});
});

it('tracks currency changed event', () => {
const mockCurrency = 'USD';

updateUserTraitsWithCurrentCurrency(mockCurrency, mockMetrics);

// Check if trackEvent was called with the correct event and properties
expect(mockMetrics.trackEvent).toHaveBeenCalledWith(
MetaMetricsEvents.CURRENCY_CHANGED,
{
[UserProfileProperty.CURRENT_CURRENCY]: mockCurrency,
location: 'app_settings',
},
);
});

it('does not throw errors when a valid currency is passed', () => {
const mockCurrency = 'USD';

expect(() => {
updateUserTraitsWithCurrentCurrency(mockCurrency, mockMetrics);
}).not.toThrow();
});
});

describe('updateUserTraitsWithCurrencyType', () => {
let mockMetrics: { addTraitsToUser: () => void; trackEvent: () => void };

beforeEach(() => {
// Create a mock for the metrics object with spies on the required methods
mockMetrics = {
addTraitsToUser: jest.fn(),
trackEvent: jest.fn(),
};
});

afterEach(() => {
jest.clearAllMocks(); // Reset mocks after each test
});

it('adds the primary currency preference', () => {
const primaryCurrency = 'fiat';

updateUserTraitsWithCurrencyType(primaryCurrency, mockMetrics);

// Check if addTraitsToUser was called with the correct argument
expect(mockMetrics.addTraitsToUser).toHaveBeenCalledWith({
[UserProfileProperty.PRIMARY_CURRENCY]: primaryCurrency,
});
});

it('tracks the primary currency toggle event', () => {
const primaryCurrency = 'crypto';

updateUserTraitsWithCurrencyType(primaryCurrency, mockMetrics);

// Check if trackEvent was called with the correct event and properties
expect(mockMetrics.trackEvent).toHaveBeenCalledWith(
MetaMetricsEvents.PRIMARY_CURRENCY_TOGGLE,
{
[UserProfileProperty.PRIMARY_CURRENCY]: primaryCurrency,
location: 'app_settings',
},
);
});

it('does not throw errors if metrics object is properly passed', () => {
const primaryCurrency = 'fiat';

expect(() => {
updateUserTraitsWithCurrencyType(primaryCurrency, mockMetrics);
}).not.toThrow();
});
});
2 changes: 2 additions & 0 deletions app/core/Analytics/MetaMetrics.events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ enum EVENT_NAME {
// Settings
SETTINGS_VIEWED = 'Settings Viewed',
SETTINGS_UPDATED = 'Settings Updated',
CURRENCY_CHANGED = 'Selected Currency Changed',

// Reveal SRP
REVEAL_SRP_CTA = 'Clicks Reveal Secret Recovery Phrase',
Expand Down Expand Up @@ -472,6 +473,7 @@ const events = {
EVENT_NAME.COLLECTIBLE_DETAILS_OPENED,
),
COLLECTIBLE_REMOVED: generateOpt(EVENT_NAME.COLLECTIBLE_REMOVED),
CURRENCY_CHANGED: generateOpt(EVENT_NAME.CURRENCY_CHANGED),
NETWORK_SWITCHED: generateOpt(EVENT_NAME.NETWORK_SWITCHED),
NETWORK_ADDED: generateOpt(EVENT_NAME.NETWORK_ADDED),
NETWORK_REQUESTED: generateOpt(EVENT_NAME.NETWORK_REQUESTED),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export enum UserProfileProperty {
MULTI_ACCOUNT_BALANCE = 'Batch account balance requests',
SECURITY_PROVIDERS = 'security_providers',
PRIMARY_CURRENCY = 'primary_currency',
CURRENT_CURRENCY = 'current_currency',
}

export interface UserProfileMetaData {
Expand All @@ -20,4 +21,5 @@ export interface UserProfileMetaData {
[UserProfileProperty.MULTI_ACCOUNT_BALANCE]: string;
[UserProfileProperty.SECURITY_PROVIDERS]: string;
[UserProfileProperty.PRIMARY_CURRENCY]?: string;
[UserProfileProperty.CURRENT_CURRENCY]?: string;
}

0 comments on commit e2994bb

Please sign in to comment.