From ad51477e3672225c2d238abe7a91799e092e2832 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Mon, 17 Feb 2025 18:41:18 +0200 Subject: [PATCH 1/4] feat(clerk-js): Track usage of UI modals --- .changeset/poor-cobras-sin.md | 5 ++ packages/clerk-js/src/core/clerk.ts | 86 ++++++++++++++++++++--------- 2 files changed, 64 insertions(+), 27 deletions(-) create mode 100644 .changeset/poor-cobras-sin.md diff --git a/.changeset/poor-cobras-sin.md b/.changeset/poor-cobras-sin.md new file mode 100644 index 00000000000..f775d708db8 --- /dev/null +++ b/.changeset/poor-cobras-sin.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-js': minor +--- + +Track usage of modal UI Components as part of telemetry. diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 3a9a4fa70c8..411c4023f1e 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -404,11 +404,12 @@ export class Clerk implements ClerkInterface { }; public openGoogleOneTap = (props?: GoogleOneTapProps): void => { - // TODO: add telemetry this.assertComponentsReady(this.#componentControls); void this.#componentControls .ensureMounted({ preloadHint: 'GoogleOneTap' }) .then(controls => controls.openModal('googleOneTap', props || {})); + + this.telemetry?.record(eventPrebuiltComponentMounted(`GoogleOneTap`, props)); }; public closeGoogleOneTap = (): void => { @@ -429,6 +430,8 @@ export class Clerk implements ClerkInterface { void this.#componentControls .ensureMounted({ preloadHint: 'SignIn' }) .then(controls => controls.openModal('signIn', props || {})); + + this.#recordSignInUsage(props, 'Modal'); }; public closeSignIn = (): void => { @@ -449,6 +452,8 @@ export class Clerk implements ClerkInterface { void this.#componentControls .ensureMounted({ preloadHint: 'UserVerification' }) .then(controls => controls.openModal('userVerification', props || {})); + + this.telemetry?.record(eventPrebuiltComponentMounted(`UserVerification`, props)); }; public __internal_closeReverification = (): void => { @@ -483,6 +488,8 @@ export class Clerk implements ClerkInterface { void this.#componentControls .ensureMounted({ preloadHint: 'SignUp' }) .then(controls => controls.openModal('signUp', props || {})); + + this.#recordSignUpUsage(props, 'Modal'); }; public closeSignUp = (): void => { @@ -503,6 +510,8 @@ export class Clerk implements ClerkInterface { void this.#componentControls .ensureMounted({ preloadHint: 'UserProfile' }) .then(controls => controls.openModal('userProfile', props || {})); + + this.#recordUserProfileUsage(props, 'Modal'); }; public closeUserProfile = (): void => { @@ -531,6 +540,7 @@ export class Clerk implements ClerkInterface { void this.#componentControls .ensureMounted({ preloadHint: 'OrganizationProfile' }) .then(controls => controls.openModal('organizationProfile', props || {})); + this.#recordOrganizationProfileUsage(props, 'Modal'); }; public closeOrganizationProfile = (): void => { @@ -551,6 +561,8 @@ export class Clerk implements ClerkInterface { void this.#componentControls .ensureMounted({ preloadHint: 'CreateOrganization' }) .then(controls => controls.openModal('createOrganization', props || {})); + + this.#recordCreateOrganizationUsage(props, 'Modal'); }; public closeCreateOrganization = (): void => { @@ -563,6 +575,8 @@ export class Clerk implements ClerkInterface { void this.#componentControls .ensureMounted({ preloadHint: 'Waitlist' }) .then(controls => controls.openModal('waitlist', props || {})); + + this.#recordWaitlistUsage(props, 'Modal'); }; public closeWaitlist = (): void => { @@ -580,17 +594,7 @@ export class Clerk implements ClerkInterface { props, }), ); - this.telemetry?.record( - eventPrebuiltComponentMounted( - 'SignIn', - { - ...props, - }, - { - withSignUp: props?.withSignUp ?? this.#isCombinedSignInOrUpFlow(), - }, - ), - ); + this.#recordSignInUsage(props); }; public unmountSignIn = (node: HTMLDivElement): void => { @@ -612,7 +616,7 @@ export class Clerk implements ClerkInterface { props, }), ); - this.telemetry?.record(eventPrebuiltComponentMounted('SignUp', props)); + this.#recordSignUpUsage(props); }; public unmountSignUp = (node: HTMLDivElement): void => { @@ -643,17 +647,7 @@ export class Clerk implements ClerkInterface { }), ); - this.telemetry?.record( - eventPrebuiltComponentMounted( - 'UserProfile', - props, - props?.customPages?.length || 0 > 0 - ? { - customPages: true, - } - : undefined, - ), - ); + this.#recordUserProfileUsage(props); }; public unmountUserProfile = (node: HTMLDivElement): void => { @@ -693,7 +687,7 @@ export class Clerk implements ClerkInterface { }), ); - this.telemetry?.record(eventPrebuiltComponentMounted('OrganizationProfile', props)); + this.#recordOrganizationProfileUsage(props); }; public unmountOrganizationProfile = (node: HTMLDivElement) => { @@ -724,7 +718,7 @@ export class Clerk implements ClerkInterface { }), ); - this.telemetry?.record(eventPrebuiltComponentMounted('CreateOrganization', props)); + this.#recordCreateOrganizationUsage(props); }; public unmountCreateOrganization = (node: HTMLDivElement) => { @@ -841,7 +835,7 @@ export class Clerk implements ClerkInterface { }), ); - this.telemetry?.record(eventPrebuiltComponentMounted('Waitlist', props)); + this.#recordWaitlistUsage(props); }; public unmountWaitlist = (node: HTMLDivElement): void => { @@ -2246,4 +2240,42 @@ export class Clerk implements ClerkInterface { return allowedProtocols; } + + #recordSignInUsage = (props?: SignInProps, mode?: 'Modal') => { + this.telemetry?.record( + eventPrebuiltComponentMounted(`SignIn${mode || ''}`, props, { + withSignUp: props?.withSignUp ?? this.#isCombinedSignInOrUpFlow(), + }), + ); + }; + + #recordSignUpUsage = (props?: SignUpProps, mode?: 'Modal') => { + this.telemetry?.record(eventPrebuiltComponentMounted(`SignUp${mode || ''}`, props)); + }; + + #recordUserProfileUsage = (props?: UserProfileProps, mode?: 'Modal') => { + this.telemetry?.record( + eventPrebuiltComponentMounted( + `UserProfile${mode || ''}`, + props, + props?.customPages?.length || 0 > 0 + ? { + customPages: true, + } + : undefined, + ), + ); + }; + + #recordOrganizationProfileUsage = (props?: OrganizationProfileProps, mode?: 'Modal') => { + this.telemetry?.record(eventPrebuiltComponentMounted(`OrganizationProfile${mode || ''}`, props)); + }; + + #recordCreateOrganizationUsage = (props?: OrganizationProfileProps, mode?: 'Modal') => { + this.telemetry?.record(eventPrebuiltComponentMounted(`CreateOrganization${mode || ''}`, props)); + }; + + #recordWaitlistUsage = (props?: WaitlistProps, mode?: 'Modal') => { + this.telemetry?.record(eventPrebuiltComponentMounted(`Waitlist${mode || ''}`, props)); + }; } From 7b5d541384f881fd26f9a2cb2d72501b28e5cd69 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Mon, 17 Feb 2025 19:12:37 +0200 Subject: [PATCH 2/4] clean up --- packages/clerk-js/src/core/clerk.ts | 87 ++++++++++------------------- 1 file changed, 31 insertions(+), 56 deletions(-) diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 411c4023f1e..bb40cb8a5f6 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -152,6 +152,8 @@ const defaultOptions: ClerkOptions = { signUpForceRedirectUrl: undefined, }; +type ComponentRenderingMode = 'modal' | 'mounted'; + export class Clerk implements ClerkInterface { public static mountComponentRenderer?: MountComponentRenderer; @@ -431,7 +433,7 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'SignIn' }) .then(controls => controls.openModal('signIn', props || {})); - this.#recordSignInUsage(props, 'Modal'); + this.#recordSignInUsage(props, 'modal'); }; public closeSignIn = (): void => { @@ -489,7 +491,7 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'SignUp' }) .then(controls => controls.openModal('signUp', props || {})); - this.#recordSignUpUsage(props, 'Modal'); + this.#recordSignUpUsage(props, 'modal'); }; public closeSignUp = (): void => { @@ -511,7 +513,7 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'UserProfile' }) .then(controls => controls.openModal('userProfile', props || {})); - this.#recordUserProfileUsage(props, 'Modal'); + this.#recordUserProfileUsage(props, 'modal'); }; public closeUserProfile = (): void => { @@ -540,7 +542,7 @@ export class Clerk implements ClerkInterface { void this.#componentControls .ensureMounted({ preloadHint: 'OrganizationProfile' }) .then(controls => controls.openModal('organizationProfile', props || {})); - this.#recordOrganizationProfileUsage(props, 'Modal'); + this.#recordComponentUsage('modal', 'OrganizationProfile', props); }; public closeOrganizationProfile = (): void => { @@ -562,7 +564,7 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'CreateOrganization' }) .then(controls => controls.openModal('createOrganization', props || {})); - this.#recordCreateOrganizationUsage(props, 'Modal'); + this.#recordComponentUsage('modal', 'CreateOrganization', props); }; public closeCreateOrganization = (): void => { @@ -576,7 +578,7 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'Waitlist' }) .then(controls => controls.openModal('waitlist', props || {})); - this.#recordWaitlistUsage(props, 'Modal'); + this.#recordComponentUsage('modal', 'Waitlist', props); }; public closeWaitlist = (): void => { @@ -687,7 +689,7 @@ export class Clerk implements ClerkInterface { }), ); - this.#recordOrganizationProfileUsage(props); + this.#recordComponentUsage('mounted', 'OrganizationProfile', props); }; public unmountOrganizationProfile = (node: HTMLDivElement) => { @@ -718,7 +720,7 @@ export class Clerk implements ClerkInterface { }), ); - this.#recordCreateOrganizationUsage(props); + this.#recordComponentUsage('mounted', 'CreateOrganization', props); }; public unmountCreateOrganization = (node: HTMLDivElement) => { @@ -749,7 +751,7 @@ export class Clerk implements ClerkInterface { }), ); - this.telemetry?.record(eventPrebuiltComponentMounted('OrganizationSwitcher', props)); + this.#recordComponentUsage('mounted', 'OrganizationSwitcher', props); }; public unmountOrganizationSwitcher = (node: HTMLDivElement): void => { @@ -783,7 +785,7 @@ export class Clerk implements ClerkInterface { }), ); - this.telemetry?.record(eventPrebuiltComponentMounted('OrganizationList', props)); + this.#recordComponentUsage('mounted', 'OrganizationList', props); }; public unmountOrganizationList = (node: HTMLDivElement): void => { @@ -802,21 +804,12 @@ export class Clerk implements ClerkInterface { }), ); - this.telemetry?.record( - eventPrebuiltComponentMounted('UserButton', props, { - ...(props?.customMenuItems?.length || 0 > 0 - ? { - customItems: true, - } - : undefined), - - ...(props?.__experimental_asStandalone - ? { - standalone: true, - } - : undefined), - }), - ); + const additionalData = { + ...(props?.customMenuItems?.length || 0 > 0 ? { customItems: true } : undefined), + ...(props?.__experimental_asStandalone ? { standalone: true } : undefined), + }; + + this.#recordComponentUsage('mounted', 'UserButton', props, additionalData); }; public unmountUserButton = (node: HTMLDivElement): void => { @@ -835,7 +828,7 @@ export class Clerk implements ClerkInterface { }), ); - this.#recordWaitlistUsage(props); + this.#recordComponentUsage('mounted', 'Waitlist', props); }; public unmountWaitlist = (node: HTMLDivElement): void => { @@ -2241,41 +2234,23 @@ export class Clerk implements ClerkInterface { return allowedProtocols; } - #recordSignInUsage = (props?: SignInProps, mode?: 'Modal') => { - this.telemetry?.record( - eventPrebuiltComponentMounted(`SignIn${mode || ''}`, props, { - withSignUp: props?.withSignUp ?? this.#isCombinedSignInOrUpFlow(), - }), - ); - }; - - #recordSignUpUsage = (props?: SignUpProps, mode?: 'Modal') => { - this.telemetry?.record(eventPrebuiltComponentMounted(`SignUp${mode || ''}`, props)); - }; - - #recordUserProfileUsage = (props?: UserProfileProps, mode?: 'Modal') => { - this.telemetry?.record( - eventPrebuiltComponentMounted( - `UserProfile${mode || ''}`, - props, - props?.customPages?.length || 0 > 0 - ? { - customPages: true, - } - : undefined, - ), - ); + #recordComponentUsage = (...args: [ComponentRenderingMode, ...Parameters]) => { + const [mode, name, ...data] = args; + const nameWithMode = mode === 'modal' ? `${name}Modal` : name; + this.telemetry?.record(eventPrebuiltComponentMounted(nameWithMode, ...data)); }; - #recordOrganizationProfileUsage = (props?: OrganizationProfileProps, mode?: 'Modal') => { - this.telemetry?.record(eventPrebuiltComponentMounted(`OrganizationProfile${mode || ''}`, props)); + #recordSignInUsage = (props?: SignInProps, mode: ComponentRenderingMode = 'mounted') => { + const additionalData = { withSignUp: props?.withSignUp ?? this.#isCombinedSignInOrUpFlow() }; + this.#recordComponentUsage(mode, 'SignIn', props, additionalData); }; - #recordCreateOrganizationUsage = (props?: OrganizationProfileProps, mode?: 'Modal') => { - this.telemetry?.record(eventPrebuiltComponentMounted(`CreateOrganization${mode || ''}`, props)); + #recordSignUpUsage = (props?: SignUpProps, mode: ComponentRenderingMode = 'mounted') => { + this.#recordComponentUsage(mode, 'SignUp', props); }; - #recordWaitlistUsage = (props?: WaitlistProps, mode?: 'Modal') => { - this.telemetry?.record(eventPrebuiltComponentMounted(`Waitlist${mode || ''}`, props)); + #recordUserProfileUsage = (props?: UserProfileProps, mode: ComponentRenderingMode = 'mounted') => { + const additionalData = props?.customPages?.length || 0 > 0 ? { customPages: true } : undefined; + this.#recordComponentUsage(mode, 'UserProfile', props, additionalData); }; } From fed0b5518c32801079b45e5d25cabbda34cc9dc9 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Mon, 17 Feb 2025 22:06:37 +0200 Subject: [PATCH 3/4] introduce a new event --- packages/clerk-js/src/core/clerk.ts | 69 ++++++++----------- .../src/telemetry/events/component-mounted.ts | 57 +++++++++++---- 2 files changed, 72 insertions(+), 54 deletions(-) diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index bb40cb8a5f6..dabddd02c25 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -5,7 +5,11 @@ import { parsePublishableKey } from '@clerk/shared/keys'; import { LocalStorageBroadcastChannel } from '@clerk/shared/localStorageBroadcastChannel'; import { logger } from '@clerk/shared/logger'; import { isHttpOrHttps, isValidProxyUrl, proxyUrlToAbsoluteURL } from '@clerk/shared/proxy'; -import { eventPrebuiltComponentMounted, TelemetryCollector } from '@clerk/shared/telemetry'; +import { + eventPrebuiltComponentMounted, + eventPrebuiltComponentOpened, + TelemetryCollector, +} from '@clerk/shared/telemetry'; import { addClerkPrefix, isAbsoluteUrl, stripScheme } from '@clerk/shared/url'; import { handleValueOrFn, noop } from '@clerk/shared/utils'; import type { @@ -152,8 +156,6 @@ const defaultOptions: ClerkOptions = { signUpForceRedirectUrl: undefined, }; -type ComponentRenderingMode = 'modal' | 'mounted'; - export class Clerk implements ClerkInterface { public static mountComponentRenderer?: MountComponentRenderer; @@ -411,7 +413,7 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'GoogleOneTap' }) .then(controls => controls.openModal('googleOneTap', props || {})); - this.telemetry?.record(eventPrebuiltComponentMounted(`GoogleOneTap`, props)); + this.telemetry?.record(eventPrebuiltComponentOpened(`GoogleOneTap`, props)); }; public closeGoogleOneTap = (): void => { @@ -433,7 +435,8 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'SignIn' }) .then(controls => controls.openModal('signIn', props || {})); - this.#recordSignInUsage(props, 'modal'); + const additionalData = { withSignUp: props?.withSignUp ?? this.#isCombinedSignInOrUpFlow() }; + this.telemetry?.record(eventPrebuiltComponentOpened(`SignIn`, props, additionalData)); }; public closeSignIn = (): void => { @@ -455,7 +458,7 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'UserVerification' }) .then(controls => controls.openModal('userVerification', props || {})); - this.telemetry?.record(eventPrebuiltComponentMounted(`UserVerification`, props)); + this.telemetry?.record(eventPrebuiltComponentOpened(`UserVerification`, props)); }; public __internal_closeReverification = (): void => { @@ -491,7 +494,7 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'SignUp' }) .then(controls => controls.openModal('signUp', props || {})); - this.#recordSignUpUsage(props, 'modal'); + this.telemetry?.record(eventPrebuiltComponentOpened('SignUp', props)); }; public closeSignUp = (): void => { @@ -513,7 +516,8 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'UserProfile' }) .then(controls => controls.openModal('userProfile', props || {})); - this.#recordUserProfileUsage(props, 'modal'); + const additionalData = props?.customPages?.length || 0 > 0 ? { customPages: true } : undefined; + this.telemetry?.record(eventPrebuiltComponentOpened('UserProfile', props, additionalData)); }; public closeUserProfile = (): void => { @@ -542,7 +546,8 @@ export class Clerk implements ClerkInterface { void this.#componentControls .ensureMounted({ preloadHint: 'OrganizationProfile' }) .then(controls => controls.openModal('organizationProfile', props || {})); - this.#recordComponentUsage('modal', 'OrganizationProfile', props); + + this.telemetry?.record(eventPrebuiltComponentOpened('OrganizationProfile', props)); }; public closeOrganizationProfile = (): void => { @@ -564,7 +569,7 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'CreateOrganization' }) .then(controls => controls.openModal('createOrganization', props || {})); - this.#recordComponentUsage('modal', 'CreateOrganization', props); + this.telemetry?.record(eventPrebuiltComponentOpened('CreateOrganization', props)); }; public closeCreateOrganization = (): void => { @@ -578,7 +583,7 @@ export class Clerk implements ClerkInterface { .ensureMounted({ preloadHint: 'Waitlist' }) .then(controls => controls.openModal('waitlist', props || {})); - this.#recordComponentUsage('modal', 'Waitlist', props); + this.telemetry?.record(eventPrebuiltComponentOpened('Waitlist', props)); }; public closeWaitlist = (): void => { @@ -596,7 +601,9 @@ export class Clerk implements ClerkInterface { props, }), ); - this.#recordSignInUsage(props); + + const additionalData = { withSignUp: props?.withSignUp ?? this.#isCombinedSignInOrUpFlow() }; + this.telemetry?.record(eventPrebuiltComponentMounted(`SignIn`, props, additionalData)); }; public unmountSignIn = (node: HTMLDivElement): void => { @@ -618,7 +625,8 @@ export class Clerk implements ClerkInterface { props, }), ); - this.#recordSignUpUsage(props); + + this.telemetry?.record(eventPrebuiltComponentMounted(`SignUp`, props)); }; public unmountSignUp = (node: HTMLDivElement): void => { @@ -649,7 +657,8 @@ export class Clerk implements ClerkInterface { }), ); - this.#recordUserProfileUsage(props); + const additionalData = props?.customPages?.length || 0 > 0 ? { customPages: true } : undefined; + this.telemetry?.record(eventPrebuiltComponentMounted('UserProfile', props, additionalData)); }; public unmountUserProfile = (node: HTMLDivElement): void => { @@ -689,7 +698,7 @@ export class Clerk implements ClerkInterface { }), ); - this.#recordComponentUsage('mounted', 'OrganizationProfile', props); + this.telemetry?.record(eventPrebuiltComponentMounted('OrganizationProfile', props)); }; public unmountOrganizationProfile = (node: HTMLDivElement) => { @@ -720,7 +729,7 @@ export class Clerk implements ClerkInterface { }), ); - this.#recordComponentUsage('mounted', 'CreateOrganization', props); + this.telemetry?.record(eventPrebuiltComponentMounted('CreateOrganization', props)); }; public unmountCreateOrganization = (node: HTMLDivElement) => { @@ -751,7 +760,7 @@ export class Clerk implements ClerkInterface { }), ); - this.#recordComponentUsage('mounted', 'OrganizationSwitcher', props); + this.telemetry?.record(eventPrebuiltComponentMounted('OrganizationSwitcher', props)); }; public unmountOrganizationSwitcher = (node: HTMLDivElement): void => { @@ -785,7 +794,7 @@ export class Clerk implements ClerkInterface { }), ); - this.#recordComponentUsage('mounted', 'OrganizationList', props); + this.telemetry?.record(eventPrebuiltComponentMounted('OrganizationList', props)); }; public unmountOrganizationList = (node: HTMLDivElement): void => { @@ -809,7 +818,7 @@ export class Clerk implements ClerkInterface { ...(props?.__experimental_asStandalone ? { standalone: true } : undefined), }; - this.#recordComponentUsage('mounted', 'UserButton', props, additionalData); + this.telemetry?.record(eventPrebuiltComponentMounted('UserButton', props, additionalData)); }; public unmountUserButton = (node: HTMLDivElement): void => { @@ -828,7 +837,7 @@ export class Clerk implements ClerkInterface { }), ); - this.#recordComponentUsage('mounted', 'Waitlist', props); + this.telemetry?.record(eventPrebuiltComponentMounted('Waitlist', props)); }; public unmountWaitlist = (node: HTMLDivElement): void => { @@ -2233,24 +2242,4 @@ export class Clerk implements ClerkInterface { return allowedProtocols; } - - #recordComponentUsage = (...args: [ComponentRenderingMode, ...Parameters]) => { - const [mode, name, ...data] = args; - const nameWithMode = mode === 'modal' ? `${name}Modal` : name; - this.telemetry?.record(eventPrebuiltComponentMounted(nameWithMode, ...data)); - }; - - #recordSignInUsage = (props?: SignInProps, mode: ComponentRenderingMode = 'mounted') => { - const additionalData = { withSignUp: props?.withSignUp ?? this.#isCombinedSignInOrUpFlow() }; - this.#recordComponentUsage(mode, 'SignIn', props, additionalData); - }; - - #recordSignUpUsage = (props?: SignUpProps, mode: ComponentRenderingMode = 'mounted') => { - this.#recordComponentUsage(mode, 'SignUp', props); - }; - - #recordUserProfileUsage = (props?: UserProfileProps, mode: ComponentRenderingMode = 'mounted') => { - const additionalData = props?.customPages?.length || 0 > 0 ? { customPages: true } : undefined; - this.#recordComponentUsage(mode, 'UserProfile', props, additionalData); - }; } diff --git a/packages/shared/src/telemetry/events/component-mounted.ts b/packages/shared/src/telemetry/events/component-mounted.ts index 41d5bf68747..777ae94284c 100644 --- a/packages/shared/src/telemetry/events/component-mounted.ts +++ b/packages/shared/src/telemetry/events/component-mounted.ts @@ -1,13 +1,14 @@ import type { TelemetryEventRaw } from '@clerk/types'; const EVENT_COMPONENT_MOUNTED = 'COMPONENT_MOUNTED'; +const EVENT_COMPONENT_OPENED = 'COMPONENT_OPENED'; const EVENT_SAMPLING_RATE = 0.1; type ComponentMountedBase = { component: string; }; -type EventPrebuiltComponentMounted = ComponentMountedBase & { +type EventPrebuiltComponent = ComponentMountedBase & { appearanceProp: boolean; elements: boolean; variables: boolean; @@ -16,6 +17,27 @@ type EventPrebuiltComponentMounted = ComponentMountedBase & { type EventComponentMounted = ComponentMountedBase & TelemetryEventRaw['payload']; +function createPrebuiltComponentEvent(event: typeof EVENT_COMPONENT_MOUNTED | typeof EVENT_COMPONENT_OPENED) { + return function ( + component: string, + props?: Record, + additionalPayload?: TelemetryEventRaw['payload'], + ): TelemetryEventRaw { + return { + event, + eventSamplingRate: EVENT_SAMPLING_RATE, + payload: { + component, + appearanceProp: Boolean(props?.appearance), + baseTheme: Boolean(props?.appearance?.baseTheme), + elements: Boolean(props?.appearance?.elements), + variables: Boolean(props?.appearance?.variables), + ...additionalPayload, + }, + }; + }; +} + /** * Helper function for `telemetry.record()`. Create a consistent event object for when a prebuilt (AIO) component is mounted. * @@ -30,19 +52,26 @@ export function eventPrebuiltComponentMounted( component: string, props?: Record, additionalPayload?: TelemetryEventRaw['payload'], -): TelemetryEventRaw { - return { - event: EVENT_COMPONENT_MOUNTED, - eventSamplingRate: EVENT_SAMPLING_RATE, - payload: { - component, - appearanceProp: Boolean(props?.appearance), - baseTheme: Boolean(props?.appearance?.baseTheme), - elements: Boolean(props?.appearance?.elements), - variables: Boolean(props?.appearance?.variables), - ...additionalPayload, - }, - }; +): TelemetryEventRaw { + return createPrebuiltComponentEvent(EVENT_COMPONENT_MOUNTED)(component, props, additionalPayload); +} + +/** + * Helper function for `telemetry.record()`. Create a consistent event object for when a prebuilt (AIO) component is mounted. + * + * @param component - The name of the component. + * @param props - The props passed to the component. Will be filtered to a known list of props. + * @param additionalPayload - Additional data to send with the event. + * + * @example + * telemetry.record(eventPrebuiltComponentOpened('GoogleOneTap', props)); + */ +export function eventPrebuiltComponentOpened( + component: string, + props?: Record, + additionalPayload?: TelemetryEventRaw['payload'], +): TelemetryEventRaw { + return createPrebuiltComponentEvent(EVENT_COMPONENT_OPENED)(component, props, additionalPayload); } /** From 23a1208ca4b277f0a9d1fe5d3d9cf847cd0cbb14 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 19 Feb 2025 13:20:35 +0200 Subject: [PATCH 4/4] Update packages/shared/src/telemetry/events/component-mounted.ts Co-authored-by: Bryce Kalow --- packages/shared/src/telemetry/events/component-mounted.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/telemetry/events/component-mounted.ts b/packages/shared/src/telemetry/events/component-mounted.ts index 777ae94284c..7f3e7bbc5f3 100644 --- a/packages/shared/src/telemetry/events/component-mounted.ts +++ b/packages/shared/src/telemetry/events/component-mounted.ts @@ -57,7 +57,7 @@ export function eventPrebuiltComponentMounted( } /** - * Helper function for `telemetry.record()`. Create a consistent event object for when a prebuilt (AIO) component is mounted. + * Helper function for `telemetry.record()`. Create a consistent event object for when a prebuilt (AIO) component is opened as a modal. * * @param component - The name of the component. * @param props - The props passed to the component. Will be filtered to a known list of props.