diff --git a/apps/app/components/core/gpt-assistant-modal.tsx b/apps/app/components/core/gpt-assistant-modal.tsx index 75af0a50b..d3280ad66 100644 --- a/apps/app/components/core/gpt-assistant-modal.tsx +++ b/apps/app/components/core/gpt-assistant-modal.tsx @@ -7,11 +7,13 @@ import dynamic from "next/dynamic"; import { useForm } from "react-hook-form"; // services import aiService from "services/ai.service"; +import trackEventServices from "services/track-event.service"; // hooks import useToast from "hooks/use-toast"; // ui import { Input, PrimaryButton, SecondaryButton } from "components/ui"; +import { IIssue, IPageBlock } from "types"; type Props = { isOpen: boolean; handleClose: () => void; @@ -20,6 +22,8 @@ type Props = { htmlContent?: string; onResponse: (response: string) => void; projectId: string; + block?: IPageBlock; + issue?: IIssue; }; type FormData = { @@ -39,6 +43,8 @@ export const GptAssistantModal: React.FC = ({ htmlContent, onResponse, projectId, + block, + issue, }) => { const [response, setResponse] = useState(""); const [invalidResponse, setInvalidResponse] = useState(false); @@ -166,6 +172,13 @@ export const GptAssistantModal: React.FC = ({ onClick={() => { onResponse(response); onClose(); + if (block) + trackEventServices.trackUseGPTResponseEvent( + block, + "USE_GPT_RESPONSE_IN_PAGE_BLOCK" + ); + else if (issue) + trackEventServices.trackUseGPTResponseEvent(issue, "USE_GPT_RESPONSE_IN_ISSUE"); }} > Use this response diff --git a/apps/app/components/pages/single-page-block.tsx b/apps/app/components/pages/single-page-block.tsx index 48155fc0f..315217895 100644 --- a/apps/app/components/pages/single-page-block.tsx +++ b/apps/app/components/pages/single-page-block.tsx @@ -21,11 +21,7 @@ import { CustomMenu, Input, Loader, TextArea } from "components/ui"; // icons import { LayerDiagonalIcon } from "components/icons"; import { ArrowPathIcon } from "@heroicons/react/20/solid"; -import { - BoltIcon, - CheckIcon, - SparklesIcon, -} from "@heroicons/react/24/outline"; +import { BoltIcon, CheckIcon, SparklesIcon } from "@heroicons/react/24/outline"; // helpers import { copyTextToClipboard } from "helpers/string.helper"; // types @@ -326,6 +322,7 @@ export const SinglePageBlock: React.FC = ({ block, projectDetails }) => { )} /> setGptAssistantModal(false)} inset="top-2 left-0" diff --git a/apps/app/pages/api/track-event.ts b/apps/app/pages/api/track-event.ts index c9255d215..9112faeea 100644 --- a/apps/app/pages/api/track-event.ts +++ b/apps/app/pages/api/track-event.ts @@ -37,12 +37,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) // TODO: cache user info jitsu - .id({ - id: user.id, - email: user.email, - first_name: user.first_name, - last_name: user.last_name, - }) + .id( + { + id: user.id, + email: user.email, + first_name: user.first_name, + last_name: user.last_name, + }, + true + ) .then(() => { jitsu.track(eventName, { ...extra, diff --git a/apps/app/services/ai.service.ts b/apps/app/services/ai.service.ts index 26168115e..6d1e3b0f9 100644 --- a/apps/app/services/ai.service.ts +++ b/apps/app/services/ai.service.ts @@ -1,10 +1,15 @@ // services import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + // types import { IGptResponse } from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + class AiServices extends APIService { constructor() { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); @@ -16,7 +21,10 @@ class AiServices extends APIService { data: { prompt: string; task: string } ): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/ai-assistant/`, data) - .then((response) => response?.data) + .then((response) => { + if (trackEvent) trackEventServices.trackAskGptEvent(response?.data, "ASK_GPT"); + return response?.data; + }) .catch((error) => { throw error?.response; }); diff --git a/apps/app/services/cycles.service.ts b/apps/app/services/cycles.service.ts index 48fc4b335..2713dbc8f 100644 --- a/apps/app/services/cycles.service.ts +++ b/apps/app/services/cycles.service.ts @@ -26,7 +26,7 @@ class ProjectCycleServices extends APIService { async createCycle(workspaceSlug: string, projectId: string, data: any): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackCycleCreateEvent(response?.data); + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_CREATE"); return response?.data; }) .catch((error) => { @@ -103,7 +103,7 @@ class ProjectCycleServices extends APIService { data ) .then((response) => { - if (trackEvent) trackEventServices.trackCycleUpdateEvent(response?.data); + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE"); return response?.data; }) .catch((error) => { @@ -122,7 +122,7 @@ class ProjectCycleServices extends APIService { data ) .then((response) => { - if (trackEvent) trackEventServices.trackCycleUpdateEvent(response?.data); + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE"); return response?.data; }) .catch((error) => { @@ -133,7 +133,7 @@ class ProjectCycleServices extends APIService { async deleteCycle(workspaceSlug: string, projectId: string, cycleId: string): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`) .then((response) => { - if (trackEvent) trackEventServices.trackCycleDeleteEvent(response?.data); + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_DELETE"); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/issues.service.ts b/apps/app/services/issues.service.ts index 6c787a0e4..e6848f7b5 100644 --- a/apps/app/services/issues.service.ts +++ b/apps/app/services/issues.service.ts @@ -17,7 +17,7 @@ class ProjectIssuesServices extends APIService { async createIssues(workspaceSlug: string, projectId: string, data: any): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackIssueCreateEvent(response.data); + if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_CREATE"); return response?.data; }) .catch((error) => { @@ -249,7 +249,7 @@ class ProjectIssuesServices extends APIService { data ) .then((response) => { - if (trackEvent) trackEventServices.trackIssueUpdateEvent(data); + if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_UPDATE"); return response?.data; }) .catch((error) => { @@ -268,7 +268,7 @@ class ProjectIssuesServices extends APIService { data ) .then((response) => { - if (trackEvent) trackEventServices.trackIssueUpdateEvent(data); + if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_UPDATE"); return response?.data; }) .catch((error) => { @@ -279,7 +279,7 @@ class ProjectIssuesServices extends APIService { async deleteIssue(workspaceSlug: string, projectId: string, issuesId: string): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issuesId}/`) .then((response) => { - if (trackEvent) trackEventServices.trackIssueDeleteEvent({ issuesId }); + if (trackEvent) trackEventServices.trackIssueEvent({ issuesId }, "ISSUE_DELETE"); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/modules.service.ts b/apps/app/services/modules.service.ts index 8dbabf01e..419d6033c 100644 --- a/apps/app/services/modules.service.ts +++ b/apps/app/services/modules.service.ts @@ -26,7 +26,7 @@ class ProjectIssuesServices extends APIService { async createModule(workspaceSlug: string, projectId: string, data: any): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackModuleCreateEvent(response?.data); + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_CREATE"); return response?.data; }) .catch((error) => { @@ -45,7 +45,7 @@ class ProjectIssuesServices extends APIService { data ) .then((response) => { - if (trackEvent) trackEventServices.trackModuleUpdateEvent(response?.data); + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE"); return response?.data; }) .catch((error) => { @@ -72,7 +72,7 @@ class ProjectIssuesServices extends APIService { data ) .then((response) => { - if (trackEvent) trackEventServices.trackModuleUpdateEvent(response?.data); + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE"); return response?.data; }) .catch((error) => { @@ -85,7 +85,7 @@ class ProjectIssuesServices extends APIService { `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/` ) .then((response) => { - if (trackEvent) trackEventServices.trackModuleDeleteEvent(response?.data); + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_DELETE"); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/pages.service.ts b/apps/app/services/pages.service.ts index d6e2c654b..89fba2624 100644 --- a/apps/app/services/pages.service.ts +++ b/apps/app/services/pages.service.ts @@ -1,11 +1,15 @@ // services import APIService from "services/api.service"; -import { IIssue } from "types"; +import trackEventServices from "services/track-event.service"; + // types -import { IPage, IPageBlock, RecentPagesResponse } from "types/pages"; +import { IPage, IPageBlock, RecentPagesResponse, IIssue } from "types"; const { NEXT_PUBLIC_API_BASE_URL } = process.env; +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + class PageServices extends APIService { constructor() { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); @@ -13,7 +17,10 @@ class PageServices extends APIService { async createPage(workspaceSlug: string, projectId: string, data: Partial): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`, data) - .then((response) => response?.data) + .then((response) => { + if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_CREATE"); + return response?.data; + }) .catch((error) => { throw error?.response?.data; }); @@ -29,7 +36,10 @@ class PageServices extends APIService { `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`, data ) - .then((response) => response?.data) + .then((response) => { + if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_UPDATE"); + return response?.data; + }) .catch((error) => { throw error?.response?.data; }); @@ -37,7 +47,10 @@ class PageServices extends APIService { async deletePage(workspaceSlug: string, projectId: string, pageId: string): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`) - .then((response) => response?.data) + .then((response) => { + if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_DELETE"); + return response?.data; + }) .catch((error) => { throw error?.response?.data; }); @@ -130,7 +143,10 @@ class PageServices extends APIService { `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/`, data ) - .then((response) => response?.data) + .then((response) => { + if (trackEvent) trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_CREATE"); + return response?.data; + }) .catch((error) => { throw error?.response?.data; }); @@ -162,7 +178,10 @@ class PageServices extends APIService { `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/`, data ) - .then((response) => response?.data) + .then((response) => { + if (trackEvent) trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_UPDATE"); + return response?.data; + }) .catch((error) => { throw error?.response?.data; }); @@ -177,7 +196,10 @@ class PageServices extends APIService { return this.delete( `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/` ) - .then((response) => response?.data) + .then((response) => { + if (trackEvent) trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_DELETE"); + return response?.data; + }) .catch((error) => { throw error?.response?.data; }); @@ -206,7 +228,11 @@ class PageServices extends APIService { return this.post( `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${blockId}/issues/` ) - .then((response) => response?.data) + .then((response) => { + if (trackEvent) + trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_CONVERTED_TO_ISSUE"); + return response?.data; + }) .catch((error) => { throw error?.response?.data; }); diff --git a/apps/app/services/project.service.ts b/apps/app/services/project.service.ts index 4690ffe67..7d6d8c4ce 100644 --- a/apps/app/services/project.service.ts +++ b/apps/app/services/project.service.ts @@ -25,7 +25,7 @@ class ProjectServices extends APIService { async createProject(workspaceSlug: string, data: Partial): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackCreateProjectEvent(response.data); + if (trackEvent) trackEventServices.trackProjectEvent(response.data, "CREATE_PROJECT"); return response?.data; }) .catch((error) => { @@ -68,7 +68,7 @@ class ProjectServices extends APIService { ): Promise { return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackUpdateProjectEvent(response.data); + if (trackEvent) trackEventServices.trackProjectEvent(response.data, "UPDATE_PROJECT"); return response?.data; }) .catch((error) => { @@ -79,7 +79,7 @@ class ProjectServices extends APIService { async deleteProject(workspaceSlug: string, projectId: string): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`) .then((response) => { - if (trackEvent) trackEventServices.trackDeleteProjectEvent({ projectId }); + if (trackEvent) trackEventServices.trackProjectEvent({ projectId }, "DELETE_PROJECT"); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/state.service.ts b/apps/app/services/state.service.ts index cdf80fe5b..61cfd4d25 100644 --- a/apps/app/services/state.service.ts +++ b/apps/app/services/state.service.ts @@ -18,7 +18,7 @@ class ProjectStateServices extends APIService { async createState(workspaceSlug: string, projectId: string, data: any): Promise { return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackStateCreateEvent(response?.data); + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_CREATE"); return response?.data; }) .catch((error) => { @@ -62,7 +62,7 @@ class ProjectStateServices extends APIService { data ) .then((response) => { - if (trackEvent) trackEventServices.trackStateUpdateEvent(response?.data); + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE"); return response?.data; }) .catch((error) => { @@ -81,7 +81,7 @@ class ProjectStateServices extends APIService { data ) .then((response) => { - if (trackEvent) trackEventServices.trackStateUpdateEvent(response?.data); + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE"); return response?.data; }) .catch((error) => { @@ -92,7 +92,7 @@ class ProjectStateServices extends APIService { async deleteState(workspaceSlug: string, projectId: string, stateId: string): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`) .then((response) => { - if (trackEvent) trackEventServices.trackStateDeleteEvent(response?.data); + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_DELETE"); return response?.data; }) .catch((error) => { diff --git a/apps/app/services/track-event.service.ts b/apps/app/services/track-event.service.ts index 845a27cf1..a0f50afac 100644 --- a/apps/app/services/track-event.service.ts +++ b/apps/app/services/track-event.service.ts @@ -1,25 +1,75 @@ // services import APIService from "services/api.service"; -// types -import type { ICycle, IIssue, IModule, IProject, IState, IWorkspace } from "types"; -// TODO: as we add more events, we can refactor this to be divided into different classes +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +// types +import type { + ICycle, + IGptResponse, + IIssue, + IModule, + IPage, + IPageBlock, + IProject, + IState, + IWorkspace, +} from "types"; + +type WorkspaceEventType = + | "CREATE_WORKSPACE" + | "UPDATE_WORKSPACE" + | "DELETE_WORKSPACE" + | "WORKSPACE_USER_INVITE" + | "WORKSPACE_USER_INVITE_ACCEPT" + | "WORKSPACE_USER_BULK_INVITE_ACCEPT"; + +type ProjectEventType = "CREATE_PROJECT" | "UPDATE_PROJECT" | "DELETE_PROJECT"; + +type IssueEventType = "ISSUE_CREATE" | "ISSUE_UPDATE" | "ISSUE_DELETE"; + +type CycleEventType = "CYCLE_CREATE" | "CYCLE_UPDATE" | "CYCLE_DELETE"; + +type StateEventType = "STATE_CREATE" | "STATE_UPDATE" | "STATE_DELETE"; + +type ModuleEventType = "MODULE_CREATE" | "MODULE_UPDATE" | "MODULE_DELETE"; + +type PagesEventType = "PAGE_CREATE" | "PAGE_UPDATE" | "PAGE_DELETE"; + +type PageBlocksEventType = + | "PAGE_BLOCK_CREATE" + | "PAGE_BLOCK_UPDATE" + | "PAGE_BLOCK_DELETE" + | "PAGE_BLOCK_CONVERTED_TO_ISSUE"; + +type GptEventType = "ASK_GPT" | "USE_GPT_RESPONSE_IN_ISSUE" | "USE_GPT_RESPONSE_IN_PAGE_BLOCK"; + class TrackEventServices extends APIService { constructor() { super("/"); } - async trackCreateWorkspaceEvent(data: IWorkspace): Promise { - const payload = { - workspaceId: data.id, - workspaceSlug: data.slug, - workspaceName: data.name, - }; + async trackWorkspaceEvent(data: IWorkspace | any, eventName: WorkspaceEventType): Promise { + let payload: any; + if ( + eventName !== "DELETE_WORKSPACE" && + eventName !== "WORKSPACE_USER_INVITE" && + eventName !== "WORKSPACE_USER_INVITE_ACCEPT" && + eventName !== "WORKSPACE_USER_BULK_INVITE_ACCEPT" + ) + payload = { + workspaceId: data.id, + workspaceSlug: data.slug, + workspaceName: data.name, + }; + else payload = data; + return this.request({ url: "/api/track-event", method: "POST", data: { - eventName: "CREATE_WORKSPACE", + eventName, extra: { ...payload, }, @@ -27,17 +77,26 @@ class TrackEventServices extends APIService { }); } - async trackUpdateWorkspaceEvent(data: Partial): Promise { - const payload = { - workspaceId: data.id, - workspaceSlug: data.slug, - workspaceName: data.name, - }; + async trackProjectEvent( + data: Partial | any, + eventName: ProjectEventType + ): Promise { + let payload: any; + if (eventName !== "DELETE_PROJECT") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.id, + projectName: data?.name, + }; + else payload = data; + return this.request({ url: "/api/track-event", method: "POST", data: { - eventName: "UPDATE_WORKSPACE", + eventName, extra: { ...payload, }, @@ -45,111 +104,6 @@ class TrackEventServices extends APIService { }); } - async trackDeleteWorkspaceEvent(data: any): Promise { - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "DELETE_WORKSPACE", - extra: { - ...data, - }, - }, - }); - } - - async trackCreateProjectEvent(data: IProject): Promise { - const payload = { - workspaceId: data.workspace_detail.id, - workspaceName: data.workspace_detail.name, - workspaceSlug: data.workspace_detail.slug, - projectId: data.id, - projectName: data.name, - }; - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "CREATE_PROJECT", - extra: { - ...payload, - }, - }, - }); - } - - async trackUpdateProjectEvent(data: Partial): Promise { - const payload = { - workspaceId: data?.workspace_detail?.id, - workspaceName: data?.workspace_detail?.name, - workspaceSlug: data?.workspace_detail?.slug, - projectId: data.id, - projectName: data.name, - }; - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "UPDATE_PROJECT", - extra: { - ...payload, - }, - }, - }); - } - - async trackDeleteProjectEvent(data: any): Promise { - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "DELETE_PROJECT", - extra: { - ...data, - }, - }, - }); - } - - async trackWorkspaceUserInviteEvent(data: any): Promise { - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "WORKSPACE_USER_INVITE", - extra: { - ...data, - }, - }, - }); - } - - async trackWorkspaceUserJoinEvent(data: any): Promise { - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "WORKSPACE_USER_INVITE_ACCEPT", - extra: { - ...data, - }, - }, - }); - } - - async trackWorkspaceUserBulkJoinEvent(data: any): Promise { - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "WORKSPACE_USER_BULK_INVITE_ACCEPT", - extra: { - ...data, - }, - }, - }); - } - async trackUserOnboardingCompleteEvent(data: any): Promise { return this.request({ url: "/api/track-event", @@ -163,22 +117,26 @@ class TrackEventServices extends APIService { }); } - async trackIssueCreateEvent(data: IIssue): Promise { - const payload = { - workspaceId: data.workspace_detail.id, - workspaceName: data.workspace_detail.name, - workspaceSlug: data.workspace_detail.slug, - projectId: data.project_detail.id, - projectName: data.project_detail.name, - projectIdentifier: data.project_detail.identifier, - issueId: data.id, - issueTitle: data.name, - }; + async trackIssueEvent(data: IIssue | any, eventName: IssueEventType): Promise { + let payload: any; + if (eventName !== "ISSUE_DELETE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + issueId: data?.id, + issueTitle: data?.name, + }; + else payload = data; + return this.request({ url: "/api/track-event", method: "POST", data: { - eventName: "ISSUE_CREATE", + eventName, extra: { ...payload, }, @@ -186,42 +144,6 @@ class TrackEventServices extends APIService { }); } - async trackIssueUpdateEvent(data: Partial): Promise { - const payload = { - workspaceId: data?.workspace_detail?.id, - workspaceName: data.workspace_detail?.name, - workspaceSlug: data?.workspace_detail?.slug, - projectId: data?.project_detail?.id, - projectName: data?.project_detail?.name, - projectIdentifier: data?.project_detail?.identifier, - issueId: data.id, - issueTitle: data.name, - }; - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "ISSUE_UPDATE", - extra: { - ...payload, - }, - }, - }); - } - - async trackIssueDeleteEvent(data: any): Promise { - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "ISSUE_DELETE", - extra: { - ...data, - }, - }, - }); - } - async trackIssueBulkDeleteEvent(data: any): Promise { return this.request({ url: "/api/track-event", @@ -235,45 +157,168 @@ class TrackEventServices extends APIService { }); } - async trackStateCreateEvent(data: IState): Promise { + async trackStateEvent(data: IState | any, eventName: StateEventType): Promise { + let payload: any; + if (eventName !== "STATE_DELETE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + stateId: data.id, + stateName: data.name, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + }, + }); + } + + async trackCycleEvent(data: ICycle | any, eventName: CycleEventType): Promise { + let payload: any; + if (eventName !== "CYCLE_DELETE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + cycleId: data.id, + cycleName: data.name, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + }, + }); + } + + async trackModuleEvent(data: IModule | any, eventName: ModuleEventType): Promise { + let payload: any; + if (eventName !== "MODULE_DELETE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + moduleId: data.id, + moduleName: data.name, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + }, + }); + } + + async trackPageEvent(data: Partial | any, eventName: PagesEventType): Promise { + let payload: any; + if (eventName !== "PAGE_DELETE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + pageId: data.id, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + }, + }); + } + + async trackPageBlockEvent( + data: Partial | IIssue, + eventName: PageBlocksEventType + ): Promise { + let payload: any; + if (eventName !== "PAGE_BLOCK_DELETE" && eventName !== "PAGE_BLOCK_CONVERTED_TO_ISSUE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + pageId: (data as IPageBlock)?.page, + pageBlockId: data.id, + }; + else if (eventName === "PAGE_BLOCK_CONVERTED_TO_ISSUE") { + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + issueId: data?.id, + }; + } else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + }, + }); + } + + async trackAskGptEvent(data: IGptResponse, eventName: GptEventType): Promise { const payload = { workspaceId: data?.workspace_detail?.id, workspaceName: data?.workspace_detail?.name, workspaceSlug: data?.workspace_detail?.slug, projectId: data?.project_detail?.id, - projectName: data?.project_detail?.name, projectIdentifier: data?.project_detail?.identifier, - stateId: data.id, - stateName: data.name, - }; - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "STATE_CREATE", - extra: { - ...payload, - }, - }, - }); - } - - async trackStateUpdateEvent(data: Partial): Promise { - const payload = { - workspaceId: data?.workspace_detail?.id, - workspaceName: data?.workspace_detail?.name, - workspaceSlug: data?.workspace_detail?.slug, - projectId: data?.project_detail?.id, projectName: data?.project_detail?.name, - projectIdentifier: data?.project_detail?.identifier, - stateId: data.id, - stateName: data.name, + count: data?.count, }; return this.request({ url: "/api/track-event", method: "POST", data: { - eventName: "STATE_UPDATE", + eventName, extra: { ...payload, }, @@ -281,134 +326,45 @@ class TrackEventServices extends APIService { }); } - async trackStateDeleteEvent(data: any): Promise { - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "STATE_DELETE", - extra: { - ...data, - }, - }, - }); - } + async trackUseGPTResponseEvent(data: IIssue | IPageBlock, eventName: GptEventType): Promise { + if (!trackEvent) return; + + let payload: any; + + if (eventName === "USE_GPT_RESPONSE_IN_ISSUE") { + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectIdentifier: data?.project_detail?.identifier, + projectName: data?.project_detail?.name, + issueId: data.id, + }; + } else if (eventName === "USE_GPT_RESPONSE_IN_PAGE_BLOCK") { + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectIdentifier: data?.project_detail?.identifier, + projectName: data?.project_detail?.name, + pageId: (data as IPageBlock)?.page, + pageBlockId: data.id, + }; + } - async trackCycleCreateEvent(data: ICycle): Promise { - const payload = { - workspaceId: data?.workspace_detail?.id, - workspaceName: data?.workspace_detail?.name, - workspaceSlug: data?.workspace_detail?.slug, - projectId: data?.project_detail?.id, - projectName: data?.project_detail?.name, - projectIdentifier: data?.project_detail?.identifier, - cycleId: data.id, - cycleName: data.name, - }; return this.request({ url: "/api/track-event", method: "POST", data: { - eventName: "CYCLE_CREATE", + eventName, extra: { ...payload, }, }, }); } - - async trackCycleUpdateEvent(data: Partial): Promise { - const payload = { - workspaceId: data?.workspace_detail?.id, - workspaceName: data?.workspace_detail?.name, - workspaceSlug: data?.workspace_detail?.slug, - projectId: data?.project_detail?.id, - projectName: data?.project_detail?.name, - projectIdentifier: data?.project_detail?.identifier, - cycleId: data.id, - cycleName: data.name, - }; - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "CYCLE_UPDATE", - extra: { - ...payload, - }, - }, - }); - } - - async trackCycleDeleteEvent(data: any): Promise { - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "CYCLE_DELETE", - extra: { - ...data, - }, - }, - }); - } - - async trackModuleCreateEvent(data: IModule): Promise { - const payload = { - workspaceId: data?.workspace_detail.id, - workspaceName: data?.workspace_detail.name, - workspaceSlug: data?.workspace_detail.slug, - projectId: data?.project_detail?.id, - projectName: data.project_detail?.name, - moduleId: data.id, - moduleName: data.name, - }; - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "MODULE_CREATE", - extra: { - ...payload, - }, - }, - }); - } - - async trackModuleUpdateEvent(data: Partial): Promise { - const payload = { - workspaceId: data?.workspace_detail?.id, - workspaceName: data?.workspace_detail?.name, - workspaceSlug: data?.workspace_detail?.slug, - projectId: data?.project_detail?.id, - projectName: data.project_detail?.name, - moduleId: data.id, - moduleName: data.name, - }; - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "MODULE_UPDATE", - extra: { - ...payload, - }, - }, - }); - } - - async trackModuleDeleteEvent(data: any): Promise { - return this.request({ - url: "/api/track-event", - method: "POST", - data: { - eventName: "MODULE_DELETE", - extra: { - ...data, - }, - }, - }); - } } const trackEventServices = new TrackEventServices(); diff --git a/apps/app/services/workspace.service.ts b/apps/app/services/workspace.service.ts index 14562b1d1..1cb13d2b5 100644 --- a/apps/app/services/workspace.service.ts +++ b/apps/app/services/workspace.service.ts @@ -42,7 +42,7 @@ class WorkspaceService extends APIService { async createWorkspace(data: Partial): Promise { return this.post("/api/workspaces/", data) .then((response) => { - if (trackEvent) trackEventServices.trackCreateWorkspaceEvent(response.data); + if (trackEvent) trackEventServices.trackWorkspaceEvent(response.data, "CREATE_WORKSPACE"); return response?.data; }) .catch((error) => { @@ -53,7 +53,7 @@ class WorkspaceService extends APIService { async updateWorkspace(workspaceSlug: string, data: Partial): Promise { return this.patch(`/api/workspaces/${workspaceSlug}/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackUpdateWorkspaceEvent(response.data); + if (trackEvent) trackEventServices.trackWorkspaceEvent(response.data, "UPDATE_WORKSPACE"); return response?.data; }) .catch((error) => { @@ -64,7 +64,8 @@ class WorkspaceService extends APIService { async deleteWorkspace(workspaceSlug: string): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/`) .then((response) => { - if (trackEvent) trackEventServices.trackDeleteWorkspaceEvent({ workspaceSlug }); + if (trackEvent) + trackEventServices.trackWorkspaceEvent({ workspaceSlug }, "DELETE_WORKSPACE"); return response?.data; }) .catch((error) => { @@ -75,7 +76,8 @@ class WorkspaceService extends APIService { async inviteWorkspace(workspaceSlug: string, data: any): Promise { return this.post(`/api/workspaces/${workspaceSlug}/invite/`, data) .then((response) => { - if (trackEvent) trackEventServices.trackWorkspaceUserInviteEvent(response.data); + if (trackEvent) + trackEventServices.trackWorkspaceEvent(response.data, "WORKSPACE_USER_INVITE"); return response?.data; }) .catch((error) => { @@ -92,7 +94,8 @@ class WorkspaceService extends APIService { } ) .then((response) => { - if (trackEvent) trackEventServices.trackWorkspaceUserJoinEvent(response.data); + if (trackEvent) + trackEventServices.trackWorkspaceEvent(response.data, "WORKSPACE_USER_INVITE_ACCEPT"); return response?.data; }) .catch((error) => { diff --git a/apps/app/types/ai.d.ts b/apps/app/types/ai.d.ts index ec7de3244..6c933a033 100644 --- a/apps/app/types/ai.d.ts +++ b/apps/app/types/ai.d.ts @@ -1,4 +1,9 @@ +import { IProjectLite, IWorkspaceLite } from "types"; + export interface IGptResponse { response: string; response_html: string; + count: number; + project_detail: IProjectLite; + workspace_detail: IWorkspaceLite; } diff --git a/apps/app/types/pages.d.ts b/apps/app/types/pages.d.ts index c72e7293e..6be966f7c 100644 --- a/apps/app/types/pages.d.ts +++ b/apps/app/types/pages.d.ts @@ -1,5 +1,5 @@ // types -import { IIssue, IIssueLabels } from "./issues"; +import { IIssue, IIssueLabels, IWorkspaceLite, IProjectLite } from "types"; export interface IPage { access: number; @@ -18,9 +18,11 @@ export interface IPage { name: string; owned_by: string; project: string; + project_detail: IProjectLite; updated_at: Date; updated_by: string; workspace: string; + workspace_detail: IWorkspaceLite; } export interface RecentPagesResponse { @@ -40,11 +42,13 @@ export interface IPageBlock { name: string; page: string; project: string; + project_detail: IProjectLite; sort_order: number; sync: boolean; updated_at: Date; updated_by: string; workspace: string; + workspace_detail: IWorkspaceLite; } export type TPageViewProps = "list" | "detailed" | "masonry";