[WEB-4604] feat: add missing posthog events for project grouping, trial and upgrade. (#3783)

This commit is contained in:
Prateek Shourya
2025-07-30 17:46:22 +05:30
committed by GitHub
parent 0f66c8d7b1
commit 76dee7cbcc
7 changed files with 101 additions and 7 deletions

View File

@@ -4,6 +4,7 @@ import React from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// plane imports
import { PROJECT_GROUPING_TRACKER_EVENTS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { EUserWorkspaceRoles } from "@plane/types";
import { ToggleSwitch } from "@plane/ui";
@@ -12,6 +13,7 @@ import { NotAuthorizedView } from "@/components/auth-screens";
import { PageHead } from "@/components/core";
// store hooks
import { SettingsContentWrapper, SettingsHeading } from "@/components/settings";
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
import { useUserPermissions, useWorkspace } from "@/hooks/store";
// plane web components
import { WithFeatureFlagHOC } from "@/plane-web/components/feature-flags";
@@ -44,13 +46,24 @@ const WorklogsPage = observer(() => {
if (!isAdmin) return <NotAuthorizedView section="settings" className="h-auto" />;
const toggleProjectGroupingFeature = async () => {
const willEnableProjectGrouping = !isProjectGroupingEnabled;
try {
const payload = {
[EWorkspaceFeatures.IS_PROJECT_GROUPING_ENABLED]: !isProjectGroupingEnabled,
[EWorkspaceFeatures.IS_PROJECT_GROUPING_ENABLED]: willEnableProjectGrouping,
};
await updateWorkspaceFeature(workspaceSlug.toString(), payload);
captureSuccess({
eventName: willEnableProjectGrouping
? PROJECT_GROUPING_TRACKER_EVENTS.ENABLE
: PROJECT_GROUPING_TRACKER_EVENTS.DISABLE,
});
} catch (error) {
console.error(error);
captureError({
eventName: willEnableProjectGrouping
? PROJECT_GROUPING_TRACKER_EVENTS.DISABLE
: PROJECT_GROUPING_TRACKER_EVENTS.ENABLE,
});
}
};

View File

@@ -4,19 +4,23 @@ import { useState } from "react";
import { useParams } from "next/navigation";
// plane imports
import { Loader } from "lucide-react";
import { LICENSE_TRACKER_ELEMENTS, LICENSE_TRACKER_EVENTS } from "@plane/constants";
import { EProductSubscriptionEnum } from "@plane/types";
import { setToast, TOAST_TYPE } from "@plane/ui";
import { cn } from "@plane/utils";
// plane web imports
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
import { useWorkspaceSubscription } from "@/plane-web/hooks/store";
export type TTrialButtonProps = {
productId: string | undefined;
priceId: string | undefined;
handleClose: () => void;
priceId: string | undefined;
productId: string | undefined;
variant: EProductSubscriptionEnum;
};
export const TrialButton: React.FC<TTrialButtonProps> = (props: TTrialButtonProps) => {
const { productId, priceId, handleClose } = props;
const { handleClose, productId, priceId, variant } = props;
// router
const { workspaceSlug } = useParams();
// states
@@ -39,6 +43,12 @@ export const TrialButton: React.FC<TTrialButtonProps> = (props: TTrialButtonProp
await freeTrialSubscription(workspaceSlug.toString(), { product_id: productId, price_id: priceId });
handleClose();
handleSuccessModalToggle(true);
captureSuccess({
eventName: LICENSE_TRACKER_EVENTS.trial_started,
payload: {
plan: variant,
},
});
} catch (error) {
const currentError = error as unknown as { error: string; detail: string };
console.error("Error in freeTrialSubscription", error);
@@ -47,6 +57,12 @@ export const TrialButton: React.FC<TTrialButtonProps> = (props: TTrialButtonProp
title: "Error!",
message: currentError?.detail ?? currentError?.error ?? "Something went wrong. Please try again.",
});
captureError({
eventName: LICENSE_TRACKER_EVENTS.trial_started,
payload: {
plan: variant,
},
});
} finally {
setTrialLoader(false);
}
@@ -54,6 +70,7 @@ export const TrialButton: React.FC<TTrialButtonProps> = (props: TTrialButtonProp
return (
<button
data-element={LICENSE_TRACKER_ELEMENTS.MODAL_TRIAL_BUTTON}
disabled={trialLoader}
className="text-center text-sm text-custom-text-300 hover:text-custom-text-100 font-medium transition-all flex justify-center items-center gap-1.5 -ml-5"
onClick={() => handleTrial(productId, priceId)}

View File

@@ -8,6 +8,8 @@ import useSWR from "swr";
import {
BUSINESS_PLAN_FEATURES,
ENTERPRISE_PLAN_FEATURES,
LICENSE_TRACKER_ELEMENTS,
LICENSE_TRACKER_EVENTS,
PRO_PLAN_FEATURES,
SUBSCRIPTION_WEBPAGE_URLS,
SUBSCRIPTION_WITH_TRIAL,
@@ -19,6 +21,7 @@ import { cn, getSubscriptionName } from "@plane/utils";
import { FreePlanCard, PlanUpgradeCard } from "@/components/license";
import { TCheckoutParams } from "@/components/license/modal/card/checkout-button";
// plane web imports
import { captureClick, captureError, captureSuccess } from "@/helpers/event-tracker.helper";
import { useSelfHostedSubscription, useWorkspaceSubscription } from "@/plane-web/hooks/store";
import { PaymentService } from "@/plane-web/services/payment.service";
// local imports
@@ -71,12 +74,18 @@ export const PaidPlanUpgradeModal: FC<PaidPlanUpgradeModalProps> = observer((pro
);
const handleStripeCheckout = ({ planVariant, productId, priceId }: TCheckoutParams) => {
captureClick({
elementName: LICENSE_TRACKER_ELEMENTS.MODAL_UPGRADE_BUTTON,
});
if (!productId || !priceId) {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Unable to get the product id or price id. Please try again.",
});
captureError({
eventName: LICENSE_TRACKER_EVENTS.upgrade_product_or_price_not_found,
});
return;
}
setUpgradeLoaderType(planVariant);
@@ -88,6 +97,9 @@ export const PaidPlanUpgradeModal: FC<PaidPlanUpgradeModalProps> = observer((pro
.then((response) => {
if (response.url) {
window.open(response.url, "_blank");
captureSuccess({
eventName: LICENSE_TRACKER_EVENTS.upgrade_url_received,
});
}
})
.catch((error) => {
@@ -96,6 +108,9 @@ export const PaidPlanUpgradeModal: FC<PaidPlanUpgradeModalProps> = observer((pro
title: "Error!",
message: error?.error ?? "Failed to generate payment link. Please try again.",
});
captureError({
eventName: LICENSE_TRACKER_EVENTS.upgrade_url_received,
});
})
.finally(() => {
setUpgradeLoaderType(undefined);
@@ -108,7 +123,7 @@ export const PaidPlanUpgradeModal: FC<PaidPlanUpgradeModalProps> = observer((pro
priceId: string | undefined
) => {
if (SUBSCRIPTION_WITH_TRIAL.includes(variant)) {
return <TrialButton productId={productId} priceId={priceId} handleClose={handleClose} />;
return <TrialButton handleClose={handleClose} productId={productId} priceId={priceId} variant={variant} />;
}
return null;
};

View File

@@ -1,7 +1,7 @@
import { FC } from "react";
import { observer } from "mobx-react";
// plane imports
import { EProductSubscriptionTier } from "@plane/constants";
import { EProductSubscriptionTier, LICENSE_TRACKER_ELEMENTS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { EProductSubscriptionEnum, IPaymentProduct } from "@plane/types";
import { Button, getButtonStyling, getUpgradeButtonStyle, Loader } from "@plane/ui";
@@ -73,6 +73,7 @@ export const SubscriptionButton: FC<TSubscriptionButtonProps> = observer((props)
return (
<button
data-ph-element={LICENSE_TRACKER_ELEMENTS.BILLING_PAGE_COMPARISON_SECTION_UPGRADE_BUTTON}
onClick={() => handleSubscriptionUpgrade(subscriptionType)}
className={cn(upgradeButtonStyle, COMMON_BUTTON_STYLE)}
disabled={!!upgradeLoader}

View File

@@ -1,6 +1,7 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { LoaderIcon } from "lucide-react";
import { LICENSE_TRACKER_ELEMENTS } from "@plane/constants";
import { EProductSubscriptionEnum } from "@plane/types";
// plane imports
import { Button } from "@plane/ui";
@@ -35,6 +36,7 @@ export const TrialDetails: FC<TTrialDetailsProps> = observer((props) => {
if (isTrialAllowed) {
return (
<Button
data-ph-element={LICENSE_TRACKER_ELEMENTS.BILLING_PAGE_TRIAL_BUTTON}
variant="link-neutral"
size="sm"
onClick={() => handleTrial(subscriptionType)}

View File

@@ -3,7 +3,12 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import useSWR from "swr";
// plane imports
import { DEFAULT_PRODUCT_BILLING_FREQUENCY, SUBSCRIPTION_WITH_BILLING_FREQUENCY } from "@plane/constants";
import {
DEFAULT_PRODUCT_BILLING_FREQUENCY,
LICENSE_TRACKER_ELEMENTS,
LICENSE_TRACKER_EVENTS,
SUBSCRIPTION_WITH_BILLING_FREQUENCY,
} from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import {
EProductSubscriptionEnum,
@@ -18,6 +23,7 @@ import { cn, getSubscriptionProduct, getSubscriptionProductPrice } from "@plane/
// helpers
import { SettingsHeading } from "@/components/settings";
// plane web imports
import { captureClick, captureError, captureSuccess } from "@/helpers/event-tracker.helper";
import {
CloudFreePlanCard,
OnePlanCard,
@@ -92,6 +98,12 @@ export const BillingRoot = observer(() => {
price_id: selectedPriceId,
});
handleSuccessModalToggle(true);
captureSuccess({
eventName: LICENSE_TRACKER_EVENTS.trial_started,
payload: {
plan: selectedSubscriptionType,
},
});
} catch (error) {
const currentError = error as unknown as { error: string; detail: string };
console.error("Error in freeTrialSubscription", error);
@@ -100,6 +112,12 @@ export const BillingRoot = observer(() => {
title: "Error!",
message: currentError?.detail ?? currentError?.error ?? "Something went wrong. Please try again.",
});
captureError({
eventName: LICENSE_TRACKER_EVENTS.trial_started,
payload: {
plan: selectedSubscriptionType,
},
});
} finally {
setTrialLoader(null);
}
@@ -126,6 +144,9 @@ export const BillingRoot = observer(() => {
}
if (!selectedProductId || !selectedPriceId) {
setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: "Missing product or price ID" });
captureError({
eventName: LICENSE_TRACKER_EVENTS.upgrade_product_or_price_not_found,
});
return;
}
setUpgradeLoader(selectedSubscriptionType);
@@ -136,6 +157,9 @@ export const BillingRoot = observer(() => {
})
.then((response) => {
if (response.url) window.open(response.url, isSelfManaged ? "_blank" : "_self");
captureSuccess({
eventName: LICENSE_TRACKER_EVENTS.upgrade_url_received,
});
})
.catch((error) => {
setToast({
@@ -143,6 +167,9 @@ export const BillingRoot = observer(() => {
title: "Error!",
message: error?.error ?? "Failed to generate payment link",
});
captureError({
eventName: LICENSE_TRACKER_EVENTS.upgrade_url_received,
});
})
.finally(() => setUpgradeLoader(null));
};
@@ -191,6 +218,9 @@ export const BillingRoot = observer(() => {
*/
const handleSelectedPlanUpgrade = (selectedSubscriptionType: EProductSubscriptionEnum): Promise<void> => {
const { selectedProduct, selectedPrice } = getSelectedProductAndPrice(selectedSubscriptionType);
captureClick({
elementName: LICENSE_TRACKER_ELEMENTS.BILLING_PAGE_PLAN_CARD_UPGRADE_BUTTON,
});
return handleUpgradeSubscription({
selectedSubscriptionType,
selectedProductId: selectedProduct?.id,

View File

@@ -12,6 +12,22 @@ export const EPIC_TRACKER_ELEMENTS = {
export const LICENSE_TRACKER_EVENTS = {
purchase_modal_opened: "purchase_modal_opened",
success_modal_opened: "success_modal_opened",
trial_started: "trial_started",
upgrade_url_received: "upgrade_url_received",
upgrade_product_or_price_not_found: "upgrade_product_or_price_not_found",
};
export const LICENSE_TRACKER_ELEMENTS = {
MODAL_TRIAL_BUTTON: "modal_trial_button",
BILLING_PAGE_TRIAL_BUTTON: "billing_page_trial_button",
MODAL_UPGRADE_BUTTON: "modal_upgrade_button",
BILLING_PAGE_COMPARISON_SECTION_UPGRADE_BUTTON: "billing_page_comparison_section_upgrade_button",
BILLING_PAGE_PLAN_CARD_UPGRADE_BUTTON: "billing_page_plan_card_upgrade_button",
};
export const PROJECT_GROUPING_TRACKER_EVENTS = {
ENABLE: "project_grouping_enabled",
DISABLE: "project_grouping_disabled",
};
export const PROJECT_OVERVIEW_TRACKER_EVENTS = {