plane/web/store/event-tracker.store.ts

339 lines
11 KiB
TypeScript

import { action, computed, makeObservable, observable } from "mobx";
import posthog from "posthog-js";
// stores
import { RootStore } from "./root.store";
// helpers
import { getUserRole } from "helpers/user.helper";
// constants
import {
EventProps,
IssueEventProps,
getCycleEventPayload,
getIssueEventPayload,
getModuleEventPayload,
getProjectEventPayload,
getProjectStateEventPayload,
getWorkspaceEventPayload,
getPageEventPayload,
getIssuesListOpenedPayload,
getIssuesFilterEventPayload,
getIssuesDisplayFilterPayload,
LP_UPDATED,
ISSUES_LIST_OPENED,
GROUP_WORKSPACE,
WORKSPACE_CREATED,
LABEL_REMOVED_G,
LABEL_ADDED_G,
} from "@/constants/event-tracker";
import { IIssueLabelTree } from "@plane/types";
export interface IEventTrackerStore {
// properties
trackElement: string | undefined;
// computed
getRequiredProperties: any;
getTrackElement: string | undefined;
// actions
resetSession: () => void;
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;
capturePageEvent: (props: EventProps) => void;
captureIssueEvent: (props: IssueEventProps) => void;
captureProjectStateEvent: (props: EventProps) => void;
captureIssuesListOpenedEvent: (payload: any) => void;
captureIssuesFilterEvent: (props: EventProps) => void;
captureIssuesDisplayFilterEvent: (props: EventProps) => void;
captureLabelDragNDropEvent: (
childLabelParent: string | null | undefined,
parentLabel: string | null | undefined,
childLabel: string | null | undefined,
projectLabelsTree: IIssueLabelTree[] | undefined
) => void;
}
export class EventTrackerStore implements IEventTrackerStore {
trackElement: string | undefined = undefined;
rootStore;
constructor(_rootStore: RootStore) {
makeObservable(this, {
// properties
trackElement: observable,
// computed
getRequiredProperties: computed,
getTrackElement: computed,
// actions
resetSession: action,
setTrackElement: action,
captureEvent: action,
captureProjectEvent: action,
captureCycleEvent: action,
captureModuleEvent: action,
capturePageEvent: action,
captureIssueEvent: action,
captureProjectStateEvent: action,
captureIssuesListOpenedEvent: action,
joinWorkspaceMetricGroup: action,
captureWorkspaceEvent: action,
});
// store
this.rootStore = _rootStore;
}
/**
* @description: Returns the current track element.
*/
get getTrackElement() {
return this.trackElement;
}
/**
* @description: Returns the necessary property for the event tracking
*/
get getRequiredProperties() {
const currentWorkspaceRole = this.rootStore.user.membership.currentWorkspaceRole;
const currentWorkspaceDetails = this.rootStore.workspaceRoot.currentWorkspace;
const currentProjectDetails = this.rootStore.projectRoot.project.currentProjectDetails;
return {
workspace_id: currentWorkspaceDetails?.id,
project_id: currentProjectDetails?.id,
user_project_role: currentProjectDetails?.member_role
? getUserRole(currentProjectDetails?.member_role as number)
: undefined,
user_workspace_role: getUserRole(currentWorkspaceRole as number),
};
}
/**
* @description: Set the trigger point of event.
* @param {string} element
*/
setTrackElement = (element?: string) => {
this.trackElement = element;
};
/**
* @description: Reset the session.
*/
resetSession = () => {
posthog?.reset();
};
/**
* @description: Creates the workspace metric group.
* @param {string} userEmail
* @param {string} workspaceId
*/
joinWorkspaceMetricGroup = (workspaceId?: string) => {
if (!workspaceId) return;
posthog?.group(GROUP_WORKSPACE, workspaceId, {
date: new Date().toDateString(),
workspace_id: workspaceId,
});
};
/**
* @description: Captures the event.
* @param {string} eventName
* @param {any} payload
*/
captureEvent = (eventName: string, payload?: any) => {
posthog?.capture(eventName, {
...this.getRequiredProperties,
...payload,
element: payload?.element ?? this.trackElement,
});
this.setTrackElement(undefined);
};
/**
* @description: Captures the workspace crud related events.
* @param {EventProps} props
*/
captureWorkspaceEvent = (props: EventProps) => {
const { eventName, payload } = props;
if (eventName === WORKSPACE_CREATED && payload.state == "SUCCESS") {
this.joinWorkspaceMetricGroup(payload.id);
}
const eventPayload: any = {
...getWorkspaceEventPayload(payload),
...this.getRequiredProperties,
element: payload.element ?? this.trackElement,
};
posthog?.capture(eventName, eventPayload);
this.setTrackElement(undefined);
};
/**
* @description: Captures the project related events.
* @param {EventProps} props
*/
captureProjectEvent = (props: EventProps) => {
const { eventName, payload } = props;
const eventPayload: any = {
...getProjectEventPayload(payload),
...this.getRequiredProperties,
element: payload.element ?? this.trackElement,
};
posthog?.capture(eventName, eventPayload);
this.setTrackElement(undefined);
};
/**
* @description: Captures the cycle related events.
* @param {EventProps} props
*/
captureCycleEvent = (props: EventProps) => {
const { eventName, payload } = props;
const eventPayload: any = {
...getCycleEventPayload(payload),
...this.getRequiredProperties,
element: payload.element ?? this.trackElement,
};
posthog?.capture(eventName, eventPayload);
this.setTrackElement(undefined);
};
/**
* @description: Captures the module related events.
* @param {EventProps} props
*/
captureModuleEvent = (props: EventProps) => {
const { eventName, payload } = props;
const eventPayload: any = {
...getModuleEventPayload(payload),
...this.getRequiredProperties,
element: payload.element ?? this.trackElement,
};
posthog?.capture(eventName, eventPayload);
this.setTrackElement(undefined);
};
/**
* @description: Captures the project pages related events.
* @param {EventProps} props
*/
capturePageEvent = (props: EventProps) => {
const { eventName, payload } = props;
const eventPayload: any = {
...getPageEventPayload(payload),
...this.getRequiredProperties,
element: payload.element ?? this.trackElement,
};
posthog?.capture(eventName, eventPayload);
this.setTrackElement(undefined);
};
/**
* @description: Captures the issue related events.
* @param {IssueEventProps} props
*/
captureIssueEvent = (props: IssueEventProps) => {
const { eventName, payload } = props;
const eventPayload: any = {
...getIssueEventPayload(props),
...this.getRequiredProperties,
state_group: this.rootStore.state.getStateById(payload.state_id)?.group ?? "",
element: payload.element ?? this.trackElement,
};
posthog?.capture(eventName, eventPayload);
this.setTrackElement(undefined);
};
/**
* @description: Captures the issue related events.
* @param {IssueEventProps} props
*/
captureProjectStateEvent = (props: EventProps) => {
const { eventName, payload } = props;
const eventPayload: any = {
...getProjectStateEventPayload(payload),
...this.getRequiredProperties,
element: payload.element ?? this.trackElement,
};
posthog?.capture(eventName, eventPayload);
this.setTrackElement(undefined);
};
/**
* @description: Captures the event whenever the issues list is opened.
* @param {any} payload
*/
captureIssuesListOpenedEvent = (payload: any) => {
const eventPayload = {
...getIssuesListOpenedPayload(payload),
...this.getRequiredProperties,
type: this.getRequiredProperties.project_id ? "Project" : "Workspace",
};
posthog?.capture(ISSUES_LIST_OPENED, eventPayload);
this.setTrackElement(undefined);
};
/**
* @description: Captures the event whenever the issues filters are changed.
* @param {IssueEventProps} props
*/
captureIssuesFilterEvent = (props: EventProps) => {
const { eventName, payload } = props;
const eventPayload = {
...getIssuesFilterEventPayload(payload),
...this.getRequiredProperties,
type: this.getRequiredProperties.project_id ? "Project" : "Workspace",
};
posthog?.capture(eventName, eventPayload);
this.setTrackElement(undefined);
};
/**
* @description: Captures the event whenever the issues display-filters are changed.
* @param {IssueEventProps} props
*/
captureIssuesDisplayFilterEvent = (props: EventProps) => {
const { eventName, payload } = props;
const eventPayload = {
...getIssuesDisplayFilterPayload(payload),
...this.getRequiredProperties,
type: this.getRequiredProperties.project_id ? "Project" : "Workspace",
current_display_filter: eventName === LP_UPDATED ? payload?.filters?.displayFilters : undefined,
};
posthog?.capture(eventName, eventPayload);
this.setTrackElement(undefined);
};
captureLabelDragNDropEvent = (
childLabelParent: string | null | undefined,
parentLabel: string | null | undefined,
childLabel: string | null | undefined,
projectLabelsTree: IIssueLabelTree[] | undefined
) => {
if (childLabelParent != parentLabel) {
// if the child label has a parent, then remove it from the parent and add it to a new parent.
if (childLabelParent) {
this.captureEvent(LABEL_REMOVED_G, {
group_id: childLabelParent,
child_id: childLabel,
child_count: (projectLabelsTree?.find((label) => label.id === childLabelParent)?.children?.length ?? 0) - 1,
});
parentLabel &&
this.captureEvent(LABEL_ADDED_G, {
group_id: parentLabel,
child_id: childLabel,
child_count: (projectLabelsTree?.find((label) => label.id === parentLabel)?.children?.length ?? 0) + 1,
});
} else {
// if the child label has no parent, then add it to a new parent.
this.captureEvent(LABEL_ADDED_G, {
group_id: parentLabel,
child_id: childLabel,
child_count: (projectLabelsTree?.find((label) => label.id === parentLabel)?.children?.length ?? 0) + 1,
});
}
}
};
}