diff --git a/web/components/core/activity.tsx b/web/components/core/activity.tsx index 97927d216..2f89820af 100644 --- a/web/components/core/activity.tsx +++ b/web/components/core/activity.tsx @@ -21,17 +21,22 @@ import { } from "lucide-react"; import { IIssueActivity } from "@plane/types"; import { Tooltip, BlockedIcon, BlockerIcon, RelatedIcon, LayersIcon, DiceIcon } from "@plane/ui"; +// constants +import { ISSUE_OPENED } from "constants/event-tracker"; // helpers import { renderFormattedDate } from "@/helpers/date-time.helper"; +import { getElementFromPath } from "@/helpers/event-tracker.helper"; import { capitalizeFirstLetter } from "@/helpers/string.helper"; -import { useEstimate, useLabel } from "@/hooks/store"; +import { useEstimate, useLabel, useEventTracker } from "@/hooks/store"; import { usePlatformOS } from "@/hooks/use-platform-os"; // types export const IssueLink = ({ activity }: { activity: IIssueActivity }) => { const router = useRouter(); const { workspaceSlug } = router.query; + // hooks const { isMobile } = usePlatformOS(); + const { captureEvent } = useEventTracker(); return ( { target={activity.issue === null ? "_self" : "_blank"} rel={activity.issue === null ? "" : "noopener noreferrer"} className="inline items-center gap-1 font-medium text-custom-text-100 hover:underline" + onClick={() => + captureEvent(ISSUE_OPENED, { + element: getElementFromPath(router.asPath), + element_id: "activity", + mode: "detail", + }) + } > {`${activity.project_detail.identifier}-${activity.issue_detail.sequence_id}`}{" "} {activity.issue_detail?.name} diff --git a/web/components/cycles/active-cycle/cycle-stats.tsx b/web/components/cycles/active-cycle/cycle-stats.tsx index e31e9af53..01a5ab635 100644 --- a/web/components/cycles/active-cycle/cycle-stats.tsx +++ b/web/components/cycles/active-cycle/cycle-stats.tsx @@ -15,13 +15,14 @@ import { StateDropdown } from "@/components/dropdowns"; import { EmptyState } from "@/components/empty-state"; // constants import { EmptyStateType } from "@/constants/empty-state"; +import { ISSUE_OPENED, E_ACYCLE } from "@/constants/event-tracker"; import { CYCLE_ISSUES_WITH_PARAMS } from "@/constants/fetch-keys"; import { EIssuesStoreType } from "@/constants/issue"; // helper import { cn } from "@/helpers/common.helper"; import { renderFormattedDate, renderFormattedDateWithoutYear } from "@/helpers/date-time.helper"; // hooks -import { useIssues, useProject } from "@/hooks/store"; +import { useIssues, useProject, useEventTracker } from "@/hooks/store"; import useLocalStorage from "@/hooks/use-local-storage"; export type ActiveCycleStatsProps = { @@ -50,6 +51,7 @@ export const ActiveCycleStats: FC = observer((props) => { const { issues: { fetchActiveCycleIssues }, } = useIssues(EIssuesStoreType.CYCLE); + const { captureEvent } = useEventTracker(); const { currentProjectDetails } = useProject(); @@ -140,6 +142,13 @@ export const ActiveCycleStats: FC = observer((props) => { key={issue.id} href={`/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`} className="group flex cursor-pointer items-center justify-between gap-2 rounded-md hover:bg-custom-background-90 p-1" + onClick={() => + captureEvent(ISSUE_OPENED, { + element: E_ACYCLE, + element_id: tab?.toLowerCase(), + mode: "detail", + }) + } >
diff --git a/web/components/dashboard/widgets/issue-panels/issues-list.tsx b/web/components/dashboard/widgets/issue-panels/issues-list.tsx index c38229267..4af3d14be 100644 --- a/web/components/dashboard/widgets/issue-panels/issues-list.tsx +++ b/web/components/dashboard/widgets/issue-panels/issues-list.tsx @@ -14,11 +14,12 @@ import { CreatedUpcomingIssueListItem, IssueListItemProps, } from "@/components/dashboard/widgets"; -// ui +// constants +import { E_DASHBOARD, ISSUE_OPENED } from "constants/event-tracker"; // helpers import { cn } from "@/helpers/common.helper"; import { getRedirectionFilters } from "@/helpers/dashboard.helper"; -import { useIssueDetail } from "@/hooks/store"; +import { useIssueDetail, useEventTracker } from "@/hooks/store"; // types export type WidgetIssuesListProps = { @@ -33,9 +34,19 @@ export const WidgetIssuesList: React.FC = (props) => { const { isLoading, tab, type, widgetStats, workspaceSlug } = props; // store hooks const { setPeekIssue } = useIssueDetail(); + const { captureEvent } = useEventTracker(); - const handleIssuePeekOverview = (issue: TIssue) => + const handleIssuePeekOverview = (issue: TIssue) => { setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id }); + captureEvent(ISSUE_OPENED, { + element: E_DASHBOARD, + element_id: tab, + mode: "peek", + filters: { + target_date: issue.target_date, + }, + }); + }; const filterParams = getRedirectionFilters(tab); diff --git a/web/components/issues/issue-layouts/roots/all-issue-layout-root.tsx b/web/components/issues/issue-layouts/roots/all-issue-layout-root.tsx index 51188fe72..8945a33a7 100644 --- a/web/components/issues/issue-layouts/roots/all-issue-layout-root.tsx +++ b/web/components/issues/issue-layouts/roots/all-issue-layout-root.tsx @@ -188,7 +188,7 @@ export const AllIssueLayoutRoot: React.FC = observer(() => { isWorkspaceLevel /> {/* peek overview */} - + )}
diff --git a/web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx b/web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx index bcec481be..a7cb1cf43 100644 --- a/web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx +++ b/web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx @@ -62,7 +62,7 @@ export const ArchivedIssueLayoutRoot: React.FC = observer(() => {
- + )} diff --git a/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx b/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx index 6f83e72b8..fdcffe378 100644 --- a/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx +++ b/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx @@ -133,7 +133,7 @@ export const CycleLayoutRoot: React.FC = observer(() => { ) : null} {/* peek overview */} - + )} diff --git a/web/components/issues/issue-layouts/roots/draft-issue-layout-root.tsx b/web/components/issues/issue-layouts/roots/draft-issue-layout-root.tsx index c4acb670a..68aafa2b1 100644 --- a/web/components/issues/issue-layouts/roots/draft-issue-layout-root.tsx +++ b/web/components/issues/issue-layouts/roots/draft-issue-layout-root.tsx @@ -68,7 +68,7 @@ export const DraftIssueLayoutRoot: React.FC = observer(() => { ) : null} {/* issue peek overview */} - + )} diff --git a/web/components/issues/issue-layouts/roots/module-layout-root.tsx b/web/components/issues/issue-layouts/roots/module-layout-root.tsx index 3d8d994b5..b38c16ece 100644 --- a/web/components/issues/issue-layouts/roots/module-layout-root.tsx +++ b/web/components/issues/issue-layouts/roots/module-layout-root.tsx @@ -118,7 +118,7 @@ export const ModuleLayoutRoot: React.FC = observer(() => { ) : null} {/* peek overview */} - + )} diff --git a/web/components/issues/issue-layouts/roots/project-layout-root.tsx b/web/components/issues/issue-layouts/roots/project-layout-root.tsx index b41984b95..650c69764 100644 --- a/web/components/issues/issue-layouts/roots/project-layout-root.tsx +++ b/web/components/issues/issue-layouts/roots/project-layout-root.tsx @@ -86,7 +86,7 @@ export const ProjectLayoutRoot: FC = observer(() => { {/* peek overview */} - + )} diff --git a/web/components/issues/issue-layouts/roots/project-view-layout-root.tsx b/web/components/issues/issue-layouts/roots/project-view-layout-root.tsx index a2de200c7..d46c55e6f 100644 --- a/web/components/issues/issue-layouts/roots/project-view-layout-root.tsx +++ b/web/components/issues/issue-layouts/roots/project-view-layout-root.tsx @@ -83,7 +83,7 @@ export const ProjectViewLayoutRoot: React.FC = observer(() => { {/* peek overview */} - + )} diff --git a/web/components/issues/peek-overview/header.tsx b/web/components/issues/peek-overview/header.tsx index 9f146cdc0..c2a32046b 100644 --- a/web/components/issues/peek-overview/header.tsx +++ b/web/components/issues/peek-overview/header.tsx @@ -1,6 +1,7 @@ import { FC } from "react"; import { observer } from "mobx-react"; import Link from "next/link"; +import { useRouter } from "next/router"; import { ArchiveRestoreIcon, Link2, MoveDiagonal, MoveRight, Trash2 } from "lucide-react"; // ui import { @@ -16,11 +17,14 @@ import { // components import { IssueSubscription, IssueUpdateStatus } from "@/components/issues"; import { STATE_GROUPS } from "@/constants/state"; +// constants +import { ISSUE_OPENED } from "constants/event-tracker"; // helpers import { cn } from "@/helpers/common.helper"; +import { getElementIdFromPath } from "@/helpers/event-tracker.helper"; import { copyUrlToClipboard } from "@/helpers/string.helper"; // store hooks -import { useIssueDetail, useProjectState, useUser } from "@/hooks/store"; +import { useIssueDetail, useProjectState, useUser, useEventTracker } from "@/hooks/store"; // hooks import { usePlatformOS } from "@/hooks/use-platform-os"; export type TPeekModes = "side-peek" | "modal" | "full-screen"; @@ -73,6 +77,8 @@ export const IssuePeekOverviewHeader: FC = observer((pr handleRestoreIssue, isSubmitting, } = props; + // router + const router = useRouter(); // store hooks const { data: currentUser } = useUser(); const { @@ -80,6 +86,7 @@ export const IssuePeekOverviewHeader: FC = observer((pr } = useIssueDetail(); const { getStateById } = useProjectState(); const { isMobile } = usePlatformOS(); + const { captureEvent } = useEventTracker(); // derived values const issueDetails = getIssueById(issueId); const stateDetails = issueDetails ? getStateById(issueDetails?.state_id) : undefined; @@ -118,7 +125,17 @@ export const IssuePeekOverviewHeader: FC = observer((pr
- removeRoutePeekId()}> + { + removeRoutePeekId(); + captureEvent(ISSUE_OPENED, { + element: "peek", + elementId: getElementIdFromPath(router.asPath), + mode: "detail", + }); + }} + > diff --git a/web/components/issues/peek-overview/root.tsx b/web/components/issues/peek-overview/root.tsx index 8bf03b269..7848d681c 100644 --- a/web/components/issues/peek-overview/root.tsx +++ b/web/components/issues/peek-overview/root.tsx @@ -2,21 +2,24 @@ import { FC, useEffect, useState, useMemo } from "react"; import { observer } from "mobx-react"; import { useRouter } from "next/router"; // types -import { TIssue } from "@plane/types"; +import { IIssueFilters, TIssue } from "@plane/types"; // ui import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/ui"; // components import { IssueView } from "@/components/issues"; // constants -import { ISSUE_UPDATED, ISSUE_DELETED, ISSUE_ARCHIVED, ISSUE_RESTORED } from "@/constants/event-tracker"; +import { ISSUE_UPDATED, ISSUE_DELETED, ISSUE_ARCHIVED, ISSUE_RESTORED, ISSUE_OPENED } from "@/constants/event-tracker"; import { EIssuesStoreType } from "@/constants/issue"; import { EUserProjectRoles } from "@/constants/project"; +// helpers +import { getElementFromPath, getElementIdFromPath } from "@/helpers/event-tracker.helper"; // hooks import { useEventTracker, useIssueDetail, useIssues, useUser } from "@/hooks/store"; interface IIssuePeekOverview { is_archived?: boolean; is_draft?: boolean; + issuesFilter?: IIssueFilters; } export type TIssuePeekOperations = { @@ -43,9 +46,10 @@ export type TIssuePeekOperations = { }; export const IssuePeekOverview: FC = observer((props) => { - const { is_archived = false, is_draft = false } = props; + const { is_archived = false, is_draft = false, issuesFilter } = props; // router const router = useRouter(); + const { userId } = router.query; const { membership: { currentWorkspaceAllProjectsRole }, } = useUser(); @@ -67,7 +71,7 @@ export const IssuePeekOverview: FC = observer((props) => { removeIssueFromModule, removeModulesFromIssue, } = useIssueDetail(); - const { captureIssueEvent } = useEventTracker(); + const { captureIssueEvent, captureEvent } = useEventTracker(); // state const [loader, setLoader] = useState(false); @@ -387,6 +391,20 @@ export const IssuePeekOverview: FC = observer((props) => { } }, [peekIssue, issueOperations]); + useEffect(() => { + if (peekIssue && issuesFilter) { + captureEvent(ISSUE_OPENED, { + layout: issuesFilter?.displayFilters?.layout, + display_properties: issuesFilter?.displayFilters, + filters: issuesFilter?.filters, + mode: "peek", + profile_id: userId, + element: getElementFromPath(router.asPath), + elementId: getElementIdFromPath(router.asPath), + }); + } + }, [peekIssue, userId, captureEvent, router.asPath]); + if (!peekIssue?.workspaceSlug || !peekIssue?.projectId || !peekIssue?.issueId) return <>; const issue = getIssueById(peekIssue.issueId) || undefined; diff --git a/web/components/notifications/notification-card.tsx b/web/components/notifications/notification-card.tsx index cfae8a7c1..79f3e9f50 100644 --- a/web/components/notifications/notification-card.tsx +++ b/web/components/notifications/notification-card.tsx @@ -10,6 +10,7 @@ import type { IUserNotification, NotificationType } from "@plane/types"; import { ArchiveIcon, CustomMenu, Tooltip, TOAST_TYPE, setToast } from "@plane/ui"; // constants import { + E_NOTIFICATION, ISSUE_OPENED, NOTIFICATIONS_READ, NOTIFICATION_ARCHIVED, @@ -27,6 +28,8 @@ type NotificationCardProps = { selectedTab: NotificationType; notification: IUserNotification; isSnoozedTabOpen: boolean; + isArchivedTabOpen: boolean; + isUnreadTabOpen: boolean; closePopover: () => void; markNotificationReadStatus: (notificationId: string) => Promise; markNotificationReadStatusToggle: (notificationId: string) => Promise; @@ -40,6 +43,8 @@ export const NotificationCard: React.FC = (props) => { selectedTab, notification, isSnoozedTabOpen, + isArchivedTabOpen, + isUnreadTabOpen, closePopover, markNotificationReadStatus, markNotificationReadStatusToggle, @@ -131,7 +136,14 @@ export const NotificationCard: React.FC = (props) => { markNotificationReadStatus(notification.id); captureEvent(ISSUE_OPENED, { issue_id: notification.data.issue.id, - element: "notification", + element: E_NOTIFICATION, + element_id: isArchivedTabOpen + ? "archived" + : isSnoozedTabOpen + ? "snoozed" + : isUnreadTabOpen + ? "unread" + : selectedTab, }); closePopover(); }} diff --git a/web/components/notifications/notification-popover.tsx b/web/components/notifications/notification-popover.tsx index 8917b9210..310905ccc 100644 --- a/web/components/notifications/notification-popover.tsx +++ b/web/components/notifications/notification-popover.tsx @@ -63,12 +63,12 @@ export const NotificationPopover = observer(() => { const currentTabEmptyState = snoozed ? EmptyStateType.NOTIFICATION_SNOOZED_EMPTY_STATE : archived - ? EmptyStateType.NOTIFICATION_ARCHIVED_EMPTY_STATE - : selectedTab === "created" - ? EmptyStateType.NOTIFICATION_CREATED_EMPTY_STATE - : selectedTab === "watching" - ? EmptyStateType.NOTIFICATION_SUBSCRIBED_EMPTY_STATE - : EmptyStateType.NOTIFICATION_MY_ISSUE_EMPTY_STATE; + ? EmptyStateType.NOTIFICATION_ARCHIVED_EMPTY_STATE + : selectedTab === "created" + ? EmptyStateType.NOTIFICATION_CREATED_EMPTY_STATE + : selectedTab === "watching" + ? EmptyStateType.NOTIFICATION_SUBSCRIBED_EMPTY_STATE + : EmptyStateType.NOTIFICATION_MY_ISSUE_EMPTY_STATE; return ( <> @@ -154,6 +154,8 @@ export const NotificationPopover = observer(() => { selectedTab={selectedTab} key={notification.id} isSnoozedTabOpen={snoozed} + isArchivedTabOpen={archived} + isUnreadTabOpen={readNotification} closePopover={() => setIsActive(false)} notification={notification} markNotificationArchivedStatus={markNotificationArchivedStatus} diff --git a/web/components/profile/profile-issues.tsx b/web/components/profile/profile-issues.tsx index 4d722bfef..3c74eade0 100644 --- a/web/components/profile/profile-issues.tsx +++ b/web/components/profile/profile-issues.tsx @@ -69,7 +69,7 @@ export const ProfileIssuesPage = observer((props: IProfileIssuesPage) => { ) : null} {/* peek overview */} - + ); }); diff --git a/web/constants/event-tracker.ts b/web/constants/event-tracker.ts index 7362fe4a6..63f339875 100644 --- a/web/constants/event-tracker.ts +++ b/web/constants/event-tracker.ts @@ -18,145 +18,6 @@ export type EventProps = { payload: any; }; -export const getWorkspaceEventPayload = (payload: any) => ({ - workspace_id: payload.id, - created_at: payload.created_at, - updated_at: payload.updated_at, - organization_size: payload.organization_size, - first_time: payload.first_time, - state: payload.state, - element: payload.element, -}); - -export const getProjectEventPayload = (payload: any) => ({ - workspace_id: payload.workspace_id, - project_id: payload.id, - identifier: payload.identifier, - project_visibility: payload.network == 2 ? "Public" : "Private", - changed_properties: payload.changed_properties, - lead_id: payload.project_lead, - created_at: payload.created_at, - updated_at: payload.updated_at, - state: payload.state, - element: payload.element, -}); - -export const getCycleEventPayload = (payload: any) => ({ - workspace_id: payload.workspace_id, - project_id: payload.project, - cycle_id: payload.id, - created_at: payload.created_at, - updated_at: payload.updated_at, - start_date: payload.start_date, - target_date: payload.target_date, - cycle_status: payload.status, - changed_properties: payload.changed_properties, - state: payload.state, - element: payload.element, -}); - -export const getModuleEventPayload = (payload: any) => ({ - workspace_id: payload.workspace_id, - project_id: payload.project, - module_id: payload.id, - created_at: payload.created_at, - updated_at: payload.updated_at, - start_date: payload.start_date, - target_date: payload.target_date, - module_status: payload.status, - lead_id: payload.lead, - changed_properties: payload.changed_properties, - member_ids: payload.members, - state: payload.state, - element: payload.element, -}); - -export const getPageEventPayload = (payload: any) => ({ - workspace_id: payload.workspace_id, - project_id: payload.project, - created_at: payload.created_at, - updated_at: payload.updated_at, - access: payload.access === 0 ? "Public" : "Private", - is_locked: payload.is_locked, - archived_at: payload.archived_at, - created_by: payload.created_by, - state: payload.state, - element: payload.element, -}); - -export const getIssueEventPayload = (props: IssueEventProps) => { - const { eventName, payload, updates, routePath } = props; - let eventPayload: any = { - issue_id: payload.id, - estimate_point: payload.estimate_point, - link_count: payload.link_count, - target_date: payload.target_date, - is_draft: payload.is_draft, - label_ids: payload.label_ids, - assignee_ids: payload.assignee_ids, - created_at: payload.created_at, - updated_at: payload.updated_at, - sequence_id: payload.sequence_id, - module_ids: payload.module_ids, - sub_issues_count: payload.sub_issues_count, - parent_id: payload.parent_id, - project_id: payload.project_id, - workspace_id: payload.workspace_id, - priority: payload.priority, - state_id: payload.state_id, - start_date: payload.start_date, - attachment_count: payload.attachment_count, - cycle_id: payload.cycle_id, - 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() : "", - }; - - if (eventName === ISSUE_UPDATED) { - eventPayload = { - ...eventPayload, - ...updates, - updated_from: elementFromPath(routePath), - }; - } - return eventPayload; -}; - -export const getProjectStateEventPayload = (payload: any) => ({ - workspace_id: payload.workspace_id, - project_id: payload.id, - state_id: payload.id, - created_at: payload.created_at, - updated_at: payload.updated_at, - group: payload.group, - color: payload.color, - default: payload.default, - state: payload.state, - element: payload.element, -}); - -export const getIssuesListOpenedPayload = (payload: any) => ({ - type: payload.project_id ? "Project" : "Workspace", - layout: payload?.filters?.displayFilters?.layout, - filters: payload?.filters?.filters, - display_properties: payload?.filters?.displayProperties, - workspace_id: payload.workspace_id, - project_id: payload.project_id, -}); - -// Returns the element based on the path -const elementFromPath = (routePath?: string) => { - if (routePath?.includes("workspace-views")) return E_WORKSPACE_VIEW; - if (routePath?.includes("cycles")) return E_CYCLE; - if (routePath?.includes("modules")) return E_MODULE; - if (routePath?.includes("views")) return E_PROJECT_VIEW; - if (routePath?.includes("inbox")) return E_INBOX; - if (routePath?.includes("draft")) return E_DRAFT; - if (routePath?.includes("archived")) return E_ARCHIVE; - return ""; -}; - // Workspace crud Events export const WORKSPACE_CREATED = "Workspace created"; export const WORKSPACE_UPDATED = "Workspace updated"; @@ -189,6 +50,8 @@ export const ISSUE_RESTORED = "Issue restored"; // Issue Checkout Events export const ISSUES_LIST_OPENED = "Issues list opened"; export const ISSUE_OPENED = "Issue opened"; +// Layout & Filter Events +export const LAYOUT_CHANGED = "Layout changed"; // Project State Events export const STATE_CREATED = "State created"; export const STATE_UPDATED = "State updated"; @@ -244,9 +107,13 @@ export const GROUP_WORKSPACE = "Workspace_metrics"; // Elements export const E_PROJECT = "Project"; export const E_CYCLE = "Cycle"; +export const E_ACYCLE = "Active cycle"; export const E_MODULE = "Module"; export const E_PROJECT_VIEW = "Project view"; export const E_WORKSPACE_VIEW = "Workspace view"; export const E_DRAFT = "Draft"; export const E_ARCHIVE = "Archives"; export const E_INBOX = "Inbox"; +export const E_NOTIFICATION = "Notification"; +export const E_DASHBOARD= "Dashboard"; +export const E_PROFILE = "Profile"; diff --git a/web/helpers/event-tracker.helper.ts b/web/helpers/event-tracker.helper.ts new file mode 100644 index 000000000..3086dc32d --- /dev/null +++ b/web/helpers/event-tracker.helper.ts @@ -0,0 +1,168 @@ +import { + // elements + E_ARCHIVE, + E_CYCLE, + E_DASHBOARD, + E_DRAFT, + E_INBOX, + E_MODULE, + E_PROFILE, + E_PROJECT, + E_PROJECT_VIEW, + E_WORKSPACE_VIEW, + // events + ISSUE_UPDATED, + // types + IssueEventProps, +} from "@/constants/event-tracker"; + +export const getWorkspaceEventPayload = (payload: any) => ({ + workspace_id: payload.id, + created_at: payload.created_at, + updated_at: payload.updated_at, + organization_size: payload.organization_size, + first_time: payload.first_time, + state: payload.state, + element: payload.element, +}); + +export const getProjectEventPayload = (payload: any) => ({ + workspace_id: payload.workspace_id, + project_id: payload.id, + identifier: payload.identifier, + project_visibility: payload.network == 2 ? "Public" : "Private", + changed_properties: payload.changed_properties, + lead_id: payload.project_lead, + created_at: payload.created_at, + updated_at: payload.updated_at, + state: payload.state, + element: payload.element, +}); + +export const getCycleEventPayload = (payload: any) => ({ + workspace_id: payload.workspace_id, + project_id: payload.project, + cycle_id: payload.id, + created_at: payload.created_at, + updated_at: payload.updated_at, + start_date: payload.start_date, + target_date: payload.target_date, + cycle_status: payload.status, + changed_properties: payload.changed_properties, + state: payload.state, + element: payload.element, +}); + +export const getModuleEventPayload = (payload: any) => ({ + workspace_id: payload.workspace_id, + project_id: payload.project, + module_id: payload.id, + created_at: payload.created_at, + updated_at: payload.updated_at, + start_date: payload.start_date, + target_date: payload.target_date, + module_status: payload.status, + lead_id: payload.lead, + changed_properties: payload.changed_properties, + member_ids: payload.members, + state: payload.state, + element: payload.element, +}); + +export const getPageEventPayload = (payload: any) => ({ + workspace_id: payload.workspace_id, + project_id: payload.project, + created_at: payload.created_at, + updated_at: payload.updated_at, + access: payload.access === 0 ? "Public" : "Private", + is_locked: payload.is_locked, + archived_at: payload.archived_at, + created_by: payload.created_by, + state: payload.state, + element: payload.element, +}); + +export const getIssueEventPayload = (props: IssueEventProps) => { + const { eventName, payload, updates, routePath } = props; + let eventPayload: any = { + issue_id: payload.id, + estimate_point: payload.estimate_point, + link_count: payload.link_count, + target_date: payload.target_date, + is_draft: payload.is_draft, + label_ids: payload.label_ids, + assignee_ids: payload.assignee_ids, + created_at: payload.created_at, + updated_at: payload.updated_at, + sequence_id: payload.sequence_id, + module_ids: payload.module_ids, + sub_issues_count: payload.sub_issues_count, + parent_id: payload.parent_id, + project_id: payload.project_id, + workspace_id: payload.workspace_id, + priority: payload.priority, + state_id: payload.state_id, + start_date: payload.start_date, + attachment_count: payload.attachment_count, + cycle_id: payload.cycle_id, + 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() : "", + }; + + if (eventName === ISSUE_UPDATED) { + eventPayload = { + ...eventPayload, + ...updates, + updated_from: getElementFromPath(routePath), + }; + } + return eventPayload; +}; + +export const getProjectStateEventPayload = (payload: any) => ({ + workspace_id: payload.workspace_id, + project_id: payload.id, + state_id: payload.id, + created_at: payload.created_at, + updated_at: payload.updated_at, + group: payload.group, + color: payload.color, + default: payload.default, + state: payload.state, + element: payload.element, +}); + +export const getIssuesListOpenedPayload = (payload: any) => ({ + type: payload.project_id ? "Project" : "Workspace", + layout: payload?.filters?.displayFilters?.layout, + filters: payload?.filters?.filters, + display_properties: payload?.filters?.displayProperties, + workspace_id: payload.workspace_id, + project_id: payload.project_id, +}); + +// Returns the element based on the path +export const getElementFromPath = (routePath?: string) => { + if (routePath?.includes("workspace-views")) return E_WORKSPACE_VIEW; + if (routePath?.includes("profile")) return E_PROFILE; + if (routePath?.includes("cycles")) return E_CYCLE; + if (routePath?.includes("modules")) return E_MODULE; + if (routePath?.includes("views")) return E_PROJECT_VIEW; + if (routePath?.includes("inbox")) return E_INBOX; + if (routePath?.includes("draft")) return E_DRAFT; + if (routePath?.includes("archives")) return E_ARCHIVE; + if (routePath?.includes("projects")) return E_PROJECT; + if (routePath?.split("/").length === 2) return E_DASHBOARD; + return ""; +}; + +export const getElementIdFromPath = (routePath?: string) => { + const element = getElementFromPath(routePath); + return [E_PROJECT, E_DRAFT].includes(element) + ? routePath?.split("/").at(-2) + : element === E_ARCHIVE + ? routePath?.split("/").at(-3) + : routePath?.split("/").at(-1); +}; diff --git a/web/store/event-tracker.store.ts b/web/store/event-tracker.store.ts index 1c157af19..0b45aaa56 100644 --- a/web/store/event-tracker.store.ts +++ b/web/store/event-tracker.store.ts @@ -2,10 +2,15 @@ import { action, computed, makeObservable, observable } from "mobx"; import posthog from "posthog-js"; // stores import { - //types EventProps, IssueEventProps, - // payload helpers + IssuesListOpenedEventProps, + ISSUES_LIST_OPENED, + GROUP_WORKSPACE, + WORKSPACE_CREATED, +} from "@/constants/event-tracker"; +// helpers +import { getCycleEventPayload, getIssueEventPayload, getModuleEventPayload, @@ -14,12 +19,7 @@ import { getWorkspaceEventPayload, getPageEventPayload, getIssuesListOpenedPayload, - // event constants - ISSUES_LIST_OPENED, - GROUP_WORKSPACE, - WORKSPACE_CREATED, - IssuesListOpenedEventProps, -} from "@/constants/event-tracker"; +} from "@/helpers/event-tracker.helper"; import { RootStore } from "./root.store"; export interface IEventTrackerStore {