feat: add PostHog event tracking for feature opt-in banner and dialog (#27579)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Eunjae LeeandDevin AI authored and GitHub committed 2026-02-04 09:32:35 +00:00
1 parent 4367028492
commit 5804cc4fb0
3 files changed
+63 -2

No files matched your search

@@ -3,7 +3,8 @@
import type { OptInFeatureConfig } from "@calcom/features/feature-opt-in/config";
import { getOptInFeatureConfig, shouldDisplayFeatureAt } from "@calcom/features/feature-opt-in/config";
import { trpc } from "@calcom/trpc/react";
import { useCallback, useEffect, useMemo, useState } from "react";
import posthog from "posthog-js";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
getFeatureOptInTimestamp,
isFeatureDismissed,
@@ -28,6 +29,12 @@ type FeatureOptInMutations = {
invalidateQueries: () => void;
};
type FeatureOptInTrackingData = {
enableFor: "user" | "organization" | "teams";
teamCount?: number;
autoOptIn: boolean;
};
type UseFeatureOptInBannerResult = {
shouldShow: boolean;
isLoading: boolean;
@@ -41,6 +48,7 @@ type UseFeatureOptInBannerResult = {
dismiss: () => void;
markOptedIn: () => void;
mutations: FeatureOptInMutations;
trackFeatureEnabled: (data: FeatureOptInTrackingData) => void;
};
function isFeatureOptedIn(featureId: string): boolean {
@@ -108,7 +116,12 @@ function useFeatureOptInBanner(featureId: string): UseFeatureOptInBannerResult {
]
);
const hasBannerShownBeenTracked = useRef(false);
const dismiss = useCallback(() => {
posthog.capture("feature_opt_in_banner_dismissed", {
feature_slug: featureId,
});
setFeatureDismissed(featureId);
setIsDismissed(true);
}, [featureId]);
@@ -119,13 +132,28 @@ function useFeatureOptInBanner(featureId: string): UseFeatureOptInBannerResult {
}, [featureId]);
const openDialog = useCallback(() => {
posthog.capture("feature_opt_in_banner_try_it_clicked", {
feature_slug: featureId,
});
setIsDialogOpen(true);
}, []);
}, [featureId]);
const closeDialog = useCallback(() => {
setIsDialogOpen(false);
}, []);
const trackFeatureEnabled = useCallback(
(data: FeatureOptInTrackingData) => {
posthog.capture("feature_opt_in_enabled", {
feature_slug: featureId,
enable_for: data.enableFor,
team_count: data.teamCount,
auto_opt_in: data.autoOptIn,
});
},
[featureId]
);
const shouldShow = useMemo(() => {
if (isDismissed) return false;
if (isOptedIn) return false;
@@ -137,6 +165,15 @@ function useFeatureOptInBanner(featureId: string): UseFeatureOptInBannerResult {
return eligibilityQuery.data.status === "can_opt_in";
}, [isDismissed, isOptedIn, featureConfig, eligibilityQuery.isLoading, eligibilityQuery.data]);
useEffect(() => {
if (shouldShow && !hasBannerShownBeenTracked.current) {
hasBannerShownBeenTracked.current = true;
posthog.capture("feature_opt_in_banner_shown", {
feature_slug: featureId,
});
}
}, [shouldShow, featureId]);
return {
shouldShow,
isLoading: eligibilityQuery.isLoading,
@@ -150,6 +187,7 @@ function useFeatureOptInBanner(featureId: string): UseFeatureOptInBannerResult {
dismiss,
markOptedIn,
mutations,
trackFeatureEnabled,
};
}