[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:
parent
fa9c63716c
commit
cfe169c6d7
139 changed files with 2095 additions and 1888 deletions
|
|
@ -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`}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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(() => {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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...",
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue