diff --git a/web/components/headers/project-inbox.tsx b/web/components/headers/project-inbox.tsx
index 80a39862b..59a18e306 100644
--- a/web/components/headers/project-inbox.tsx
+++ b/web/components/headers/project-inbox.tsx
@@ -8,8 +8,10 @@ import { Breadcrumbs, Button, LayersIcon } from "@plane/ui";
import { BreadcrumbLink } from "@/components/common";
import { InboxIssueCreateEditModalRoot } from "@/components/inbox";
import { ProjectLogo } from "@/components/project";
+// constants
+import { E_INBOX } from "@/constants/event-tracker";
// hooks
-import { useProject, useProjectInbox } from "@/hooks/store";
+import { useEventTracker, useProject, useProjectInbox } from "@/hooks/store";
export const ProjectInboxHeader: FC = observer(() => {
// states
@@ -20,6 +22,7 @@ export const ProjectInboxHeader: FC = observer(() => {
// store hooks
const { currentProjectDetails } = useProject();
const { loader } = useProjectInbox();
+ const { setTrackElement } = useEventTracker();
return (
@@ -70,7 +73,15 @@ export const ProjectInboxHeader: FC = observer(() => {
issue={undefined}
/>
- } size="sm" onClick={() => setCreateIssueModal(true)}>
+ }
+ size="sm"
+ onClick={() => {
+ setTrackElement(E_INBOX);
+ setCreateIssueModal(true);
+ }}
+ >
Add Issue
diff --git a/web/components/inbox/content/inbox-issue-header.tsx b/web/components/inbox/content/inbox-issue-header.tsx
index 23ff83706..f73b44d6d 100644
--- a/web/components/inbox/content/inbox-issue-header.tsx
+++ b/web/components/inbox/content/inbox-issue-header.tsx
@@ -25,12 +25,13 @@ import {
} from "@/components/inbox";
import { IssueUpdateStatus } from "@/components/issues";
// constants
+import { INBOX_ISSUE_DELETED, INBOX_ISSUE_UPDATED } from "@/constants/event-tracker";
import { EUserProjectRoles } from "@/constants/project";
// helpers
import { EInboxIssueStatus } from "@/helpers/inbox.helper";
import { copyUrlToClipboard } from "@/helpers/string.helper";
// hooks
-import { useUser, useProjectInbox, useProject } from "@/hooks/store";
+import { useUser, useProjectInbox, useProject, useEventTracker } from "@/hooks/store";
// store types
import type { IInboxIssueStore } from "@/store/inbox/inbox-issue.store";
@@ -60,6 +61,7 @@ export const InboxIssueActionsHeader: FC = observer((p
const router = useRouter();
const { getProjectById } = useProject();
+ const { captureEvent } = useEventTracker();
const issue = inboxIssue?.issue;
// derived values
@@ -98,6 +100,10 @@ export const InboxIssueActionsHeader: FC = observer((p
await inboxIssue?.updateInboxIssueStatus(EInboxIssueStatus.ACCEPTED);
setAcceptIssueModal(false);
handleRedirection(nextOrPreviousIssueId);
+ captureEvent(INBOX_ISSUE_UPDATED, {
+ issue_status: "accepted",
+ issue_id: currentInboxIssueId,
+ });
};
const handleInboxIssueDecline = async () => {
@@ -105,6 +111,10 @@ export const InboxIssueActionsHeader: FC = observer((p
await inboxIssue?.updateInboxIssueStatus(EInboxIssueStatus.DECLINED);
setDeclineIssueModal(false);
handleRedirection(nextOrPreviousIssueId);
+ captureEvent(INBOX_ISSUE_UPDATED, {
+ issue_status: "declined",
+ issue_id: currentInboxIssueId,
+ });
};
const handleInboxSIssueSnooze = async (date: Date) => {
@@ -112,14 +122,25 @@ export const InboxIssueActionsHeader: FC = observer((p
await inboxIssue?.updateInboxIssueSnoozeTill(date);
setIsSnoozeDateModalOpen(false);
handleRedirection(nextOrPreviousIssueId);
+ captureEvent(INBOX_ISSUE_UPDATED, {
+ issue_status: "snoozed",
+ issue_id: currentInboxIssueId,
+ });
};
const handleInboxIssueDuplicate = async (issueId: string) => {
await inboxIssue?.updateInboxIssueDuplicateTo(issueId);
+ captureEvent(INBOX_ISSUE_UPDATED, {
+ issue_status: "mark as duplicate",
+ issue_id: currentInboxIssueId,
+ });
};
const handleInboxIssueDelete = async () => {
if (!inboxIssue || !currentInboxIssueId) return;
+ captureEvent(INBOX_ISSUE_DELETED, {
+ issue_id: currentInboxIssueId,
+ });
await deleteInboxIssue(workspaceSlug, projectId, currentInboxIssueId).finally(() => {
router.push(`/${workspaceSlug}/projects/${projectId}/inbox`);
});
diff --git a/web/components/inbox/content/issue-root.tsx b/web/components/inbox/content/issue-root.tsx
index 7f8892ef5..cdfcd359a 100644
--- a/web/components/inbox/content/issue-root.tsx
+++ b/web/components/inbox/content/issue-root.tsx
@@ -13,6 +13,8 @@ import {
TIssueOperations,
IssueAttachmentRoot,
} from "@/components/issues";
+// constants
+import { E_INBOX, INBOX_ISSUE_UPDATED } from "@/constants/event-tracker";
// hooks
import { useEventTracker, useProjectInbox, useUser } from "@/hooks/store";
import useReloadConfirmations from "@/hooks/use-reload-confirmation";
@@ -36,7 +38,7 @@ export const InboxIssueMainContent: React.FC = observer((props) => {
// hooks
const { data: currentUser } = useUser();
const { setShowAlert } = useReloadConfirmations(isSubmitting === "submitting");
- const { captureIssueEvent } = useEventTracker();
+ const { captureEvent } = useEventTracker();
const { loader } = useProjectInbox();
useEffect(() => {
@@ -82,14 +84,12 @@ export const InboxIssueMainContent: React.FC = observer((props) => {
update: async (workspaceSlug: string, projectId: string, issueId: string, data: Partial) => {
try {
await inboxIssue.updateIssue(data);
- captureIssueEvent({
- eventName: "Inbox issue updated",
- payload: { ...data, state: "SUCCESS", element: "Inbox" },
- updates: {
- changed_property: Object.keys(data).join(","),
- change_details: Object.values(data).join(","),
- },
- routePath: router.asPath,
+ captureEvent(INBOX_ISSUE_UPDATED, {
+ ...data,
+ changed_property: Object.keys(data).join(","),
+ change_details: Object.values(data).join(","),
+ element: E_INBOX,
+ state: "SUCCESS",
});
} catch (error) {
setToast({
@@ -97,14 +97,12 @@ export const InboxIssueMainContent: React.FC = observer((props) => {
type: TOAST_TYPE.ERROR,
message: "Issue update failed",
});
- captureIssueEvent({
- eventName: "Inbox issue updated",
- payload: { state: "SUCCESS", element: "Inbox" },
- updates: {
- changed_property: Object.keys(data).join(","),
- change_details: Object.values(data).join(","),
- },
- routePath: router.asPath,
+ captureEvent(INBOX_ISSUE_UPDATED, {
+ ...data,
+ changed_property: Object.keys(data).join(","),
+ change_details: Object.values(data).join(","),
+ element: E_INBOX,
+ state: "FAILED",
});
}
},
diff --git a/web/components/inbox/inbox-filter/filters/date.tsx b/web/components/inbox/inbox-filter/filters/date.tsx
index aee188be8..902ead05f 100644
--- a/web/components/inbox/inbox-filter/filters/date.tsx
+++ b/web/components/inbox/inbox-filter/filters/date.tsx
@@ -2,19 +2,26 @@ import { FC, useState } from "react";
import concat from "lodash/concat";
import uniq from "lodash/uniq";
import { observer } from "mobx-react";
-import { TInboxIssueFilterDateKeys } from "@plane/types";
+import { TInboxIssueFilter, TInboxIssueFilterDateKeys } from "@plane/types";
// components
import { DateFilterModal } from "@/components/core";
import { FilterHeader, FilterOption } from "@/components/issues";
// constants
import { PAST_DURATION_FILTER_OPTIONS } from "@/helpers/inbox.helper";
// hooks
-import { useProjectInbox } from "@/hooks/store";
+import { useEventTracker } from "@/hooks/store";
type Props = {
filterKey: TInboxIssueFilterDateKeys;
label?: string;
searchQuery: string;
+ inboxFilters: Partial;
+ handleFilterUpdate: (
+ filterKey: keyof TInboxIssueFilter,
+ filterValue: TInboxIssueFilter[keyof TInboxIssueFilter],
+ isSelected: boolean,
+ interactedValue: string
+ ) => void;
};
const isDate = (date: string) => {
@@ -23,9 +30,7 @@ const isDate = (date: string) => {
};
export const FilterDate: FC = observer((props) => {
- const { filterKey, label, searchQuery } = props;
- // hooks
- const { inboxFilters, handleInboxIssueFilters } = useProjectInbox();
+ const { filterKey, label, searchQuery, inboxFilters, handleFilterUpdate } = props;
// state
const [previewEnabled, setPreviewEnabled] = useState(true);
const [isDateFilterModalOpen, setIsDateFilterModalOpen] = useState(false);
@@ -46,7 +51,7 @@ export const FilterDate: FC = observer((props) => {
const handleCustomDate = () => {
if (isCustomDateSelected()) {
const updateAppliedFilters = filterValue?.filter((f) => !isDate(f.split(";")[0])) || [];
- handleInboxIssueFilters(filterKey, updateAppliedFilters);
+ handleFilterUpdate(filterKey, updateAppliedFilters, true, "Custom");
} else {
setIsDateFilterModalOpen(true);
}
@@ -58,7 +63,7 @@ export const FilterDate: FC = observer((props) => {
setIsDateFilterModalOpen(false)}
isOpen={isDateFilterModalOpen}
- onSelect={(val) => handleInboxIssueFilters(filterKey, val)}
+ onSelect={(val) => handleFilterUpdate(filterKey, val, false, "Custom")}
title="Created date"
/>
)}
@@ -75,7 +80,14 @@ export const FilterDate: FC = observer((props) => {
handleInboxIssueFilters(filterKey, handleFilterValue(option.value))}
+ onClick={() =>
+ handleFilterUpdate(
+ filterKey,
+ handleFilterValue(option.value),
+ filterValue?.includes(option.value),
+ option.name
+ )
+ }
title={option.name}
multiple={false}
/>
diff --git a/web/components/inbox/inbox-filter/filters/filter-selection.tsx b/web/components/inbox/inbox-filter/filters/filter-selection.tsx
index fd1dc951c..8f3711c12 100644
--- a/web/components/inbox/inbox-filter/filters/filter-selection.tsx
+++ b/web/components/inbox/inbox-filter/filters/filter-selection.tsx
@@ -1,6 +1,7 @@
-import { FC, useState } from "react";
+import { FC, useCallback, useState } from "react";
import { observer } from "mobx-react";
import { Search, X } from "lucide-react";
+import { TInboxIssueFilter } from "@plane/types";
// components
import {
FilterStatus,
@@ -10,8 +11,11 @@ import {
FilterLabels,
FilterState,
} from "@/components/inbox/inbox-filter/filters";
+// constants
+import { INBOX_FILTERS_APPLIED, INBOX_FILTERS_REMOVED } from "@/constants/event-tracker";
+import { INBOX_STATUS } from "@/constants/inbox";
// hooks
-import { useMember, useLabel, useProjectState } from "@/hooks/store";
+import { useMember, useLabel, useProjectState, useProjectInbox, useEventTracker } from "@/hooks/store";
export const InboxIssueFilterSelection: FC = observer(() => {
// hooks
@@ -20,9 +24,31 @@ export const InboxIssueFilterSelection: FC = observer(() => {
} = useMember();
const { projectLabels } = useLabel();
const { projectStates } = useProjectState();
+ const { inboxFilters, handleInboxIssueFilters } = useProjectInbox();
+ const { captureEvent } = useEventTracker();
// states
const [filtersSearchQuery, setFiltersSearchQuery] = useState("");
+ const handleFilterUpdate = useCallback(
+ (
+ filterKey: keyof TInboxIssueFilter,
+ filterValue: TInboxIssueFilter[keyof TInboxIssueFilter],
+ isSelected: boolean,
+ interactedValue: string
+ ) => {
+ captureEvent(isSelected ? INBOX_FILTERS_REMOVED : INBOX_FILTERS_APPLIED, {
+ filter_type: filterKey,
+ filter_property: interactedValue,
+ current_filters: {
+ ...inboxFilters,
+ status: inboxFilters?.status?.map((status) => INBOX_STATUS.find((s) => s.status === status)?.title),
+ },
+ });
+ handleInboxIssueFilters(filterKey, filterValue);
+ },
+ [captureEvent, inboxFilters, handleInboxIssueFilters]
+ );
+
return (
@@ -47,21 +73,36 @@ export const InboxIssueFilterSelection: FC = observer(() => {
{/* status */}
-
+
{/* state */}
-
+
{/* Priority */}
-
+
{/* assignees */}
@@ -71,21 +112,40 @@ export const InboxIssueFilterSelection: FC = observer(() => {
{/* Labels */}
-
+
{/* Created at */}
-
+
{/* Updated at */}
-
+
diff --git a/web/components/inbox/inbox-filter/filters/labels.tsx b/web/components/inbox/inbox-filter/filters/labels.tsx
index 8f6b765b5..74f284d69 100644
--- a/web/components/inbox/inbox-filter/filters/labels.tsx
+++ b/web/components/inbox/inbox-filter/filters/labels.tsx
@@ -1,11 +1,9 @@
import { FC, useState } from "react";
import { observer } from "mobx-react";
-import { IIssueLabel } from "@plane/types";
+import { IIssueLabel, TInboxIssueFilter } from "@plane/types";
import { Loader } from "@plane/ui";
// components
import { FilterHeader, FilterOption } from "@/components/issues";
-// hooks
-import { useProjectInbox } from "@/hooks/store";
const LabelIcons = ({ color }: { color: string }) => (
@@ -14,16 +12,21 @@ const LabelIcons = ({ color }: { color: string }) => (
type Props = {
labels: IIssueLabel[] | undefined;
searchQuery: string;
+ inboxFilters: Partial
;
+ handleFilterUpdate: (
+ filterKey: keyof TInboxIssueFilter,
+ filterValue: TInboxIssueFilter[keyof TInboxIssueFilter],
+ isSelected: boolean,
+ interactedValue: string
+ ) => void;
};
export const FilterLabels: FC = observer((props) => {
- const { labels, searchQuery } = props;
+ const { labels, searchQuery, inboxFilters, handleFilterUpdate } = props;
const [itemsToRender, setItemsToRender] = useState(5);
const [previewEnabled, setPreviewEnabled] = useState(true);
- const { inboxFilters, handleInboxIssueFilters } = useProjectInbox();
-
const filterValue = inboxFilters?.labels || [];
const appliedFiltersCount = filterValue?.length ?? 0;
@@ -56,7 +59,14 @@ export const FilterLabels: FC = observer((props) => {
handleInboxIssueFilters("labels", handleFilterValue(label.id))}
+ onClick={() =>
+ handleFilterUpdate(
+ "labels",
+ handleFilterValue(label?.id),
+ filterValue?.includes(label?.id),
+ label?.id
+ )
+ }
icon={}
title={label.name}
/>
diff --git a/web/components/inbox/inbox-filter/filters/members.tsx b/web/components/inbox/inbox-filter/filters/members.tsx
index f86c385e7..9f20fa975 100644
--- a/web/components/inbox/inbox-filter/filters/members.tsx
+++ b/web/components/inbox/inbox-filter/filters/members.tsx
@@ -1,24 +1,29 @@
import { FC, useMemo, useState } from "react";
import sortBy from "lodash/sortBy";
import { observer } from "mobx-react";
-import { TInboxIssueFilterMemberKeys } from "@plane/types";
+import { TInboxIssueFilter, TInboxIssueFilterMemberKeys } from "@plane/types";
import { Avatar, Loader } from "@plane/ui";
// components
import { FilterHeader, FilterOption } from "@/components/issues";
// hooks
-import { useMember, useProjectInbox, useUser } from "@/hooks/store";
+import { useEventTracker, useMember, useUser } from "@/hooks/store";
type Props = {
filterKey: TInboxIssueFilterMemberKeys;
label?: string;
memberIds: string[] | undefined;
searchQuery: string;
+ inboxFilters: Partial;
+ handleFilterUpdate: (
+ filterKey: keyof TInboxIssueFilter,
+ filterValue: TInboxIssueFilter[keyof TInboxIssueFilter],
+ isSelected: boolean,
+ interactedValue: string
+ ) => void;
};
export const FilterMember: FC = observer((props: Props) => {
- const { filterKey, label = "Members", memberIds, searchQuery } = props;
- // hooks
- const { inboxFilters, handleInboxIssueFilters } = useProjectInbox();
+ const { filterKey, label = "Members", memberIds, searchQuery, inboxFilters, handleFilterUpdate } = props;
const { getUserDetails } = useMember();
const { currentUser } = useUser();
// states
@@ -71,7 +76,14 @@ export const FilterMember: FC = observer((props: Props) => {
handleInboxIssueFilters(filterKey, handleFilterValue(member.id))}
+ onClick={() =>
+ handleFilterUpdate(
+ filterKey,
+ handleFilterValue(member.id),
+ filterValue?.includes(member.id),
+ member.id
+ )
+ }
icon={}
title={currentUser?.id === member.id ? "You" : member?.display_name}
/>
diff --git a/web/components/inbox/inbox-filter/filters/priority.tsx b/web/components/inbox/inbox-filter/filters/priority.tsx
index 0639623e4..373cf719e 100644
--- a/web/components/inbox/inbox-filter/filters/priority.tsx
+++ b/web/components/inbox/inbox-filter/filters/priority.tsx
@@ -1,22 +1,25 @@
import { FC, useState } from "react";
import { observer } from "mobx-react";
-import { TIssuePriorities } from "@plane/types";
+import { TInboxIssueFilter, TIssuePriorities } from "@plane/types";
import { PriorityIcon } from "@plane/ui";
// components
import { FilterHeader, FilterOption } from "@/components/issues";
// constants
import { ISSUE_PRIORITIES } from "@/constants/issue";
-// hooks
-import { useProjectInbox } from "@/hooks/store/use-project-inbox";
type Props = {
searchQuery: string;
+ inboxFilters: Partial;
+ handleFilterUpdate: (
+ filterKey: keyof TInboxIssueFilter,
+ filterValue: TInboxIssueFilter[keyof TInboxIssueFilter],
+ isSelected: boolean,
+ interactedValue: string
+ ) => void;
};
export const FilterPriority: FC = observer((props) => {
- const { searchQuery } = props;
- // hooks
- const { inboxFilters, handleInboxIssueFilters } = useProjectInbox();
+ const { searchQuery, inboxFilters, handleFilterUpdate } = props;
// states
const [previewEnabled, setPreviewEnabled] = useState(true);
// derived values
@@ -41,7 +44,14 @@ export const FilterPriority: FC = observer((props) => {
handleInboxIssueFilters("priority", handleFilterValue(priority.key))}
+ onClick={() =>
+ handleFilterUpdate(
+ "priority",
+ handleFilterValue(priority.key),
+ filterValue?.includes(priority.key),
+ priority.title
+ )
+ }
icon={}
title={priority.title}
/>
diff --git a/web/components/inbox/inbox-filter/filters/state.tsx b/web/components/inbox/inbox-filter/filters/state.tsx
index b3cfad435..c2730e35d 100644
--- a/web/components/inbox/inbox-filter/filters/state.tsx
+++ b/web/components/inbox/inbox-filter/filters/state.tsx
@@ -1,25 +1,28 @@
import { FC, useState } from "react";
import { observer } from "mobx-react";
-import { IState } from "@plane/types";
+import { IState, TInboxIssueFilter } from "@plane/types";
import { Loader, StateGroupIcon } from "@plane/ui";
// components
import { FilterHeader, FilterOption } from "@/components/issues";
-// hooks
-import { useProjectInbox } from "@/hooks/store";
type Props = {
states: IState[] | undefined;
searchQuery: string;
+ inboxFilters: Partial;
+ handleFilterUpdate: (
+ filterKey: keyof TInboxIssueFilter,
+ filterValue: TInboxIssueFilter[keyof TInboxIssueFilter],
+ isSelected: boolean,
+ interactedValue: string
+ ) => void;
};
export const FilterState: FC = observer((props) => {
- const { states, searchQuery } = props;
+ const { states, inboxFilters, searchQuery, handleFilterUpdate } = props;
const [itemsToRender, setItemsToRender] = useState(5);
const [previewEnabled, setPreviewEnabled] = useState(true);
- const { inboxFilters, handleInboxIssueFilters } = useProjectInbox();
-
const filterValue = inboxFilters?.state || [];
const appliedFiltersCount = filterValue?.length ?? 0;
@@ -52,7 +55,14 @@ export const FilterState: FC = observer((props) => {
handleInboxIssueFilters("state", handleFilterValue(state.id))}
+ onClick={() =>
+ handleFilterUpdate(
+ "state",
+ handleFilterValue(state.id),
+ filterValue?.includes(state.id),
+ state.id
+ )
+ }
icon={}
title={state.name}
/>
diff --git a/web/components/inbox/inbox-filter/filters/status.tsx b/web/components/inbox/inbox-filter/filters/status.tsx
index b27f360da..f90799132 100644
--- a/web/components/inbox/inbox-filter/filters/status.tsx
+++ b/web/components/inbox/inbox-filter/filters/status.tsx
@@ -1,22 +1,29 @@
import { FC, useState } from "react";
import { observer } from "mobx-react";
// types
-import { TInboxIssueStatus } from "@plane/types";
+import { TInboxIssueFilter, TInboxIssueFilterMemberKeys, TInboxIssueStatus } from "@plane/types";
// components
import { FilterHeader, FilterOption } from "@/components/issues";
// constants
import { INBOX_STATUS } from "@/constants/inbox";
// hooks
-import { useProjectInbox } from "@/hooks/store/use-project-inbox";
+import { useProjectInbox } from "@/hooks/store";
type Props = {
searchQuery: string;
+ inboxFilters: Partial;
+ handleFilterUpdate: (
+ filterKey: keyof TInboxIssueFilter,
+ filterValue: TInboxIssueFilter[keyof TInboxIssueFilter],
+ isSelected: boolean,
+ interactedValue: string
+ ) => void;
};
export const FilterStatus: FC = observer((props) => {
- const { searchQuery } = props;
+ const { searchQuery, inboxFilters, handleFilterUpdate } = props;
// hooks
- const { currentTab, inboxFilters, handleInboxIssueFilters } = useProjectInbox();
+ const { currentTab } = useProjectInbox();
// states
const [previewEnabled, setPreviewEnabled] = useState(true);
// derived values
@@ -34,7 +41,13 @@ export const FilterStatus: FC = observer((props) => {
const handleStatusFilterSelect = (status: TInboxIssueStatus) => {
const selectedStatus = handleFilterValue(status);
- if (selectedStatus.length >= 1) handleInboxIssueFilters("status", selectedStatus);
+ if (selectedStatus.length >= 1)
+ handleFilterUpdate(
+ "status",
+ selectedStatus,
+ filterValue?.includes(status),
+ INBOX_STATUS.find((s) => s.status === status)?.title ?? ""
+ );
};
return (
diff --git a/web/components/inbox/inbox-filter/sorting/order-by.tsx b/web/components/inbox/inbox-filter/sorting/order-by.tsx
index 4eb9dde22..75d67a59e 100644
--- a/web/components/inbox/inbox-filter/sorting/order-by.tsx
+++ b/web/components/inbox/inbox-filter/sorting/order-by.tsx
@@ -1,20 +1,35 @@
-import { FC } from "react";
+import { FC, useCallback } from "react";
import { observer } from "mobx-react";
import { ArrowDownWideNarrow, ArrowUpWideNarrow, Check, ChevronDown } from "lucide-react";
+import { TInboxIssueSorting } from "@plane/types";
import { CustomMenu, getButtonStyling } from "@plane/ui";
// constants
+import { INBOX_SORT_UPDATED } from "@/constants/event-tracker";
import { INBOX_ISSUE_ORDER_BY_OPTIONS, INBOX_ISSUE_SORT_BY_OPTIONS } from "@/constants/inbox";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
-import { useProjectInbox } from "@/hooks/store";
+import { useProjectInbox, useEventTracker } from "@/hooks/store";
export const InboxIssueOrderByDropdown: FC = observer(() => {
// hooks
const { inboxSorting, handleInboxIssueSorting } = useProjectInbox();
+ const { captureEvent } = useEventTracker();
const orderByDetails =
INBOX_ISSUE_ORDER_BY_OPTIONS.find((option) => inboxSorting?.order_by?.includes(option.key)) || undefined;
+ const handleIssueSorting = useCallback(
+ (filterKey: keyof TInboxIssueSorting, filterValue: TInboxIssueSorting[keyof TInboxIssueSorting]) => {
+ captureEvent(INBOX_SORT_UPDATED, {
+ changed_property: filterKey,
+ changed_details: filterValue,
+ current_sort: inboxSorting,
+ });
+ handleInboxIssueSorting(filterKey, filterValue);
+ },
+ [handleInboxIssueSorting, captureEvent, inboxSorting]
+ );
+
return (
{
handleInboxIssueSorting("order_by", option.key)}
+ onClick={() => handleIssueSorting("order_by", option.key)}
>
{option.label}
{inboxSorting?.order_by?.includes(option.key) && }
@@ -47,7 +62,7 @@ export const InboxIssueOrderByDropdown: FC = observer(() => {
handleInboxIssueSorting("sort_by", option.key)}
+ onClick={() => handleIssueSorting("sort_by", option.key)}
>
{option.label}
{inboxSorting?.sort_by?.includes(option.key) && }
diff --git a/web/components/inbox/modals/create-edit-modal/create-root.tsx b/web/components/inbox/modals/create-edit-modal/create-root.tsx
index e317e0879..62c971f31 100644
--- a/web/components/inbox/modals/create-edit-modal/create-root.tsx
+++ b/web/components/inbox/modals/create-edit-modal/create-root.tsx
@@ -11,7 +11,7 @@ import {
InboxIssueProperties,
} from "@/components/inbox/modals/create-edit-modal";
// constants
-import { ISSUE_CREATED } from "@/constants/event-tracker";
+import { INBOX_ISSUE_CREATED, getIssueEventPayload } from "@/constants/event-tracker";
// helpers
import { renderFormattedPayloadDate } from "@/helpers/date-time.helper";
// hooks
@@ -41,7 +41,7 @@ export const InboxIssueCreateRoot: FC = observer((props)
// refs
const descriptionEditorRef = useRef(null);
// hooks
- const { captureIssueEvent } = useEventTracker();
+ const { captureEvent } = useEventTracker();
const { createInboxIssue } = useProjectInbox();
const { getWorkspaceBySlug } = useWorkspace();
const workspaceId = getWorkspaceBySlug(workspaceSlug)?.id;
@@ -81,14 +81,13 @@ export const InboxIssueCreateRoot: FC = observer((props)
descriptionEditorRef?.current?.clearEditor();
setFormData(defaultIssueData);
}
- captureIssueEvent({
- eventName: ISSUE_CREATED,
- payload: {
- ...formData,
- state: "SUCCESS",
- element: "Inbox page",
- },
- routePath: router.pathname,
+ captureEvent(INBOX_ISSUE_CREATED, {
+ issue_id: res?.issue?.id,
+ properties: getIssueEventPayload({
+ eventName: INBOX_ISSUE_CREATED,
+ payload: res?.issue,
+ }),
+ state: "SUCCESS",
});
setToast({
type: TOAST_TYPE.SUCCESS,
@@ -98,14 +97,12 @@ export const InboxIssueCreateRoot: FC = observer((props)
})
.catch((error) => {
console.error(error);
- captureIssueEvent({
- eventName: ISSUE_CREATED,
- payload: {
- ...formData,
- state: "FAILED",
- element: "Inbox page",
- },
- routePath: router.pathname,
+ captureEvent(INBOX_ISSUE_CREATED, {
+ properties: getIssueEventPayload({
+ eventName: INBOX_ISSUE_CREATED,
+ payload: formData,
+ }),
+ state: "FAILED",
});
setToast({
type: TOAST_TYPE.ERROR,
diff --git a/web/components/inbox/sidebar/inbox-list-item.tsx b/web/components/inbox/sidebar/inbox-list-item.tsx
index 89b6a8f8a..1b08fb5ac 100644
--- a/web/components/inbox/sidebar/inbox-list-item.tsx
+++ b/web/components/inbox/sidebar/inbox-list-item.tsx
@@ -5,11 +5,13 @@ import { useRouter } from "next/router";
import { Tooltip, PriorityIcon } from "@plane/ui";
// components
import { InboxIssueStatus } from "@/components/inbox";
+// constants
+import { INBOX_ISSUE_OPENED } from "@/constants/event-tracker";
// helpers
import { cn } from "@/helpers/common.helper";
import { renderFormattedDate } from "@/helpers/date-time.helper";
// hooks
-import { useLabel, useProjectInbox } from "@/hooks/store";
+import { useEventTracker, useLabel, useProjectInbox } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
// store
import { IInboxIssueStore } from "@/store/inbox/inbox-issue.store";
@@ -23,7 +25,7 @@ type InboxIssueListItemProps = {
};
export const InboxIssueListItem: FC = observer((props) => {
- const { workspaceSlug, projectId, inboxIssue, projectIdentifier,setToggleMobileSidebar } = props;
+ const { workspaceSlug, projectId, inboxIssue, projectIdentifier, setToggleMobileSidebar } = props;
// router
const router = useRouter();
const { inboxIssueId } = router.query;
@@ -31,6 +33,7 @@ export const InboxIssueListItem: FC = observer((props)
const { currentTab } = useProjectInbox();
const { projectLabels } = useLabel();
const { isMobile } = usePlatformOS();
+ const { captureEvent } = useEventTracker();
const issue = inboxIssue.issue;
const handleIssueRedirection = (event: MouseEvent, currentIssueId: string | undefined) => {
@@ -45,7 +48,12 @@ export const InboxIssueListItem: FC = observer((props)
id={`inbox-issue-list-item-${issue.id}`}
key={`${projectId}_${issue.id}`}
href={`/${workspaceSlug}/projects/${projectId}/inbox?currentTab=${currentTab}&inboxIssueId=${issue.id}`}
- onClick={(e) => handleIssueRedirection(e, issue.id)}
+ onClick={(e) => {
+ handleIssueRedirection(e, issue.id);
+ captureEvent(INBOX_ISSUE_OPENED, {
+ issueId: issue.id,
+ });
+ }}
>
= observer((props) => {
fetchInboxPaginationIssues,
getAppliedFiltersCount,
} = useProjectInbox();
+ const {captureEvent} = useEventTracker();
const router = useRouter();
@@ -78,6 +80,9 @@ export const InboxSidebar: FC
= observer((props) => {
onClick={() => {
if (currentTab != option?.key) handleCurrentTab(option?.key);
router.push(`/${workspaceSlug}/projects/${projectId}/inbox?currentTab=${option?.key}`);
+ captureEvent(INBOX_TAB_CHANGED, {
+ tab: option?.key,
+ });
}}
>
{option?.label}
diff --git a/web/components/issues/issue-detail/issue-activity/root.tsx b/web/components/issues/issue-detail/issue-activity/root.tsx
index cf1481b10..42453405e 100644
--- a/web/components/issues/issue-detail/issue-activity/root.tsx
+++ b/web/components/issues/issue-detail/issue-activity/root.tsx
@@ -9,7 +9,7 @@ import { TOAST_TYPE, setToast } from "@plane/ui";
// components
import { IssueActivityCommentRoot, IssueCommentRoot, IssueCommentCreate } from "@/components/issues";
// constants
-import { COMMENT_CREATED, COMMENT_DELETED, COMMENT_UPDATED } from "@/constants/event-tracker";
+import { COMMENT_CREATED, COMMENT_DELETED, COMMENT_UPDATED, E_INBOX, E_ISSUE_DETAILS } from "@/constants/event-tracker";
// hooks
import { useIssueDetail, useProject, useEventTracker } from "@/hooks/store";
@@ -45,7 +45,7 @@ export const IssueActivity: FC = observer((props) => {
const { workspaceSlug, projectId, issueId, disabled = false } = props;
// router
const router = useRouter();
- const { inboxId } = router.query;
+ const { inboxIssueId } = router.query;
// hooks
const { createComment, updateComment, removeComment } = useIssueDetail();
const { captureEvent } = useEventTracker();
@@ -59,11 +59,12 @@ export const IssueActivity: FC = observer((props) => {
createComment: async (data: Partial) => {
try {
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing fields");
- await createComment(workspaceSlug, projectId, issueId, data);
+ const res = await createComment(workspaceSlug, projectId, issueId, data);
captureEvent(COMMENT_CREATED, {
issue_id: issueId,
+ comment_id: res?.id,
is_public: data.access === "EXTERNAL",
- element: peekIssue ? "Peek issue" : inboxId ? "Inbox issue" : "Issue detail",
+ element: peekIssue ? "Peek issue" : inboxIssueId ? E_INBOX : E_ISSUE_DETAILS,
});
setToast({
title: "Comment created successfully.",
@@ -84,8 +85,9 @@ export const IssueActivity: FC = observer((props) => {
await updateComment(workspaceSlug, projectId, issueId, commentId, data);
captureEvent(COMMENT_UPDATED, {
issue_id: issueId,
+ comment_id: commentId,
is_public: data.access === "EXTERNAL",
- element: peekIssue ? "Peek issue" : inboxId ? "Inbox issue" : "Issue detail",
+ element: peekIssue ? "Peek issue" : inboxIssueId ? E_INBOX : E_ISSUE_DETAILS,
});
setToast({
title: "Comment updated successfully.",
@@ -106,7 +108,8 @@ export const IssueActivity: FC = observer((props) => {
await removeComment(workspaceSlug, projectId, issueId, commentId);
captureEvent(COMMENT_DELETED, {
issue_id: issueId,
- element: peekIssue ? "Peek issue" : inboxId ? "Inbox issue" : "Issue detail",
+ comment_id: commentId,
+ element: peekIssue ? "Peek issue" : inboxIssueId ? E_INBOX : E_ISSUE_DETAILS,
});
setToast({
title: "Comment removed successfully.",
diff --git a/web/constants/event-tracker.ts b/web/constants/event-tracker.ts
index 22fed506d..0c7a6ad33 100644
--- a/web/constants/event-tracker.ts
+++ b/web/constants/event-tracker.ts
@@ -98,7 +98,8 @@ export const getIssueEventPayload = (props: IssueEventProps) => {
module_id: payload.module_id,
archived_at: payload.archived_at,
state: payload.state,
- view_id: routePath?.includes("workspace-views") || routePath?.includes("views") ? routePath.split("/").pop() : "",
+ view_id:
+ routePath?.includes("workspace-views") || routePath?.includes("views") ? routePath.split("/").pop() : undefined,
};
if (eventName === ISSUE_UPDATED) {
@@ -214,6 +215,15 @@ export const ISSUE_UPDATED = "Issue updated";
export const ISSUE_DELETED = "Issue deleted";
export const ISSUE_ARCHIVED = "Issue archived";
export const ISSUE_RESTORED = "Issue restored";
+// Inbox Events
+export const INBOX_ISSUE_CREATED = "Inbox issue created";
+export const INBOX_ISSUE_UPDATED = "Inbox issue updated";
+export const INBOX_ISSUE_DELETED = "Inbox issue deleted";
+export const INBOX_FILTERS_APPLIED = "Inbox filters applied";
+export const INBOX_FILTERS_REMOVED = "Inbox filters removed";
+export const INBOX_SORT_UPDATED= "Inbox sort updated";
+export const INBOX_ISSUE_OPENED = "Inbox issue opened";
+export const INBOX_TAB_CHANGED = "Inbox tab changed";
// Comment Events
export const COMMENT_CREATED = "Comment created";
export const COMMENT_UPDATED = "Comment updated";