feat: added tracker for page, page block, and gpt (#623)

* refactor: made events function generic

* feat: added tracker for page, page block, and gpt
This commit is contained in:
Dakshesh Jain 2023-03-30 19:27:46 +05:30 committed by GitHub
parent 50275fd2ad
commit 66ed6a1dc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 375 additions and 360 deletions

View File

@ -7,11 +7,13 @@ import dynamic from "next/dynamic";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
// services // services
import aiService from "services/ai.service"; import aiService from "services/ai.service";
import trackEventServices from "services/track-event.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// ui // ui
import { Input, PrimaryButton, SecondaryButton } from "components/ui"; import { Input, PrimaryButton, SecondaryButton } from "components/ui";
import { IIssue, IPageBlock } from "types";
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
handleClose: () => void; handleClose: () => void;
@ -20,6 +22,8 @@ type Props = {
htmlContent?: string; htmlContent?: string;
onResponse: (response: string) => void; onResponse: (response: string) => void;
projectId: string; projectId: string;
block?: IPageBlock;
issue?: IIssue;
}; };
type FormData = { type FormData = {
@ -39,6 +43,8 @@ export const GptAssistantModal: React.FC<Props> = ({
htmlContent, htmlContent,
onResponse, onResponse,
projectId, projectId,
block,
issue,
}) => { }) => {
const [response, setResponse] = useState(""); const [response, setResponse] = useState("");
const [invalidResponse, setInvalidResponse] = useState(false); const [invalidResponse, setInvalidResponse] = useState(false);
@ -166,6 +172,13 @@ export const GptAssistantModal: React.FC<Props> = ({
onClick={() => { onClick={() => {
onResponse(response); onResponse(response);
onClose(); 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 Use this response

View File

@ -21,11 +21,7 @@ import { CustomMenu, Input, Loader, TextArea } from "components/ui";
// icons // icons
import { LayerDiagonalIcon } from "components/icons"; import { LayerDiagonalIcon } from "components/icons";
import { ArrowPathIcon } from "@heroicons/react/20/solid"; import { ArrowPathIcon } from "@heroicons/react/20/solid";
import { import { BoltIcon, CheckIcon, SparklesIcon } from "@heroicons/react/24/outline";
BoltIcon,
CheckIcon,
SparklesIcon,
} from "@heroicons/react/24/outline";
// helpers // helpers
import { copyTextToClipboard } from "helpers/string.helper"; import { copyTextToClipboard } from "helpers/string.helper";
// types // types
@ -326,6 +322,7 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails }) => {
)} )}
/> />
<GptAssistantModal <GptAssistantModal
block={block}
isOpen={gptAssistantModal} isOpen={gptAssistantModal}
handleClose={() => setGptAssistantModal(false)} handleClose={() => setGptAssistantModal(false)}
inset="top-2 left-0" inset="top-2 left-0"

View File

@ -37,12 +37,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
// TODO: cache user info // TODO: cache user info
jitsu jitsu
.id({ .id(
{
id: user.id, id: user.id,
email: user.email, email: user.email,
first_name: user.first_name, first_name: user.first_name,
last_name: user.last_name, last_name: user.last_name,
}) },
true
)
.then(() => { .then(() => {
jitsu.track(eventName, { jitsu.track(eventName, {
...extra, ...extra,

View File

@ -1,10 +1,15 @@
// services // services
import APIService from "services/api.service"; import APIService from "services/api.service";
import trackEventServices from "services/track-event.service";
// types // types
import { IGptResponse } from "types"; import { IGptResponse } from "types";
const { NEXT_PUBLIC_API_BASE_URL } = process.env; 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 { class AiServices extends APIService {
constructor() { constructor() {
super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000");
@ -16,7 +21,10 @@ class AiServices extends APIService {
data: { prompt: string; task: string } data: { prompt: string; task: string }
): Promise<IGptResponse> { ): Promise<IGptResponse> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/ai-assistant/`, data) 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) => { .catch((error) => {
throw error?.response; throw error?.response;
}); });

View File

@ -26,7 +26,7 @@ class ProjectCycleServices extends APIService {
async createCycle(workspaceSlug: string, projectId: string, data: any): Promise<any> { async createCycle(workspaceSlug: string, projectId: string, data: any): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, data) return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, data)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackCycleCreateEvent(response?.data); if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_CREATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -103,7 +103,7 @@ class ProjectCycleServices extends APIService {
data data
) )
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackCycleUpdateEvent(response?.data); if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -122,7 +122,7 @@ class ProjectCycleServices extends APIService {
data data
) )
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackCycleUpdateEvent(response?.data); if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -133,7 +133,7 @@ class ProjectCycleServices extends APIService {
async deleteCycle(workspaceSlug: string, projectId: string, cycleId: string): Promise<any> { async deleteCycle(workspaceSlug: string, projectId: string, cycleId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`) return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackCycleDeleteEvent(response?.data); if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_DELETE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {

View File

@ -17,7 +17,7 @@ class ProjectIssuesServices extends APIService {
async createIssues(workspaceSlug: string, projectId: string, data: any): Promise<any> { async createIssues(workspaceSlug: string, projectId: string, data: any): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, data) return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, data)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackIssueCreateEvent(response.data); if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_CREATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -249,7 +249,7 @@ class ProjectIssuesServices extends APIService {
data data
) )
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackIssueUpdateEvent(data); if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_UPDATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -268,7 +268,7 @@ class ProjectIssuesServices extends APIService {
data data
) )
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackIssueUpdateEvent(data); if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_UPDATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -279,7 +279,7 @@ class ProjectIssuesServices extends APIService {
async deleteIssue(workspaceSlug: string, projectId: string, issuesId: string): Promise<any> { async deleteIssue(workspaceSlug: string, projectId: string, issuesId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issuesId}/`) return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issuesId}/`)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackIssueDeleteEvent({ issuesId }); if (trackEvent) trackEventServices.trackIssueEvent({ issuesId }, "ISSUE_DELETE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {

View File

@ -26,7 +26,7 @@ class ProjectIssuesServices extends APIService {
async createModule(workspaceSlug: string, projectId: string, data: any): Promise<any> { async createModule(workspaceSlug: string, projectId: string, data: any): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/`, data) return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/`, data)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackModuleCreateEvent(response?.data); if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_CREATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -45,7 +45,7 @@ class ProjectIssuesServices extends APIService {
data data
) )
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackModuleUpdateEvent(response?.data); if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -72,7 +72,7 @@ class ProjectIssuesServices extends APIService {
data data
) )
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackModuleUpdateEvent(response?.data); if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -85,7 +85,7 @@ class ProjectIssuesServices extends APIService {
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/` `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/`
) )
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackModuleDeleteEvent(response?.data); if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_DELETE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {

View File

@ -1,11 +1,15 @@
// services // services
import APIService from "services/api.service"; import APIService from "services/api.service";
import { IIssue } from "types"; import trackEventServices from "services/track-event.service";
// types // types
import { IPage, IPageBlock, RecentPagesResponse } from "types/pages"; import { IPage, IPageBlock, RecentPagesResponse, IIssue } from "types";
const { NEXT_PUBLIC_API_BASE_URL } = process.env; 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 { class PageServices extends APIService {
constructor() { constructor() {
super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); 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<IPage>): Promise<IPage> { async createPage(workspaceSlug: string, projectId: string, data: Partial<IPage>): Promise<IPage> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`, data) 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) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });
@ -29,7 +36,10 @@ class PageServices extends APIService {
`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`, `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`,
data data
) )
.then((response) => response?.data) .then((response) => {
if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_UPDATE");
return response?.data;
})
.catch((error) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });
@ -37,7 +47,10 @@ class PageServices extends APIService {
async deletePage(workspaceSlug: string, projectId: string, pageId: string): Promise<any> { async deletePage(workspaceSlug: string, projectId: string, pageId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`) 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) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });
@ -130,7 +143,10 @@ class PageServices extends APIService {
`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/`, `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/`,
data data
) )
.then((response) => response?.data) .then((response) => {
if (trackEvent) trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_CREATE");
return response?.data;
})
.catch((error) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });
@ -162,7 +178,10 @@ class PageServices extends APIService {
`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/`, `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/`,
data data
) )
.then((response) => response?.data) .then((response) => {
if (trackEvent) trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_UPDATE");
return response?.data;
})
.catch((error) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });
@ -177,7 +196,10 @@ class PageServices extends APIService {
return this.delete( return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/` `/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) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });
@ -206,7 +228,11 @@ class PageServices extends APIService {
return this.post( return this.post(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${blockId}/issues/` `/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) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
}); });

View File

@ -25,7 +25,7 @@ class ProjectServices extends APIService {
async createProject(workspaceSlug: string, data: Partial<IProject>): Promise<IProject> { async createProject(workspaceSlug: string, data: Partial<IProject>): Promise<IProject> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/`, data) return this.post(`/api/workspaces/${workspaceSlug}/projects/`, data)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackCreateProjectEvent(response.data); if (trackEvent) trackEventServices.trackProjectEvent(response.data, "CREATE_PROJECT");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -68,7 +68,7 @@ class ProjectServices extends APIService {
): Promise<IProject> { ): Promise<IProject> {
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`, data) return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`, data)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackUpdateProjectEvent(response.data); if (trackEvent) trackEventServices.trackProjectEvent(response.data, "UPDATE_PROJECT");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -79,7 +79,7 @@ class ProjectServices extends APIService {
async deleteProject(workspaceSlug: string, projectId: string): Promise<any> { async deleteProject(workspaceSlug: string, projectId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`) return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackDeleteProjectEvent({ projectId }); if (trackEvent) trackEventServices.trackProjectEvent({ projectId }, "DELETE_PROJECT");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {

View File

@ -18,7 +18,7 @@ class ProjectStateServices extends APIService {
async createState(workspaceSlug: string, projectId: string, data: any): Promise<any> { async createState(workspaceSlug: string, projectId: string, data: any): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`, data) return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`, data)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackStateCreateEvent(response?.data); if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_CREATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -62,7 +62,7 @@ class ProjectStateServices extends APIService {
data data
) )
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackStateUpdateEvent(response?.data); if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -81,7 +81,7 @@ class ProjectStateServices extends APIService {
data data
) )
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackStateUpdateEvent(response?.data); if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -92,7 +92,7 @@ class ProjectStateServices extends APIService {
async deleteState(workspaceSlug: string, projectId: string, stateId: string): Promise<any> { async deleteState(workspaceSlug: string, projectId: string, stateId: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`) return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackStateDeleteEvent(response?.data); if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_DELETE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {

View File

@ -1,25 +1,75 @@
// services // services
import APIService from "services/api.service"; 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 { class TrackEventServices extends APIService {
constructor() { constructor() {
super("/"); super("/");
} }
async trackCreateWorkspaceEvent(data: IWorkspace): Promise<any> { async trackWorkspaceEvent(data: IWorkspace | any, eventName: WorkspaceEventType): Promise<any> {
const payload = { 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, workspaceId: data.id,
workspaceSlug: data.slug, workspaceSlug: data.slug,
workspaceName: data.name, workspaceName: data.name,
}; };
else payload = data;
return this.request({ return this.request({
url: "/api/track-event", url: "/api/track-event",
method: "POST", method: "POST",
data: { data: {
eventName: "CREATE_WORKSPACE", eventName,
extra: { extra: {
...payload, ...payload,
}, },
@ -27,70 +77,26 @@ class TrackEventServices extends APIService {
}); });
} }
async trackUpdateWorkspaceEvent(data: Partial<IWorkspace>): Promise<any> { async trackProjectEvent(
const payload = { data: Partial<IProject> | any,
workspaceId: data.id, eventName: ProjectEventType
workspaceSlug: data.slug, ): Promise<any> {
workspaceName: data.name, let payload: any;
}; if (eventName !== "DELETE_PROJECT")
return this.request({ payload = {
url: "/api/track-event",
method: "POST",
data: {
eventName: "UPDATE_WORKSPACE",
extra: {
...payload,
},
},
});
}
async trackDeleteWorkspaceEvent(data: any): Promise<any> {
return this.request({
url: "/api/track-event",
method: "POST",
data: {
eventName: "DELETE_WORKSPACE",
extra: {
...data,
},
},
});
}
async trackCreateProjectEvent(data: IProject): Promise<any> {
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<IProject>): Promise<any> {
const payload = {
workspaceId: data?.workspace_detail?.id, workspaceId: data?.workspace_detail?.id,
workspaceName: data?.workspace_detail?.name, workspaceName: data?.workspace_detail?.name,
workspaceSlug: data?.workspace_detail?.slug, workspaceSlug: data?.workspace_detail?.slug,
projectId: data.id, projectId: data?.id,
projectName: data.name, projectName: data?.name,
}; };
else payload = data;
return this.request({ return this.request({
url: "/api/track-event", url: "/api/track-event",
method: "POST", method: "POST",
data: { data: {
eventName: "UPDATE_PROJECT", eventName,
extra: { extra: {
...payload, ...payload,
}, },
@ -98,58 +104,6 @@ class TrackEventServices extends APIService {
}); });
} }
async trackDeleteProjectEvent(data: any): Promise<any> {
return this.request({
url: "/api/track-event",
method: "POST",
data: {
eventName: "DELETE_PROJECT",
extra: {
...data,
},
},
});
}
async trackWorkspaceUserInviteEvent(data: any): Promise<any> {
return this.request({
url: "/api/track-event",
method: "POST",
data: {
eventName: "WORKSPACE_USER_INVITE",
extra: {
...data,
},
},
});
}
async trackWorkspaceUserJoinEvent(data: any): Promise<any> {
return this.request({
url: "/api/track-event",
method: "POST",
data: {
eventName: "WORKSPACE_USER_INVITE_ACCEPT",
extra: {
...data,
},
},
});
}
async trackWorkspaceUserBulkJoinEvent(data: any): Promise<any> {
return this.request({
url: "/api/track-event",
method: "POST",
data: {
eventName: "WORKSPACE_USER_BULK_INVITE_ACCEPT",
extra: {
...data,
},
},
});
}
async trackUserOnboardingCompleteEvent(data: any): Promise<any> { async trackUserOnboardingCompleteEvent(data: any): Promise<any> {
return this.request({ return this.request({
url: "/api/track-event", url: "/api/track-event",
@ -163,45 +117,26 @@ class TrackEventServices extends APIService {
}); });
} }
async trackIssueCreateEvent(data: IIssue): Promise<any> { async trackIssueEvent(data: IIssue | any, eventName: IssueEventType): Promise<any> {
const payload = { let payload: any;
workspaceId: data.workspace_detail.id, if (eventName !== "ISSUE_DELETE")
workspaceName: data.workspace_detail.name, payload = {
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_CREATE",
extra: {
...payload,
},
},
});
}
async trackIssueUpdateEvent(data: Partial<IIssue>): Promise<any> {
const payload = {
workspaceId: data?.workspace_detail?.id, workspaceId: data?.workspace_detail?.id,
workspaceName: data.workspace_detail?.name, workspaceName: data?.workspace_detail?.name,
workspaceSlug: data?.workspace_detail?.slug, workspaceSlug: data?.workspace_detail?.slug,
projectId: data?.project_detail?.id, projectId: data?.project_detail?.id,
projectName: data?.project_detail?.name, projectName: data?.project_detail?.name,
projectIdentifier: data?.project_detail?.identifier, projectIdentifier: data?.project_detail?.identifier,
issueId: data.id, issueId: data?.id,
issueTitle: data.name, issueTitle: data?.name,
}; };
else payload = data;
return this.request({ return this.request({
url: "/api/track-event", url: "/api/track-event",
method: "POST", method: "POST",
data: { data: {
eventName: "ISSUE_UPDATE", eventName,
extra: { extra: {
...payload, ...payload,
}, },
@ -209,19 +144,6 @@ class TrackEventServices extends APIService {
}); });
} }
async trackIssueDeleteEvent(data: any): Promise<any> {
return this.request({
url: "/api/track-event",
method: "POST",
data: {
eventName: "ISSUE_DELETE",
extra: {
...data,
},
},
});
}
async trackIssueBulkDeleteEvent(data: any): Promise<any> { async trackIssueBulkDeleteEvent(data: any): Promise<any> {
return this.request({ return this.request({
url: "/api/track-event", url: "/api/track-event",
@ -235,8 +157,10 @@ class TrackEventServices extends APIService {
}); });
} }
async trackStateCreateEvent(data: IState): Promise<any> { async trackStateEvent(data: IState | any, eventName: StateEventType): Promise<any> {
const payload = { let payload: any;
if (eventName !== "STATE_DELETE")
payload = {
workspaceId: data?.workspace_detail?.id, workspaceId: data?.workspace_detail?.id,
workspaceName: data?.workspace_detail?.name, workspaceName: data?.workspace_detail?.name,
workspaceSlug: data?.workspace_detail?.slug, workspaceSlug: data?.workspace_detail?.slug,
@ -246,11 +170,13 @@ class TrackEventServices extends APIService {
stateId: data.id, stateId: data.id,
stateName: data.name, stateName: data.name,
}; };
else payload = data;
return this.request({ return this.request({
url: "/api/track-event", url: "/api/track-event",
method: "POST", method: "POST",
data: { data: {
eventName: "STATE_CREATE", eventName,
extra: { extra: {
...payload, ...payload,
}, },
@ -258,44 +184,10 @@ class TrackEventServices extends APIService {
}); });
} }
async trackStateUpdateEvent(data: Partial<IState>): Promise<any> { async trackCycleEvent(data: ICycle | any, eventName: CycleEventType): Promise<any> {
const payload = { let payload: any;
workspaceId: data?.workspace_detail?.id, if (eventName !== "CYCLE_DELETE")
workspaceName: data?.workspace_detail?.name, payload = {
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_UPDATE",
extra: {
...payload,
},
},
});
}
async trackStateDeleteEvent(data: any): Promise<any> {
return this.request({
url: "/api/track-event",
method: "POST",
data: {
eventName: "STATE_DELETE",
extra: {
...data,
},
},
});
}
async trackCycleCreateEvent(data: ICycle): Promise<any> {
const payload = {
workspaceId: data?.workspace_detail?.id, workspaceId: data?.workspace_detail?.id,
workspaceName: data?.workspace_detail?.name, workspaceName: data?.workspace_detail?.name,
workspaceSlug: data?.workspace_detail?.slug, workspaceSlug: data?.workspace_detail?.slug,
@ -305,11 +197,13 @@ class TrackEventServices extends APIService {
cycleId: data.id, cycleId: data.id,
cycleName: data.name, cycleName: data.name,
}; };
else payload = data;
return this.request({ return this.request({
url: "/api/track-event", url: "/api/track-event",
method: "POST", method: "POST",
data: { data: {
eventName: "CYCLE_CREATE", eventName,
extra: { extra: {
...payload, ...payload,
}, },
@ -317,22 +211,52 @@ class TrackEventServices extends APIService {
}); });
} }
async trackCycleUpdateEvent(data: Partial<ICycle>): Promise<any> { async trackModuleEvent(data: IModule | any, eventName: ModuleEventType): Promise<any> {
const payload = { 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<IPage> | any, eventName: PagesEventType): Promise<any> {
let payload: any;
if (eventName !== "PAGE_DELETE")
payload = {
workspaceId: data?.workspace_detail?.id, workspaceId: data?.workspace_detail?.id,
workspaceName: data?.workspace_detail?.name, workspaceName: data?.workspace_detail?.name,
workspaceSlug: data?.workspace_detail?.slug, workspaceSlug: data?.workspace_detail?.slug,
projectId: data?.project_detail?.id, projectId: data?.project_detail?.id,
projectName: data?.project_detail?.name, projectName: data?.project_detail?.name,
projectIdentifier: data?.project_detail?.identifier, projectIdentifier: data?.project_detail?.identifier,
cycleId: data.id, pageId: data.id,
cycleName: data.name,
}; };
else payload = data;
return this.request({ return this.request({
url: "/api/track-event", url: "/api/track-event",
method: "POST", method: "POST",
data: { data: {
eventName: "CYCLE_UPDATE", eventName,
extra: { extra: {
...payload, ...payload,
}, },
@ -340,34 +264,39 @@ class TrackEventServices extends APIService {
}); });
} }
async trackCycleDeleteEvent(data: any): Promise<any> { async trackPageBlockEvent(
return this.request({ data: Partial<IPageBlock> | IIssue,
url: "/api/track-event", eventName: PageBlocksEventType
method: "POST", ): Promise<any> {
data: { let payload: any;
eventName: "CYCLE_DELETE", if (eventName !== "PAGE_BLOCK_DELETE" && eventName !== "PAGE_BLOCK_CONVERTED_TO_ISSUE")
extra: { payload = {
...data, workspaceId: data?.workspace_detail?.id,
}, workspaceName: data?.workspace_detail?.name,
}, workspaceSlug: data?.workspace_detail?.slug,
});
}
async trackModuleCreateEvent(data: IModule): Promise<any> {
const payload = {
workspaceId: data?.workspace_detail.id,
workspaceName: data?.workspace_detail.name,
workspaceSlug: data?.workspace_detail.slug,
projectId: data?.project_detail?.id, projectId: data?.project_detail?.id,
projectName: data.project_detail?.name, projectName: data?.project_detail?.name,
moduleId: data.id, projectIdentifier: data?.project_detail?.identifier,
moduleName: data.name, 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({ return this.request({
url: "/api/track-event", url: "/api/track-event",
method: "POST", method: "POST",
data: { data: {
eventName: "MODULE_CREATE", eventName,
extra: { extra: {
...payload, ...payload,
}, },
@ -375,21 +304,21 @@ class TrackEventServices extends APIService {
}); });
} }
async trackModuleUpdateEvent(data: Partial<IModule>): Promise<any> { async trackAskGptEvent(data: IGptResponse, eventName: GptEventType): Promise<any> {
const payload = { const payload = {
workspaceId: data?.workspace_detail?.id, workspaceId: data?.workspace_detail?.id,
workspaceName: data?.workspace_detail?.name, workspaceName: data?.workspace_detail?.name,
workspaceSlug: data?.workspace_detail?.slug, workspaceSlug: data?.workspace_detail?.slug,
projectId: data?.project_detail?.id, projectId: data?.project_detail?.id,
projectName: data.project_detail?.name, projectIdentifier: data?.project_detail?.identifier,
moduleId: data.id, projectName: data?.project_detail?.name,
moduleName: data.name, count: data?.count,
}; };
return this.request({ return this.request({
url: "/api/track-event", url: "/api/track-event",
method: "POST", method: "POST",
data: { data: {
eventName: "MODULE_UPDATE", eventName,
extra: { extra: {
...payload, ...payload,
}, },
@ -397,14 +326,41 @@ class TrackEventServices extends APIService {
}); });
} }
async trackModuleDeleteEvent(data: any): Promise<any> { async trackUseGPTResponseEvent(data: IIssue | IPageBlock, eventName: GptEventType): Promise<any> {
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,
};
}
return this.request({ return this.request({
url: "/api/track-event", url: "/api/track-event",
method: "POST", method: "POST",
data: { data: {
eventName: "MODULE_DELETE", eventName,
extra: { extra: {
...data, ...payload,
}, },
}, },
}); });

View File

@ -42,7 +42,7 @@ class WorkspaceService extends APIService {
async createWorkspace(data: Partial<IWorkspace>): Promise<IWorkspace> { async createWorkspace(data: Partial<IWorkspace>): Promise<IWorkspace> {
return this.post("/api/workspaces/", data) return this.post("/api/workspaces/", data)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackCreateWorkspaceEvent(response.data); if (trackEvent) trackEventServices.trackWorkspaceEvent(response.data, "CREATE_WORKSPACE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -53,7 +53,7 @@ class WorkspaceService extends APIService {
async updateWorkspace(workspaceSlug: string, data: Partial<IWorkspace>): Promise<IWorkspace> { async updateWorkspace(workspaceSlug: string, data: Partial<IWorkspace>): Promise<IWorkspace> {
return this.patch(`/api/workspaces/${workspaceSlug}/`, data) return this.patch(`/api/workspaces/${workspaceSlug}/`, data)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackUpdateWorkspaceEvent(response.data); if (trackEvent) trackEventServices.trackWorkspaceEvent(response.data, "UPDATE_WORKSPACE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -64,7 +64,8 @@ class WorkspaceService extends APIService {
async deleteWorkspace(workspaceSlug: string): Promise<any> { async deleteWorkspace(workspaceSlug: string): Promise<any> {
return this.delete(`/api/workspaces/${workspaceSlug}/`) return this.delete(`/api/workspaces/${workspaceSlug}/`)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackDeleteWorkspaceEvent({ workspaceSlug }); if (trackEvent)
trackEventServices.trackWorkspaceEvent({ workspaceSlug }, "DELETE_WORKSPACE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -75,7 +76,8 @@ class WorkspaceService extends APIService {
async inviteWorkspace(workspaceSlug: string, data: any): Promise<any> { async inviteWorkspace(workspaceSlug: string, data: any): Promise<any> {
return this.post(`/api/workspaces/${workspaceSlug}/invite/`, data) return this.post(`/api/workspaces/${workspaceSlug}/invite/`, data)
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackWorkspaceUserInviteEvent(response.data); if (trackEvent)
trackEventServices.trackWorkspaceEvent(response.data, "WORKSPACE_USER_INVITE");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {
@ -92,7 +94,8 @@ class WorkspaceService extends APIService {
} }
) )
.then((response) => { .then((response) => {
if (trackEvent) trackEventServices.trackWorkspaceUserJoinEvent(response.data); if (trackEvent)
trackEventServices.trackWorkspaceEvent(response.data, "WORKSPACE_USER_INVITE_ACCEPT");
return response?.data; return response?.data;
}) })
.catch((error) => { .catch((error) => {

View File

@ -1,4 +1,9 @@
import { IProjectLite, IWorkspaceLite } from "types";
export interface IGptResponse { export interface IGptResponse {
response: string; response: string;
response_html: string; response_html: string;
count: number;
project_detail: IProjectLite;
workspace_detail: IWorkspaceLite;
} }

View File

@ -1,5 +1,5 @@
// types // types
import { IIssue, IIssueLabels } from "./issues"; import { IIssue, IIssueLabels, IWorkspaceLite, IProjectLite } from "types";
export interface IPage { export interface IPage {
access: number; access: number;
@ -18,9 +18,11 @@ export interface IPage {
name: string; name: string;
owned_by: string; owned_by: string;
project: string; project: string;
project_detail: IProjectLite;
updated_at: Date; updated_at: Date;
updated_by: string; updated_by: string;
workspace: string; workspace: string;
workspace_detail: IWorkspaceLite;
} }
export interface RecentPagesResponse { export interface RecentPagesResponse {
@ -40,11 +42,13 @@ export interface IPageBlock {
name: string; name: string;
page: string; page: string;
project: string; project: string;
project_detail: IProjectLite;
sort_order: number; sort_order: number;
sync: boolean; sync: boolean;
updated_at: Date; updated_at: Date;
updated_by: string; updated_by: string;
workspace: string; workspace: string;
workspace_detail: IWorkspaceLite;
} }
export type TPageViewProps = "list" | "detailed" | "masonry"; export type TPageViewProps = "list" | "detailed" | "masonry";