diff --git a/web/core/components/onboarding/create-workspace.tsx b/web/core/components/onboarding/create-workspace.tsx index 157beec74a9..d9cf3d11637 100644 --- a/web/core/components/onboarding/create-workspace.tsx +++ b/web/core/components/onboarding/create-workspace.tsx @@ -4,19 +4,15 @@ import { useState } from "react"; import { observer } from "mobx-react"; import { Controller, useForm } from "react-hook-form"; // constants -import { - ONBOARDING_TRACKER_EVENTS, - ORGANIZATION_SIZE, - RESTRICTED_URLS, - WORKSPACE_TRACKER_EVENTS, -} from "@plane/constants"; +import { ORGANIZATION_SIZE, RESTRICTED_URLS, WORKSPACE_TRACKER_EVENTS } from "@plane/constants"; // types import { useTranslation } from "@plane/i18n"; import { IUser, IWorkspace, TOnboardingSteps } from "@plane/types"; // ui import { Button, CustomSelect, Input, Spinner, TOAST_TYPE, setToast } from "@plane/ui"; // hooks -import { useEventTracker, useUserProfile, useUserSettings, useWorkspace } from "@/hooks/store"; +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; +import { useUserProfile, useUserSettings, useWorkspace } from "@/hooks/store"; // services import { WorkspaceService } from "@/plane-web/services"; @@ -41,7 +37,6 @@ export const CreateWorkspace: React.FC = observer((props) => { const { updateUserProfile } = useUserProfile(); const { fetchCurrentUserSettings } = useUserSettings(); const { createWorkspace, fetchWorkspaces } = useWorkspace(); - const { captureWorkspaceEvent } = useEventTracker(); // form info const { handleSubmit, @@ -73,26 +68,18 @@ export const CreateWorkspace: React.FC = observer((props) => { title: t("workspace_creation.toast.success.title"), message: t("workspace_creation.toast.success.message"), }); - captureWorkspaceEvent({ + captureSuccess({ eventName: WORKSPACE_TRACKER_EVENTS.create, - payload: { - ...workspaceResponse, - state: "SUCCESS", - first_time: true, - element: ONBOARDING_TRACKER_EVENTS.root, - }, + payload: { slug: formData.slug }, }); await fetchWorkspaces(); await completeStep(workspaceResponse.id); }) .catch(() => { - captureWorkspaceEvent({ + captureError({ eventName: WORKSPACE_TRACKER_EVENTS.create, - payload: { - state: "FAILED", - first_time: true, - element: ONBOARDING_TRACKER_EVENTS.root, - }, + payload: { slug: formData.slug }, + error: new Error("Error creating workspace"), }); setToast({ type: TOAST_TYPE.ERROR, @@ -290,7 +277,14 @@ export const CreateWorkspace: React.FC = observer((props) => { )} - diff --git a/web/core/components/workspace/create-workspace-form.tsx b/web/core/components/workspace/create-workspace-form.tsx index 0f51e74b26f..8a1313b4d21 100644 --- a/web/core/components/workspace/create-workspace-form.tsx +++ b/web/core/components/workspace/create-workspace-form.tsx @@ -11,7 +11,8 @@ import { IWorkspace } from "@plane/types"; // ui import { Button, CustomSelect, Input, TOAST_TYPE, setToast } from "@plane/ui"; // hooks -import { useEventTracker, useWorkspace } from "@/hooks/store"; +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; +import { useWorkspace } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; // services import { WorkspaceService } from "@/plane-web/services"; @@ -51,7 +52,6 @@ export const CreateWorkspaceForm: FC = observer((props) => { // router const router = useAppRouter(); // store hooks - const { captureWorkspaceEvent } = useEventTracker(); const { createWorkspace } = useWorkspace(); // form info const { @@ -71,13 +71,9 @@ export const CreateWorkspaceForm: FC = observer((props) => { await createWorkspace(formData) .then(async (res) => { - captureWorkspaceEvent({ + captureSuccess({ eventName: WORKSPACE_TRACKER_EVENTS.create, - payload: { - ...res, - state: "SUCCESS", - element: "Create workspace page", - }, + payload: { slug: formData.slug }, }); setToast({ type: TOAST_TYPE.SUCCESS, @@ -88,12 +84,10 @@ export const CreateWorkspaceForm: FC = observer((props) => { if (onSubmit) await onSubmit(res); }) .catch(() => { - captureWorkspaceEvent({ + captureError({ eventName: WORKSPACE_TRACKER_EVENTS.create, - payload: { - state: "FAILED", - element: "Create workspace page", - }, + payload: { slug: formData.slug }, + error: new Error("Error creating workspace"), }); setToast({ type: TOAST_TYPE.ERROR, @@ -248,7 +242,14 @@ export const CreateWorkspaceForm: FC = observer((props) => {
{secondaryButton} - {!secondaryButton && ( diff --git a/web/core/components/workspace/delete-workspace-form.tsx b/web/core/components/workspace/delete-workspace-form.tsx index c668ad300c6..ea3358a1868 100644 --- a/web/core/components/workspace/delete-workspace-form.tsx +++ b/web/core/components/workspace/delete-workspace-form.tsx @@ -13,7 +13,8 @@ import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui"; // constants // hooks import { cn } from "@plane/utils"; -import { useEventTracker, useUserSettings, useWorkspace } from "@/hooks/store"; +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; +import { useUserSettings, useWorkspace } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; type Props = { @@ -31,7 +32,6 @@ export const DeleteWorkspaceForm: React.FC = observer((props) => { // router const router = useAppRouter(); // store hooks - const { captureWorkspaceEvent } = useEventTracker(); const { deleteWorkspace } = useWorkspace(); const { t } = useTranslation(); const { getWorkspaceRedirectionUrl } = useWorkspace(); @@ -64,13 +64,9 @@ export const DeleteWorkspaceForm: React.FC = observer((props) => { await fetchCurrentUserSettings(); handleClose(); router.push(getWorkspaceRedirectionUrl()); - captureWorkspaceEvent({ + captureSuccess({ eventName: WORKSPACE_TRACKER_EVENTS.delete, - payload: { - ...data, - state: "SUCCESS", - element: "Workspace general settings page", - }, + payload: { slug: data.slug }, }); setToast({ type: TOAST_TYPE.SUCCESS, @@ -84,13 +80,10 @@ export const DeleteWorkspaceForm: React.FC = observer((props) => { title: t("workspace_settings.settings.general.delete_modal.error_title"), message: t("workspace_settings.settings.general.delete_modal.error_message"), }); - captureWorkspaceEvent({ + captureError({ eventName: WORKSPACE_TRACKER_EVENTS.delete, - payload: { - ...data, - state: "FAILED", - element: "Workspace general settings page", - }, + payload: { slug: data.slug }, + error: new Error("Error deleting workspace"), }); }); }; @@ -169,7 +162,14 @@ export const DeleteWorkspaceForm: React.FC = observer((props) => { -
diff --git a/web/core/components/workspace/settings/workspace-details.tsx b/web/core/components/workspace/settings/workspace-details.tsx index e9a83784b58..1bbf8f83fe4 100644 --- a/web/core/components/workspace/settings/workspace-details.tsx +++ b/web/core/components/workspace/settings/workspace-details.tsx @@ -15,7 +15,8 @@ import { LogoSpinner } from "@/components/common"; import { WorkspaceImageUploadModal } from "@/components/core"; // helpers // hooks -import { useEventTracker, useUserPermissions, useWorkspace } from "@/hooks/store"; +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; +import { useUserPermissions, useWorkspace } from "@/hooks/store"; // plane web components import { DeleteWorkspaceSection } from "@/plane-web/components/workspace"; @@ -31,7 +32,6 @@ export const WorkspaceDetails: FC = observer(() => { const [isLoading, setIsLoading] = useState(false); const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false); // store hooks - const { captureWorkspaceEvent } = useEventTracker(); const { currentWorkspace, updateWorkspace } = useWorkspace(); const { allowPermissions } = useUserPermissions(); const { t } = useTranslation(); @@ -61,13 +61,9 @@ export const WorkspaceDetails: FC = observer(() => { await updateWorkspace(currentWorkspace.slug, payload) .then((res) => { - captureWorkspaceEvent({ + captureSuccess({ eventName: WORKSPACE_TRACKER_EVENTS.update, - payload: { - ...res, - state: "SUCCESS", - element: "Workspace general settings page", - }, + payload: { slug: currentWorkspace.slug }, }); setToast({ title: "Success!", @@ -76,12 +72,10 @@ export const WorkspaceDetails: FC = observer(() => { }); }) .catch((err) => { - captureWorkspaceEvent({ + captureError({ eventName: WORKSPACE_TRACKER_EVENTS.update, - payload: { - state: "FAILED", - element: "Workspace general settings page", - }, + payload: { slug: currentWorkspace.slug }, + error: err, }); console.error(err); }); @@ -282,7 +276,12 @@ export const WorkspaceDetails: FC = observer(() => { {isAdmin && (
-
diff --git a/web/core/lib/posthog-provider.tsx b/web/core/lib/posthog-provider.tsx index cf135a49b10..7e8bd47a1e7 100644 --- a/web/core/lib/posthog-provider.tsx +++ b/web/core/lib/posthog-provider.tsx @@ -11,7 +11,7 @@ import { GROUP_WORKSPACE_TRACKER_EVENT, TTrackingElement } from "@plane/constant // helpers import { getUserRole } from "@plane/utils"; // hooks -import { trackClick } from "@/helpers/event-tracker.helper"; +import { captureClick } from "@/helpers/event-tracker.helper"; import { useWorkspace, useUser, useInstance, useUserPermissions } from "@/hooks/store"; // dynamic imports const PostHogPageView = dynamic(() => import("@/lib/posthog-view"), { ssr: false }); @@ -73,7 +73,7 @@ const PostHogProvider: FC = observer((props) => { const target = event.target as HTMLElement; const element = target.getAttribute("data-ph-element"); if (element) { - trackClick({ elementName: element as TTrackingElement }); + captureClick({ elementName: element as TTrackingElement }); } }; diff --git a/web/core/store/event-tracker.store.ts b/web/core/store/event-tracker.store.ts index 8116eaaf0f3..a72f12a026e 100644 --- a/web/core/store/event-tracker.store.ts +++ b/web/core/store/event-tracker.store.ts @@ -10,9 +10,7 @@ import { getModuleEventPayload, getProjectEventPayload, getProjectStateEventPayload, - getWorkspaceEventPayload, getPageEventPayload, - WORKSPACE_TRACKER_EVENTS, } from "@plane/constants"; import { CoreRootStore } from "./root.store"; @@ -26,7 +24,6 @@ export interface ICoreEventTrackerStore { setTrackElement: (element: string) => void; captureEvent: (eventName: string, payload?: any) => void; joinWorkspaceMetricGroup: (workspaceId?: string) => void; - captureWorkspaceEvent: (props: EventProps) => void; captureProjectEvent: (props: EventProps) => void; captureCycleEvent: (props: EventProps) => void; captureModuleEvent: (props: EventProps) => void; @@ -109,23 +106,6 @@ export abstract class CoreEventTrackerStore implements ICoreEventTrackerStore { this.setTrackElement(undefined); }; - /** - * @description: Captures the workspace crud related events. - * @param {EventProps} props - */ - captureWorkspaceEvent = (props: EventProps) => { - const { eventName, payload } = props; - if (eventName === WORKSPACE_TRACKER_EVENTS.create && payload.state == "SUCCESS") { - this.joinWorkspaceMetricGroup(payload.id); - } - const eventPayload: any = getWorkspaceEventPayload({ - ...payload, - element: payload.element ?? this.trackElement, - }); - posthog?.capture(eventName, eventPayload); - this.setTrackElement(undefined); - }; - /** * @description: Captures the project related events. * @param {EventProps} props diff --git a/web/helpers/event-tracker.helper.ts b/web/helpers/event-tracker.helper.ts index 0f0ff151671..175c6458a7a 100644 --- a/web/helpers/event-tracker.helper.ts +++ b/web/helpers/event-tracker.helper.ts @@ -19,7 +19,7 @@ type TTrackElementParams = { * @param element - Generic UI element type * @param context - Context about where and why the interaction happened */ -const trackElement = (params: TTrackElementParams) => { +const captureElement = (params: TTrackElementParams) => { const { elementName, interaction_type, context } = params; if (!posthog) return; @@ -40,8 +40,8 @@ type TTrackClickParams = Omit; * @param element - The element that was clicked * @param context - Additional context */ -export const trackClick = (params: TTrackClickParams) => { - trackElement({ ...params, interaction_type: "clicked" }); +export const captureClick = (params: TTrackClickParams) => { + captureElement({ ...params, interaction_type: "clicked" }); }; type TTrackViewParams = Omit; @@ -50,8 +50,8 @@ type TTrackViewParams = Omit; * @param element - The element that was viewed * @param context - Additional context */ -export const trackView = (params: TTrackViewParams) => { - trackElement({ ...params, interaction_type: "viewed" }); +export const captureView = (params: TTrackViewParams) => { + captureElement({ ...params, interaction_type: "viewed" }); }; type TTrackHoverParams = Omit; @@ -60,8 +60,8 @@ type TTrackHoverParams = Omit; * @param element - The element that was hovered * @param context - Additional context */ -export const trackHover = (params: TTrackHoverParams) => { - trackElement({ ...params, interaction_type: "hovered" }); +export const captureHover = (params: TTrackHoverParams) => { + captureElement({ ...params, interaction_type: "hovered" }); }; type TTrackEventParams = { @@ -80,7 +80,7 @@ type TTrackEventParams = { * @param payload - Event-specific data * @param context - Additional context */ -const trackEvent = (params: TTrackEventParams) => { +const captureEvent = (params: TTrackEventParams) => { const { eventName, payload, context, state } = params; if (!posthog) return; @@ -101,8 +101,8 @@ type TTrackSuccessParams = Omit; * @param payload - Additional payload * @param context - Additional context */ -export const trackSuccess = (params: TTrackSuccessParams) => { - trackEvent({ ...params, state: "SUCCESS" }); +export const captureSuccess = (params: TTrackSuccessParams) => { + captureEvent({ ...params, state: "SUCCESS" }); }; type TTrackErrorParams = Omit & { @@ -116,8 +116,8 @@ type TTrackErrorParams = Omit & { * @param payload - Additional payload * @param context - Additional context */ -export const trackError = (params: TTrackErrorParams) => { - trackEvent({ ...params, state: "ERROR", payload: { ...params.payload, error: params.error } }); +export const captureError = (params: TTrackErrorParams) => { + captureEvent({ ...params, state: "ERROR", payload: { ...params.payload, error: params.error } }); }; type TTrackElementAndEventParams = { @@ -130,11 +130,11 @@ type TTrackElementAndEventParams = { * @param element - The element that was interacted with * @param event - The business event that was triggered */ -export const trackElementAndEvent = (params: TTrackElementAndEventParams) => { +export const captureElementAndEvent = (params: TTrackElementAndEventParams) => { const { element, event } = params; // Track the element interaction first - trackElement({ ...element, interaction_type: "clicked" }); + captureElement({ ...element, interaction_type: "clicked" }); - // Then track the business event - trackEvent(event); + // Then capture the business event + captureEvent(event); };