chore: added project-views related events

This commit is contained in:
LAKHAN BAHETI 2024-02-21 15:29:32 +05:30
parent 64fe785722
commit c237effa75
7 changed files with 109 additions and 22 deletions

View File

@ -2,7 +2,7 @@ import { useRouter } from "next/router";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { Plus } from "lucide-react"; import { Plus } from "lucide-react";
// hooks // hooks
import { useApplication, useProject, useUser } from "hooks/store"; import { useApplication, useEventTracker, useProject, useUser } from "hooks/store";
// components // components
import { Breadcrumbs, PhotoFilterIcon, Button } from "@plane/ui"; import { Breadcrumbs, PhotoFilterIcon, Button } from "@plane/ui";
import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle";
@ -24,6 +24,7 @@ export const ProjectViewsHeader: React.FC = observer(() => {
membership: { currentProjectRole }, membership: { currentProjectRole },
} = useUser(); } = useUser();
const { currentProjectDetails } = useProject(); const { currentProjectDetails } = useProject();
const { setTrackElement } = useEventTracker();
const canUserCreateIssue = const canUserCreateIssue =
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole); currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
@ -75,7 +76,10 @@ export const ProjectViewsHeader: React.FC = observer(() => {
variant="primary" variant="primary"
size="sm" size="sm"
prependIcon={<Plus className="h-3.5 w-3.5 stroke-2" />} prependIcon={<Plus className="h-3.5 w-3.5 stroke-2" />}
onClick={() => toggleCreateViewModal(true)} onClick={() => {
setTrackElement("Views page");
toggleCreateViewModal(true);
}}
> >
Create View Create View
</Button> </Button>

View File

@ -2,14 +2,16 @@ import { useRouter } from "next/router";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import isEqual from "lodash/isEqual"; import isEqual from "lodash/isEqual";
// hooks // hooks
import { useIssues, useLabel, useProjectState, useProjectView } from "hooks/store"; import { useEventTracker, useIssues, useLabel, useProjectState, useProjectView } from "hooks/store";
// components // components
import { AppliedFiltersList } from "components/issues"; import { AppliedFiltersList } from "components/issues";
// ui // ui
import { Button } from "@plane/ui"; import { Button } from "@plane/ui";
// types // types
import { IIssueFilterOptions } from "@plane/types"; import { IIssueFilterOptions } from "@plane/types";
// constants
import { EIssueFilterType, EIssuesStoreType } from "constants/issue"; import { EIssueFilterType, EIssuesStoreType } from "constants/issue";
import { VIEW_UPDATED } from "constants/event-tracker";
export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => { export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
// router // router
@ -26,6 +28,7 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
const { projectLabels } = useLabel(); const { projectLabels } = useLabel();
const { projectStates } = useProjectState(); const { projectStates } = useProjectState();
const { viewMap, updateView } = useProjectView(); const { viewMap, updateView } = useProjectView();
const { captureEvent } = useEventTracker();
// derived values // derived values
const viewDetails = viewId ? viewMap[viewId.toString()] : null; const viewDetails = viewId ? viewMap[viewId.toString()] : null;
const userFilters = issueFilters?.filters; const userFilters = issueFilters?.filters;
@ -87,6 +90,13 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
filters: { filters: {
...(appliedFilters ?? {}), ...(appliedFilters ?? {}),
}, },
}).then((res) => {
captureEvent(VIEW_UPDATED, {
view_id: res.id,
filters: res.filters,
element: "View Navbar",
state: "SUCCESS",
});
}); });
}; };

View File

@ -4,12 +4,13 @@ import { observer } from "mobx-react-lite";
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
import { AlertTriangle } from "lucide-react"; import { AlertTriangle } from "lucide-react";
// hooks // hooks
import { useProjectView } from "hooks/store"; import { useProjectView, useEventTracker } from "hooks/store";
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// ui // ui
import { Button } from "@plane/ui"; import { Button } from "@plane/ui";
// types // types
import { IProjectView } from "@plane/types"; import { IProjectView } from "@plane/types";
import { VIEW_DELETED } from "constants/event-tracker";
type Props = { type Props = {
data: IProjectView; data: IProjectView;
@ -26,6 +27,7 @@ export const DeleteProjectViewModal: React.FC<Props> = observer((props) => {
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
// store hooks // store hooks
const { deleteView } = useProjectView(); const { deleteView } = useProjectView();
const { captureEvent } = useEventTracker();
// toast alert // toast alert
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -42,20 +44,29 @@ export const DeleteProjectViewModal: React.FC<Props> = observer((props) => {
await deleteView(workspaceSlug.toString(), projectId.toString(), data.id) await deleteView(workspaceSlug.toString(), projectId.toString(), data.id)
.then(() => { .then(() => {
handleClose(); handleClose();
captureEvent(VIEW_DELETED, {
view_id: data.id,
element: "Views page",
state: "SUCCESS",
});
setToastAlert({ setToastAlert({
type: "success", type: "success",
title: "Success!", title: "Success!",
message: "View deleted successfully.", message: "View deleted successfully.",
}); });
}) })
.catch(() => .catch(() => {
captureEvent(VIEW_DELETED, {
view_id: data.id,
element: "Views page",
state: "FAILED",
});
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "View could not be deleted. Please try again.", message: "View could not be deleted. Please try again.",
}) });
) })
.finally(() => { .finally(() => {
setIsDeleteLoading(false); setIsDeleteLoading(false);
}); });

View File

@ -1,13 +1,16 @@
import { FC, Fragment } from "react"; import { FC, Fragment } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
// hooks // hooks
import { useProjectView } from "hooks/store"; import { useEventTracker, useProjectView } from "hooks/store";
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// components // components
import { ProjectViewForm } from "components/views"; import { ProjectViewForm } from "components/views";
// types // types
import { IProjectView } from "@plane/types"; import { IProjectView } from "@plane/types";
// constants
import { VIEW_CREATED, VIEW_UPDATED } from "constants/event-tracker";
type Props = { type Props = {
data?: IProjectView | null; data?: IProjectView | null;
@ -20,8 +23,12 @@ type Props = {
export const CreateUpdateProjectViewModal: FC<Props> = observer((props) => { export const CreateUpdateProjectViewModal: FC<Props> = observer((props) => {
const { data, isOpen, onClose, preLoadedData, workspaceSlug, projectId } = props; const { data, isOpen, onClose, preLoadedData, workspaceSlug, projectId } = props;
// router
const router = useRouter();
const { cycleId, moduleId, viewId } = router.query;
// store hooks // store hooks
const { createView, updateView } = useProjectView(); const { createView, updateView } = useProjectView();
const { captureEvent, trackElement } = useEventTracker();
// toast alert // toast alert
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -31,33 +38,64 @@ export const CreateUpdateProjectViewModal: FC<Props> = observer((props) => {
const handleCreateView = async (payload: IProjectView) => { const handleCreateView = async (payload: IProjectView) => {
await createView(workspaceSlug, projectId, payload) await createView(workspaceSlug, projectId, payload)
.then(() => { .then((res) => {
handleClose(); handleClose();
captureEvent(VIEW_CREATED, {
view_id: res.id,
filters: res.filters,
element_id: cycleId ?? moduleId ?? viewId ?? projectId,
element: trackElement
? trackElement
: cycleId
? "Cycle issues page"
: moduleId
? "Module issues page"
: viewId
? "View issues page"
: "Project issues page",
state: "SUCCESS",
});
setToastAlert({ setToastAlert({
type: "success", type: "success",
title: "Success!", title: "Success!",
message: "View created successfully.", message: "View created successfully.",
}); });
}) })
.catch(() => .catch(() => {
captureEvent(VIEW_CREATED, {
state: "FAILED",
});
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "Something went wrong. Please try again.", message: "Something went wrong. Please try again.",
}) });
); });
}; };
const handleUpdateView = async (payload: IProjectView) => { const handleUpdateView = async (payload: IProjectView) => {
await updateView(workspaceSlug, projectId, data?.id as string, payload) await updateView(workspaceSlug, projectId, data?.id as string, payload)
.then(() => handleClose()) .then((res) => {
.catch((err) => captureEvent(VIEW_UPDATED, {
view_id: res.id,
filters: res.filters,
element: "Views page",
state: "SUCCESS",
});
handleClose();
})
.catch((err) => {
captureEvent(VIEW_UPDATED, {
view_id: data?.id,
element: "Views page",
state: "FAILED",
});
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: err.detail ?? "Something went wrong. Please try again.", message: err.detail ?? "Something went wrong. Please try again.",
}) });
); });
}; };
const handleFormSubmit = async (formData: IProjectView) => { const handleFormSubmit = async (formData: IProjectView) => {

View File

@ -4,7 +4,7 @@ import { useRouter } from "next/router";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { LinkIcon, PencilIcon, StarIcon, TrashIcon } from "lucide-react"; import { LinkIcon, PencilIcon, StarIcon, TrashIcon } from "lucide-react";
// hooks // hooks
import { useProjectView, useUser } from "hooks/store"; import { useEventTracker, useProjectView, useUser } from "hooks/store";
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// components // components
import { CreateUpdateProjectViewModal, DeleteProjectViewModal } from "components/views"; import { CreateUpdateProjectViewModal, DeleteProjectViewModal } from "components/views";
@ -17,6 +17,7 @@ import { copyUrlToClipboard } from "helpers/string.helper";
import { IProjectView } from "@plane/types"; import { IProjectView } from "@plane/types";
// constants // constants
import { EUserProjectRoles } from "constants/project"; import { EUserProjectRoles } from "constants/project";
import { VIEW_FAVORITED, VIEW_UNFAVORITED } from "constants/event-tracker";
type Props = { type Props = {
view: IProjectView; view: IProjectView;
@ -37,17 +38,30 @@ export const ProjectViewListItem: React.FC<Props> = observer((props) => {
membership: { currentProjectRole }, membership: { currentProjectRole },
} = useUser(); } = useUser();
const { addViewToFavorites, removeViewFromFavorites } = useProjectView(); const { addViewToFavorites, removeViewFromFavorites } = useProjectView();
const { captureEvent } = useEventTracker();
const handleAddToFavorites = () => { const handleAddToFavorites = () => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
addViewToFavorites(workspaceSlug.toString(), projectId.toString(), view.id); addViewToFavorites(workspaceSlug.toString(), projectId.toString(), view.id).then(() => {
captureEvent(VIEW_FAVORITED, {
view_id: view.id,
element: "Views page",
state: "SUCCESS",
});
});
}; };
const handleRemoveFromFavorites = () => { const handleRemoveFromFavorites = () => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
removeViewFromFavorites(workspaceSlug.toString(), projectId.toString(), view.id); removeViewFromFavorites(workspaceSlug.toString(), projectId.toString(), view.id).then(() => {
captureEvent(VIEW_UNFAVORITED, {
view_id: view.id,
element: "Views page",
state: "SUCCESS",
});
});
}; };
const handleCopyText = (e: React.MouseEvent<HTMLButtonElement>) => { const handleCopyText = (e: React.MouseEvent<HTMLButtonElement>) => {

View File

@ -3,7 +3,7 @@ import { observer } from "mobx-react-lite";
import { Search } from "lucide-react"; import { Search } from "lucide-react";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
// hooks // hooks
import { useApplication, useProjectView, useUser } from "hooks/store"; import { useApplication, useEventTracker, useProjectView, useUser } from "hooks/store";
// components // components
import { ProjectViewListItem } from "components/views"; import { ProjectViewListItem } from "components/views";
import { EmptyState, getEmptyStateImagePath } from "components/empty-state"; import { EmptyState, getEmptyStateImagePath } from "components/empty-state";
@ -28,6 +28,7 @@ export const ProjectViewsList = observer(() => {
currentUser, currentUser,
} = useUser(); } = useUser();
const { projectViewIds, getViewById, loader } = useProjectView(); const { projectViewIds, getViewById, loader } = useProjectView();
const { setTrackElement } = useEventTracker();
if (loader || !projectViewIds) return <ViewListLoader />; if (loader || !projectViewIds) return <ViewListLoader />;
@ -73,7 +74,10 @@ export const ProjectViewsList = observer(() => {
}} }}
primaryButton={{ primaryButton={{
text: VIEW_EMPTY_STATE_DETAILS["project-views"].primaryButton.text, text: VIEW_EMPTY_STATE_DETAILS["project-views"].primaryButton.text,
onClick: () => toggleCreateViewModal(true), onClick: () => {
setTrackElement("Views empty state");
toggleCreateViewModal(true);
},
}} }}
size="lg" size="lg"
disabled={!isEditingAllowed} disabled={!isEditingAllowed}

View File

@ -165,6 +165,12 @@ export const MODULE_UNFAVORITED = "Module unfavorited";
export const MODULE_LINK_CREATED = "Module link created"; export const MODULE_LINK_CREATED = "Module link created";
export const MODULE_LINK_UPDATED = "Module link updated"; export const MODULE_LINK_UPDATED = "Module link updated";
export const MODULE_LINK_DELETED = "Module link deleted"; export const MODULE_LINK_DELETED = "Module link deleted";
// Project View Events
export const VIEW_CREATED = "View created";
export const VIEW_UPDATED = "View updated";
export const VIEW_DELETED = "View deleted";
export const VIEW_FAVORITED = "View favorited";
export const VIEW_UNFAVORITED = "View unfavorited";
// Issue Events // Issue Events
export const ISSUE_CREATED = "Issue created"; export const ISSUE_CREATED = "Issue created";
export const ISSUE_UPDATED = "Issue updated"; export const ISSUE_UPDATED = "Issue updated";