From 05ac0bbf74383f8c8d9686c9e9fae11095065cb7 Mon Sep 17 00:00:00 2001 From: gakshita Date: Tue, 1 Jul 2025 15:07:09 +0530 Subject: [PATCH 1/2] chore: member-tracker-events --- packages/constants/src/event-tracker/core.ts | 11 ++++ .../settings/(workspace)/members/page.tsx | 51 ++++++++++--------- web/app/(all)/invitations/page.tsx | 34 ++++++------- .../components/onboarding/invitations.tsx | 36 +++++++------ .../components/onboarding/invite-members.tsx | 33 +++++------- .../project/leave-project-modal.tsx | 25 +++++---- .../components/project/member-list-item.tsx | 25 ++++++--- web/core/components/project/member-list.tsx | 8 ++- .../project/send-project-invitation-modal.tsx | 28 +++++----- .../project/settings/member-columns.tsx | 3 +- .../settings/invitations-list-item.tsx | 10 +++- .../workspace/settings/member-columns.tsx | 3 +- .../workspace/settings/members-list-item.tsx | 25 ++++++--- .../workspace/sidebar/projects-list-item.tsx | 11 ++-- 14 files changed, 169 insertions(+), 134 deletions(-) diff --git a/packages/constants/src/event-tracker/core.ts b/packages/constants/src/event-tracker/core.ts index bbb1319ffbf..6e93a0458b3 100644 --- a/packages/constants/src/event-tracker/core.ts +++ b/packages/constants/src/event-tracker/core.ts @@ -222,6 +222,17 @@ export const MEMBER_TRACKER_EVENTS = { }, }; +export const MEMBER_TRACKER_ELEMENTS = { + HEADER_BUTTON: "header_add_member_button", + INVITATION_BUTTON: "accept_invitation_button", + ONBOARDING_JOIN_WORKSPACE: "workspace_join_continue_to_workspace_button", + ONBOARDING_INVITE_MEMBER: "invite_member_continue_button", + SIDEBAR_PROJECT_QUICK_ACTIONS: "sidebar_project_quick_actions", + PROJECT_MEMBER_TABLE_CONTEXT_MENU: "project_member_table_context_menu", + WORKSPACE_MEMBER_TABLE_CONTEXT_MENU: "workspace_member_table_context_menu", + WORKSPACE_INVITATIONS_LIST_CONTEXT_MENU: "workspace_invitations_list_context_menu", +} as const; + export const AUTH_TRACKER_EVENTS = { navigate: { sign_up: "navigate_to_sign_up_page", diff --git a/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/members/page.tsx b/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/members/page.tsx index 001c00dd27e..0dc0ae64fbe 100644 --- a/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/members/page.tsx +++ b/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/members/page.tsx @@ -5,12 +5,17 @@ import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import { Search } from "lucide-react"; // types -import { EUserPermissions, EUserPermissionsLevel, MEMBER_TRACKER_EVENTS } from "@plane/constants"; +import { + EUserPermissions, + EUserPermissionsLevel, + MEMBER_TRACKER_ELEMENTS, + MEMBER_TRACKER_EVENTS, +} from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { IWorkspaceBulkInviteFormData } from "@plane/types"; // ui import { Button, TOAST_TYPE, setToast } from "@plane/ui"; -import { cn, getUserRole } from "@plane/utils"; +import { cn } from "@plane/utils"; // components import { NotAuthorizedView } from "@/components/auth-screens"; import { CountChip } from "@/components/common"; @@ -19,7 +24,8 @@ import { SettingsContentWrapper } from "@/components/settings"; import { WorkspaceMembersList } from "@/components/workspace"; // helpers // hooks -import { useEventTracker, useMember, useUserPermissions, useWorkspace } from "@/hooks/store"; +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; +import { useMember, useUserPermissions, useWorkspace } from "@/hooks/store"; // plane web components import { BillingActionsButton } from "@/plane-web/components/workspace/billing"; import { SendWorkspaceInvitationModal } from "@/plane-web/components/workspace/members"; @@ -32,7 +38,6 @@ const WorkspaceMembersSettingsPage = observer(() => { const { workspaceSlug } = useParams(); // store hooks const { workspaceUserInfo, allowPermissions } = useUserPermissions(); - const { captureEvent } = useEventTracker(); const { workspace: { workspaceMemberIds, inviteMembersToWorkspace }, } = useMember(); @@ -52,16 +57,11 @@ const WorkspaceMembersSettingsPage = observer(() => { return inviteMembersToWorkspace(workspaceSlug.toString(), data) .then(() => { setInviteModal(false); - captureEvent(MEMBER_TRACKER_EVENTS.invite, { - emails: [ - ...data.emails.map((email) => ({ - email: email.email, - role: getUserRole(email.role as unknown as EUserPermissions), - })), - ], - project_id: undefined, - state: "SUCCESS", - element: "Workspace settings member page", + captureSuccess({ + eventName: MEMBER_TRACKER_EVENTS.invite, + payload: { + emails: [...data.emails.map((email) => email.email)], + }, }); setToast({ type: TOAST_TYPE.SUCCESS, @@ -70,16 +70,12 @@ const WorkspaceMembersSettingsPage = observer(() => { }); }) .catch((err) => { - captureEvent(MEMBER_TRACKER_EVENTS.invite, { - emails: [ - ...data.emails.map((email) => ({ - email: email.email, - role: getUserRole(email.role as unknown as EUserPermissions), - })), - ], - project_id: undefined, - state: "FAILED", - element: "Workspace settings member page", + captureError({ + eventName: MEMBER_TRACKER_EVENTS.invite, + payload: { + emails: [...data.emails.map((email) => email.email)], + }, + error: err, }); setToast({ type: TOAST_TYPE.ERROR, @@ -129,7 +125,12 @@ const WorkspaceMembersSettingsPage = observer(() => { /> {canPerformWorkspaceAdminActions && ( - )} diff --git a/web/app/(all)/invitations/page.tsx b/web/app/(all)/invitations/page.tsx index 5e5f1958fe0..764ed1b3f18 100644 --- a/web/app/(all)/invitations/page.tsx +++ b/web/app/(all)/invitations/page.tsx @@ -9,19 +9,20 @@ import { useTheme } from "next-themes"; import useSWR, { mutate } from "swr"; import { CheckCircle2 } from "lucide-react"; // plane imports -import { ROLE, EUserPermissions, MEMBER_TRACKER_EVENTS } from "@plane/constants"; +import { ROLE, MEMBER_TRACKER_EVENTS, MEMBER_TRACKER_ELEMENTS } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; // types import type { IWorkspaceMemberInvitation } from "@plane/types"; // ui import { Button, TOAST_TYPE, setToast } from "@plane/ui"; -import { truncateText, getUserRole } from "@plane/utils"; +import { truncateText } from "@plane/utils"; // components import { EmptyState } from "@/components/common"; import { WorkspaceLogo } from "@/components/workspace/logo"; import { USER_WORKSPACES_LIST } from "@/constants/fetch-keys"; // helpers // hooks +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; import { useEventTracker, useUser, useUserProfile, useWorkspace } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; // services @@ -43,7 +44,7 @@ const UserInvitationsPage = observer(() => { const router = useAppRouter(); // store hooks const { t } = useTranslation(); - const { captureEvent, joinWorkspaceMetricGroup } = useEventTracker(); + const { joinWorkspaceMetricGroup } = useEventTracker(); const { data: currentUser } = useUser(); const { updateUserProfile } = useUserProfile(); @@ -86,14 +87,11 @@ const UserInvitationsPage = observer(() => { const invitation = invitations?.find((i) => i.id === firstInviteId); const redirectWorkspace = invitations?.find((i) => i.id === firstInviteId)?.workspace; joinWorkspaceMetricGroup(redirectWorkspace?.id); - captureEvent(MEMBER_TRACKER_EVENTS.accept, { - member_id: invitation?.id, - // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain - role: getUserRole((invitation?.role as unknown as EUserPermissions)!), - project_id: undefined, - accepted_from: "App", - state: "SUCCESS", - element: "Workspace invitations page", + captureSuccess({ + eventName: MEMBER_TRACKER_EVENTS.accept, + payload: { + member_id: invitation?.id, + }, }); updateUserProfile({ last_workspace_id: redirectWorkspace?.id }) .then(() => { @@ -111,12 +109,13 @@ const UserInvitationsPage = observer(() => { setIsJoiningWorkspaces(false); }); }) - .catch(() => { - captureEvent(MEMBER_TRACKER_EVENTS.accept, { - project_id: undefined, - accepted_from: "App", - state: "FAILED", - element: "Workspace invitations page", + .catch((err) => { + captureError({ + eventName: MEMBER_TRACKER_EVENTS.accept, + payload: { + member_id: invitationsRespond?.[0], + }, + error: err, }); setToast({ type: TOAST_TYPE.ERROR, @@ -194,6 +193,7 @@ const UserInvitationsPage = observer(() => { onClick={submitInvitations} disabled={isJoiningWorkspaces || invitationsRespond.length === 0} loading={isJoiningWorkspaces} + data-ph-element={MEMBER_TRACKER_ELEMENTS.INVITATION_BUTTON} > {t("accept_and_join")} diff --git a/web/core/components/onboarding/invitations.tsx b/web/core/components/onboarding/invitations.tsx index 349b9143101..3d16af81b0e 100644 --- a/web/core/components/onboarding/invitations.tsx +++ b/web/core/components/onboarding/invitations.tsx @@ -2,17 +2,18 @@ import React, { useState } from "react"; // plane imports -import { ROLE, MEMBER_TRACKER_EVENTS } from "@plane/constants"; +import { ROLE, MEMBER_TRACKER_EVENTS, MEMBER_TRACKER_ELEMENTS } from "@plane/constants"; // types import { IWorkspaceMemberInvitation } from "@plane/types"; // ui import { Button, Checkbox, Spinner } from "@plane/ui"; -import { truncateText, getUserRole } from "@plane/utils"; +import { truncateText } from "@plane/utils"; // constants // helpers import { WorkspaceLogo } from "@/components/workspace/logo"; // hooks -import { useEventTracker, useUserSettings, useWorkspace } from "@/hooks/store"; +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; +import { useUserSettings, useWorkspace } from "@/hooks/store"; // services import { WorkspaceService } from "@/plane-web/services"; @@ -29,7 +30,6 @@ export const Invitations: React.FC = (props) => { const [isJoiningWorkspaces, setIsJoiningWorkspaces] = useState(false); const [invitationsRespond, setInvitationsRespond] = useState([]); // store hooks - const { captureEvent } = useEventTracker(); const { fetchWorkspaces } = useWorkspace(); const { fetchCurrentUserSettings } = useUserSettings(); @@ -50,26 +50,23 @@ export const Invitations: React.FC = (props) => { try { await workspaceService.joinWorkspaces({ invitations: invitationsRespond }); - captureEvent(MEMBER_TRACKER_EVENTS.accept, { - member_id: invitation?.id, - role: getUserRole(invitation?.role as any), - project_id: undefined, - accepted_from: "App", - state: "SUCCESS", - element: "Workspace invitations page", + captureSuccess({ + eventName: MEMBER_TRACKER_EVENTS.accept, + payload: { + member_id: invitation?.id, + }, }); await fetchWorkspaces(); await fetchCurrentUserSettings(); await handleNextStep(); - } catch (error) { + } catch (error: any) { console.error(error); - captureEvent(MEMBER_TRACKER_EVENTS.accept, { - member_id: invitation?.id, - role: getUserRole(invitation?.role as any), - project_id: undefined, - accepted_from: "App", - state: "FAILED", - element: "Workspace invitations page", + captureError({ + eventName: MEMBER_TRACKER_EVENTS.accept, + payload: { + member_id: invitation?.id, + }, + error: error, }); setIsJoiningWorkspaces(false); } @@ -117,6 +114,7 @@ export const Invitations: React.FC = (props) => { className="w-full" onClick={submitInvitations} disabled={isJoiningWorkspaces || !invitationsRespond.length} + data-ph-element={MEMBER_TRACKER_ELEMENTS.ONBOARDING_JOIN_WORKSPACE} > {isJoiningWorkspaces ? : "Continue to workspace"} diff --git a/web/core/components/onboarding/invite-members.tsx b/web/core/components/onboarding/invite-members.tsx index 6865b78565b..bb7b24f7a7b 100644 --- a/web/core/components/onboarding/invite-members.tsx +++ b/web/core/components/onboarding/invite-members.tsx @@ -20,7 +20,7 @@ import { usePopper } from "react-popper"; import { Check, ChevronDown, Plus, XCircle } from "lucide-react"; import { Listbox } from "@headlessui/react"; // plane imports -import { ROLE, ROLE_DETAILS, EUserPermissions, MEMBER_TRACKER_EVENTS } from "@plane/constants"; +import { ROLE, ROLE_DETAILS, EUserPermissions, MEMBER_TRACKER_EVENTS, MEMBER_TRACKER_ELEMENTS } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; // types import { IUser, IWorkspace } from "@plane/types"; @@ -28,9 +28,8 @@ import { IUser, IWorkspace } from "@plane/types"; import { Button, Input, Spinner, TOAST_TYPE, setToast } from "@plane/ui"; // constants // helpers -import { getUserRole } from "@plane/utils"; // hooks -import { useEventTracker } from "@/hooks/store"; +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; // services import { WorkspaceService } from "@/plane-web/services"; // assets @@ -276,8 +275,6 @@ export const InviteMembers: React.FC = (props) => { const [isInvitationDisabled, setIsInvitationDisabled] = useState(true); const { resolvedTheme } = useTheme(); - // store hooks - const { captureEvent } = useEventTracker(); const { control, @@ -311,16 +308,11 @@ export const InviteMembers: React.FC = (props) => { })), }) .then(async () => { - captureEvent(MEMBER_TRACKER_EVENTS.invite, { - emails: [ - ...payload.emails.map((email) => ({ - email: email.email, - role: getUserRole(email.role), - })), - ], - project_id: undefined, - state: "SUCCESS", - element: "Onboarding", + captureSuccess({ + eventName: MEMBER_TRACKER_EVENTS.invite, + payload: { + workspace: workspace.slug, + }, }); setToast({ type: TOAST_TYPE.SUCCESS, @@ -331,10 +323,12 @@ export const InviteMembers: React.FC = (props) => { await nextStep(); }) .catch((err) => { - captureEvent(MEMBER_TRACKER_EVENTS.invite, { - project_id: undefined, - state: "FAILED", - element: "Onboarding", + captureError({ + eventName: MEMBER_TRACKER_EVENTS.invite, + payload: { + workspace: workspace.slug, + }, + error: err, }); setToast({ type: TOAST_TYPE.ERROR, @@ -426,6 +420,7 @@ export const InviteMembers: React.FC = (props) => { size="lg" className="w-full" disabled={isInvitationDisabled || !isValid || isSubmitting} + data-ph-element={MEMBER_TRACKER_ELEMENTS.ONBOARDING_INVITE_MEMBER} > {isSubmitting ? : "Continue"} diff --git a/web/core/components/project/leave-project-modal.tsx b/web/core/components/project/leave-project-modal.tsx index 3e03c579bfd..7f9bde99f72 100644 --- a/web/core/components/project/leave-project-modal.tsx +++ b/web/core/components/project/leave-project-modal.tsx @@ -14,7 +14,8 @@ import { IProject } from "@plane/types"; import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui"; // constants // hooks -import { useEventTracker, useUserPermissions } from "@/hooks/store"; +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; +import { useUserPermissions } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; type FormData = { @@ -39,7 +40,6 @@ export const LeaveProjectModal: FC = observer((props) => { const router = useAppRouter(); const { workspaceSlug } = useParams(); // store hooks - const { captureEvent } = useEventTracker(); const { leaveProject } = useUserPermissions(); const { @@ -64,21 +64,26 @@ export const LeaveProjectModal: FC = observer((props) => { return leaveProject(workspaceSlug.toString(), project.id) .then(() => { handleClose(); - captureEvent(MEMBER_TRACKER_EVENTS.project.leave, { - state: "SUCCESS", - element: "Project settings members page", + captureSuccess({ + eventName: MEMBER_TRACKER_EVENTS.project.leave, + payload: { + project: project.id, + }, }); }) - .catch(() => { + .catch((err) => { + captureError({ + eventName: MEMBER_TRACKER_EVENTS.project.leave, + payload: { + project: project.id, + }, + error: err, + }); setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: "Something went wrong please try again later.", }); - captureEvent(MEMBER_TRACKER_EVENTS.project.leave, { - state: "FAILED", - element: "Project settings members page", - }); }); } else { setToast({ diff --git a/web/core/components/project/member-list-item.tsx b/web/core/components/project/member-list-item.tsx index 619f3b29263..d729c48b93f 100644 --- a/web/core/components/project/member-list-item.tsx +++ b/web/core/components/project/member-list-item.tsx @@ -7,7 +7,8 @@ import { TOAST_TYPE, Table, setToast } from "@plane/ui"; // components import { ConfirmProjectMemberRemove } from "@/components/project"; // hooks -import { useEventTracker, useMember, useUser, useUserPermissions } from "@/hooks/store"; +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; +import { useMember, useUser, useUserPermissions } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; // plane web imports import { useProjectColumns } from "@/plane-web/components/projects/settings/useProjectColumns"; @@ -30,7 +31,6 @@ export const ProjectMemberListItem: React.FC = observer((props) => { const { project: { removeMemberFromProject }, } = useMember(); - const { captureEvent } = useEventTracker(); // helper hooks const { columns, removeMemberModal, setRemoveMemberModal } = useProjectColumns({ projectId, @@ -44,18 +44,27 @@ export const ProjectMemberListItem: React.FC = observer((props) => { await leaveProject(workspaceSlug.toString(), projectId.toString()) .then(async () => { router.push(`/${workspaceSlug}/projects`); - captureEvent(MEMBER_TRACKER_EVENTS.project.leave, { - state: "SUCCESS", - element: "Project settings members page", + captureSuccess({ + eventName: MEMBER_TRACKER_EVENTS.project.leave, + payload: { + project: projectId, + }, }); }) - .catch((err) => + .catch((err) => { + captureError({ + eventName: MEMBER_TRACKER_EVENTS.project.leave, + payload: { + project: projectId, + }, + error: err, + }); setToast({ type: TOAST_TYPE.ERROR, title: "You can’t leave this project yet.", message: err?.error || "Something went wrong. Please try again.", - }) - ); + }); + }); } else await removeMemberFromProject(workspaceSlug.toString(), projectId.toString(), memberId).catch((err) => setToast({ diff --git a/web/core/components/project/member-list.tsx b/web/core/components/project/member-list.tsx index 2314bb10e44..6dc378a4481 100644 --- a/web/core/components/project/member-list.tsx +++ b/web/core/components/project/member-list.tsx @@ -4,14 +4,14 @@ import { useState } from "react"; import { observer } from "mobx-react"; import { Search } from "lucide-react"; // plane imports -import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants"; +import { EUserPermissions, EUserPermissionsLevel, MEMBER_TRACKER_ELEMENTS } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { Button } from "@plane/ui"; // components import { ProjectMemberListItem, SendProjectInvitationModal } from "@/components/project"; import { MembersSettingsLoader } from "@/components/ui"; // hooks -import { useEventTracker, useMember, useUserPermissions } from "@/hooks/store"; +import { useMember, useUserPermissions } from "@/hooks/store"; type TProjectMemberListProps = { projectId: string; @@ -23,8 +23,6 @@ export const ProjectMemberList: React.FC = observer((pr // states const [inviteModal, setInviteModal] = useState(false); const [searchQuery, setSearchQuery] = useState(""); - // store hooks - const { setTrackElement } = useEventTracker(); const { project: { projectMemberIds, getProjectMemberDetails }, } = useMember(); @@ -73,9 +71,9 @@ export const ProjectMemberList: React.FC = observer((pr variant="primary" size="sm" onClick={() => { - setTrackElement("PROJECT_SETTINGS_MEMBERS_PAGE_HEADER"); setInviteModal(true); }} + data-ph-element={MEMBER_TRACKER_ELEMENTS.HEADER_BUTTON} > {t("add_member")} diff --git a/web/core/components/project/send-project-invitation-modal.tsx b/web/core/components/project/send-project-invitation-modal.tsx index 114ee3a4f1e..561dcd6a832 100644 --- a/web/core/components/project/send-project-invitation-modal.tsx +++ b/web/core/components/project/send-project-invitation-modal.tsx @@ -12,7 +12,8 @@ import { Avatar, Button, CustomSelect, CustomSearchSelect, TOAST_TYPE, setToast // helpers import { getFileURL } from "@plane/utils"; // hooks -import { useEventTracker, useMember, useUserPermissions } from "@/hooks/store"; +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; +import { useMember, useUserPermissions } from "@/hooks/store"; type Props = { isOpen: boolean; @@ -45,7 +46,6 @@ export const SendProjectInvitationModal: React.FC = observer((props) => { // plane hooks const { t } = useTranslation(); // store hooks - const { captureEvent } = useEventTracker(); const { getProjectRoleByWorkspaceSlugAndProjectId } = useUserPermissions(); const { project: { getProjectMemberDetails, bulkAddMembersToProject }, @@ -86,22 +86,22 @@ export const SendProjectInvitationModal: React.FC = observer((props) => { type: TOAST_TYPE.SUCCESS, message: "Members added successfully.", }); - captureEvent(MEMBER_TRACKER_EVENTS.project.add, { - members: [ - ...payload.members.map((member) => ({ - member_id: member.member_id, - role: ROLE[member.role], - })), - ], - state: "SUCCESS", - element: "Project settings members page", + + captureSuccess({ + eventName: MEMBER_TRACKER_EVENTS.project.add, + payload: { + members: [...payload.members.map((member) => member.member_id)], + }, }); }) .catch((error) => { console.error(error); - captureEvent(MEMBER_TRACKER_EVENTS.project.add, { - state: "FAILED", - element: "Project settings members page", + captureError({ + eventName: MEMBER_TRACKER_EVENTS.project.add, + payload: { + members: [...payload.members.map((member) => member.member_id)], + }, + error: error, }); }) .finally(() => { diff --git a/web/core/components/project/settings/member-columns.tsx b/web/core/components/project/settings/member-columns.tsx index 393a4012a60..4de2392a791 100644 --- a/web/core/components/project/settings/member-columns.tsx +++ b/web/core/components/project/settings/member-columns.tsx @@ -4,7 +4,7 @@ import { Controller, useForm } from "react-hook-form"; import { CircleMinus } from "lucide-react"; import { Disclosure } from "@headlessui/react"; // plane imports -import { ROLE, EUserPermissions, EUserProjectRoles } from "@plane/constants"; +import { ROLE, EUserPermissions, EUserProjectRoles, MEMBER_TRACKER_ELEMENTS } from "@plane/constants"; import { IUser, IWorkspaceMember, TProjectMembership } from "@plane/types"; import { CustomMenu, CustomSelect, TOAST_TYPE, setToast } from "@plane/ui"; import { getFileURL } from "@plane/utils"; @@ -70,6 +70,7 @@ export const NameColumn: React.FC = (props) => {
setRemoveMemberModal(rowData)} > diff --git a/web/core/components/workspace/settings/invitations-list-item.tsx b/web/core/components/workspace/settings/invitations-list-item.tsx index dc815b52cc3..1fa1fce2f60 100644 --- a/web/core/components/workspace/settings/invitations-list-item.tsx +++ b/web/core/components/workspace/settings/invitations-list-item.tsx @@ -5,13 +5,14 @@ import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import { ChevronDown, LinkIcon, Trash2 } from "lucide-react"; // plane imports -import { ROLE, EUserPermissions, EUserPermissionsLevel } from "@plane/constants"; +import { ROLE, EUserPermissions, EUserPermissionsLevel, MEMBER_TRACKER_ELEMENTS } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { CustomSelect, TOAST_TYPE, setToast, TContextMenuItem, CustomMenu } from "@plane/ui"; import { cn, copyTextToClipboard } from "@plane/utils"; // components import { ConfirmWorkspaceMemberRemove } from "@/components/workspace"; // hooks +import { captureClick } from "@/helpers/event-tracker.helper"; import { useMember, useUserPermissions } from "@/hooks/store"; type Props = { @@ -93,7 +94,12 @@ export const WorkspaceInvitationsListItem: FC = observer((props) => { }, { key: "remove", - action: () => setRemoveMemberModal(true), + action: () => { + captureClick({ + elementName: MEMBER_TRACKER_ELEMENTS.WORKSPACE_INVITATIONS_LIST_CONTEXT_MENU, + }); + setRemoveMemberModal(true); + }, title: t("common.remove"), icon: Trash2, shouldRender: isAdmin, diff --git a/web/core/components/workspace/settings/member-columns.tsx b/web/core/components/workspace/settings/member-columns.tsx index 1e5036fefc2..edff3f15ad4 100644 --- a/web/core/components/workspace/settings/member-columns.tsx +++ b/web/core/components/workspace/settings/member-columns.tsx @@ -4,7 +4,7 @@ import { Controller, useForm } from "react-hook-form"; import { Trash2 } from "lucide-react"; import { Disclosure } from "@headlessui/react"; // plane imports -import { ROLE, EUserPermissions, EUserPermissionsLevel } from "@plane/constants"; +import { ROLE, EUserPermissions, EUserPermissionsLevel, MEMBER_TRACKER_ELEMENTS } from "@plane/constants"; import { IUser, IWorkspaceMember } from "@plane/types"; // plane ui import { CustomSelect, PopoverMenu, TOAST_TYPE, setToast } from "@plane/ui"; @@ -74,6 +74,7 @@ export const NameColumn: React.FC = (props) => {
setRemoveMemberModal(rowData)} + data-ph-element={MEMBER_TRACKER_ELEMENTS.WORKSPACE_MEMBER_TABLE_CONTEXT_MENU} > {id === currentUser?.id ? "Leave " : "Remove "}
diff --git a/web/core/components/workspace/settings/members-list-item.tsx b/web/core/components/workspace/settings/members-list-item.tsx index 978b757b368..db7e7e2753e 100644 --- a/web/core/components/workspace/settings/members-list-item.tsx +++ b/web/core/components/workspace/settings/members-list-item.tsx @@ -13,7 +13,8 @@ import { MembersLayoutLoader } from "@/components/ui/loader/layouts/members-layo import { ConfirmWorkspaceMemberRemove } from "@/components/workspace"; // constants // hooks -import { useEventTracker, useMember, useUser, useUserPermissions, useUserSettings, useWorkspace } from "@/hooks/store"; +import { captureError, captureSuccess } from "@/helpers/event-tracker.helper"; +import { useMember, useUser, useUserPermissions, useUserSettings, useWorkspace } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; import { useMemberColumns } from "@/plane-web/components/workspace/settings/useMemberColumns"; @@ -32,7 +33,6 @@ export const WorkspaceMembersListItem: FC = observer((props) => { workspace: { removeMemberFromWorkspace }, } = useMember(); const { leaveWorkspace } = useUserPermissions(); - const { captureEvent } = useEventTracker(); const { getWorkspaceRedirectionUrl } = useWorkspace(); const { fetchCurrentUserSettings } = useUserSettings(); const { t } = useTranslation(); @@ -45,18 +45,27 @@ export const WorkspaceMembersListItem: FC = observer((props) => { .then(async () => { await fetchCurrentUserSettings(); router.push(getWorkspaceRedirectionUrl()); - captureEvent(MEMBER_TRACKER_EVENTS.workspace.leave, { - state: "SUCCESS", - element: "Workspace settings members page", + captureSuccess({ + eventName: MEMBER_TRACKER_EVENTS.workspace.leave, + payload: { + workspace: workspaceSlug, + }, }); }) - .catch((err: any) => + .catch((err: any) => { + captureError({ + eventName: MEMBER_TRACKER_EVENTS.workspace.leave, + payload: { + workspace: workspaceSlug, + }, + error: err, + }); setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: err?.error || t("something_went_wrong_please_try_again"), - }) - ); + }); + }); }; const handleRemoveMember = async (memberId: string) => { diff --git a/web/core/components/workspace/sidebar/projects-list-item.tsx b/web/core/components/workspace/sidebar/projects-list-item.tsx index d6f4365793c..55278b0477b 100644 --- a/web/core/components/workspace/sidebar/projects-list-item.tsx +++ b/web/core/components/workspace/sidebar/projects-list-item.tsx @@ -12,7 +12,7 @@ import { createRoot } from "react-dom/client"; import { LinkIcon, Settings, Share2, LogOut, MoreHorizontal, ChevronRight } from "lucide-react"; import { Disclosure, Transition } from "@headlessui/react"; // plane helpers -import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants"; +import { EUserPermissions, EUserPermissionsLevel, MEMBER_TRACKER_ELEMENTS } from "@plane/constants"; import { useOutsideClickDetector } from "@plane/hooks"; import { useTranslation } from "@plane/i18n"; // ui @@ -23,7 +23,7 @@ import { Logo } from "@/components/common/logo"; import { LeaveProjectModal, PublishProjectModal } from "@/components/project"; // helpers // hooks -import { useAppTheme, useCommandPalette, useEventTracker, useProject, useUserPermissions } from "@/hooks/store"; +import { useAppTheme, useCommandPalette, useProject, useUserPermissions } from "@/hooks/store"; import { usePlatformOS } from "@/hooks/use-platform-os"; // plane-web components import { ProjectNavigationRoot } from "@/plane-web/components/sidebar"; @@ -59,7 +59,6 @@ export const SidebarProjectsListItem: React.FC = observer((props) => { // store hooks const { sidebarCollapsed } = useAppTheme(); const { t } = useTranslation(); - const { setTrackElement } = useEventTracker(); const { getPartialProjectById } = useProject(); const { isMobile } = usePlatformOS(); const { allowPermissions } = useUserPermissions(); @@ -97,7 +96,6 @@ export const SidebarProjectsListItem: React.FC = observer((props) => { ); const handleLeaveProject = () => { - setTrackElement("APP_SIDEBAR_PROJECT_DROPDOWN"); setLeaveProjectModal(true); }; @@ -376,7 +374,10 @@ export const SidebarProjectsListItem: React.FC = observer((props) => { {/* leave project */} {!isAuthorized && ( - +
{t("leave_project")} From c0b6354600441c6ef9822335a8bb0c26649e7f56 Mon Sep 17 00:00:00 2001 From: gakshita Date: Tue, 1 Jul 2025 15:16:42 +0530 Subject: [PATCH 2/2] fix: constants --- packages/constants/src/event-tracker/core.ts | 5 ++--- .../(settings)/settings/(workspace)/members/page.tsx | 2 +- web/app/(all)/invitations/page.tsx | 2 +- web/core/components/project/member-list.tsx | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/constants/src/event-tracker/core.ts b/packages/constants/src/event-tracker/core.ts index d057a1641d7..16dae31f2d6 100644 --- a/packages/constants/src/event-tracker/core.ts +++ b/packages/constants/src/event-tracker/core.ts @@ -25,7 +25,6 @@ export const getProjectEventPayload = (payload: any) => ({ element: payload.element, }); - export const getPageEventPayload = (payload: any) => ({ workspace_id: payload.workspace_id, project_id: payload.project, @@ -197,8 +196,8 @@ export const MEMBER_TRACKER_EVENTS = { }; export const MEMBER_TRACKER_ELEMENTS = { - HEADER_BUTTON: "header_add_member_button", - INVITATION_BUTTON: "accept_invitation_button", + HEADER_ADD_BUTTON: "header_add_member_button", + ACCEPT_INVITATION_BUTTON: "accept_invitation_button", ONBOARDING_JOIN_WORKSPACE: "workspace_join_continue_to_workspace_button", ONBOARDING_INVITE_MEMBER: "invite_member_continue_button", SIDEBAR_PROJECT_QUICK_ACTIONS: "sidebar_project_quick_actions", diff --git a/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/members/page.tsx b/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/members/page.tsx index 0dc0ae64fbe..e05eb30f057 100644 --- a/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/members/page.tsx +++ b/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/members/page.tsx @@ -129,7 +129,7 @@ const WorkspaceMembersSettingsPage = observer(() => { variant="primary" size="sm" onClick={() => setInviteModal(true)} - data-ph-element={MEMBER_TRACKER_ELEMENTS.HEADER_BUTTON} + data-ph-element={MEMBER_TRACKER_ELEMENTS.HEADER_ADD_BUTTON} > {t("workspace_settings.settings.members.add_member")} diff --git a/web/app/(all)/invitations/page.tsx b/web/app/(all)/invitations/page.tsx index 764ed1b3f18..bb555ccc455 100644 --- a/web/app/(all)/invitations/page.tsx +++ b/web/app/(all)/invitations/page.tsx @@ -193,7 +193,7 @@ const UserInvitationsPage = observer(() => { onClick={submitInvitations} disabled={isJoiningWorkspaces || invitationsRespond.length === 0} loading={isJoiningWorkspaces} - data-ph-element={MEMBER_TRACKER_ELEMENTS.INVITATION_BUTTON} + data-ph-element={MEMBER_TRACKER_ELEMENTS.ACCEPT_INVITATION_BUTTON} > {t("accept_and_join")} diff --git a/web/core/components/project/member-list.tsx b/web/core/components/project/member-list.tsx index 6dc378a4481..ff9d63564eb 100644 --- a/web/core/components/project/member-list.tsx +++ b/web/core/components/project/member-list.tsx @@ -73,7 +73,7 @@ export const ProjectMemberList: React.FC = observer((pr onClick={() => { setInviteModal(true); }} - data-ph-element={MEMBER_TRACKER_ELEMENTS.HEADER_BUTTON} + data-ph-element={MEMBER_TRACKER_ELEMENTS.HEADER_ADD_BUTTON} > {t("add_member")}