Skip to content

Commit

Permalink
rework of new event object
Browse files Browse the repository at this point in the history
encapsulate
track function overload
  • Loading branch information
NicolasMassart committed Sep 27, 2024
1 parent 781238e commit 4233171
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 93 deletions.
7 changes: 3 additions & 4 deletions app/components/UI/NetworkModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const NetworkModals = (props: NetworkProps) => {
onNetworkSwitch,
safeChains,
} = props;
const { createEventBuilder } = useMetrics();
const { trackEvent, createEventBuilder } = useMetrics();
const [showDetails, setShowDetails] = React.useState(false);
const [networkAdded, setNetworkAdded] = React.useState(false);
const [showCheckNetwork, setShowCheckNetwork] = React.useState(false);
Expand Down Expand Up @@ -107,14 +107,13 @@ const NetworkModals = (props: NetworkProps) => {
const isValidUrl = validateRpcUrl(rpcUrl);
if (showPopularNetworkModal) {
// track popular network
createEventBuilder(MetaMetricsEvents.NETWORK_ADDED)
trackEvent(createEventBuilder(MetaMetricsEvents.NETWORK_ADDED)

Check failure on line 110 in app/components/UI/NetworkModal/index.tsx

View workflow job for this annotation

GitHub Actions / scripts (lint:tsc)

Argument of type 'ITrackingEvent' is not assignable to parameter of type 'IMetaMetricsEvent'.
.addProperties({
chain_id: toHex(chainId),
source: 'Popular network list',
symbol: ticker,
})
.build()
.track();
.build());
} else if (safeChains) {
const { safeChain, safeRPCUrl } = rpcIdentifierUtility(
rpcUrl,
Expand Down
1 change: 1 addition & 0 deletions app/components/hooks/useMetrics/useMetrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ const useMetrics = (): IUseMetricsHook => {

return {
trackEvent,
track: MetaMetrics.getInstance().track,

Check failure on line 114 in app/components/hooks/useMetrics/useMetrics.ts

View workflow job for this annotation

GitHub Actions / scripts (lint:tsc)

Property 'track' does not exist on type 'IMetaMetrics'.
enable: MetaMetrics.getInstance().enable,
addTraitsToUser: MetaMetrics.getInstance().addTraitsToUser,
createDataDeletionTask: MetaMetrics.getInstance().createDataDeletionTask,
Expand Down
13 changes: 11 additions & 2 deletions app/components/hooks/useMetrics/useMetrics.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
IDeleteRegulationStatus,
IMetaMetricsEvent,
} from '../../../core/Analytics/MetaMetrics.types';
import MetricsEventBuilder from '../../../core/Analytics/MetricsEventBuilder';
import { MetricsEventBuilder, ITrackingEvent} from '../../../core/Analytics/MetricsEventBuilder';

export const SourceType = {
SDK: 'sdk',
Expand All @@ -22,13 +22,22 @@ export interface IUseMetricsHook {
addTraitsToUser(userTraits: UserTraits): Promise<void>;

/**
* @deprecated use {@link MetricsEventBuilder} instead
* @deprecated use {@link track} instead
*/
trackEvent(
event: IMetaMetricsEvent,
properties?: CombinedProperties,
saveDataRecording?: boolean,
): void;
/**
* track an event
* @param event - Analytics event build with {@link MetricsEventBuilder}
* @param saveDataRecording - param to skip saving the data recording flag (optional)
*/
track(
event: ITrackingEvent,
saveDataRecording?: boolean,
): void;
createDataDeletionTask(): Promise<IDeleteRegulationResponse>;
checkDataDeleteStatus(): Promise<IDeleteRegulationStatus>;
getDeleteRegulationCreationDate(): DataDeleteDate;
Expand Down
103 changes: 75 additions & 28 deletions app/core/Analytics/MetaMetrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ import {
IDeleteRegulationStatusResponse,
IMetaMetrics,
IMetaMetricsEvent,
isCombinedProperties,
ISegmentClient,
isTrackingEvent,
} from './MetaMetrics.types';
import { METAMETRICS_ANONYMOUS_ID } from './MetaMetrics.constants';
import { v4 as uuidv4 } from 'uuid';
Expand All @@ -39,6 +41,7 @@ import generateDeviceAnalyticsMetaData from '../../util/metrics/DeviceAnalyticsM
import generateUserSettingsAnalyticsMetaData from '../../util/metrics/UserSettingsAnalyticsMetaData/generateUserProfileAnalyticsMetaData';
import { isE2E } from '../../util/test/utils';
import convertLegacyProperties from '../../util/events/convertLegacyProperties';
import { ITrackingEvent } from './MetricsEventBuilder';

/**
* MetaMetrics using Segment as the analytics provider.
Expand Down Expand Up @@ -336,14 +339,14 @@ class MetaMetrics implements IMetaMetrics {
};

/**
* Track an analytics event
* Send an analytics event to the Segment SDK track function
*
* @param event - Analytics event name
* @param properties - Object containing any event relevant traits or properties (optional)
* @param saveDataRecording - param to skip saving the data recording flag (optional)
* @see https://segment.com/docs/connections/sources/catalog/libraries/mobile/react-native/#track
*/
#trackEvent = (
#trackWithSdkClient = (
event: string,
properties: JsonMap,
saveDataRecording = true,
Expand Down Expand Up @@ -616,6 +619,21 @@ class MetaMetrics implements IMetaMetrics {
return Promise.resolve();
};

/**
* Legacy event tracking
*
* @param event - Legacy analytics event
* @param properties - Object containing any event relevant traits or properties (optional).
* @param saveDataRecording - param to skip saving the data recording flag (optional)
* @deprecated use new {@link isTrackingEvent( event: ITrackingEvent, saveDataRecording: boolean)}
*/
trackEvent(
// Legacy signature
event: IMetaMetricsEvent,
properties?: CombinedProperties,
saveDataRecording?: boolean,
): void;

/**
* Track an event
*
Expand Down Expand Up @@ -662,58 +680,87 @@ class MetaMetrics implements IMetaMetrics {
* sensitiveProperties: { ...anonymousParameters },
* });
*
* @param event - Analytics event name
* @param properties - Object containing any event relevant traits or properties (optional).
* @param event - Analytics event built with {@link MetricsEventBuilder}
* @param saveDataRecording - param to skip saving the data recording flag (optional)
*/
trackEvent = (
event: IMetaMetricsEvent,
properties: CombinedProperties = {},
saveDataRecording = true,
): void => {
trackEvent(
// New signature
event: ITrackingEvent,
saveDataRecording?: boolean,
): void;

// Implementation
trackEvent(
_event: IMetaMetricsEvent | ITrackingEvent,
_propertiesOrSaveData?: CombinedProperties | boolean,
_saveData?: boolean,
): void {
if (!this.enabled) {
return;
}

// type guard for optional boolean properties
const isSaveDataRecording = (value: unknown): value is boolean =>
typeof value === 'boolean';

// set all the implementation variables to match one of the two signatures
const isNewEventType = isTrackingEvent(_event);
const legacyProperties = isCombinedProperties(_propertiesOrSaveData)
? _propertiesOrSaveData
: {};
const hasProperties = isNewEventType
? _event.hasProperties
: legacyProperties && Object.keys(legacyProperties).length;
const saveDataRecording = isSaveDataRecording(_propertiesOrSaveData)
? _propertiesOrSaveData
: _saveData || true;

// if event does not have properties, only send the non-anonymous empty event
// and return to prevent any additional processing
if (!properties || Object.keys(properties).length === 0) {
this.#trackEvent(
event?.category,
// pass the IMetaMetricsEvent properties in the tracking props in case they exist(if it's a legacy event)
{ anonymous: false, ...event?.properties },
if (!hasProperties) {
this.#trackWithSdkClient(
isNewEventType ? _event.name : _event?.category,
{ anonymous: false },
saveDataRecording,
);
return;
}

// if event has properties, convert then to the new EventProperties format,
const convertedProperties = convertLegacyProperties(properties);
// if event is new format, use the props directly,
// otherwise if it is legacy and has properties, convert then to the new EventProperties format first,
const convertedLegacyProperties = convertLegacyProperties(legacyProperties);

// Log all non-anonymous properties, or an empty event if there's no non-anon props.
// In any case, there's a non-anon event tracked, see MetaMetrics.test.ts Tracking table.
this.#trackEvent(
event?.category,
{ anonymous: false, ...convertedProperties.properties },
this.#trackWithSdkClient(
isNewEventType ? _event.name : _event?.category,
{
anonymous: false,
...(isNewEventType
? _event.properties
: convertedLegacyProperties.properties),
},
saveDataRecording,
);

const isAnonymous = isNewEventType
? _event.isAnonymous
: convertedLegacyProperties.sensitiveProperties &&
Object.keys(convertedLegacyProperties.sensitiveProperties).length;

// Track all anonymous properties in an anonymous event
if (
convertedProperties.sensitiveProperties &&
Object.keys(convertedProperties.sensitiveProperties).length
) {
this.#trackEvent(
event.category,
if (isAnonymous) {
this.#trackWithSdkClient(
isNewEventType ? _event.name : _event?.category,
{
anonymous: true,
...convertedProperties.sensitiveProperties,
...convertedProperties.properties,
...convertedLegacyProperties.sensitiveProperties,
...convertedLegacyProperties.properties,
},
saveDataRecording,
);
}
};
}

/**
* Clear the internal state of the library for the current user and reset the user ID
Expand Down
59 changes: 53 additions & 6 deletions app/core/Analytics/MetaMetrics.types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import type {
JsonMap,
UserTraits,
GroupTraits,
} from '@segment/analytics-react-native';

import type { UserTraits, GroupTraits } from '@segment/analytics-react-native';
/**
* custom implementation of the Segment ClientMethods type
* Allows to mock the Segment client
Expand Down Expand Up @@ -55,12 +50,19 @@ export interface IMetaMetrics {
* @param event - Analytics event
* @param properties - Object containing any event relevant traits or properties (optional).
* @param saveDataRecording - param to skip saving the data recording flag (optional)
* @deprecated use {@link track} instead
*/
trackEvent(
event: IMetaMetricsEvent,
properties?: CombinedProperties,
saveDataRecording?: boolean,
): void;
/**
* track an event
* @param event - ITrackingEvent event build with {@link MetricsEventBuilder}
* @param saveDataRecording - param to skip saving the data recording flag (optional)
*/
trackEvent(event: ITrackingEvent, saveDataRecording?: boolean): void;
/**
* clear the internal state of the library for the current user and group.
*/
Expand Down Expand Up @@ -89,6 +91,44 @@ export interface IMetaMetrics {
getMetaMetricsId(): Promise<string | undefined>;
}

/**
* represents values that can be passed as properties to the event tracking function
* It's a proxy type to the JsonValue type from Segment SDK in order to decouple the SDK from the app
*/
export type JsonValue =
| boolean
| number
| string
| null
| JsonValue[]
| JsonMap
| undefined;

/**
* represents the map object used to pass properties to the event tracking function
* It's a proxy type to the JsonMap type from Segment SDK in order to decouple the SDK from the app
*/
export interface JsonMap {
[key: string]: JsonValue;
[index: number]: JsonValue;
}

/**
* type guard to check if the event is a tracking event
*/
export const isTrackingEvent = (
event: IMetaMetricsEvent | ITrackingEvent,
): event is ITrackingEvent =>
(event as ITrackingEvent).saveDataRecording !== undefined;

export interface ITrackingEvent {
readonly name: string;
properties: JsonMap;
sensitiveProperties: JsonMap;
saveDataRecording: boolean;
get isAnonymous(): boolean;
get hasProperties(): boolean;
}
/**
* MetaMetrics event interface
*/
Expand Down Expand Up @@ -150,5 +190,12 @@ export interface EventProperties {
sensitiveProperties?: JsonMap;
}

export const isCombinedProperties = (
properties: CombinedProperties | boolean | undefined,
): properties is CombinedProperties =>
typeof properties === 'object' &&
properties !== null &&
!Array.isArray(properties);

// EventProperties is the new type, direct JsonMap is for backward compatibility
export type CombinedProperties = JsonMap | EventProperties;
Loading

0 comments on commit 4233171

Please sign in to comment.