[WEB-4423] refactor: event trackers (#7289)

* feat: event tracker helper

* feat: track click events for `data-ph-element`

* fix: handled click events

* fix: handled name

* chore: tracker element updates

* chore: remove export

* chore: tracker element type

* chore: track element and event helper.

* chore: minor improvements

* chore: minor refactors

* fix: workspace events

* fix: added slug

* fix: changes nomenclature

* fix: nomenclature

* chore: update event tracker helper types

* fix: data id

* refactor: cycle events (#7290)

* chore: update event tracker helper types

* refactor: cycle events

* refactor: cycle events

* refactor: cycle event tracker

* chore: update tracker elements

* chore: check for closest element with data-ph-element attribute

---------

Co-authored-by: Prateek Shourya <prateekshourya@Prateeks-MacBook-Pro.local>

* Refactor module events (#7291)

* chore: update event tracker helper types

* refactor: cycle events

* refactor: cycle events

* refactor: cycle event tracker

* refactor: module tracker event and element

* chore: update tracker element

* chore: revert unnecessary changes

---------

Co-authored-by: Prateek Shourya <prateekshourya@Prateeks-MacBook-Pro.local>

* refactor: global views, product tour, notifications, onboarding, users and sidebar related events

* chore: member tracker events (#7302)

* chore: member-tracker-events

* fix: constants

* refactor: update event tracker constants

* refactor: auth related event trackers (#7306)

* Chore: state events (#7307)

* chore: state events

* fix: refactor

* chore: project events (#7305)

* chore: project-events

* fix: refactor

* fix: removed hardcoded values

* fix: github redirection event

* chore: project page tracker events (#7304)

* added events for most page events

* refactor: simplify lock button event handling in PageLockControl

---------

Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>

* chore: minor cleanup and import fixes

* refactor: added tracker elements for buttons (#7308)

Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>

* fix: event type

* refactor: posthog group event

* chore: removed instances of event tracker (#7309)

* refactor: remove event tracker stores and hooks

* refactor: remove event tracker store

* fix: build errors

* clean up event tracker payloads

* fix: coderabbit suggestions

---------

Co-authored-by: Prateek Shourya <prateekshourya@Prateeks-MacBook-Pro.local>
Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>
Co-authored-by: Vamsi Krishna <46787868+vamsikrishnamathala@users.noreply.github.com>
This commit is contained in:
Akshita Goyal 2025-07-02 15:23:18 +05:30 committed by GitHub
parent fa9c63716c
commit cfe169c6d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
139 changed files with 2095 additions and 1888 deletions

View file

@ -12,6 +12,7 @@ import {
EUserPermissionsLevel,
EEstimateSystem,
MODULE_TRACKER_EVENTS,
MODULE_TRACKER_ELEMENTS,
} from "@plane/constants";
// plane types
import { useTranslation } from "@plane/i18n";
@ -22,15 +23,10 @@ import { Loader, LayersIcon, CustomSelect, ModuleStatusIcon, TOAST_TYPE, setToas
// helpers
import { getDate, renderFormattedPayloadDate } from "@plane/utils";
import { DateRangeDropdown, MemberDropdown } from "@/components/dropdowns";
import {
ArchiveModuleModal,
DeleteModuleModal,
CreateUpdateModuleLinkModal,
ModuleAnalyticsProgress,
ModuleLinksList,
} from "@/components/modules";
import { CreateUpdateModuleLinkModal, ModuleAnalyticsProgress, ModuleLinksList } from "@/components/modules";
import { captureElementAndEvent, captureSuccess, captureError } from "@/helpers/event-tracker.helper";
// hooks
import { useModule, useEventTracker, useProjectEstimates, useUserPermissions } from "@/hooks/store";
import { useModule, useProjectEstimates, useUserPermissions } from "@/hooks/store";
// plane web constants
const defaultValues: Partial<IModule> = {
lead_id: "",
@ -50,8 +46,6 @@ type Props = {
export const ModuleAnalyticsSidebar: React.FC<Props> = observer((props) => {
const { moduleId, handleClose, isArchived } = props;
// states
const [moduleDeleteModal, setModuleDeleteModal] = useState(false);
const [archiveModuleModal, setArchiveModuleModal] = useState(false);
const [moduleLinkModal, setModuleLinkModal] = useState(false);
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);
// router
@ -62,7 +56,6 @@ export const ModuleAnalyticsSidebar: React.FC<Props> = observer((props) => {
const { allowPermissions } = useUserPermissions();
const { getModuleById, updateModuleDetails, createModuleLink, updateModuleLink, deleteModuleLink } = useModule();
const { captureModuleEvent, captureEvent } = useEventTracker();
const { areEstimateEnabledByProjectId, currentActiveEstimateId, estimateById } = useProjectEstimates();
// derived values
@ -79,15 +72,22 @@ export const ModuleAnalyticsSidebar: React.FC<Props> = observer((props) => {
if (!workspaceSlug || !projectId || !moduleId) return;
updateModuleDetails(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), data)
.then((res) => {
captureModuleEvent({
eventName: MODULE_TRACKER_EVENTS.update,
payload: { ...res, changed_properties: Object.keys(data)[0], element: "Right side-peek", state: "SUCCESS" },
captureElementAndEvent({
element: {
elementName: MODULE_TRACKER_ELEMENTS.RIGHT_SIDEBAR,
},
event: {
eventName: MODULE_TRACKER_EVENTS.update,
payload: { id: res.id },
state: "SUCCESS",
},
});
})
.catch(() => {
captureModuleEvent({
.catch((error) => {
captureError({
eventName: MODULE_TRACKER_EVENTS.update,
payload: { ...data, state: "FAILED" },
payload: { id: moduleId },
error,
});
});
};
@ -97,12 +97,20 @@ export const ModuleAnalyticsSidebar: React.FC<Props> = observer((props) => {
const payload = { metadata: {}, ...formData };
await createModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), payload).then(() =>
captureEvent(MODULE_TRACKER_EVENTS.link.create, {
module_id: moduleId,
state: "SUCCESS",
})
);
await createModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), payload)
.then(() =>
captureSuccess({
eventName: MODULE_TRACKER_EVENTS.link.create,
payload: { id: moduleId },
})
)
.catch((error) => {
captureError({
eventName: MODULE_TRACKER_EVENTS.link.create,
payload: { id: moduleId },
error,
});
});
};
const handleUpdateLink = async (formData: ModuleLink, linkId: string) => {
@ -110,13 +118,20 @@ export const ModuleAnalyticsSidebar: React.FC<Props> = observer((props) => {
const payload = { metadata: {}, ...formData };
await updateModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), linkId, payload).then(
() =>
captureEvent(MODULE_TRACKER_EVENTS.link.update, {
module_id: moduleId,
state: "SUCCESS",
await updateModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), linkId, payload)
.then(() =>
captureSuccess({
eventName: MODULE_TRACKER_EVENTS.link.update,
payload: { id: moduleId },
})
);
)
.catch((error) => {
captureError({
eventName: MODULE_TRACKER_EVENTS.link.update,
payload: { id: moduleId },
error,
});
});
};
const handleDeleteLink = async (linkId: string) => {
@ -124,9 +139,9 @@ export const ModuleAnalyticsSidebar: React.FC<Props> = observer((props) => {
deleteModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), linkId)
.then(() => {
captureEvent(MODULE_TRACKER_EVENTS.link.delete, {
module_id: moduleId,
state: "SUCCESS",
captureSuccess({
eventName: MODULE_TRACKER_EVENTS.link.delete,
payload: { id: moduleId },
});
setToast({
type: TOAST_TYPE.SUCCESS,
@ -140,6 +155,10 @@ export const ModuleAnalyticsSidebar: React.FC<Props> = observer((props) => {
title: "Error!",
message: "Some error occurred",
});
captureError({
eventName: MODULE_TRACKER_EVENTS.link.delete,
payload: { id: moduleId },
});
});
};
@ -213,16 +232,6 @@ export const ModuleAnalyticsSidebar: React.FC<Props> = observer((props) => {
createLink={handleCreateLink}
updateLink={handleUpdateLink}
/>
{workspaceSlug && projectId && (
<ArchiveModuleModal
workspaceSlug={workspaceSlug.toString()}
projectId={projectId.toString()}
moduleId={moduleId}
isOpen={archiveModuleModal}
handleClose={() => setArchiveModuleModal(false)}
/>
)}
<DeleteModuleModal isOpen={moduleDeleteModal} onClose={() => setModuleDeleteModal(false)} data={moduleDetails} />
<>
<div
className={`sticky z-10 top-0 flex items-center justify-between bg-custom-sidebar-background-100 pb-5 pt-5`}

View file

@ -10,8 +10,10 @@ import type { IModule } from "@plane/types";
// ui
import { AlertModalCore, TOAST_TYPE, setToast } from "@plane/ui";
// constants
// helpers
import { captureSuccess, captureError } from "@/helpers/event-tracker.helper";
// hooks
import { useEventTracker, useModule } from "@/hooks/store";
import { useModule } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
type Props = {
@ -28,7 +30,6 @@ export const DeleteModuleModal: React.FC<Props> = observer((props) => {
const router = useAppRouter();
const { workspaceSlug, projectId, moduleId, peekModule } = useParams();
// store hooks
const { captureModuleEvent } = useEventTracker();
const { deleteModule } = useModule();
const { t } = useTranslation();
@ -51,9 +52,9 @@ export const DeleteModuleModal: React.FC<Props> = observer((props) => {
title: "Success!",
message: "Module deleted successfully.",
});
captureModuleEvent({
captureSuccess({
eventName: MODULE_TRACKER_EVENTS.delete,
payload: { ...data, state: "SUCCESS" },
payload: { id: data.id },
});
})
.catch((errors) => {
@ -66,9 +67,10 @@ export const DeleteModuleModal: React.FC<Props> = observer((props) => {
type: TOAST_TYPE.ERROR,
message: currentError.i18n_message && t(currentError.i18n_message),
});
captureModuleEvent({
captureError({
eventName: MODULE_TRACKER_EVENTS.delete,
payload: { ...data, state: "FAILED" },
payload: { id: data.id },
error: errors,
});
})
.finally(() => handleClose());

View file

@ -1,6 +1,7 @@
import { observer } from "mobx-react";
import { Copy, Pencil, Trash2 } from "lucide-react";
// plane types
import { MODULE_TRACKER_ELEMENTS } from "@plane/constants";
import { ILinkDetails } from "@plane/types";
// plane ui
import { setToast, TOAST_TYPE, Tooltip } from "@plane/ui";
@ -58,6 +59,7 @@ export const ModulesLinksListItem: React.FC<Props> = observer((props) => {
<button
type="button"
className="grid place-items-center p-1 hover:bg-custom-background-80"
data-ph-element={MODULE_TRACKER_ELEMENTS.LIST_ITEM}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
@ -77,6 +79,7 @@ export const ModulesLinksListItem: React.FC<Props> = observer((props) => {
<button
type="button"
className="grid place-items-center p-1 hover:bg-custom-background-80"
data-ph-element={MODULE_TRACKER_ELEMENTS.LIST_ITEM}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();

View file

@ -11,8 +11,10 @@ import { EModalPosition, EModalWidth, ModalCore, TOAST_TYPE, setToast } from "@p
// components
import { ModuleForm } from "@/components/modules";
// constants
// helpers
import { captureSuccess, captureError } from "@/helpers/event-tracker.helper";
// hooks
import { useEventTracker, useModule, useProject } from "@/hooks/store";
import { useModule, useProject } from "@/hooks/store";
import useKeypress from "@/hooks/use-keypress";
import { usePlatformOS } from "@/hooks/use-platform-os";
@ -37,7 +39,6 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
// states
const [activeProject, setActiveProject] = useState<string | null>(null);
// store hooks
const { captureModuleEvent } = useEventTracker();
const { workspaceProjectIds } = useProject();
const { createModule, updateModuleDetails } = useModule();
const { isMobile } = usePlatformOS();
@ -63,9 +64,9 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
title: "Success!",
message: "Module created successfully.",
});
captureModuleEvent({
captureSuccess({
eventName: MODULE_TRACKER_EVENTS.create,
payload: { ...res, state: "SUCCESS" },
payload: { id: res.id },
});
})
.catch((err) => {
@ -74,14 +75,15 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
title: "Error!",
message: err?.detail ?? err?.error ?? "Module could not be created. Please try again.",
});
captureModuleEvent({
captureError({
eventName: MODULE_TRACKER_EVENTS.create,
payload: { ...data, state: "FAILED" },
payload: { id: data?.id },
error: err,
});
});
};
const handleUpdateModule = async (payload: Partial<IModule>, dirtyFields: any) => {
const handleUpdateModule = async (payload: Partial<IModule>) => {
if (!workspaceSlug || !projectId || !data) return;
const selectedProjectId = payload.project_id ?? projectId.toString();
@ -94,9 +96,9 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
title: "Success!",
message: "Module updated successfully.",
});
captureModuleEvent({
captureSuccess({
eventName: MODULE_TRACKER_EVENTS.update,
payload: { ...res, changed_properties: Object.keys(dirtyFields || {}), state: "SUCCESS" },
payload: { id: res.id },
});
})
.catch((err) => {
@ -105,21 +107,22 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
title: "Error!",
message: err?.detail ?? err?.error ?? "Module could not be updated. Please try again.",
});
captureModuleEvent({
captureError({
eventName: MODULE_TRACKER_EVENTS.update,
payload: { ...data, state: "FAILED" },
payload: { id: data.id },
error: err,
});
});
};
const handleFormSubmit = async (formData: Partial<IModule>, dirtyFields: unknown) => {
const handleFormSubmit = async (formData: Partial<IModule>) => {
if (!workspaceSlug || !projectId) return;
const payload: Partial<IModule> = {
...formData,
};
if (!data) await handleCreateModule(payload);
else await handleUpdateModule(payload, dirtyFields);
else await handleUpdateModule(payload);
};
useEffect(() => {

View file

@ -13,6 +13,7 @@ import {
EUserPermissionsLevel,
IS_FAVORITE_MENU_OPEN,
MODULE_TRACKER_EVENTS,
MODULE_TRACKER_ELEMENTS,
} from "@plane/constants";
import { useLocalStorage } from "@plane/hooks";
import { IModule } from "@plane/types";
@ -33,8 +34,9 @@ import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
import { ModuleQuickActions } from "@/components/modules";
import { ModuleStatusDropdown } from "@/components/modules/module-status-dropdown";
// helpers
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
// hooks
import { useEventTracker, useMember, useModule, useUserPermissions } from "@/hooks/store";
import { useMember, useModule, useUserPermissions } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web constants
@ -56,7 +58,6 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
const { allowPermissions } = useUserPermissions();
const { getModuleById, addModuleToFavorites, removeModuleFromFavorites, updateModuleDetails } = useModule();
const { getUserDetails } = useMember();
const { captureEvent } = useEventTracker();
// local storage
const { setValue: toggleFavoriteMenu, storedValue } = useLocalStorage<boolean>(IS_FAVORITE_MENU_OPEN, false);
@ -79,10 +80,15 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
const addToFavoritePromise = addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), moduleId).then(
() => {
if (!storedValue) toggleFavoriteMenu(true);
captureEvent(MODULE_TRACKER_EVENTS.favorite, {
module_id: moduleId,
element: "Grid layout",
state: "SUCCESS",
captureElementAndEvent({
element: {
elementName: MODULE_TRACKER_ELEMENTS.CARD_ITEM,
},
event: {
eventName: MODULE_TRACKER_EVENTS.favorite,
payload: { id: moduleId },
state: "SUCCESS",
},
});
}
);
@ -110,10 +116,15 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
projectId.toString(),
moduleId
).then(() => {
captureEvent(MODULE_TRACKER_EVENTS.unfavorite, {
module_id: moduleId,
element: "Grid layout",
state: "SUCCESS",
captureElementAndEvent({
element: {
elementName: MODULE_TRACKER_ELEMENTS.CARD_ITEM,
},
event: {
eventName: MODULE_TRACKER_EVENTS.unfavorite,
payload: { id: moduleId },
state: "SUCCESS",
},
});
});

View file

@ -12,6 +12,7 @@ import {
EUserPermissionsLevel,
IS_FAVORITE_MENU_OPEN,
MODULE_TRACKER_EVENTS,
MODULE_TRACKER_ELEMENTS,
} from "@plane/constants";
import { useLocalStorage } from "@plane/hooks";
import { useTranslation } from "@plane/i18n";
@ -24,8 +25,10 @@ import { DateRangeDropdown } from "@/components/dropdowns";
import { ModuleQuickActions } from "@/components/modules";
import { ModuleStatusDropdown } from "@/components/modules/module-status-dropdown";
// constants
// helpers
import { captureElementAndEvent, captureError } from "@/helpers/event-tracker.helper";
// hooks
import { useEventTracker, useMember, useModule, useUserPermissions } from "@/hooks/store";
import { useMember, useModule, useUserPermissions } from "@/hooks/store";
import { ButtonAvatars } from "../dropdowns/member/avatar";
type Props = {
@ -42,7 +45,6 @@ export const ModuleListItemAction: FC<Props> = observer((props) => {
const { allowPermissions } = useUserPermissions();
const { addModuleToFavorites, removeModuleFromFavorites, updateModuleDetails } = useModule();
const { getUserDetails } = useMember();
const { captureEvent } = useEventTracker();
const { t } = useTranslation();
@ -64,17 +66,28 @@ export const ModuleListItemAction: FC<Props> = observer((props) => {
e.preventDefault();
if (!workspaceSlug || !projectId) return;
const addToFavoritePromise = addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), moduleId).then(
() => {
const addToFavoritePromise = addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), moduleId)
.then(() => {
// open favorites menu if closed
if (!storedValue) toggleFavoriteMenu(true);
captureEvent(MODULE_TRACKER_EVENTS.favorite, {
module_id: moduleId,
element: "Grid layout",
state: "SUCCESS",
captureElementAndEvent({
element: {
elementName: MODULE_TRACKER_ELEMENTS.LIST_ITEM,
},
event: {
eventName: MODULE_TRACKER_EVENTS.favorite,
payload: { id: moduleId },
state: "SUCCESS",
},
});
}
);
})
.catch((error) => {
captureError({
eventName: MODULE_TRACKER_EVENTS.favorite,
payload: { id: moduleId },
error,
});
});
setPromiseToast(addToFavoritePromise, {
loading: "Adding module to favorites...",
@ -98,13 +111,26 @@ export const ModuleListItemAction: FC<Props> = observer((props) => {
workspaceSlug.toString(),
projectId.toString(),
moduleId
).then(() => {
captureEvent(MODULE_TRACKER_EVENTS.unfavorite, {
module_id: moduleId,
element: "Grid layout",
state: "SUCCESS",
)
.then(() => {
captureElementAndEvent({
element: {
elementName: MODULE_TRACKER_ELEMENTS.LIST_ITEM,
},
event: {
eventName: MODULE_TRACKER_EVENTS.unfavorite,
payload: { id: moduleId },
state: "SUCCESS",
},
});
})
.catch((error) => {
captureError({
eventName: MODULE_TRACKER_EVENTS.unfavorite,
payload: { id: moduleId },
error,
});
});
});
setPromiseToast(removeFromFavoritePromise, {
loading: "Removing module from favorites...",

View file

@ -2,7 +2,7 @@ import { observer } from "mobx-react";
import Image from "next/image";
import { useParams, useSearchParams } from "next/navigation";
// components
import { EUserPermissionsLevel } from "@plane/constants";
import { EUserPermissionsLevel, MODULE_TRACKER_ELEMENTS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { EUserProjectRoles } from "@plane/types";
import { ContentWrapper, Row, ERowVariant } from "@plane/ui";
@ -11,7 +11,7 @@ import { DetailedEmptyState, ComicBoxButton } from "@/components/empty-state";
import { ModuleCardItem, ModuleListItem, ModulePeekOverview, ModulesListGanttChartView } from "@/components/modules";
import { CycleModuleBoardLayout, CycleModuleListLayout, GanttLayoutLoader } from "@/components/ui";
// hooks
import { useCommandPalette, useEventTracker, useModule, useModuleFilter, useUserPermissions } from "@/hooks/store";
import { useCommandPalette, useModule, useModuleFilter, useUserPermissions } from "@/hooks/store";
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
import AllFiltersImage from "@/public/empty-state/module/all-filters.svg";
import NameFilterImage from "@/public/empty-state/module/name-filter.svg";
@ -25,7 +25,6 @@ export const ModulesListView: React.FC = observer(() => {
const { t } = useTranslation();
// store hooks
const { toggleCreateModuleModal } = useCommandPalette();
const { setTrackElement } = useEventTracker();
const { getProjectModuleIds, getFilteredModuleIds, loader } = useModule();
const { currentProjectDisplayFilters: displayFilters, searchQuery } = useModuleFilter();
const { allowPermissions } = useUserPermissions();
@ -60,8 +59,8 @@ export const ModulesListView: React.FC = observer(() => {
label={t("project_module.empty_state.general.primary_button.text")}
title={t("project_module.empty_state.general.primary_button.comic.title")}
description={t("project_module.empty_state.general.primary_button.comic.description")}
data-ph-element={MODULE_TRACKER_ELEMENTS.EMPTY_STATE_ADD_BUTTON}
onClick={() => {
setTrackElement("Module empty state");
toggleCreateModuleModal(true);
}}
disabled={!canPerformEmptyStateActions}

View file

@ -6,7 +6,12 @@ import { observer } from "mobx-react";
// icons
import { ArchiveRestoreIcon, ExternalLink, LinkIcon, Pencil, Trash2 } from "lucide-react";
// plane imports
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import {
EUserPermissions,
EUserPermissionsLevel,
MODULE_TRACKER_ELEMENTS,
MODULE_TRACKER_EVENTS,
} from "@plane/constants";
import { useTranslation } from "@plane/i18n";
// ui
import { ArchiveIcon, ContextMenu, CustomMenu, TContextMenuItem, TOAST_TYPE, setToast } from "@plane/ui";
@ -14,8 +19,9 @@ import { copyUrlToClipboard, cn } from "@plane/utils";
// components
import { ArchiveModuleModal, CreateUpdateModuleModal, DeleteModuleModal } from "@/components/modules";
// helpers
import { captureClick, captureSuccess, captureError } from "@/helpers/event-tracker.helper";
// hooks
import { useModule, useEventTracker, useUserPermissions } from "@/hooks/store";
import { useModule, useUserPermissions } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
type Props = {
@ -35,7 +41,6 @@ export const ModuleQuickActions: React.FC<Props> = observer((props) => {
const [archiveModuleModal, setArchiveModuleModal] = useState(false);
const [deleteModal, setDeleteModal] = useState(false);
// store hooks
const { setTrackElement } = useEventTracker();
const { allowPermissions } = useUserPermissions();
const { getModuleById, restoreModule } = useModule();
@ -67,7 +72,6 @@ export const ModuleQuickActions: React.FC<Props> = observer((props) => {
const handleOpenInNewTab = () => window.open(`/${moduleLink}`, "_blank");
const handleEditModule = () => {
setTrackElement("Modules page list layout");
setEditModal(true);
};
@ -81,18 +85,26 @@ export const ModuleQuickActions: React.FC<Props> = observer((props) => {
title: "Restore success",
message: "Your module can be found in project modules.",
});
captureSuccess({
eventName: MODULE_TRACKER_EVENTS.restore,
payload: { id: moduleId },
});
router.push(`/${workspaceSlug}/projects/${projectId}/archives/modules`);
})
.catch(() =>
.catch((error) => {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Module could not be restored. Please try again.",
})
);
});
captureError({
eventName: MODULE_TRACKER_EVENTS.restore,
payload: { id: moduleId },
error,
});
});
const handleDeleteModule = () => {
setTrackElement("Modules page list layout");
setDeleteModal(true);
};
@ -145,6 +157,16 @@ export const ModuleQuickActions: React.FC<Props> = observer((props) => {
},
];
const CONTEXT_MENU_ITEMS: TContextMenuItem[] = MENU_ITEMS.map((item) => ({
...item,
onClick: () => {
captureClick({
elementName: MODULE_TRACKER_ELEMENTS.CONTEXT_MENU,
});
item.action();
},
}));
return (
<>
{moduleDetails && (
@ -166,7 +188,7 @@ export const ModuleQuickActions: React.FC<Props> = observer((props) => {
<DeleteModuleModal data={moduleDetails} isOpen={deleteModal} onClose={() => setDeleteModal(false)} />
</div>
)}
<ContextMenu parentRef={parentRef} items={MENU_ITEMS} />
<ContextMenu parentRef={parentRef} items={CONTEXT_MENU_ITEMS} />
<CustomMenu ellipsis placement="bottom-end" closeOnSelect buttonClassName={customClassName}>
{MENU_ITEMS.map((item) => {
if (item.shouldRender === false) return null;
@ -176,6 +198,9 @@ export const ModuleQuickActions: React.FC<Props> = observer((props) => {
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
captureClick({
elementName: MODULE_TRACKER_ELEMENTS.QUICK_ACTIONS,
});
item.action();
}}
className={cn(