diff --git a/apps/browser-extension-wallet/diff.diff b/apps/browser-extension-wallet/diff.diff new file mode 100644 index 000000000..ae9c45d1a --- /dev/null +++ b/apps/browser-extension-wallet/diff.diff @@ -0,0 +1,808 @@ +diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/AnalyticsTracker.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/AnalyticsTracker.ts +index 9e500322b..a4e2b08f9 100644 +--- a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/AnalyticsTracker.ts ++++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/AnalyticsTracker.ts +@@ -14,15 +14,18 @@ import { + } from '../../PostHogClientProvider/client'; + import { getUserIdService } from '@providers/AnalyticsProvider/getUserIdService'; + import { UserIdService } from '@lib/scripts/types'; ++import { PostHogMultiWalletAction, PostHogOnboardingAction } from './events'; ++ ++type Action = PostHogAction | PostHogMultiWalletAction | PostHogOnboardingAction; + + interface AnalyticsTrackerArgs { +- postHogClient?: PostHogClient; ++ postHogClient?: PostHogClient; + view?: ExtensionViews; + analyticsDisabled?: boolean; + isPostHogEnabled?: boolean; + excludedEvents?: string; + } +-export class AnalyticsTracker implements IAnalyticsTracker { ++export class AnalyticsTracker implements IAnalyticsTracker { + protected postHogClient?: PostHogClient; + protected userIdService?: UserIdService; + protected excludedEvents: string; +@@ -89,7 +92,7 @@ export class AnalyticsTracker implements IAnalyticsTracker { + await this.postHogClient?.sendMergeEvent(extendedAccountPublicKey); + } + +- async sendEventToPostHog(action: PostHogAction, properties: PostHogProperties = {}): Promise { ++ async sendEventToPostHog(action: Action, properties: PostHogProperties = {}): Promise { + const isEventExcluded = this.isEventExcluded(action); + const shouldOmitEvent = this.shouldOmitSendEventToPostHog(); + if (shouldOmitEvent || isEventExcluded) return; +@@ -107,7 +110,7 @@ export class AnalyticsTracker implements IAnalyticsTracker { + return POSTHOG_OPTED_OUT_EVENTS_DISABLED && isOptedOutUser; + } + +- private isEventExcluded(action: PostHogAction) { ++ private isEventExcluded(action: Action) { + return this.excludedEvents && this.excludedEvents.split(',').some((exclude: string) => action.startsWith(exclude)); + } + } +diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events.ts +deleted file mode 100644 +index 1bd6eab64..000000000 +--- a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events.ts ++++ /dev/null +@@ -1,81 +0,0 @@ +-import { PostHogAction, PostHogMultiWalletActionsType, PostHogOnboardingActionsType } from './types'; +- +-export const postHogOnboardingActions: PostHogOnboardingActionsType = { +- onboarding: { +- ANALYTICS_AGREE_CLICK: PostHogAction.OnboardingAnalyticsAgreeClick, +- ANALYTICS_REJECT_CLICK: PostHogAction.OnboardingAnalyticsRejectClick, +- LEARN_MORE_CLICK: PostHogAction.OnboardingAnalyticsLearnMoreClick, +- GOT_IT_CLICK: PostHogAction.OnboardingAnalyticsGotItClick, +- PIN_EXTENSION_CLICK: PostHogAction.OnboardingMainViewPinExtensionClick +- }, +- create: { +- SETUP_OPTION_CLICK: PostHogAction.OnboardingCreateClick, +- SAVE_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.OnboardingCreateSaveRecoveryPhraseNextClick, +- ENTER_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.OnboardingCreateEnterRecoveryPhraseNextClick, +- ENTER_WALLET: PostHogAction.OnboardingCreateEnterWalletClick, +- RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK: PostHogAction.OnboardingCreateSaveRecoveryPhraseIntroPlayVideoClick, +- RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK: PostHogAction.OnboardingCreateKeepWalletSecureGotItClick, +- RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK: PostHogAction.OnboardingCreateSaveRecoveryPhraseCopyToClipboardClick, +- RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: +- PostHogAction.OnboardingCreateEnterRecoveryPhrasePasteFromClipboardClick, +- RECOVERY_PHRASE_COPY_READ_MORE_CLICK: PostHogAction.OnboardingCreateSaveRecoveryPhraseCopyReadMoreClick, +- RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: PostHogAction.OnboardingCreateEnterRecoveryPhrasePasteReadMoreClick +- }, +- restore: { +- SETUP_OPTION_CLICK: PostHogAction.OnboardingRestoreClick, +- ENTER_WALLET: PostHogAction.OnboardingRestoreEnterWalletClick, +- ENTER_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.OnboardingRestoreEnterRecoveryPhraseNextClick, +- RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: +- PostHogAction.OnboardingRestoreEnterRecoveryPhrasePasteFromClipboardClick, +- RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: PostHogAction.OnboardingRestoreEnterRecoveryPhrasePasteReadMoreClick +- }, +- hw: { +- SETUP_OPTION_CLICK: PostHogAction.OnboardingHWClick, +- CONNECT_HW_VIEW: PostHogAction.OnboardingHWConnectView, +- HW_POPUP_CONNECT_CLICK: PostHogAction.OnboardingHWPopupConnectClick, +- CONNECT_HW_TRY_AGAIN_CLICK: PostHogAction.OnboardingHWConnectTryAgainClick, +- SETUP_HW_ACCOUNT_NO_CLICK: PostHogAction.OnboardingHWSetupWalletAccountNoClick, +- ENTER_WALLET: PostHogAction.OnboardingHWEnterWalletClick +- }, +- // eslint-disable-next-line camelcase +- forgot_password: { +- ENTER_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.UnlockWalletForgotPasswordRecoveryPhraseNextClick, +- ENTER_WALLET: PostHogAction.UnlockWalletForgotPasswordEnterWalletClick, +- RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: +- PostHogAction.UnlockWalletForgotPasswordRecoveryPhrasePasteFromClipboardClick +- } +-}; +- +-export const postHogMultiWalletActions: PostHogMultiWalletActionsType = { +- create: { +- SETUP_OPTION_CLICK: PostHogAction.MultiWalletCreateClick, +- SAVE_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.MultiWalletCreateSaveRecoveryPhraseNextClick, +- ENTER_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.MultiWalletCreateEnterRecoveryPhraseNextClick, +- ENTER_WALLET: PostHogAction.MultiWalletCreateEnterWalletClick, +- RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK: PostHogAction.MultiWalletCreateSaveRecoveryPhraseIntroPlayVideoClick, +- RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK: PostHogAction.MultiWalletCreateKeepWalletSecureGotItClick, +- RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK: PostHogAction.MultiWalletCreateSaveRecoveryPhraseCopyToClipboardClick, +- RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: +- PostHogAction.MultiWalletCreateEnterRecoveryPhrasePasteFromClipboardClick, +- WALLET_ADDED: PostHogAction.MultiWalletCreateAdded +- }, +- restore: { +- SETUP_OPTION_CLICK: PostHogAction.MultiWalletRestoreClick, +- ENTER_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.MultiWalletRestoreEnterRecoveryPhraseNextClick, +- ENTER_WALLET: PostHogAction.MultiWalletRestoreEnterWalletClick, +- RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: +- PostHogAction.MultiWalletRestoreEnterRecoveryPhrasePasteFromClipboardClick, +- RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: PostHogAction.MultiWalletCreateSaveRecoveryPhrasePasteReadMoreClick, +- WALLET_ADDED: PostHogAction.MultiWalletRestoreAdded, +- HD_WALLET: PostHogAction.MultiWalletRestoreHdWallet +- }, +- hardware: { +- SETUP_OPTION_CLICK: PostHogAction.MultiWalletHWClick, +- CONNECT_HW_VIEW: PostHogAction.MultiWalletHWConnectView, +- HW_POPUP_CONNECT_CLICK: PostHogAction.MultiWalletHWPopupConnectClick, +- CONNECT_HW_TRY_AGAIN_CLICK: PostHogAction.MultiWalletHWConnectTryAgainClick, +- SETUP_HW_ACCOUNT_NO_CLICK: PostHogAction.MultiWalletHWSetupWalletAccountNoClick, +- ENTER_WALLET: PostHogAction.MultiWalletHWEnterWalletClick, +- WALLET_ADDED: PostHogAction.MultiWalletHWAdded +- } +-}; +diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/index.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/index.ts +new file mode 100644 +index 000000000..8345e2a50 +--- /dev/null ++++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/index.ts +@@ -0,0 +1,4 @@ ++export { postHogMultiWalletActions } from './multi-wallet'; ++export type { PostHogMultiWalletAction, PostHogMultiWalletActions } from './multi-wallet'; ++export { postHogOnboardingActions } from './onboarding'; ++export type { PostHogOnboardingAction, PostHogOnboardingActions } from './onboarding'; +diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/multi-wallet.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/multi-wallet.ts +new file mode 100644 +index 000000000..8686a04bf +--- /dev/null ++++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/multi-wallet.ts +@@ -0,0 +1,63 @@ ++import { ExtractActionsAsUnion, ValidateMultiWalletActionsStructure } from './types'; ++ ++export type PostHogMultiWalletActions = typeof multiWalletActions; ++export type PostHogMultiWalletAction = ExtractActionsAsUnion; ++ ++const makeMultiWalletCreateEvent = (eventSuffix: E) => ++ `multiwallet | new wallet revamp | ${eventSuffix}` as const; ++const makeMultiWalletRestoreEvent = (eventSuffix: E) => ++ `multiwallet | restore wallet revamp | ${eventSuffix}` as const; ++const makeMultiWalletHardwareEvent = (eventSuffix: E) => ++ `multiwallet | hardware wallet revamp | ${eventSuffix}` as const; ++ ++const multiWalletActions = { ++ create: { ++ SETUP_OPTION_CLICK: makeMultiWalletCreateEvent('create | click'), ++ SAVE_RECOVERY_PHRASE_NEXT_CLICK: makeMultiWalletCreateEvent('save your recovery phrase | next | click'), ++ ENTER_RECOVERY_PHRASE_NEXT_CLICK: makeMultiWalletCreateEvent('enter your recovery phrase | next | click'), ++ ENTER_WALLET: makeMultiWalletCreateEvent("let's set up your new wallet | enter wallet | click"), ++ RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK: makeMultiWalletCreateEvent( ++ 'save your recovery phrase | watch video | click' ++ ), ++ RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK: makeMultiWalletCreateEvent('keeping your wallet secure | got it | click'), ++ RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK: makeMultiWalletCreateEvent( ++ 'save your recovery phrase | copy to clipboard | click' ++ ), ++ RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: makeMultiWalletCreateEvent( ++ 'enter your recovery phrase | paste from clipboard | click' ++ ), ++ RECOVERY_PHRASE_COPY_READ_MORE_CLICK: makeMultiWalletCreateEvent( ++ 'save your recovery phrase | best practices faq | click' ++ ), ++ RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: makeMultiWalletCreateEvent( ++ 'enter your recovery phrase | best practices faq | click' ++ ), ++ WALLET_ADDED: makeMultiWalletCreateEvent('added') ++ }, ++ restore: { ++ SETUP_OPTION_CLICK: makeMultiWalletRestoreEvent('restore | click'), ++ ENTER_WALLET: makeMultiWalletRestoreEvent("let's set up your new wallet | enter wallet | click"), ++ ENTER_RECOVERY_PHRASE_NEXT_CLICK: makeMultiWalletRestoreEvent(' enter your recovery phrase | next | click'), ++ RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: makeMultiWalletRestoreEvent( ++ 'enter your recovery phrase | paste from clipboard | click' ++ ), ++ RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: makeMultiWalletRestoreEvent( ++ 'enter your recovery phrase | best practices faq | click' ++ ), ++ WALLET_ADDED: makeMultiWalletRestoreEvent('added'), ++ HD_WALLET: makeMultiWalletRestoreEvent('hd wallet') ++ }, ++ hardware: { ++ SETUP_OPTION_CLICK: makeMultiWalletHardwareEvent('connect | click'), ++ CONNECT_HW_VIEW: makeMultiWalletHardwareEvent('connect your device | view'), ++ HW_POPUP_CONNECT_CLICK: makeMultiWalletHardwareEvent('native browser pop-up with HWs | connect | click'), ++ CONNECT_HW_TRY_AGAIN_CLICK: makeMultiWalletHardwareEvent('connect your device | try again | click'), ++ SETUP_HW_ACCOUNT_NO_CLICK: makeMultiWalletHardwareEvent("let's set up your wallet | Account No | click"), ++ ENTER_WALLET: makeMultiWalletHardwareEvent("let's set up your wallet | enter wallet | click"), ++ WALLET_ADDED: makeMultiWalletHardwareEvent('added'), ++ HD_WALLET: makeMultiWalletHardwareEvent('hd wallet') ++ } ++}; ++ ++export const postHogMultiWalletActions: ValidateMultiWalletActionsStructure = ++ multiWalletActions; +diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/onboarding.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/onboarding.ts +new file mode 100644 +index 000000000..34aaa3ab0 +--- /dev/null ++++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/onboarding.ts +@@ -0,0 +1,81 @@ ++/* eslint-disable sonarjs/no-duplicate-string */ ++import { ExtractActionsAsUnion, ValidateOnboardingActionsStructure } from './types'; ++ ++export type PostHogOnboardingActions = typeof onboardingActions; ++export type PostHogOnboardingAction = ExtractActionsAsUnion; ++ ++const makeOnboardingEvent = (eventSuffix: E) => `onboarding | ${eventSuffix}` as const; ++const makeOnboardingCreateEvent = (eventSuffix: E) => ++ `onboarding | new wallet revamp | ${eventSuffix}` as const; ++const makeOnboardingRestoreEvent = (eventSuffix: E) => ++ `onboarding | restore wallet revamp | ${eventSuffix}` as const; ++const makeOnboardingHardwareEvent = (eventSuffix: E) => ++ `onboarding | hardware wallet revamp | ${eventSuffix}` as const; ++const makeForgotPasswordEvent = (eventSuffix: E) => ++ `unlock wallet | forgot password? | ${eventSuffix}` as const; ++ ++const onboardingActions = { ++ onboarding: { ++ ANALYTICS_AGREE_CLICK: makeOnboardingEvent('analytics banner | agree | click'), ++ ANALYTICS_REJECT_CLICK: makeOnboardingEvent('analytics banner | reject | click'), ++ LEARN_MORE_CLICK: makeOnboardingEvent('analytics banner | learn more | click'), ++ GOT_IT_CLICK: makeOnboardingEvent('help us improve your experience | got it | click'), ++ PIN_EXTENSION_CLICK: makeOnboardingEvent('lace main view | pin the wallet extension | click') ++ }, ++ create: { ++ SETUP_OPTION_CLICK: makeOnboardingCreateEvent('create | click'), ++ SAVE_RECOVERY_PHRASE_NEXT_CLICK: makeOnboardingCreateEvent('save your recovery phrase | next | click'), ++ ENTER_RECOVERY_PHRASE_NEXT_CLICK: makeOnboardingCreateEvent('enter your recovery phrase | next | click'), ++ ENTER_WALLET: makeOnboardingCreateEvent("let's set up your new wallet | enter wallet | click"), ++ RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK: makeOnboardingCreateEvent( ++ 'save your recovery phrase | watch video | click' ++ ), ++ RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK: makeOnboardingCreateEvent('keeping your wallet secure | got it | click'), ++ RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK: makeOnboardingCreateEvent( ++ 'save your recovery phrase | copy to clipboard | click' ++ ), ++ RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: makeOnboardingCreateEvent( ++ 'enter your recovery phrase | paste from clipboard | click' ++ ), ++ RECOVERY_PHRASE_COPY_READ_MORE_CLICK: makeOnboardingCreateEvent( ++ 'save your recovery phrase | best practices faq | click' ++ ), ++ RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: makeOnboardingCreateEvent( ++ 'enter your recovery phrase | best practices faq | click' ++ ), ++ WALLET_ADDED: makeOnboardingCreateEvent('added') ++ }, ++ restore: { ++ SETUP_OPTION_CLICK: makeOnboardingRestoreEvent('restore | click'), ++ ENTER_WALLET: makeOnboardingRestoreEvent("let's set up your new wallet | enter wallet | click"), ++ ENTER_RECOVERY_PHRASE_NEXT_CLICK: makeOnboardingRestoreEvent(' enter your recovery phrase | next | click'), ++ RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: makeOnboardingRestoreEvent( ++ 'enter your recovery phrase | paste from clipboard | click' ++ ), ++ RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: makeOnboardingRestoreEvent( ++ 'enter your recovery phrase | best practices faq | click' ++ ), ++ WALLET_ADDED: makeOnboardingRestoreEvent('added'), ++ HD_WALLET: makeOnboardingRestoreEvent('hd wallet') ++ }, ++ hw: { ++ SETUP_OPTION_CLICK: makeOnboardingHardwareEvent('connect | click'), ++ CONNECT_HW_VIEW: makeOnboardingHardwareEvent('connect your device | view'), ++ HW_POPUP_CONNECT_CLICK: makeOnboardingHardwareEvent('native browser pop-up with HWs | connect | click'), ++ CONNECT_HW_TRY_AGAIN_CLICK: makeOnboardingHardwareEvent('connect your device | try again | click'), ++ SETUP_HW_ACCOUNT_NO_CLICK: makeOnboardingHardwareEvent("let's set up your wallet | Account No | click"), ++ ENTER_WALLET: makeOnboardingHardwareEvent("let's set up your wallet | enter wallet | click"), ++ WALLET_ADDED: makeOnboardingHardwareEvent('added'), ++ HD_WALLET: makeOnboardingHardwareEvent('hd wallet') ++ }, ++ // eslint-disable-next-line camelcase ++ forgot_password: { ++ ENTER_RECOVERY_PHRASE_NEXT_CLICK: makeForgotPasswordEvent('enter your recovery phrase | next | click'), ++ ENTER_WALLET: makeForgotPasswordEvent('set up your password | enter wallet | click'), ++ RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: makeForgotPasswordEvent( ++ 'enter your recovery phrase | paste from clipboard | click' ++ ) ++ } ++}; ++ ++export const postHogOnboardingActions: ValidateOnboardingActionsStructure = onboardingActions; +diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/types.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/types.ts +new file mode 100644 +index 000000000..21c9da28a +--- /dev/null ++++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/types.ts +@@ -0,0 +1,67 @@ ++export type CreateFlowActions = Record< ++ | 'SETUP_OPTION_CLICK' ++ | 'SAVE_RECOVERY_PHRASE_NEXT_CLICK' ++ | 'ENTER_RECOVERY_PHRASE_NEXT_CLICK' ++ | 'ENTER_WALLET' ++ | 'RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK' ++ | 'RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK' ++ | 'RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK' ++ | 'RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK' ++ | 'RECOVERY_PHRASE_COPY_READ_MORE_CLICK' ++ | 'RECOVERY_PHRASE_PASTE_READ_MORE_CLICK' ++ | 'WALLET_ADDED', ++ string ++>; ++export type RestoreFlowActions = Record< ++ | 'SETUP_OPTION_CLICK' ++ | 'ENTER_RECOVERY_PHRASE_NEXT_CLICK' ++ | 'ENTER_WALLET' ++ | 'RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK' ++ | 'RECOVERY_PHRASE_PASTE_READ_MORE_CLICK' ++ | 'WALLET_ADDED' ++ | 'HD_WALLET', ++ string ++>; ++export type HardwareFlowActions = Record< ++ | 'SETUP_OPTION_CLICK' ++ | 'CONNECT_HW_VIEW' ++ | 'HW_POPUP_CONNECT_CLICK' ++ | 'CONNECT_HW_TRY_AGAIN_CLICK' ++ | 'SETUP_HW_ACCOUNT_NO_CLICK' ++ | 'ENTER_WALLET' ++ | 'WALLET_ADDED' ++ | 'HD_WALLET', ++ string ++>; ++ ++export type ValidateOnboardingActionsStructure< ++ T extends { ++ create: CreateFlowActions; ++ restore: RestoreFlowActions; ++ hw: HardwareFlowActions; ++ // eslint-disable-next-line camelcase ++ forgot_password: Record< ++ 'ENTER_RECOVERY_PHRASE_NEXT_CLICK' | 'ENTER_WALLET' | 'RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK', ++ string ++ >; ++ onboarding: Record< ++ 'ANALYTICS_AGREE_CLICK' | 'ANALYTICS_REJECT_CLICK' | 'LEARN_MORE_CLICK' | 'GOT_IT_CLICK' | 'PIN_EXTENSION_CLICK', ++ string ++ >; ++ } ++> = T; ++ ++export type ValidateMultiWalletActionsStructure< ++ T extends { ++ create: CreateFlowActions; ++ restore: RestoreFlowActions; ++ hardware: HardwareFlowActions; ++ } ++> = T; ++ ++type ActionsObject = Record>; ++type Values = T[keyof T]; ++type ActionsMap = { ++ [Prop in keyof T]: T[Prop][keyof T[Prop]]; ++}; ++export type ExtractActionsAsUnion = Values>; +diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/types.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/types.ts +index 7f62e4e64..8d04f4db2 100644 +--- a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/types.ts ++++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/types.ts +@@ -1,15 +1,7 @@ + /* eslint-disable camelcase */ +-import { PostHogAction } from '@lace/common'; +- + export { PostHogAction } from '@lace/common'; + export type { IAnalyticsTracker } from '@lace/common'; + +-export type Metadata = { +- _id?: string; +- cookie?: number; +- url: string; +-}; +- + export enum EnhancedAnalyticsOptInStatus { + OptedIn = 'ACCEPTED', + OptedOut = 'REJECTED', +@@ -38,35 +30,6 @@ export enum TxCreationType { + External = 'external' + } + +-export type OnboardingFlows = 'create' | 'restore' | 'hw' | 'forgot_password' | 'onboarding'; +-export type MultiWalletFlows = 'create' | 'restore' | 'hardware'; +-export type PostHogActionsKeys = +- | 'SETUP_OPTION_CLICK' +- | 'ANALYTICS_AGREE_CLICK' +- | 'LEARN_MORE_CLICK' +- | 'ANALYTICS_REJECT_CLICK' +- | 'SAVE_RECOVERY_PHRASE_NEXT_CLICK' +- | 'ENTER_RECOVERY_PHRASE_NEXT_CLICK' +- | 'ENTER_WALLET' +- | 'GOT_IT_CLICK' +- | 'PIN_EXTENSION_CLICK' +- | 'CONNECT_HW_VIEW' +- | 'HW_POPUP_CONNECT_CLICK' +- | 'CONNECT_HW_TRY_AGAIN_CLICK' +- | 'SETUP_HW_ACCOUNT_NO_CLICK' +- | 'WALLET_NAME_PASSWORD_NEXT_CLICK' +- | 'RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK' +- | 'RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK' +- | 'RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK' +- | 'RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK' +- | 'RECOVERY_PASSPHRASE_VERIFICATION_NEXT_CLICK' +- | 'RECOVERY_PHRASE_COPY_READ_MORE_CLICK' +- | 'RECOVERY_PHRASE_PASTE_READ_MORE_CLICK' +- | 'WALLET_ADDED' +- | 'HD_WALLET'; +-export type PostHogActions = Partial>; +-export type PostHogOnboardingActionsType = Record; +-export type PostHogMultiWalletActionsType = Record; + export type PostHogPersonProperties = { + $set: { + user_tracking_type: UserTrackingType; +diff --git a/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/PostHogClient.ts b/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/PostHogClient.ts +index 845c4cef4..72690a252 100644 +--- a/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/PostHogClient.ts ++++ b/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/PostHogClient.ts +@@ -27,7 +27,7 @@ import { PostHogAction, PostHogProperties } from '@lace/common'; + * PostHog API reference: + * https://posthog.com/docs/libraries/js + */ +-export class PostHogClient { ++export class PostHogClient { + protected static postHogClientInstance: PostHogClient; + private userTrackingType: UserTrackingType; + private currentUserTrackingType?: UserTrackingType; +@@ -167,7 +167,7 @@ export class PostHogClient { + }); + } + +- async sendEvent(action: PostHogAction, properties: PostHogProperties = {}): Promise { ++ async sendEvent(action: Action, properties: PostHogProperties = {}): Promise { + const payload = { + ...(await this.getEventMetadata()), + ...properties +diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/create-wallet/context.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/create-wallet/context.tsx +index 7314e0da4..65f774ffc 100644 +--- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/create-wallet/context.tsx ++++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/create-wallet/context.tsx +@@ -1,7 +1,7 @@ + import { CreateWalletParams } from '@hooks'; + import { Wallet } from '@lace/cardano'; + import { walletRoutePaths } from '@routes'; +-import React, { createContext, useContext, useMemo, useState } from 'react'; ++import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; + import { useHistory } from 'react-router'; + import { useHotWalletCreation } from '../useHotWalletCreation'; + import { useWalletOnboarding } from '../walletOnboardingContext'; +@@ -44,24 +44,27 @@ export const CreateWalletProvider = ({ children }: Props): React.ReactElement => + }); + const [step, setStep] = useState(WalletCreateStep.RecoveryPhraseWriteDown); + +- const generateMnemonic = () => { ++ const generateMnemonic = useCallback(() => { + setCreateWalletData((prevState) => ({ ...prevState, mnemonic: Wallet.KeyManagement.util.generateMnemonicWords() })); +- }; ++ }, [setCreateWalletData]); + +- const onNameAndPasswordChange: OnNameAndPasswordChange = ({ name, password }) => { +- setCreateWalletData((prevState) => ({ ...prevState, name, password })); +- }; ++ const onNameAndPasswordChange: OnNameAndPasswordChange = useCallback( ++ ({ name, password }) => { ++ setCreateWalletData((prevState) => ({ ...prevState, name, password })); ++ }, ++ [setCreateWalletData] ++ ); + +- const finalizeWalletCreation = async () => { ++ const finalizeWalletCreation = useCallback(async () => { + const wallet = await createHotWallet(); + await sendPostWalletAddAnalytics({ + extendedAccountPublicKey: wallet.source.account.extendedAccountPublicKey, +- walletAddedPostHogAction: postHogActions.create.WALLET_ADDED ++ postHogActionWalletAdded: postHogActions.create.WALLET_ADDED + }); + clearSecrets(); +- }; ++ }, [clearSecrets, createHotWallet, postHogActions.create.WALLET_ADDED, sendPostWalletAddAnalytics]); + +- const next = async () => { ++ const next = useCallback(async () => { + switch (step) { + case WalletCreateStep.RecoveryPhraseWriteDown: { + setFormDirty(true); +@@ -78,9 +81,9 @@ export const CreateWalletProvider = ({ children }: Props): React.ReactElement => + break; + } + } +- }; ++ }, [finalizeWalletCreation, history, setFormDirty, step]); + +- const back = () => { ++ const back = useCallback(() => { + switch (step) { + case WalletCreateStep.RecoveryPhraseWriteDown: { + history.push(walletRoutePaths.newWallet.root); +@@ -97,7 +100,7 @@ export const CreateWalletProvider = ({ children }: Props): React.ReactElement => + break; + } + } +- }; ++ }, [generateMnemonic, history, setFormDirty, step]); + + const state = useMemo( + () => ({ +diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/context.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/context.tsx +index 0210377e3..13047dd19 100644 +--- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/context.tsx ++++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/context.tsx +@@ -10,6 +10,7 @@ import { useWrapWithTimeout } from './useWrapWithTimeout'; + import { useAnalyticsContext } from '@providers'; + import { getWalletAccountsQtyString } from '@utils/get-wallet-count-string'; + import { firstValueFrom } from 'rxjs'; ++import { isHdWallet } from '../isHdWallet'; + import { useWalletOnboarding } from '../walletOnboardingContext'; + + type WalletData = { +@@ -204,6 +205,11 @@ export const HardwareWalletProvider = ({ children }: HardwareWalletProviderProps + await analytics.sendMergeEvent(cardanoWallet.source.account.extendedAccountPublicKey); + + await saveHardwareWallet(cardanoWallet); ++ ++ if (await isHdWallet(cardanoWallet.wallet)) { ++ await analytics.sendEventToPostHog(postHogActions.hardware.HD_WALLET); ++ } ++ + if (aliasEventRequired) { + await analytics.sendAliasEvent(); + } +@@ -213,6 +219,7 @@ export const HardwareWalletProvider = ({ children }: HardwareWalletProviderProps + closeConnection, + connection, + createHardwareWalletRevamped, ++ postHogActions.hardware.HD_WALLET, + postHogActions.hardware.WALLET_ADDED, + saveHardwareWallet, + walletData, +diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/isHdWallet.ts b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/isHdWallet.ts +new file mode 100644 +index 000000000..e2374f250 +--- /dev/null ++++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/isHdWallet.ts +@@ -0,0 +1,8 @@ ++import { isScriptAddress } from '@cardano-sdk/wallet'; ++import { Wallet } from '@lace/cardano'; ++import { filter, firstValueFrom } from 'rxjs'; ++ ++export const isHdWallet = async (wallet: Wallet.ObservableWallet): Promise => { ++ const addresses = await firstValueFrom(wallet.addresses$.pipe(filter((a) => a.length > 0))); ++ return addresses.some((addr) => !isScriptAddress(addr) && addr.index > 0); ++}; +diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/context.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/context.tsx +index b0add4783..260781f13 100644 +--- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/context.tsx ++++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/context.tsx +@@ -1,11 +1,7 @@ + import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; + import { WalletRestoreStep } from './types'; + import { CreateWalletParams } from '@hooks'; +-import { Wallet } from '@lace/cardano'; + import { useHistory } from 'react-router'; +-import { useAnalyticsContext } from '@providers'; +-import { filter, firstValueFrom } from 'rxjs'; +-import { isScriptAddress } from '@cardano-sdk/wallet'; + import { walletRoutePaths } from '@routes'; + import { useHotWalletCreation } from '../useHotWalletCreation'; + import { RecoveryPhraseLength } from '@lace/core'; +@@ -44,7 +40,6 @@ const initialMnemonicLength: RecoveryPhraseLength = 24; + + export const RestoreWalletProvider = ({ children }: Props): React.ReactElement => { + const history = useHistory(); +- const analytics = useAnalyticsContext(); + const { forgotPasswordFlowActive, postHogActions, setFormDirty } = useWalletOnboarding(); + const [step, setStep] = useState(WalletRestoreStep.RecoveryPhrase); + const { clearSecrets, createWallet, createWalletData, sendPostWalletAddAnalytics, setCreateWalletData } = +@@ -69,21 +64,14 @@ export const RestoreWalletProvider = ({ children }: Props): React.ReactElement = + setCreateWalletData((prevState) => ({ ...prevState, name, password })); + }; + +- const sendHdWalletAnalyticEvent = async ({ wallet }: Wallet.CardanoWallet) => { +- const addresses = await firstValueFrom(wallet.addresses$.pipe(filter((a) => a.length > 0))); +- const hdWalletDiscovered = addresses.some((addr) => !isScriptAddress(addr) && addr.index > 0); +- if (hdWalletDiscovered) { +- await analytics.sendEventToPostHog(postHogActions.restore.HD_WALLET); +- } +- }; +- + const finalizeWalletRestoration = async () => { +- const wallet = await createWallet(); ++ const { source, wallet } = await createWallet(); + void sendPostWalletAddAnalytics({ +- extendedAccountPublicKey: wallet.source.account.extendedAccountPublicKey, +- walletAddedPostHogAction: postHogActions.restore.WALLET_ADDED ++ extendedAccountPublicKey: source.account.extendedAccountPublicKey, ++ postHogActionHdWallet: postHogActions.restore.HD_WALLET, ++ postHogActionWalletAdded: postHogActions.restore.WALLET_ADDED, ++ wallet + }); +- void sendHdWalletAnalyticEvent(wallet); + if (forgotPasswordFlowActive) { + deleteFromLocalStorage('isForgotPasswordFlow'); + } +diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/types.ts b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/types.ts +index 794ba19bc..1214d13e5 100644 +--- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/types.ts ++++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/types.ts +@@ -1,7 +1,9 @@ +-import { PostHogActions } from '@providers/AnalyticsProvider/analyticsTracker'; ++import { PostHogMultiWalletActions, PostHogOnboardingActions } from '@providers/AnalyticsProvider/analyticsTracker'; + + export type SetFormDirty = (dirty: boolean) => void; + + export type Flows = 'create' | 'restore' | 'hardware'; + +-export type WalletOnboardingPostHogActions = Record; ++export type WalletOnboardingPostHogActions = ++ | PostHogMultiWalletActions ++ | (Pick & Record<'hardware', PostHogOnboardingActions['hw']>); +diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/useHotWalletCreation.ts b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/useHotWalletCreation.ts +index 991c89650..3a75481f0 100644 +--- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/useHotWalletCreation.ts ++++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/useHotWalletCreation.ts +@@ -1,10 +1,12 @@ +-import { Bip32PublicKeyHex } from '@cardano-sdk/crypto/dist/esm'; ++import { Bip32PublicKeyHex } from '@cardano-sdk/crypto'; + import { CreateWalletParams, useWalletManager } from '@hooks'; +-import { PostHogAction } from '@lace/common'; ++import { Wallet } from '@lace/cardano'; + import { useAnalyticsContext } from '@providers'; ++import { PostHogMultiWalletAction, PostHogOnboardingAction } from '@providers/AnalyticsProvider/analyticsTracker'; + import { getWalletAccountsQtyString } from '@utils/get-wallet-count-string'; + import { useEffect, useState } from 'react'; + import { firstValueFrom } from 'rxjs'; ++import { isHdWallet } from './isHdWallet'; + import { useWalletOnboarding } from './walletOnboardingContext'; + + type UseSoftwareWalletCreationParams = { +@@ -13,7 +15,9 @@ type UseSoftwareWalletCreationParams = { + + type SendPostWalletAddAnalyticsParams = { + extendedAccountPublicKey: Bip32PublicKeyHex; +- walletAddedPostHogAction: PostHogAction; ++ postHogActionHdWallet?: PostHogMultiWalletAction | PostHogOnboardingAction; ++ postHogActionWalletAdded: PostHogMultiWalletAction | PostHogOnboardingAction; ++ wallet?: Wallet.ObservableWallet; + }; + + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +@@ -40,13 +44,20 @@ export const useHotWalletCreation = ({ initialMnemonic }: UseSoftwareWalletCreat + + const sendPostWalletAddAnalytics = async ({ + extendedAccountPublicKey, +- walletAddedPostHogAction ++ postHogActionHdWallet, ++ postHogActionWalletAdded, ++ wallet + }: SendPostWalletAddAnalyticsParams) => { +- await analytics.sendEventToPostHog(walletAddedPostHogAction, { ++ await analytics.sendEventToPostHog(postHogActionWalletAdded, { + // eslint-disable-next-line camelcase + $set: { wallet_accounts_quantity: await getWalletAccountsQtyString(walletManager.walletRepository) } + }); + await analytics.sendMergeEvent(extendedAccountPublicKey); ++ ++ if (postHogActionHdWallet && wallet && (await isHdWallet(wallet))) { ++ await analytics.sendEventToPostHog(postHogActionHdWallet); ++ } ++ + if (aliasEventRequired) { + await analytics.sendAliasEvent(); + } +diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/PinExtension.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/PinExtension.tsx +index 72a9d1ef4..cbe7f29e2 100644 +--- a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/PinExtension.tsx ++++ b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/PinExtension.tsx +@@ -3,22 +3,17 @@ import styles from './PinExtension.module.scss'; + import LaceLogoMark from '../../../../../assets/branding/lace-logo-mark.component.svg'; + import ExtensionIcon from '../../../../../assets/icons/extension.component.svg'; + import { useTranslation, Trans } from 'react-i18next'; +-import { PostHogAction } from '@lace/common'; + import { useAnalyticsContext } from '@providers'; +-import { postHogOnboardingActions, PostHogProperties } from '@providers/AnalyticsProvider/analyticsTracker'; ++import { postHogOnboardingActions } from '@providers/AnalyticsProvider/analyticsTracker'; + + export const PinExtension = (): React.ReactElement => { + const { t } = useTranslation(); + const analytics = useAnalyticsContext(); + +- const sendAnalytics = async (args: { postHogAction: PostHogAction; postHogProperties?: PostHogProperties }) => { +- await analytics.sendEventToPostHog(args.postHogAction, args?.postHogProperties); +- }; +- + return ( +
sendAnalytics({ postHogAction: postHogOnboardingActions.onboarding.PIN_EXTENSION_CLICK })} ++ onClick={() => analytics.sendEventToPostHog(postHogOnboardingActions.onboarding.PIN_EXTENSION_CLICK)} + > + +
+diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/WalletSetupMainPage.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/WalletSetupMainPage.tsx +index 60a66fb24..b62f81a80 100644 +--- a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/WalletSetupMainPage.tsx ++++ b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/WalletSetupMainPage.tsx +@@ -6,9 +6,7 @@ import styles from '@views/browser/features/wallet-setup/components/WalletSetup. + import { walletRoutePaths } from '@routes'; + import { + EnhancedAnalyticsOptInStatus, +- PostHogAction, + postHogOnboardingActions, +- PostHogProperties, + UserTrackingType + } from '@providers/AnalyticsProvider/analyticsTracker'; + import { useAnalyticsContext } from '@providers'; +@@ -80,10 +78,6 @@ export const WalletSetupMainPage = (): ReactElement => { + analytics.sendEventToPostHog(postHogOnboardingActions.hw?.SETUP_OPTION_CLICK); + }; + +- const sendAnalytics = async (args: { postHogAction: PostHogAction; postHogProperties?: PostHogProperties }) => { +- await analytics.sendEventToPostHog(args.postHogAction, args?.postHogProperties); +- }; +- + const handleAnalyticsChoice = async (isAccepted: boolean) => { + const analyticsStatus = isAccepted ? EnhancedAnalyticsOptInStatus.OptedIn : EnhancedAnalyticsOptInStatus.OptedOut; + setDoesUserAllowAnalytics(analyticsStatus); +@@ -99,7 +93,7 @@ export const WalletSetupMainPage = (): ReactElement => { + // eslint-disable-next-line camelcase + $set: { user_tracking_type: isAccepted ? UserTrackingType.Enhanced : UserTrackingType.Basic } + }; +- await sendAnalytics({ postHogAction, postHogProperties }); ++ await analytics.sendEventToPostHog(postHogAction, postHogProperties); + }; + + const handleRestoreWallet = () => { +@@ -108,9 +102,7 @@ export const WalletSetupMainPage = (): ReactElement => { + }; + + const handleCreateNewWallet = () => { +- sendAnalytics({ +- postHogAction: postHogOnboardingActions.create.SETUP_OPTION_CLICK +- }); ++ analytics.sendEventToPostHog(postHogOnboardingActions.create.SETUP_OPTION_CLICK); + history.push(walletRoutePaths.setup.create); + }; + +@@ -130,9 +122,7 @@ export const WalletSetupMainPage = (): ReactElement => { + className={styles.learnMore} + onClick={() => { + setIsAnalyticsModalOpen(true); +- sendAnalytics({ +- postHogAction: postHogOnboardingActions.onboarding.LEARN_MORE_CLICK +- }); ++ analytics.sendEventToPostHog(postHogOnboardingActions.onboarding.LEARN_MORE_CLICK); + }} + data-testid="analytic-banner-learn-more" + > +@@ -151,9 +141,7 @@ export const WalletSetupMainPage = (): ReactElement => { + confirmLabel={translate('core.walletAnalyticsInfo.gotIt')} + onConfirm={() => { + setIsAnalyticsModalOpen(false); +- sendAnalytics({ +- postHogAction: postHogOnboardingActions.onboarding.GOT_IT_CLICK +- }); ++ analytics.sendEventToPostHog(postHogOnboardingActions.onboarding.GOT_IT_CLICK); + }} + /> + +diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/types.ts b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/types.ts +index 9df6cf436..6bec8ab0e 100644 +--- a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/types.ts ++++ b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/types.ts +@@ -1,7 +1,7 @@ +-import { PostHogAction, PostHogProperties } from '@providers/AnalyticsProvider/analyticsTracker'; ++import { PostHogProperties } from '@providers/AnalyticsProvider/analyticsTracker'; + + export type SendOnboardingAnalyticsEvent = ( +- postHogAction: PostHogAction, ++ postHogAction: string, + postHogProperties?: PostHogProperties + ) => Promise; + +diff --git a/packages/common/src/analytics/iAnalyticsTracker.ts b/packages/common/src/analytics/iAnalyticsTracker.ts +index 48bae8b32..881d335bf 100644 +--- a/packages/common/src/analytics/iAnalyticsTracker.ts ++++ b/packages/common/src/analytics/iAnalyticsTracker.ts +@@ -1,7 +1,7 @@ + import type { PostHogAction, PostHogProperties } from './types'; + +-export interface IAnalyticsTracker { ++export interface IAnalyticsTracker { + sendPageNavigationEvent: () => Promise; + sendAliasEvent: () => Promise; +- sendEventToPostHog: (action: PostHogAction, properties?: PostHogProperties) => Promise; ++ sendEventToPostHog: (action: Action, properties?: PostHogProperties) => Promise; + } diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/AnalyticsTracker.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/AnalyticsTracker.ts index 9e500322b..a4e2b08f9 100644 --- a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/AnalyticsTracker.ts +++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/AnalyticsTracker.ts @@ -14,15 +14,18 @@ import { } from '../../PostHogClientProvider/client'; import { getUserIdService } from '@providers/AnalyticsProvider/getUserIdService'; import { UserIdService } from '@lib/scripts/types'; +import { PostHogMultiWalletAction, PostHogOnboardingAction } from './events'; + +type Action = PostHogAction | PostHogMultiWalletAction | PostHogOnboardingAction; interface AnalyticsTrackerArgs { - postHogClient?: PostHogClient; + postHogClient?: PostHogClient; view?: ExtensionViews; analyticsDisabled?: boolean; isPostHogEnabled?: boolean; excludedEvents?: string; } -export class AnalyticsTracker implements IAnalyticsTracker { +export class AnalyticsTracker implements IAnalyticsTracker { protected postHogClient?: PostHogClient; protected userIdService?: UserIdService; protected excludedEvents: string; @@ -89,7 +92,7 @@ export class AnalyticsTracker implements IAnalyticsTracker { await this.postHogClient?.sendMergeEvent(extendedAccountPublicKey); } - async sendEventToPostHog(action: PostHogAction, properties: PostHogProperties = {}): Promise { + async sendEventToPostHog(action: Action, properties: PostHogProperties = {}): Promise { const isEventExcluded = this.isEventExcluded(action); const shouldOmitEvent = this.shouldOmitSendEventToPostHog(); if (shouldOmitEvent || isEventExcluded) return; @@ -107,7 +110,7 @@ export class AnalyticsTracker implements IAnalyticsTracker { return POSTHOG_OPTED_OUT_EVENTS_DISABLED && isOptedOutUser; } - private isEventExcluded(action: PostHogAction) { + private isEventExcluded(action: Action) { return this.excludedEvents && this.excludedEvents.split(',').some((exclude: string) => action.startsWith(exclude)); } } diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events.ts deleted file mode 100644 index 1bd6eab64..000000000 --- a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { PostHogAction, PostHogMultiWalletActionsType, PostHogOnboardingActionsType } from './types'; - -export const postHogOnboardingActions: PostHogOnboardingActionsType = { - onboarding: { - ANALYTICS_AGREE_CLICK: PostHogAction.OnboardingAnalyticsAgreeClick, - ANALYTICS_REJECT_CLICK: PostHogAction.OnboardingAnalyticsRejectClick, - LEARN_MORE_CLICK: PostHogAction.OnboardingAnalyticsLearnMoreClick, - GOT_IT_CLICK: PostHogAction.OnboardingAnalyticsGotItClick, - PIN_EXTENSION_CLICK: PostHogAction.OnboardingMainViewPinExtensionClick - }, - create: { - SETUP_OPTION_CLICK: PostHogAction.OnboardingCreateClick, - SAVE_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.OnboardingCreateSaveRecoveryPhraseNextClick, - ENTER_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.OnboardingCreateEnterRecoveryPhraseNextClick, - ENTER_WALLET: PostHogAction.OnboardingCreateEnterWalletClick, - RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK: PostHogAction.OnboardingCreateSaveRecoveryPhraseIntroPlayVideoClick, - RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK: PostHogAction.OnboardingCreateKeepWalletSecureGotItClick, - RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK: PostHogAction.OnboardingCreateSaveRecoveryPhraseCopyToClipboardClick, - RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: - PostHogAction.OnboardingCreateEnterRecoveryPhrasePasteFromClipboardClick, - RECOVERY_PHRASE_COPY_READ_MORE_CLICK: PostHogAction.OnboardingCreateSaveRecoveryPhraseCopyReadMoreClick, - RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: PostHogAction.OnboardingCreateEnterRecoveryPhrasePasteReadMoreClick - }, - restore: { - SETUP_OPTION_CLICK: PostHogAction.OnboardingRestoreClick, - ENTER_WALLET: PostHogAction.OnboardingRestoreEnterWalletClick, - ENTER_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.OnboardingRestoreEnterRecoveryPhraseNextClick, - RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: - PostHogAction.OnboardingRestoreEnterRecoveryPhrasePasteFromClipboardClick, - RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: PostHogAction.OnboardingRestoreEnterRecoveryPhrasePasteReadMoreClick - }, - hw: { - SETUP_OPTION_CLICK: PostHogAction.OnboardingHWClick, - CONNECT_HW_VIEW: PostHogAction.OnboardingHWConnectView, - HW_POPUP_CONNECT_CLICK: PostHogAction.OnboardingHWPopupConnectClick, - CONNECT_HW_TRY_AGAIN_CLICK: PostHogAction.OnboardingHWConnectTryAgainClick, - SETUP_HW_ACCOUNT_NO_CLICK: PostHogAction.OnboardingHWSetupWalletAccountNoClick, - ENTER_WALLET: PostHogAction.OnboardingHWEnterWalletClick - }, - // eslint-disable-next-line camelcase - forgot_password: { - ENTER_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.UnlockWalletForgotPasswordRecoveryPhraseNextClick, - ENTER_WALLET: PostHogAction.UnlockWalletForgotPasswordEnterWalletClick, - RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: - PostHogAction.UnlockWalletForgotPasswordRecoveryPhrasePasteFromClipboardClick - } -}; - -export const postHogMultiWalletActions: PostHogMultiWalletActionsType = { - create: { - SETUP_OPTION_CLICK: PostHogAction.MultiWalletCreateClick, - SAVE_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.MultiWalletCreateSaveRecoveryPhraseNextClick, - ENTER_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.MultiWalletCreateEnterRecoveryPhraseNextClick, - ENTER_WALLET: PostHogAction.MultiWalletCreateEnterWalletClick, - RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK: PostHogAction.MultiWalletCreateSaveRecoveryPhraseIntroPlayVideoClick, - RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK: PostHogAction.MultiWalletCreateKeepWalletSecureGotItClick, - RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK: PostHogAction.MultiWalletCreateSaveRecoveryPhraseCopyToClipboardClick, - RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: - PostHogAction.MultiWalletCreateEnterRecoveryPhrasePasteFromClipboardClick, - WALLET_ADDED: PostHogAction.MultiWalletCreateAdded - }, - restore: { - SETUP_OPTION_CLICK: PostHogAction.MultiWalletRestoreClick, - ENTER_RECOVERY_PHRASE_NEXT_CLICK: PostHogAction.MultiWalletRestoreEnterRecoveryPhraseNextClick, - ENTER_WALLET: PostHogAction.MultiWalletRestoreEnterWalletClick, - RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: - PostHogAction.MultiWalletRestoreEnterRecoveryPhrasePasteFromClipboardClick, - RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: PostHogAction.MultiWalletCreateSaveRecoveryPhrasePasteReadMoreClick, - WALLET_ADDED: PostHogAction.MultiWalletRestoreAdded, - HD_WALLET: PostHogAction.MultiWalletRestoreHdWallet - }, - hardware: { - SETUP_OPTION_CLICK: PostHogAction.MultiWalletHWClick, - CONNECT_HW_VIEW: PostHogAction.MultiWalletHWConnectView, - HW_POPUP_CONNECT_CLICK: PostHogAction.MultiWalletHWPopupConnectClick, - CONNECT_HW_TRY_AGAIN_CLICK: PostHogAction.MultiWalletHWConnectTryAgainClick, - SETUP_HW_ACCOUNT_NO_CLICK: PostHogAction.MultiWalletHWSetupWalletAccountNoClick, - ENTER_WALLET: PostHogAction.MultiWalletHWEnterWalletClick, - WALLET_ADDED: PostHogAction.MultiWalletHWAdded - } -}; diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/index.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/index.ts new file mode 100644 index 000000000..8345e2a50 --- /dev/null +++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/index.ts @@ -0,0 +1,4 @@ +export { postHogMultiWalletActions } from './multi-wallet'; +export type { PostHogMultiWalletAction, PostHogMultiWalletActions } from './multi-wallet'; +export { postHogOnboardingActions } from './onboarding'; +export type { PostHogOnboardingAction, PostHogOnboardingActions } from './onboarding'; diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/multi-wallet.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/multi-wallet.ts new file mode 100644 index 000000000..8686a04bf --- /dev/null +++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/multi-wallet.ts @@ -0,0 +1,63 @@ +import { ExtractActionsAsUnion, ValidateMultiWalletActionsStructure } from './types'; + +export type PostHogMultiWalletActions = typeof multiWalletActions; +export type PostHogMultiWalletAction = ExtractActionsAsUnion; + +const makeMultiWalletCreateEvent = (eventSuffix: E) => + `multiwallet | new wallet revamp | ${eventSuffix}` as const; +const makeMultiWalletRestoreEvent = (eventSuffix: E) => + `multiwallet | restore wallet revamp | ${eventSuffix}` as const; +const makeMultiWalletHardwareEvent = (eventSuffix: E) => + `multiwallet | hardware wallet revamp | ${eventSuffix}` as const; + +const multiWalletActions = { + create: { + SETUP_OPTION_CLICK: makeMultiWalletCreateEvent('create | click'), + SAVE_RECOVERY_PHRASE_NEXT_CLICK: makeMultiWalletCreateEvent('save your recovery phrase | next | click'), + ENTER_RECOVERY_PHRASE_NEXT_CLICK: makeMultiWalletCreateEvent('enter your recovery phrase | next | click'), + ENTER_WALLET: makeMultiWalletCreateEvent("let's set up your new wallet | enter wallet | click"), + RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK: makeMultiWalletCreateEvent( + 'save your recovery phrase | watch video | click' + ), + RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK: makeMultiWalletCreateEvent('keeping your wallet secure | got it | click'), + RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK: makeMultiWalletCreateEvent( + 'save your recovery phrase | copy to clipboard | click' + ), + RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: makeMultiWalletCreateEvent( + 'enter your recovery phrase | paste from clipboard | click' + ), + RECOVERY_PHRASE_COPY_READ_MORE_CLICK: makeMultiWalletCreateEvent( + 'save your recovery phrase | best practices faq | click' + ), + RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: makeMultiWalletCreateEvent( + 'enter your recovery phrase | best practices faq | click' + ), + WALLET_ADDED: makeMultiWalletCreateEvent('added') + }, + restore: { + SETUP_OPTION_CLICK: makeMultiWalletRestoreEvent('restore | click'), + ENTER_WALLET: makeMultiWalletRestoreEvent("let's set up your new wallet | enter wallet | click"), + ENTER_RECOVERY_PHRASE_NEXT_CLICK: makeMultiWalletRestoreEvent(' enter your recovery phrase | next | click'), + RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: makeMultiWalletRestoreEvent( + 'enter your recovery phrase | paste from clipboard | click' + ), + RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: makeMultiWalletRestoreEvent( + 'enter your recovery phrase | best practices faq | click' + ), + WALLET_ADDED: makeMultiWalletRestoreEvent('added'), + HD_WALLET: makeMultiWalletRestoreEvent('hd wallet') + }, + hardware: { + SETUP_OPTION_CLICK: makeMultiWalletHardwareEvent('connect | click'), + CONNECT_HW_VIEW: makeMultiWalletHardwareEvent('connect your device | view'), + HW_POPUP_CONNECT_CLICK: makeMultiWalletHardwareEvent('native browser pop-up with HWs | connect | click'), + CONNECT_HW_TRY_AGAIN_CLICK: makeMultiWalletHardwareEvent('connect your device | try again | click'), + SETUP_HW_ACCOUNT_NO_CLICK: makeMultiWalletHardwareEvent("let's set up your wallet | Account No | click"), + ENTER_WALLET: makeMultiWalletHardwareEvent("let's set up your wallet | enter wallet | click"), + WALLET_ADDED: makeMultiWalletHardwareEvent('added'), + HD_WALLET: makeMultiWalletHardwareEvent('hd wallet') + } +}; + +export const postHogMultiWalletActions: ValidateMultiWalletActionsStructure = + multiWalletActions; diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/onboarding.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/onboarding.ts new file mode 100644 index 000000000..34aaa3ab0 --- /dev/null +++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/onboarding.ts @@ -0,0 +1,81 @@ +/* eslint-disable sonarjs/no-duplicate-string */ +import { ExtractActionsAsUnion, ValidateOnboardingActionsStructure } from './types'; + +export type PostHogOnboardingActions = typeof onboardingActions; +export type PostHogOnboardingAction = ExtractActionsAsUnion; + +const makeOnboardingEvent = (eventSuffix: E) => `onboarding | ${eventSuffix}` as const; +const makeOnboardingCreateEvent = (eventSuffix: E) => + `onboarding | new wallet revamp | ${eventSuffix}` as const; +const makeOnboardingRestoreEvent = (eventSuffix: E) => + `onboarding | restore wallet revamp | ${eventSuffix}` as const; +const makeOnboardingHardwareEvent = (eventSuffix: E) => + `onboarding | hardware wallet revamp | ${eventSuffix}` as const; +const makeForgotPasswordEvent = (eventSuffix: E) => + `unlock wallet | forgot password? | ${eventSuffix}` as const; + +const onboardingActions = { + onboarding: { + ANALYTICS_AGREE_CLICK: makeOnboardingEvent('analytics banner | agree | click'), + ANALYTICS_REJECT_CLICK: makeOnboardingEvent('analytics banner | reject | click'), + LEARN_MORE_CLICK: makeOnboardingEvent('analytics banner | learn more | click'), + GOT_IT_CLICK: makeOnboardingEvent('help us improve your experience | got it | click'), + PIN_EXTENSION_CLICK: makeOnboardingEvent('lace main view | pin the wallet extension | click') + }, + create: { + SETUP_OPTION_CLICK: makeOnboardingCreateEvent('create | click'), + SAVE_RECOVERY_PHRASE_NEXT_CLICK: makeOnboardingCreateEvent('save your recovery phrase | next | click'), + ENTER_RECOVERY_PHRASE_NEXT_CLICK: makeOnboardingCreateEvent('enter your recovery phrase | next | click'), + ENTER_WALLET: makeOnboardingCreateEvent("let's set up your new wallet | enter wallet | click"), + RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK: makeOnboardingCreateEvent( + 'save your recovery phrase | watch video | click' + ), + RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK: makeOnboardingCreateEvent('keeping your wallet secure | got it | click'), + RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK: makeOnboardingCreateEvent( + 'save your recovery phrase | copy to clipboard | click' + ), + RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: makeOnboardingCreateEvent( + 'enter your recovery phrase | paste from clipboard | click' + ), + RECOVERY_PHRASE_COPY_READ_MORE_CLICK: makeOnboardingCreateEvent( + 'save your recovery phrase | best practices faq | click' + ), + RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: makeOnboardingCreateEvent( + 'enter your recovery phrase | best practices faq | click' + ), + WALLET_ADDED: makeOnboardingCreateEvent('added') + }, + restore: { + SETUP_OPTION_CLICK: makeOnboardingRestoreEvent('restore | click'), + ENTER_WALLET: makeOnboardingRestoreEvent("let's set up your new wallet | enter wallet | click"), + ENTER_RECOVERY_PHRASE_NEXT_CLICK: makeOnboardingRestoreEvent(' enter your recovery phrase | next | click'), + RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: makeOnboardingRestoreEvent( + 'enter your recovery phrase | paste from clipboard | click' + ), + RECOVERY_PHRASE_PASTE_READ_MORE_CLICK: makeOnboardingRestoreEvent( + 'enter your recovery phrase | best practices faq | click' + ), + WALLET_ADDED: makeOnboardingRestoreEvent('added'), + HD_WALLET: makeOnboardingRestoreEvent('hd wallet') + }, + hw: { + SETUP_OPTION_CLICK: makeOnboardingHardwareEvent('connect | click'), + CONNECT_HW_VIEW: makeOnboardingHardwareEvent('connect your device | view'), + HW_POPUP_CONNECT_CLICK: makeOnboardingHardwareEvent('native browser pop-up with HWs | connect | click'), + CONNECT_HW_TRY_AGAIN_CLICK: makeOnboardingHardwareEvent('connect your device | try again | click'), + SETUP_HW_ACCOUNT_NO_CLICK: makeOnboardingHardwareEvent("let's set up your wallet | Account No | click"), + ENTER_WALLET: makeOnboardingHardwareEvent("let's set up your wallet | enter wallet | click"), + WALLET_ADDED: makeOnboardingHardwareEvent('added'), + HD_WALLET: makeOnboardingHardwareEvent('hd wallet') + }, + // eslint-disable-next-line camelcase + forgot_password: { + ENTER_RECOVERY_PHRASE_NEXT_CLICK: makeForgotPasswordEvent('enter your recovery phrase | next | click'), + ENTER_WALLET: makeForgotPasswordEvent('set up your password | enter wallet | click'), + RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK: makeForgotPasswordEvent( + 'enter your recovery phrase | paste from clipboard | click' + ) + } +}; + +export const postHogOnboardingActions: ValidateOnboardingActionsStructure = onboardingActions; diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/types.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/types.ts new file mode 100644 index 000000000..21c9da28a --- /dev/null +++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/events/types.ts @@ -0,0 +1,67 @@ +export type CreateFlowActions = Record< + | 'SETUP_OPTION_CLICK' + | 'SAVE_RECOVERY_PHRASE_NEXT_CLICK' + | 'ENTER_RECOVERY_PHRASE_NEXT_CLICK' + | 'ENTER_WALLET' + | 'RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK' + | 'RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK' + | 'RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK' + | 'RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK' + | 'RECOVERY_PHRASE_COPY_READ_MORE_CLICK' + | 'RECOVERY_PHRASE_PASTE_READ_MORE_CLICK' + | 'WALLET_ADDED', + string +>; +export type RestoreFlowActions = Record< + | 'SETUP_OPTION_CLICK' + | 'ENTER_RECOVERY_PHRASE_NEXT_CLICK' + | 'ENTER_WALLET' + | 'RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK' + | 'RECOVERY_PHRASE_PASTE_READ_MORE_CLICK' + | 'WALLET_ADDED' + | 'HD_WALLET', + string +>; +export type HardwareFlowActions = Record< + | 'SETUP_OPTION_CLICK' + | 'CONNECT_HW_VIEW' + | 'HW_POPUP_CONNECT_CLICK' + | 'CONNECT_HW_TRY_AGAIN_CLICK' + | 'SETUP_HW_ACCOUNT_NO_CLICK' + | 'ENTER_WALLET' + | 'WALLET_ADDED' + | 'HD_WALLET', + string +>; + +export type ValidateOnboardingActionsStructure< + T extends { + create: CreateFlowActions; + restore: RestoreFlowActions; + hw: HardwareFlowActions; + // eslint-disable-next-line camelcase + forgot_password: Record< + 'ENTER_RECOVERY_PHRASE_NEXT_CLICK' | 'ENTER_WALLET' | 'RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK', + string + >; + onboarding: Record< + 'ANALYTICS_AGREE_CLICK' | 'ANALYTICS_REJECT_CLICK' | 'LEARN_MORE_CLICK' | 'GOT_IT_CLICK' | 'PIN_EXTENSION_CLICK', + string + >; + } +> = T; + +export type ValidateMultiWalletActionsStructure< + T extends { + create: CreateFlowActions; + restore: RestoreFlowActions; + hardware: HardwareFlowActions; + } +> = T; + +type ActionsObject = Record>; +type Values = T[keyof T]; +type ActionsMap = { + [Prop in keyof T]: T[Prop][keyof T[Prop]]; +}; +export type ExtractActionsAsUnion = Values>; diff --git a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/types.ts b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/types.ts index 7f62e4e64..8d04f4db2 100644 --- a/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/types.ts +++ b/apps/browser-extension-wallet/src/providers/AnalyticsProvider/analyticsTracker/types.ts @@ -1,15 +1,7 @@ /* eslint-disable camelcase */ -import { PostHogAction } from '@lace/common'; - export { PostHogAction } from '@lace/common'; export type { IAnalyticsTracker } from '@lace/common'; -export type Metadata = { - _id?: string; - cookie?: number; - url: string; -}; - export enum EnhancedAnalyticsOptInStatus { OptedIn = 'ACCEPTED', OptedOut = 'REJECTED', @@ -38,35 +30,6 @@ export enum TxCreationType { External = 'external' } -export type OnboardingFlows = 'create' | 'restore' | 'hw' | 'forgot_password' | 'onboarding'; -export type MultiWalletFlows = 'create' | 'restore' | 'hardware'; -export type PostHogActionsKeys = - | 'SETUP_OPTION_CLICK' - | 'ANALYTICS_AGREE_CLICK' - | 'LEARN_MORE_CLICK' - | 'ANALYTICS_REJECT_CLICK' - | 'SAVE_RECOVERY_PHRASE_NEXT_CLICK' - | 'ENTER_RECOVERY_PHRASE_NEXT_CLICK' - | 'ENTER_WALLET' - | 'GOT_IT_CLICK' - | 'PIN_EXTENSION_CLICK' - | 'CONNECT_HW_VIEW' - | 'HW_POPUP_CONNECT_CLICK' - | 'CONNECT_HW_TRY_AGAIN_CLICK' - | 'SETUP_HW_ACCOUNT_NO_CLICK' - | 'WALLET_NAME_PASSWORD_NEXT_CLICK' - | 'RECOVERY_PHRASE_INTRO_WATCH_VIDEO_CLICK' - | 'RECOVERY_PHRASE_INTRO_VIDEO_GOTIT_CLICK' - | 'RECOVERY_PHRASE_COPY_TO_CLIPBOARD_CLICK' - | 'RECOVERY_PHRASE_PASTE_FROM_CLIPBOARD_CLICK' - | 'RECOVERY_PASSPHRASE_VERIFICATION_NEXT_CLICK' - | 'RECOVERY_PHRASE_COPY_READ_MORE_CLICK' - | 'RECOVERY_PHRASE_PASTE_READ_MORE_CLICK' - | 'WALLET_ADDED' - | 'HD_WALLET'; -export type PostHogActions = Partial>; -export type PostHogOnboardingActionsType = Record; -export type PostHogMultiWalletActionsType = Record; export type PostHogPersonProperties = { $set: { user_tracking_type: UserTrackingType; diff --git a/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/PostHogClient.ts b/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/PostHogClient.ts index 845c4cef4..72690a252 100644 --- a/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/PostHogClient.ts +++ b/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/PostHogClient.ts @@ -27,7 +27,7 @@ import { PostHogAction, PostHogProperties } from '@lace/common'; * PostHog API reference: * https://posthog.com/docs/libraries/js */ -export class PostHogClient { +export class PostHogClient { protected static postHogClientInstance: PostHogClient; private userTrackingType: UserTrackingType; private currentUserTrackingType?: UserTrackingType; @@ -167,7 +167,7 @@ export class PostHogClient { }); } - async sendEvent(action: PostHogAction, properties: PostHogProperties = {}): Promise { + async sendEvent(action: Action, properties: PostHogProperties = {}): Promise { const payload = { ...(await this.getEventMetadata()), ...properties diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/create-wallet/context.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/create-wallet/context.tsx index 7314e0da4..65f774ffc 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/create-wallet/context.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/create-wallet/context.tsx @@ -1,7 +1,7 @@ import { CreateWalletParams } from '@hooks'; import { Wallet } from '@lace/cardano'; import { walletRoutePaths } from '@routes'; -import React, { createContext, useContext, useMemo, useState } from 'react'; +import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; import { useHistory } from 'react-router'; import { useHotWalletCreation } from '../useHotWalletCreation'; import { useWalletOnboarding } from '../walletOnboardingContext'; @@ -44,24 +44,27 @@ export const CreateWalletProvider = ({ children }: Props): React.ReactElement => }); const [step, setStep] = useState(WalletCreateStep.RecoveryPhraseWriteDown); - const generateMnemonic = () => { + const generateMnemonic = useCallback(() => { setCreateWalletData((prevState) => ({ ...prevState, mnemonic: Wallet.KeyManagement.util.generateMnemonicWords() })); - }; + }, [setCreateWalletData]); - const onNameAndPasswordChange: OnNameAndPasswordChange = ({ name, password }) => { - setCreateWalletData((prevState) => ({ ...prevState, name, password })); - }; + const onNameAndPasswordChange: OnNameAndPasswordChange = useCallback( + ({ name, password }) => { + setCreateWalletData((prevState) => ({ ...prevState, name, password })); + }, + [setCreateWalletData] + ); - const finalizeWalletCreation = async () => { + const finalizeWalletCreation = useCallback(async () => { const wallet = await createHotWallet(); await sendPostWalletAddAnalytics({ extendedAccountPublicKey: wallet.source.account.extendedAccountPublicKey, - walletAddedPostHogAction: postHogActions.create.WALLET_ADDED + postHogActionWalletAdded: postHogActions.create.WALLET_ADDED }); clearSecrets(); - }; + }, [clearSecrets, createHotWallet, postHogActions.create.WALLET_ADDED, sendPostWalletAddAnalytics]); - const next = async () => { + const next = useCallback(async () => { switch (step) { case WalletCreateStep.RecoveryPhraseWriteDown: { setFormDirty(true); @@ -78,9 +81,9 @@ export const CreateWalletProvider = ({ children }: Props): React.ReactElement => break; } } - }; + }, [finalizeWalletCreation, history, setFormDirty, step]); - const back = () => { + const back = useCallback(() => { switch (step) { case WalletCreateStep.RecoveryPhraseWriteDown: { history.push(walletRoutePaths.newWallet.root); @@ -97,7 +100,7 @@ export const CreateWalletProvider = ({ children }: Props): React.ReactElement => break; } } - }; + }, [generateMnemonic, history, setFormDirty, step]); const state = useMemo( () => ({ diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/HardwareWallet.test.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/HardwareWallet.test.tsx index 6d230ca60..f831c6076 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/HardwareWallet.test.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/HardwareWallet.test.tsx @@ -8,6 +8,9 @@ jest.mock('@lib/wallet-api-ui', () => ({ }, walletManager: { activate: jest.fn().mockReturnValue(void 0) + }, + observableWallet: { + addresses$: of([[]]) } })); diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/context.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/context.tsx index 0210377e3..13047dd19 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/context.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/hardware-wallet/context.tsx @@ -10,6 +10,7 @@ import { useWrapWithTimeout } from './useWrapWithTimeout'; import { useAnalyticsContext } from '@providers'; import { getWalletAccountsQtyString } from '@utils/get-wallet-count-string'; import { firstValueFrom } from 'rxjs'; +import { isHdWallet } from '../isHdWallet'; import { useWalletOnboarding } from '../walletOnboardingContext'; type WalletData = { @@ -204,6 +205,11 @@ export const HardwareWalletProvider = ({ children }: HardwareWalletProviderProps await analytics.sendMergeEvent(cardanoWallet.source.account.extendedAccountPublicKey); await saveHardwareWallet(cardanoWallet); + + if (await isHdWallet(cardanoWallet.wallet)) { + await analytics.sendEventToPostHog(postHogActions.hardware.HD_WALLET); + } + if (aliasEventRequired) { await analytics.sendAliasEvent(); } @@ -213,6 +219,7 @@ export const HardwareWalletProvider = ({ children }: HardwareWalletProviderProps closeConnection, connection, createHardwareWalletRevamped, + postHogActions.hardware.HD_WALLET, postHogActions.hardware.WALLET_ADDED, saveHardwareWallet, walletData, diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/isHdWallet.ts b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/isHdWallet.ts new file mode 100644 index 000000000..e2374f250 --- /dev/null +++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/isHdWallet.ts @@ -0,0 +1,8 @@ +import { isScriptAddress } from '@cardano-sdk/wallet'; +import { Wallet } from '@lace/cardano'; +import { filter, firstValueFrom } from 'rxjs'; + +export const isHdWallet = async (wallet: Wallet.ObservableWallet): Promise => { + const addresses = await firstValueFrom(wallet.addresses$.pipe(filter((a) => a.length > 0))); + return addresses.some((addr) => !isScriptAddress(addr) && addr.index > 0); +}; diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/context.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/context.tsx index b0add4783..260781f13 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/context.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/restore-wallet/context.tsx @@ -1,11 +1,7 @@ import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; import { WalletRestoreStep } from './types'; import { CreateWalletParams } from '@hooks'; -import { Wallet } from '@lace/cardano'; import { useHistory } from 'react-router'; -import { useAnalyticsContext } from '@providers'; -import { filter, firstValueFrom } from 'rxjs'; -import { isScriptAddress } from '@cardano-sdk/wallet'; import { walletRoutePaths } from '@routes'; import { useHotWalletCreation } from '../useHotWalletCreation'; import { RecoveryPhraseLength } from '@lace/core'; @@ -44,7 +40,6 @@ const initialMnemonicLength: RecoveryPhraseLength = 24; export const RestoreWalletProvider = ({ children }: Props): React.ReactElement => { const history = useHistory(); - const analytics = useAnalyticsContext(); const { forgotPasswordFlowActive, postHogActions, setFormDirty } = useWalletOnboarding(); const [step, setStep] = useState(WalletRestoreStep.RecoveryPhrase); const { clearSecrets, createWallet, createWalletData, sendPostWalletAddAnalytics, setCreateWalletData } = @@ -69,21 +64,14 @@ export const RestoreWalletProvider = ({ children }: Props): React.ReactElement = setCreateWalletData((prevState) => ({ ...prevState, name, password })); }; - const sendHdWalletAnalyticEvent = async ({ wallet }: Wallet.CardanoWallet) => { - const addresses = await firstValueFrom(wallet.addresses$.pipe(filter((a) => a.length > 0))); - const hdWalletDiscovered = addresses.some((addr) => !isScriptAddress(addr) && addr.index > 0); - if (hdWalletDiscovered) { - await analytics.sendEventToPostHog(postHogActions.restore.HD_WALLET); - } - }; - const finalizeWalletRestoration = async () => { - const wallet = await createWallet(); + const { source, wallet } = await createWallet(); void sendPostWalletAddAnalytics({ - extendedAccountPublicKey: wallet.source.account.extendedAccountPublicKey, - walletAddedPostHogAction: postHogActions.restore.WALLET_ADDED + extendedAccountPublicKey: source.account.extendedAccountPublicKey, + postHogActionHdWallet: postHogActions.restore.HD_WALLET, + postHogActionWalletAdded: postHogActions.restore.WALLET_ADDED, + wallet }); - void sendHdWalletAnalyticEvent(wallet); if (forgotPasswordFlowActive) { deleteFromLocalStorage('isForgotPasswordFlow'); } diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/types.ts b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/types.ts index 794ba19bc..1214d13e5 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/types.ts +++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/types.ts @@ -1,7 +1,9 @@ -import { PostHogActions } from '@providers/AnalyticsProvider/analyticsTracker'; +import { PostHogMultiWalletActions, PostHogOnboardingActions } from '@providers/AnalyticsProvider/analyticsTracker'; export type SetFormDirty = (dirty: boolean) => void; export type Flows = 'create' | 'restore' | 'hardware'; -export type WalletOnboardingPostHogActions = Record; +export type WalletOnboardingPostHogActions = + | PostHogMultiWalletActions + | (Pick & Record<'hardware', PostHogOnboardingActions['hw']>); diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/useHotWalletCreation.ts b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/useHotWalletCreation.ts index 991c89650..3a75481f0 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/useHotWalletCreation.ts +++ b/apps/browser-extension-wallet/src/views/browser-view/features/multi-wallet/useHotWalletCreation.ts @@ -1,10 +1,12 @@ -import { Bip32PublicKeyHex } from '@cardano-sdk/crypto/dist/esm'; +import { Bip32PublicKeyHex } from '@cardano-sdk/crypto'; import { CreateWalletParams, useWalletManager } from '@hooks'; -import { PostHogAction } from '@lace/common'; +import { Wallet } from '@lace/cardano'; import { useAnalyticsContext } from '@providers'; +import { PostHogMultiWalletAction, PostHogOnboardingAction } from '@providers/AnalyticsProvider/analyticsTracker'; import { getWalletAccountsQtyString } from '@utils/get-wallet-count-string'; import { useEffect, useState } from 'react'; import { firstValueFrom } from 'rxjs'; +import { isHdWallet } from './isHdWallet'; import { useWalletOnboarding } from './walletOnboardingContext'; type UseSoftwareWalletCreationParams = { @@ -13,7 +15,9 @@ type UseSoftwareWalletCreationParams = { type SendPostWalletAddAnalyticsParams = { extendedAccountPublicKey: Bip32PublicKeyHex; - walletAddedPostHogAction: PostHogAction; + postHogActionHdWallet?: PostHogMultiWalletAction | PostHogOnboardingAction; + postHogActionWalletAdded: PostHogMultiWalletAction | PostHogOnboardingAction; + wallet?: Wallet.ObservableWallet; }; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types @@ -40,13 +44,20 @@ export const useHotWalletCreation = ({ initialMnemonic }: UseSoftwareWalletCreat const sendPostWalletAddAnalytics = async ({ extendedAccountPublicKey, - walletAddedPostHogAction + postHogActionHdWallet, + postHogActionWalletAdded, + wallet }: SendPostWalletAddAnalyticsParams) => { - await analytics.sendEventToPostHog(walletAddedPostHogAction, { + await analytics.sendEventToPostHog(postHogActionWalletAdded, { // eslint-disable-next-line camelcase $set: { wallet_accounts_quantity: await getWalletAccountsQtyString(walletManager.walletRepository) } }); await analytics.sendMergeEvent(extendedAccountPublicKey); + + if (postHogActionHdWallet && wallet && (await isHdWallet(wallet))) { + await analytics.sendEventToPostHog(postHogActionHdWallet); + } + if (aliasEventRequired) { await analytics.sendAliasEvent(); } diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/PinExtension.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/PinExtension.tsx index 72a9d1ef4..cbe7f29e2 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/PinExtension.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/PinExtension.tsx @@ -3,22 +3,17 @@ import styles from './PinExtension.module.scss'; import LaceLogoMark from '../../../../../assets/branding/lace-logo-mark.component.svg'; import ExtensionIcon from '../../../../../assets/icons/extension.component.svg'; import { useTranslation, Trans } from 'react-i18next'; -import { PostHogAction } from '@lace/common'; import { useAnalyticsContext } from '@providers'; -import { postHogOnboardingActions, PostHogProperties } from '@providers/AnalyticsProvider/analyticsTracker'; +import { postHogOnboardingActions } from '@providers/AnalyticsProvider/analyticsTracker'; export const PinExtension = (): React.ReactElement => { const { t } = useTranslation(); const analytics = useAnalyticsContext(); - const sendAnalytics = async (args: { postHogAction: PostHogAction; postHogProperties?: PostHogProperties }) => { - await analytics.sendEventToPostHog(args.postHogAction, args?.postHogProperties); - }; - return (
sendAnalytics({ postHogAction: postHogOnboardingActions.onboarding.PIN_EXTENSION_CLICK })} + onClick={() => analytics.sendEventToPostHog(postHogOnboardingActions.onboarding.PIN_EXTENSION_CLICK)} >
diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/WalletSetupMainPage.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/WalletSetupMainPage.tsx index 60a66fb24..b62f81a80 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/WalletSetupMainPage.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/components/WalletSetupMainPage.tsx @@ -6,9 +6,7 @@ import styles from '@views/browser/features/wallet-setup/components/WalletSetup. import { walletRoutePaths } from '@routes'; import { EnhancedAnalyticsOptInStatus, - PostHogAction, postHogOnboardingActions, - PostHogProperties, UserTrackingType } from '@providers/AnalyticsProvider/analyticsTracker'; import { useAnalyticsContext } from '@providers'; @@ -80,10 +78,6 @@ export const WalletSetupMainPage = (): ReactElement => { analytics.sendEventToPostHog(postHogOnboardingActions.hw?.SETUP_OPTION_CLICK); }; - const sendAnalytics = async (args: { postHogAction: PostHogAction; postHogProperties?: PostHogProperties }) => { - await analytics.sendEventToPostHog(args.postHogAction, args?.postHogProperties); - }; - const handleAnalyticsChoice = async (isAccepted: boolean) => { const analyticsStatus = isAccepted ? EnhancedAnalyticsOptInStatus.OptedIn : EnhancedAnalyticsOptInStatus.OptedOut; setDoesUserAllowAnalytics(analyticsStatus); @@ -99,7 +93,7 @@ export const WalletSetupMainPage = (): ReactElement => { // eslint-disable-next-line camelcase $set: { user_tracking_type: isAccepted ? UserTrackingType.Enhanced : UserTrackingType.Basic } }; - await sendAnalytics({ postHogAction, postHogProperties }); + await analytics.sendEventToPostHog(postHogAction, postHogProperties); }; const handleRestoreWallet = () => { @@ -108,9 +102,7 @@ export const WalletSetupMainPage = (): ReactElement => { }; const handleCreateNewWallet = () => { - sendAnalytics({ - postHogAction: postHogOnboardingActions.create.SETUP_OPTION_CLICK - }); + analytics.sendEventToPostHog(postHogOnboardingActions.create.SETUP_OPTION_CLICK); history.push(walletRoutePaths.setup.create); }; @@ -130,9 +122,7 @@ export const WalletSetupMainPage = (): ReactElement => { className={styles.learnMore} onClick={() => { setIsAnalyticsModalOpen(true); - sendAnalytics({ - postHogAction: postHogOnboardingActions.onboarding.LEARN_MORE_CLICK - }); + analytics.sendEventToPostHog(postHogOnboardingActions.onboarding.LEARN_MORE_CLICK); }} data-testid="analytic-banner-learn-more" > @@ -151,9 +141,7 @@ export const WalletSetupMainPage = (): ReactElement => { confirmLabel={translate('core.walletAnalyticsInfo.gotIt')} onConfirm={() => { setIsAnalyticsModalOpen(false); - sendAnalytics({ - postHogAction: postHogOnboardingActions.onboarding.GOT_IT_CLICK - }); + analytics.sendEventToPostHog(postHogOnboardingActions.onboarding.GOT_IT_CLICK); }} /> diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/types.ts b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/types.ts index 9df6cf436..6bec8ab0e 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/types.ts +++ b/apps/browser-extension-wallet/src/views/browser-view/features/wallet-setup/types.ts @@ -1,7 +1,7 @@ -import { PostHogAction, PostHogProperties } from '@providers/AnalyticsProvider/analyticsTracker'; +import { PostHogProperties } from '@providers/AnalyticsProvider/analyticsTracker'; export type SendOnboardingAnalyticsEvent = ( - postHogAction: PostHogAction, + postHogAction: string, postHogProperties?: PostHogProperties ) => Promise; diff --git a/packages/common/src/analytics/iAnalyticsTracker.ts b/packages/common/src/analytics/iAnalyticsTracker.ts index 48bae8b32..881d335bf 100644 --- a/packages/common/src/analytics/iAnalyticsTracker.ts +++ b/packages/common/src/analytics/iAnalyticsTracker.ts @@ -1,7 +1,7 @@ import type { PostHogAction, PostHogProperties } from './types'; -export interface IAnalyticsTracker { +export interface IAnalyticsTracker { sendPageNavigationEvent: () => Promise; sendAliasEvent: () => Promise; - sendEventToPostHog: (action: PostHogAction, properties?: PostHogProperties) => Promise; + sendEventToPostHog: (action: Action, properties?: PostHogProperties) => Promise; }