Skip to content

Commit

Permalink
chore: add analytics to install modal (#1189)
Browse files Browse the repository at this point in the history
* chore: adding core analytics structure

* added all events and params

* tidy

* fix lint & test

* pr comments

* pr fixes
  • Loading branch information
chakra-guy authored Jan 13, 2025
1 parent f4dacaa commit 29f6598
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 7 deletions.
4 changes: 4 additions & 0 deletions packages/sdk-install-modal-web/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* It contains typing information for all components that exist in this project.
*/
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
import { TrackingEvents } from "./components/misc/tracking-events";
export { TrackingEvents } from "./components/misc/tracking-events";
export namespace Components {
interface MmInstallModal {
/**
Expand Down Expand Up @@ -47,6 +49,7 @@ declare global {
interface HTMLMmInstallModalElementEventMap {
"close": any;
"startDesktopOnboarding": any;
"trackAnalytics": { event: TrackingEvents, params?: Record<string, unknown> };
}
interface HTMLMmInstallModalElement extends Components.MmInstallModal, HTMLStencilElement {
addEventListener<K extends keyof HTMLMmInstallModalElementEventMap>(type: K, listener: (this: HTMLMmInstallModalElement, ev: MmInstallModalCustomEvent<HTMLMmInstallModalElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
Expand Down Expand Up @@ -113,6 +116,7 @@ declare namespace LocalJSX {
"link"?: string;
"onClose"?: (event: MmInstallModalCustomEvent<any>) => void;
"onStartDesktopOnboarding"?: (event: MmInstallModalCustomEvent<any>) => void;
"onTrackAnalytics"?: (event: MmInstallModalCustomEvent<{ event: TrackingEvents, params?: Record<string, unknown> }>) => void;
"preferDesktop"?: boolean;
"sdkVersion"?: string;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum TrackingEvents {
SDK_MODAL_VIEWED = 'sdk_modal_viewed',
SDK_MODAL_BUTTON_CLICKED = 'sdk_modal_button_clicked',
SDK_MODAL_TOGGLE_CHANGED = 'sdk_modal_toggle_changed',
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import CloseButton from '../misc/CloseButton';
import Logo from '../misc/Logo';
import encodeQR from '@paulmillr/qr';
import { SimpleI18n } from '../misc/simple-i18n';
import { TrackingEvents } from '../misc/tracking-events';

@Component({
tag: 'mm-install-modal',
styleUrl: '../style.css',
Expand All @@ -31,6 +33,8 @@ export class InstallModal {

@Event() startDesktopOnboarding: EventEmitter;

@Event() trackAnalytics: EventEmitter<{ event: TrackingEvents, params?: Record<string, unknown> }>;

@State() tab: number = 1;

@State() isDefaultTab: boolean = true;
Expand All @@ -49,6 +53,16 @@ export class InstallModal {
this.i18nInstance = new SimpleI18n();
}

componentDidLoad() {
this.trackAnalytics.emit({
event: TrackingEvents.SDK_MODAL_VIEWED,
params: {
extensionInstalled: false,
tab: this.tab === 1 ? 'desktop' : 'mobile',
},
});
}

async connectedCallback() {
await this.i18nInstance.init({
fallbackLng: 'en'
Expand All @@ -70,11 +84,27 @@ export class InstallModal {
}

onStartDesktopOnboardingHandler() {
this.trackAnalytics.emit({
event: TrackingEvents.SDK_MODAL_BUTTON_CLICKED,
params: {
button_type: 'install_extension',
tab: 'desktop',
},
});
this.startDesktopOnboarding.emit();
}

setTab(newTab: number) {
this.tab = newTab
setTab(newTab: number, isUserAction: boolean = false) {
if (isUserAction) {
this.trackAnalytics.emit({
event: TrackingEvents.SDK_MODAL_TOGGLE_CHANGED,
params: {
toggle: this.tab === 1 ? 'desktop_to_mobile' : 'mobile_to_desktop',
},
});
}

this.tab = newTab;
this.isDefaultTab = false;
}

Expand All @@ -84,8 +114,7 @@ export class InstallModal {
}

const t = (key: string) => this.i18nInstance.t(key);

const currentTab = this.isDefaultTab ? this.preferDesktop ? 1 : 2 : this.tab
const currentTab = this.isDefaultTab ? this.preferDesktop ? 1 : 2 : this.tab;

const svgElement = encodeQR(this.link, "svg", {
ecc: "medium",
Expand All @@ -110,13 +139,13 @@ export class InstallModal {
<div class='tabcontainer'>
<div class='flexContainer'>
<div
onClick={() => this.setTab(1)}
onClick={() => this.setTab(1, true)}
class={`tab flexItem ${currentTab === 1 ? 'tabactive': ''}`}
>
{t('DESKTOP')}
</div>
<div
onClick={() => this.setTab(2)}
onClick={() => this.setTab(2, true)}
class={`tab flexItem ${currentTab === 2 ? 'tabactive': ''}`}
>
{t('MOBILE')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ describe('showInstallModal', () => {
terminate: expect.any(Function),
debug: state.developerMode,
connectWithExtension: expect.any(Function),
onAnalyticsEvent: expect.any(Function),
});
expect(mockModalsInstall).toHaveBeenCalledTimes(1);
expect(mockInstallModalMount).toHaveBeenCalledWith(link);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TrackingEvents } from '@metamask/sdk-communication-layer';
import { logger } from '../../../utils/logger';
import {
RemoteConnectionProps,
Expand Down Expand Up @@ -34,6 +35,22 @@ export function showInstallModal(
options.connectWithExtensionProvider?.();
return false;
},
onAnalyticsEvent: ({
event,
params,
}: {
event: TrackingEvents;
params?: Record<string, any>;
}) => {
const extended = {
...params,
sdkVersion: options.sdk.getVersion(),
dappId: options.dappMetadata?.name,
source: options._source,
url: options.dappMetadata?.url,
};
state.analytics?.send({ event, params: extended });
},
});
state.installModal?.mount?.(link);
}
10 changes: 9 additions & 1 deletion packages/sdk/src/services/RemoteConnection/RemoteConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
KeyInfo,
RemoteCommunication,
StorageManagerProps,
TrackingEvents,
} from '@metamask/sdk-communication-layer';
import { MetaMaskInstaller } from '../../Platform/MetaMaskInstaller';
import { PlatformManager } from '../../Platform/PlatfformManager';
Expand Down Expand Up @@ -55,13 +56,20 @@ export interface RemoteConnectionProps {
*/
modals: {
onPendingModalDisconnect?: () => void;
install?: (params: {
install?: (args: {
link: string;
debug?: boolean;
preferDesktop?: boolean;
installer: MetaMaskInstaller;
terminate?: () => void;
connectWithExtension?: () => void;
onAnalyticsEvent: ({
event,
params,
}: {
event: TrackingEvents;
params?: Record<string, unknown>;
}) => void;
}) => {
unmount?: (shouldTerminate?: boolean) => void;
mount?: (link: string) => void;
Expand Down
10 changes: 10 additions & 0 deletions packages/sdk/src/ui/InstallModal/InstallModal-web.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TrackingEvents } from '@metamask/sdk-communication-layer';
import packageJson from '../../../package.json';
import { MetaMaskInstaller } from '../../Platform/MetaMaskInstaller';
import { logger } from '../../utils/logger';
Expand All @@ -10,13 +11,21 @@ const sdkWebInstallModal = ({
terminate,
connectWithExtension,
preferDesktop,
onAnalyticsEvent,
}: {
link: string;
debug?: boolean;
preferDesktop?: boolean;
installer: MetaMaskInstaller;
terminate?: () => void;
connectWithExtension?: () => void;
onAnalyticsEvent: ({
event,
params,
}: {
event: TrackingEvents;
params?: Record<string, unknown>;
}) => void;
}) => {
let modalLoader: ModalLoader | null = null;
let div: HTMLDivElement | null = null;
Expand Down Expand Up @@ -94,6 +103,7 @@ const sdkWebInstallModal = ({
link,
metaMaskInstaller: installer,
onClose: unmount,
onAnalyticsEvent,
})
.catch((err) => {
console.error(`[UI: InstallModal-web: sdkWebInstallModal()]`, err);
Expand Down
8 changes: 8 additions & 0 deletions packages/sdk/src/ui/InstallModal/Modal-web.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TrackingEvents } from '@metamask/sdk-communication-layer';
import type { Components } from '@metamask/sdk-install-modal-web';

export interface InstallWidgetProps extends Components.MmInstallModal {
Expand All @@ -6,6 +7,10 @@ export interface InstallWidgetProps extends Components.MmInstallModal {
metaMaskInstaller: {
startDesktopOnboarding: () => void;
};
onAnalyticsEvent: (event: {
event: TrackingEvents;
params?: Record<string, unknown>;
}) => void;
}

export interface PendingWidgetProps extends Components.MmPendingModal {
Expand Down Expand Up @@ -80,6 +85,9 @@ export default class ModalLoader {
'startDesktopOnboarding',
props.metaMaskInstaller.startDesktopOnboarding,
);

modal.addEventListener('trackAnalytics', ((e: CustomEvent) =>
props.onAnalyticsEvent?.(e.detail)) as EventListener);
props.parentElement.appendChild(modal);
}

Expand Down

0 comments on commit 29f6598

Please sign in to comment.