chore: posthog event for workspace invite (#2989)

* chore: posthog event for workspace invite

* chore: updated event names, added all the existing events to workspace metrics group

* chore: seperated workspace invite

* fix: workspace invite accept event updated

---------

Co-authored-by: Ramesh Kumar Chandra <rameshkumar2299@gmail.com>
This commit is contained in:
Bavisetti Narayan 2023-12-06 17:15:14 +05:30 committed by sriram veeraghanta
parent 37c03ff239
commit b35874e294
25 changed files with 441 additions and 120 deletions

View File

@ -73,8 +73,7 @@ from plane.app.permissions import (
) )
from plane.bgtasks.workspace_invitation_task import workspace_invitation from plane.bgtasks.workspace_invitation_task import workspace_invitation
from plane.utils.issue_filters import issue_filters from plane.utils.issue_filters import issue_filters
from plane.utils.grouper import group_results from plane.bgtasks.event_tracking_task import workspace_invite_event
class WorkSpaceViewSet(BaseViewSet): class WorkSpaceViewSet(BaseViewSet):
model = Workspace model = Workspace
@ -407,6 +406,17 @@ class WorkspaceJoinEndpoint(BaseAPIView):
# Delete the invitation # Delete the invitation
workspace_invite.delete() workspace_invite.delete()
# Send event
if settings.POSTHOG_API_KEY and settings.POSTHOG_HOST:
workspace_invite_event.delay(
user=user.id if user is not None else None,
email=email,
user_agent=request.META.get("HTTP_USER_AGENT"),
ip=request.META.get("REMOTE_ADDR"),
event_name="MEMBER_ACCEPTED",
accepted_from="EMAIL",
)
return Response( return Response(
{"message": "Workspace Invitation Accepted"}, {"message": "Workspace Invitation Accepted"},

View File

@ -26,5 +26,25 @@ def auth_events(user, email, user_agent, ip, event_name, medium, first_time):
"first_time": first_time "first_time": first_time
} }
) )
except Exception as e:
capture_exception(e)
@shared_task
def workspace_invite_event(user, email, user_agent, ip, event_name, accepted_from):
try:
posthog = Posthog(settings.POSTHOG_API_KEY, host=settings.POSTHOG_HOST)
posthog.capture(
email,
event=event_name,
properties={
"event_id": uuid.uuid4().hex,
"user": {"email": email, "id": str(user)},
"device_ctx": {
"ip": ip,
"user_agent": user_agent,
},
"accepted_from": accepted_from
}
)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)

View File

@ -8,11 +8,9 @@ import githubWhiteImage from "/public/logos/github-white.png";
// components // components
import { ProductUpdatesModal } from "components/common"; import { ProductUpdatesModal } from "components/common";
import { Breadcrumbs } from "@plane/ui"; import { Breadcrumbs } from "@plane/ui";
import { useMobxStore } from "lib/mobx/store-provider";
export const WorkspaceDashboardHeader = () => { export const WorkspaceDashboardHeader = () => {
const [isProductUpdatesModalOpen, setIsProductUpdatesModalOpen] = useState(false); const [isProductUpdatesModalOpen, setIsProductUpdatesModalOpen] = useState(false);
const { trackEvent: { postHogEventTracker } } = useMobxStore();
// theme // theme
const { resolvedTheme } = useTheme(); const { resolvedTheme } = useTheme();

View File

@ -24,7 +24,7 @@ export const InboxIssueActivity: React.FC<Props> = observer(({ issueDetails }) =
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, inboxIssueId } = router.query; const { workspaceSlug, projectId, inboxIssueId } = router.query;
const { user: userStore } = useMobxStore(); const { user: userStore, trackEvent: { postHogEventTracker }, workspace: { currentWorkspace } } = useMobxStore();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -42,7 +42,22 @@ export const InboxIssueActivity: React.FC<Props> = observer(({ issueDetails }) =
await issueCommentService await issueCommentService
.patchIssueComment(workspaceSlug as string, projectId as string, inboxIssueId as string, commentId, data) .patchIssueComment(workspaceSlug as string, projectId as string, inboxIssueId as string, commentId, data)
.then(() => mutateIssueActivity()); .then((res) => {
mutateIssueActivity();
postHogEventTracker(
"COMMENT_UPDATED",
{
...res,
state: "SUCCESS"
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}
);
}; };
const handleCommentDelete = async (commentId: string) => { const handleCommentDelete = async (commentId: string) => {
@ -52,7 +67,21 @@ export const InboxIssueActivity: React.FC<Props> = observer(({ issueDetails }) =
await issueCommentService await issueCommentService
.deleteIssueComment(workspaceSlug as string, projectId as string, inboxIssueId as string, commentId) .deleteIssueComment(workspaceSlug as string, projectId as string, inboxIssueId as string, commentId)
.then(() => mutateIssueActivity()); .then(() => {
mutateIssueActivity();
postHogEventTracker(
"COMMENT_DELETED",
{
state: "SUCCESS"
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}
);
}; };
const handleAddComment = async (formData: IIssueComment) => { const handleAddComment = async (formData: IIssueComment) => {
@ -60,8 +89,20 @@ export const InboxIssueActivity: React.FC<Props> = observer(({ issueDetails }) =
await issueCommentService await issueCommentService
.createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData) .createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData)
.then(() => { .then((res) => {
mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id)); mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id));
postHogEventTracker(
"COMMENT_ADDED",
{
...res,
state: "SUCCESS"
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}) })
.catch(() => .catch(() =>
setToastAlert({ setToastAlert({

View File

@ -62,6 +62,7 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
inboxIssueDetails: inboxIssueDetailsStore, inboxIssueDetails: inboxIssueDetailsStore,
trackEvent: { postHogEventTracker }, trackEvent: { postHogEventTracker },
appConfig: { envConfig }, appConfig: { envConfig },
workspace: { currentWorkspace }
} = useMobxStore(); } = useMobxStore();
const { const {
@ -91,16 +92,30 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
router.push(`/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}?inboxIssueId=${res.issue_inbox[0].id}`); router.push(`/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}?inboxIssueId=${res.issue_inbox[0].id}`);
handleClose(); handleClose();
} else reset(defaultValues); } else reset(defaultValues);
postHogEventTracker("ISSUE_CREATE", { postHogEventTracker("ISSUE_CREATED",
...res, {
state: "SUCCESS", ...res,
}); state: "SUCCESS",
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}) })
.catch((error) => { .catch((error) => {
console.log(error); console.log(error);
postHogEventTracker("ISSUE_CREATE", { postHogEventTracker("ISSUE_CREATED",
state: "FAILED", {
}); state: "FAILED",
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}); });
}; };
@ -214,9 +229,8 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
{issueName && issueName !== "" && ( {issueName && issueName !== "" && (
<button <button
type="button" type="button"
className={`flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-custom-background-90 ${ className={`flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-custom-background-90 ${iAmFeelingLucky ? "cursor-wait" : ""
iAmFeelingLucky ? "cursor-wait" : "" }`}
}`}
onClick={handleAutoGenerateDescription} onClick={handleAutoGenerateDescription}
disabled={iAmFeelingLucky} disabled={iAmFeelingLucky}
> >
@ -296,7 +310,7 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
onClick={() => setCreateMore((prevData) => !prevData)} onClick={() => setCreateMore((prevData) => !prevData)}
> >
<span className="text-xs">Create more</span> <span className="text-xs">Create more</span>
<ToggleSwitch value={createMore} onChange={() => {}} size="md" /> <ToggleSwitch value={createMore} onChange={() => { }} size="md" />
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button variant="neutral-primary" size="sm" onClick={() => handleClose()}> <Button variant="neutral-primary" size="sm" onClick={() => handleClose()}>

View File

@ -26,7 +26,7 @@ export const DeleteInboxIssueModal: React.FC<Props> = observer(({ isOpen, onClos
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, inboxId } = router.query; const { workspaceSlug, projectId, inboxId } = router.query;
const { inboxIssueDetails: inboxIssueDetailsStore } = useMobxStore(); const { inboxIssueDetails: inboxIssueDetailsStore, trackEvent: { postHogEventTracker }, workspace: { currentWorkspace } } = useMobxStore();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -48,7 +48,17 @@ export const DeleteInboxIssueModal: React.FC<Props> = observer(({ isOpen, onClos
title: "Success!", title: "Success!",
message: "Issue deleted successfully.", message: "Issue deleted successfully.",
}); });
postHogEventTracker(
"ISSUE_DELETED",
{
state: "SUCCESS",
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
)
// remove inboxIssueId from the url // remove inboxIssueId from the url
router.push({ router.push({
pathname: `/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}`, pathname: `/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}`,
@ -56,12 +66,24 @@ export const DeleteInboxIssueModal: React.FC<Props> = observer(({ isOpen, onClos
handleClose(); handleClose();
}) })
.catch(() => .catch(() => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "Issue could not be deleted. Please try again.", message: "Issue could not be deleted. Please try again.",
}) })
postHogEventTracker(
"ISSUE_DELETED",
{
state: "FAILED",
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}
) )
.finally(() => setIsDeleting(false)); .finally(() => setIsDeleting(false));
}; };

View File

@ -24,7 +24,7 @@ export const IssueBlocksList: FC<Props> = (props) => {
{issueIds && issueIds.length > 0 ? ( {issueIds && issueIds.length > 0 ? (
issueIds.map((issueId: string) => ( issueIds.map((issueId: string) => (
<IssueBlock <IssueBlock
key={issues[issueId].id} key={issues[issueId]?.id}
columnId={columnId} columnId={columnId}
issue={issues[issueId]} issue={issues[issueId]}
handleIssues={handleIssues} handleIssues={handleIssues}

View File

@ -54,6 +54,8 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
user: userStore, user: userStore,
project: projectStore, project: projectStore,
projectState: { states }, projectState: { states },
trackEvent: { postHogEventTracker },
workspace: { currentWorkspace }
} = useMobxStore(); } = useMobxStore();
const user = userStore.currentUser ?? undefined; const user = userStore.currentUser ?? undefined;
const userRole = userStore.currentProjectRole; const userRole = userStore.currentProjectRole;
@ -82,7 +84,22 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
await issueCommentService await issueCommentService
.patchIssueComment(workspaceSlug as string, projectId as string, issueId as string, commentId, data) .patchIssueComment(workspaceSlug as string, projectId as string, issueId as string, commentId, data)
.then(() => mutateIssueActivity()); .then((res) => {
mutateIssueActivity();
postHogEventTracker(
"COMMENT_UPDATED",
{
...res,
state: "SUCCESS"
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}
);
}; };
const handleCommentDelete = async (commentId: string) => { const handleCommentDelete = async (commentId: string) => {
@ -92,7 +109,21 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
await issueCommentService await issueCommentService
.deleteIssueComment(workspaceSlug as string, projectId as string, issueId as string, commentId) .deleteIssueComment(workspaceSlug as string, projectId as string, issueId as string, commentId)
.then(() => mutateIssueActivity()); .then(() => {
mutateIssueActivity();
postHogEventTracker(
"COMMENT_DELETED",
{
state: "SUCCESS"
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}
);
}; };
const handleAddComment = async (formData: IIssueComment) => { const handleAddComment = async (formData: IIssueComment) => {
@ -100,8 +131,20 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
await issueCommentService await issueCommentService
.createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData) .createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData)
.then(() => { .then((res) => {
mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id)); mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id));
postHogEventTracker(
"COMMENT_ADDED",
{
...res,
state: "SUCCESS"
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}) })
.catch(() => .catch(() =>
setToastAlert({ setToastAlert({

View File

@ -82,6 +82,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
moduleIssues: moduleIssueStore, moduleIssues: moduleIssueStore,
user: userStore, user: userStore,
trackEvent: { postHogEventTracker }, trackEvent: { postHogEventTracker },
workspace: { currentWorkspace }
} = useMobxStore(); } = useMobxStore();
const user = userStore.currentUser; const user = userStore.currentUser;
@ -250,10 +251,16 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
title: "Success!", title: "Success!",
message: "Issue created successfully.", message: "Issue created successfully.",
}); });
postHogEventTracker("ISSUE_CREATE", { postHogEventTracker("ISSUE_CREATED", {
...res, ...res,
state: "SUCCESS", state: "SUCCESS",
}); },
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent)); if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
} }
}) })
@ -263,9 +270,15 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
title: "Error!", title: "Error!",
message: "Issue could not be created. Please try again.", message: "Issue could not be created. Please try again.",
}); });
postHogEventTracker("ISSUE_CREATE", { postHogEventTracker("ISSUE_CREATED", {
state: "FAILED", state: "FAILED",
}); },
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}); });
if (!createMore) onFormSubmitClose(); if (!createMore) onFormSubmitClose();
@ -317,10 +330,16 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
title: "Success!", title: "Success!",
message: "Issue updated successfully.", message: "Issue updated successfully.",
}); });
postHogEventTracker("ISSUE_UPDATE", { postHogEventTracker("ISSUE_UPDATED", {
...res, ...res,
state: "SUCCESS", state: "SUCCESS",
}); },
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}) })
.catch(() => { .catch(() => {
setToastAlert({ setToastAlert({
@ -328,9 +347,15 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
title: "Error!", title: "Error!",
message: "Issue could not be updated. Please try again.", message: "Issue could not be updated. Please try again.",
}); });
postHogEventTracker("ISSUE_UPDATE", { postHogEventTracker("ISSUE_UPDATED", {
state: "FAILED", state: "FAILED",
}); },
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}); });
}; };

View File

@ -26,7 +26,7 @@ export const DeleteModuleModal: React.FC<Props> = observer((props) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, moduleId, peekModule } = router.query; const { workspaceSlug, projectId, moduleId, peekModule } = router.query;
const { module: moduleStore } = useMobxStore(); const { module: moduleStore, trackEvent: { postHogEventTracker } } = useMobxStore();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -50,6 +50,12 @@ export const DeleteModuleModal: React.FC<Props> = observer((props) => {
title: "Success!", title: "Success!",
message: "Module deleted successfully.", message: "Module deleted successfully.",
}); });
postHogEventTracker(
"MODULE_DELETED",
{
state: 'SUCCESS'
}
);
}) })
.catch(() => { .catch(() => {
setToastAlert({ setToastAlert({
@ -57,6 +63,12 @@ export const DeleteModuleModal: React.FC<Props> = observer((props) => {
title: "Error!", title: "Error!",
message: "Module could not be deleted. Please try again.", message: "Module could not be deleted. Please try again.",
}); });
postHogEventTracker(
"MODULE_DELETED",
{
state: 'FAILED'
}
);
}) })
.finally(() => { .finally(() => {
setIsDeleteLoading(false); setIsDeleteLoading(false);

View File

@ -32,7 +32,7 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
const [activeProject, setActiveProject] = useState<string | null>(null); const [activeProject, setActiveProject] = useState<string | null>(null);
const { project: projectStore, module: moduleStore } = useMobxStore(); const { project: projectStore, module: moduleStore, trackEvent: { postHogEventTracker } } = useMobxStore();
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined; const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined;
@ -52,7 +52,7 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
const selectedProjectId = payload.project ?? projectId.toString(); const selectedProjectId = payload.project ?? projectId.toString();
await moduleStore await moduleStore
.createModule(workspaceSlug.toString(), selectedProjectId, payload) .createModule(workspaceSlug.toString(), selectedProjectId, payload)
.then(() => { .then((res) => {
handleClose(); handleClose();
setToastAlert({ setToastAlert({
@ -60,6 +60,13 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
title: "Success!", title: "Success!",
message: "Module created successfully.", message: "Module created successfully.",
}); });
postHogEventTracker(
"MODULE_CREATED",
{
...res,
state: "SUCCESS"
}
);
}) })
.catch(() => { .catch(() => {
setToastAlert({ setToastAlert({
@ -67,6 +74,12 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
title: "Error!", title: "Error!",
message: "Module could not be created. Please try again.", message: "Module could not be created. Please try again.",
}); });
postHogEventTracker(
"MODULE_CREATED",
{
state: "FAILED"
}
);
}); });
}; };
@ -75,7 +88,7 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
const selectedProjectId = payload.project ?? projectId.toString(); const selectedProjectId = payload.project ?? projectId.toString();
await moduleStore await moduleStore
.updateModuleDetails(workspaceSlug.toString(), selectedProjectId, data.id, payload) .updateModuleDetails(workspaceSlug.toString(), selectedProjectId, data.id, payload)
.then(() => { .then((res) => {
handleClose(); handleClose();
setToastAlert({ setToastAlert({
@ -83,6 +96,13 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
title: "Success!", title: "Success!",
message: "Module updated successfully.", message: "Module updated successfully.",
}); });
postHogEventTracker(
"MODULE_UPDATED",
{
...res,
state: "SUCCESS"
}
);
}) })
.catch(() => { .catch(() => {
setToastAlert({ setToastAlert({
@ -90,6 +110,12 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
title: "Error!", title: "Error!",
message: "Module could not be updated. Please try again.", message: "Module could not be updated. Please try again.",
}); });
postHogEventTracker(
"MODULE_UPDATED",
{
state: "FAILED"
}
);
}); });
}; };

View File

@ -62,7 +62,7 @@ export const Invitations: React.FC<Props> = (props) => {
await workspaceService await workspaceService
.joinWorkspaces({ invitations: invitationsRespond }) .joinWorkspaces({ invitations: invitationsRespond })
.then(async (res) => { .then(async (res) => {
postHogEventTracker("WORKSPACE_USER_INVITE_ACCEPT", { ...res, state: "SUCCESS" }); postHogEventTracker("MEMBER_ACCEPTED", { ...res, state: "SUCCESS", accepted_from: "App" });
await workspaceStore.fetchWorkspaces(); await workspaceStore.fetchWorkspaces();
await mutate(USER_WORKSPACES); await mutate(USER_WORKSPACES);
await updateLastWorkspace(); await updateLastWorkspace();
@ -71,7 +71,7 @@ export const Invitations: React.FC<Props> = (props) => {
}) })
.catch((error) => { .catch((error) => {
console.log(error); console.log(error);
postHogEventTracker("WORKSPACE_USER_INVITE_ACCEPT", { state: "FAILED" }); postHogEventTracker("MEMBER_ACCEPTED", { state: "FAILED", accepted_from: "App" });
}) })
.finally(() => setIsJoiningWorkspaces(false)); .finally(() => setIsJoiningWorkspaces(false));
}; };
@ -88,11 +88,10 @@ export const Invitations: React.FC<Props> = (props) => {
return ( return (
<div <div
key={invitation.id} key={invitation.id}
className={`flex cursor-pointer items-center gap-2 border p-3.5 rounded ${ className={`flex cursor-pointer items-center gap-2 border p-3.5 rounded ${isSelected
isSelected
? "border-custom-primary-100" ? "border-custom-primary-100"
: "border-onboarding-border-200 hover:bg-onboarding-background-300/30" : "border-onboarding-border-200 hover:bg-onboarding-background-300/30"
}`} }`}
onClick={() => handleInvitation(invitation, isSelected ? "withdraw" : "accepted")} onClick={() => handleInvitation(invitation, isSelected ? "withdraw" : "accepted")}
> >
<div className="flex-shrink-0"> <div className="flex-shrink-0">

View File

@ -22,7 +22,7 @@ export const WorkspaceDashboardView = observer(() => {
user: userStore, user: userStore,
project: projectStore, project: projectStore,
commandPalette: commandPaletteStore, commandPalette: commandPaletteStore,
trackEvent: { setTrackElement }, trackEvent: { setTrackElement, postHogEventTracker },
} = useMobxStore(); } = useMobxStore();
const user = userStore.currentUser; const user = userStore.currentUser;
@ -37,7 +37,18 @@ export const WorkspaceDashboardView = observer(() => {
); );
const handleTourCompleted = () => { const handleTourCompleted = () => {
userStore.updateTourCompleted(); userStore.updateTourCompleted().then(() => {
postHogEventTracker(
"USER_TOUR_COMPLETE",
{
user_id: user?.id,
email: user?.email,
state: "SUCCESS"
}
)
}).catch((error) => {
console.log(error);
})
}; };
return ( return (

View File

@ -9,8 +9,6 @@ import { PageForm } from "./page-form";
import { IPage } from "types"; import { IPage } from "types";
// store // store
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
// helpers
import { trackEvent } from "helpers/event-tracker.helper";
type Props = { type Props = {
data?: IPage | null; data?: IPage | null;
@ -27,6 +25,8 @@ export const CreateUpdatePageModal: FC<Props> = (props) => {
// store // store
const { const {
page: { createPage, updatePage }, page: { createPage, updatePage },
trackEvent: { postHogEventTracker },
workspace: { currentWorkspace }
} = useMobxStore(); } = useMobxStore();
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -47,10 +47,18 @@ export const CreateUpdatePageModal: FC<Props> = (props) => {
title: "Success!", title: "Success!",
message: "Page created successfully.", message: "Page created successfully.",
}); });
trackEvent("PAGE_CREATE", { postHogEventTracker(
...res, "PAGE_CREATED",
case: "SUCCESS", {
}); ...res,
state: "SUCCESS",
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}) })
.catch(() => { .catch(() => {
setToastAlert({ setToastAlert({
@ -58,9 +66,16 @@ export const CreateUpdatePageModal: FC<Props> = (props) => {
title: "Error!", title: "Error!",
message: "Page could not be created. Please try again.", message: "Page could not be created. Please try again.",
}); });
trackEvent("PAGE_CREATE", { postHogEventTracker("PAGE_CREATED",
case: "FAILED", {
}); state: "FAILED",
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}); });
}; };
@ -75,10 +90,17 @@ export const CreateUpdatePageModal: FC<Props> = (props) => {
title: "Success!", title: "Success!",
message: "Page updated successfully.", message: "Page updated successfully.",
}); });
trackEvent("PAGE_UPDATE", { postHogEventTracker("PAGE_UPDATED",
...res, {
case: "SUCCESS", ...res,
}); state: "SUCCESS",
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}) })
.catch(() => { .catch(() => {
setToastAlert({ setToastAlert({
@ -86,9 +108,16 @@ export const CreateUpdatePageModal: FC<Props> = (props) => {
title: "Error!", title: "Error!",
message: "Page could not be updated. Please try again.", message: "Page could not be updated. Please try again.",
}); });
trackEvent("PAGE_UPDATE", { postHogEventTracker("PAGE_UPDATED",
case: "FAILED", {
}); state: "FAILED",
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}); });
}; };

View File

@ -66,7 +66,8 @@ export const CreateProjectModal: FC<Props> = observer((props) => {
const { const {
project: projectStore, project: projectStore,
workspaceMember: { workspaceMembers }, workspaceMember: { workspaceMembers },
trackEvent: { postHogEventTracker } trackEvent: { postHogEventTracker },
workspace: { currentWorkspace },
} = useMobxStore(); } = useMobxStore();
// states // states
const [isChangeInIdentifierRequired, setIsChangeInIdentifierRequired] = useState(true); const [isChangeInIdentifierRequired, setIsChangeInIdentifierRequired] = useState(true);
@ -135,8 +136,13 @@ export const CreateProjectModal: FC<Props> = observer((props) => {
state: "SUCCESS" state: "SUCCESS"
} }
postHogEventTracker( postHogEventTracker(
"PROJECT_CREATE", "PROJECT_CREATED",
newPayload, newPayload,
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: res.workspace
}
) )
setToastAlert({ setToastAlert({
type: "success", type: "success",
@ -156,10 +162,15 @@ export const CreateProjectModal: FC<Props> = observer((props) => {
message: err.data[key], message: err.data[key],
}); });
postHogEventTracker( postHogEventTracker(
"PROJECT_CREATE", "PROJECT_CREATED",
{ {
state: "FAILED" state: "FAILED"
}, },
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
) )
} }
); );

View File

@ -12,7 +12,6 @@ import { Button, Input } from "@plane/ui";
import type { IProject } from "types"; import type { IProject } from "types";
// fetch-keys // fetch-keys
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
import { trackEvent } from "helpers/event-tracker.helper";
type DeleteProjectModal = { type DeleteProjectModal = {
isOpen: boolean; isOpen: boolean;
@ -28,7 +27,7 @@ const defaultValues = {
export const DeleteProjectModal: React.FC<DeleteProjectModal> = (props) => { export const DeleteProjectModal: React.FC<DeleteProjectModal> = (props) => {
const { isOpen, project, onClose } = props; const { isOpen, project, onClose } = props;
// store // store
const { project: projectStore } = useMobxStore(); const { project: projectStore, workspace: { currentWorkspace }, trackEvent: { postHogEventTracker } } = useMobxStore();
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -63,9 +62,17 @@ export const DeleteProjectModal: React.FC<DeleteProjectModal> = (props) => {
if (projectId && projectId.toString() === project.id) router.push(`/${workspaceSlug}/projects`); if (projectId && projectId.toString() === project.id) router.push(`/${workspaceSlug}/projects`);
handleClose(); handleClose();
trackEvent( postHogEventTracker(
'DELETE_PROJECT' 'PROJECT_DELETED',
) {
state: "SUCCESS"
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
setToastAlert({ setToastAlert({
type: "success", type: "success",
title: "Success!", title: "Success!",
@ -73,9 +80,17 @@ export const DeleteProjectModal: React.FC<DeleteProjectModal> = (props) => {
}); });
}) })
.catch(() => { .catch(() => {
trackEvent( postHogEventTracker(
'DELETE_PROJECT/FAIL' 'PROJECT_DELETED',
) {
state: "FAILED"
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",

View File

@ -28,7 +28,7 @@ const projectService = new ProjectService();
export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => { export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
const { project, workspaceSlug, isAdmin } = props; const { project, workspaceSlug, isAdmin } = props;
// store // store
const { project: projectStore, trackEvent: { postHogEventTracker } } = useMobxStore(); const { project: projectStore, trackEvent: { postHogEventTracker }, workspace: { currentWorkspace } } = useMobxStore();
// toast // toast
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
// form data // form data
@ -63,8 +63,13 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
.updateProject(workspaceSlug.toString(), project.id, payload) .updateProject(workspaceSlug.toString(), project.id, payload)
.then((res) => { .then((res) => {
postHogEventTracker( postHogEventTracker(
'PROJECT_UPDATE', 'PROJECT_UPDATED',
{...res, state: "SUCCESS"} { ...res, state: "SUCCESS" },
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: res.workspace
}
); );
setToastAlert({ setToastAlert({
type: "success", type: "success",
@ -74,9 +79,14 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
}) })
.catch((error) => { .catch((error) => {
postHogEventTracker( postHogEventTracker(
'PROJECT_UPDATE', 'PROJECT_UPDATED',
{ {
state: "FAILED" state: "FAILED"
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
} }
); );
setToastAlert({ setToastAlert({

View File

@ -57,6 +57,7 @@ export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
user: { currentProjectRole }, user: { currentProjectRole },
workspaceMember: { workspaceMembers }, workspaceMember: { workspaceMembers },
trackEvent: { postHogEventTracker }, trackEvent: { postHogEventTracker },
workspace: { currentWorkspace }
} = useMobxStore(); } = useMobxStore();
const { const {
@ -92,16 +93,30 @@ export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
type: "success", type: "success",
message: "Member added successfully", message: "Member added successfully",
}); });
postHogEventTracker("PROJECT_MEMBER_INVITE", { postHogEventTracker("MEMBER_ADDED",
...res, {
state: "SUCCESS", ...res,
}); state: "SUCCESS",
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}) })
.catch((error) => { .catch((error) => {
console.log(error); console.log(error);
postHogEventTracker("PROJECT_MEMBER_INVITE", { postHogEventTracker("MEMBER_ADDED",
state: "FAILED", {
}); state: "FAILED",
},
{
isGrouping: true,
groupType: "Workspace_metrics",
gorupId: currentWorkspace?.id!
}
);
}) })
.finally(() => { .finally(() => {
reset(defaultValues); reset(defaultValues);

View File

@ -72,7 +72,7 @@ export const CreateWorkspaceForm: FC<Props> = observer((props) => {
.createWorkspace(formData) .createWorkspace(formData)
.then(async (res) => { .then(async (res) => {
postHogEventTracker( postHogEventTracker(
"WORKSPACE_CREATE", "WORKSPACE_CREATED",
{ {
...res, ...res,
state: "SUCCESS" state: "SUCCESS"
@ -94,7 +94,7 @@ export const CreateWorkspaceForm: FC<Props> = observer((props) => {
message: "Workspace could not be created. Please try again.", message: "Workspace could not be created. Please try again.",
}) })
postHogEventTracker( postHogEventTracker(
"WORKSPACE_CREATE", "WORKSPACE_CREATED",
{ {
state: "FAILED" state: "FAILED"
}, },
@ -110,7 +110,7 @@ export const CreateWorkspaceForm: FC<Props> = observer((props) => {
message: "Some error occurred while creating workspace. Please try again.", message: "Some error occurred while creating workspace. Please try again.",
}); });
postHogEventTracker( postHogEventTracker(
"WORKSPACE_CREATE", "WORKSPACE_CREATED",
{ {
state: "FAILED" state: "FAILED"
}, },

View File

@ -63,7 +63,7 @@ export const DeleteWorkspaceModal: React.FC<Props> = observer((props) => {
.then((res) => { .then((res) => {
handleClose(); handleClose();
router.push("/"); router.push("/");
postHogEventTracker("WORKSPACE_DELETE", { postHogEventTracker("WORKSPACE_DELETED", {
res, res,
state: "SUCCESS", state: "SUCCESS",
}); });
@ -79,7 +79,7 @@ export const DeleteWorkspaceModal: React.FC<Props> = observer((props) => {
title: "Error!", title: "Error!",
message: "Something went wrong. Please try again later.", message: "Something went wrong. Please try again later.",
}); });
postHogEventTracker("WORKSPACE_DELETE", { postHogEventTracker("WORKSPACE_DELETED", {
state: "FAILED", state: "FAILED",
}); });
}); });

View File

@ -67,7 +67,7 @@ export const WorkspaceDetails: FC = observer(() => {
await updateWorkspace(currentWorkspace.slug, payload) await updateWorkspace(currentWorkspace.slug, payload)
.then((res) => { .then((res) => {
postHogEventTracker("WORKSPACE_UPDATE", { postHogEventTracker("WORKSPACE_UPDATED", {
...res, ...res,
state: "SUCCESS", state: "SUCCESS",
}); });
@ -78,7 +78,7 @@ export const WorkspaceDetails: FC = observer(() => {
}); });
}) })
.catch((err) => { .catch((err) => {
postHogEventTracker("WORKSPACE_UPDATE", { postHogEventTracker("WORKSPACE_UPDATED", {
state: "FAILED", state: "FAILED",
}); });
console.error(err); console.error(err);

View File

@ -41,7 +41,7 @@ const WorkspaceMembersSettingsPage: NextPageWithLayout = observer(() => {
return inviteMembersToWorkspace(workspaceSlug.toString(), data) return inviteMembersToWorkspace(workspaceSlug.toString(), data)
.then(async (res) => { .then(async (res) => {
setInviteModal(false); setInviteModal(false);
postHogEventTracker("WORKSPACE_USER_INVITE", { ...res, state: "SUCCESS" }); postHogEventTracker("MEMBER_INVITED", { ...res, state: "SUCCESS" });
setToastAlert({ setToastAlert({
type: "success", type: "success",
title: "Success!", title: "Success!",
@ -49,7 +49,7 @@ const WorkspaceMembersSettingsPage: NextPageWithLayout = observer(() => {
}); });
}) })
.catch((err) => { .catch((err) => {
postHogEventTracker("WORKSPACE_USER_INVITE", { state: "FAILED" }); postHogEventTracker("MEMBER_INVITED", { state: "FAILED" });
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",

View File

@ -46,6 +46,7 @@ const UserInvitationsPage: NextPageWithLayout = observer(() => {
const { const {
workspace: { workspaceSlug }, workspace: { workspaceSlug },
user: { currentUserSettings }, user: { currentUserSettings },
trackEvent: { postHogEventTracker }
} = useMobxStore(); } = useMobxStore();
const router = useRouter(); const router = useRouter();
@ -88,10 +89,18 @@ const UserInvitationsPage: NextPageWithLayout = observer(() => {
workspaceService workspaceService
.joinWorkspaces({ invitations: invitationsRespond }) .joinWorkspaces({ invitations: invitationsRespond })
.then(() => { .then((res) => {
mutate("USER_WORKSPACES"); mutate("USER_WORKSPACES");
const firstInviteId = invitationsRespond[0]; const firstInviteId = invitationsRespond[0];
const redirectWorkspace = invitations?.find((i) => i.id === firstInviteId)?.workspace; const redirectWorkspace = invitations?.find((i) => i.id === firstInviteId)?.workspace;
postHogEventTracker(
"MEMBER_ACCEPTED",
{
...res,
state: "SUCCESS",
accepted_from: "App"
}
);
userService userService
.updateUser({ last_workspace_id: redirectWorkspace?.id }) .updateUser({ last_workspace_id: redirectWorkspace?.id })
.then(() => { .then(() => {
@ -147,11 +156,10 @@ const UserInvitationsPage: NextPageWithLayout = observer(() => {
return ( return (
<div <div
key={invitation.id} key={invitation.id}
className={`flex cursor-pointer items-center gap-2 border py-5 px-3.5 rounded ${ className={`flex cursor-pointer items-center gap-2 border py-5 px-3.5 rounded ${isSelected
isSelected
? "border-custom-primary-100" ? "border-custom-primary-100"
: "border-custom-border-200 hover:bg-custom-background-80" : "border-custom-border-200 hover:bg-custom-background-80"
}`} }`}
onClick={() => handleInvitation(invitation, isSelected ? "withdraw" : "accepted")} onClick={() => handleInvitation(invitation, isSelected ? "withdraw" : "accepted")}
> >
<div className="flex-shrink-0"> <div className="flex-shrink-0">

View File

@ -36,6 +36,7 @@ const OnboardingPage: NextPageWithLayout = observer(() => {
const { const {
user: { currentUser, updateCurrentUser, updateUserOnBoard }, user: { currentUser, updateCurrentUser, updateUserOnBoard },
workspace: workspaceStore, workspace: workspaceStore,
trackEvent: { postHogEventTracker }
} = useMobxStore(); } = useMobxStore();
const router = useRouter(); const router = useRouter();
@ -77,7 +78,19 @@ const OnboardingPage: NextPageWithLayout = observer(() => {
const finishOnboarding = async () => { const finishOnboarding = async () => {
if (!user || !workspaces) return; if (!user || !workspaces) return;
await updateUserOnBoard(); await updateUserOnBoard().then(() => {
postHogEventTracker(
"USER_ONBOARDING_COMPLETE",
{
user_role: user.role,
email: user.email,
user_id: user.id,
status: "SUCCESS"
}
)
}).catch((error) => {
console.log(error);
})
router.replace(`/${workspaces[0].slug}`); router.replace(`/${workspaces[0].slug}`);
}; };

View File

@ -7,8 +7,8 @@ export interface ITrackEventStore {
setTrackElement: (element: string) => void; setTrackElement: (element: string) => void;
postHogEventTracker: ( postHogEventTracker: (
eventName: string, eventName: string,
payload: object | [] | null payload: object | [] | null,
// group: { isGrouping: boolean; groupType: string; gorupId: string } | null group?: { isGrouping: boolean | null; groupType: string | null; gorupId: string | null } | null
) => void; ) => void;
} }
@ -30,8 +30,8 @@ export class TrackEventStore implements ITrackEventStore {
postHogEventTracker = ( postHogEventTracker = (
eventName: string, eventName: string,
payload: object | [] | null payload: object | [] | null,
// group: { isGrouping: boolean; groupType: string; gorupId: string } | null group?: { isGrouping: boolean | null; groupType: string | null; gorupId: string | null } | null
) => { ) => {
try { try {
console.log("POSTHOG_EVENT: ", eventName); console.log("POSTHOG_EVENT: ", eventName);
@ -43,7 +43,7 @@ export class TrackEventStore implements ITrackEventStore {
project_id: this.rootStore.project.currentProjectDetails?.id ?? "", project_id: this.rootStore.project.currentProjectDetails?.id ?? "",
project_identifier: this.rootStore.project.currentProjectDetails?.identifier ?? "", project_identifier: this.rootStore.project.currentProjectDetails?.identifier ?? "",
}; };
if (["PROJECT_CREATE", "PROJECT_UPDATE"].includes(eventName)) { if (["PROJECT_CREATED", "PROJECT_UPDATED"].includes(eventName)) {
const project_details: any = payload as object; const project_details: any = payload as object;
extras = { extras = {
...extras, ...extras,
@ -53,24 +53,23 @@ export class TrackEventStore implements ITrackEventStore {
}; };
} }
// if (group!.isGrouping === true) { if (group && group!.isGrouping === true) {
// posthog?.group(group!.groupType, group!.gorupId, { posthog?.group(group!.groupType!, group!.gorupId!, {
// name: "PostHog", date: new Date(),
// subscription: "subscription", workspace_id: group!.gorupId,
// date_joined: "2020-01-23T00:00:00.000Z", });
// }); posthog?.capture(eventName, {
// console.log("END OF GROUPING"); ...payload,
// posthog?.capture(eventName, { extras: extras,
// ...payload, element: this.trackElement ?? "",
// element: this.trackElement ?? "", });
// }); } else {
// } else { posthog?.capture(eventName, {
posthog?.capture(eventName, { ...payload,
...payload, extras: extras,
extras: extras, element: this.trackElement ?? "",
element: this.trackElement ?? "", });
}); }
// }
console.log(payload); console.log(payload);
} catch (error) { } catch (error) {
console.log(error); console.log(error);