added cycle events

This commit is contained in:
LAKHAN BAHETI 2024-06-03 14:15:08 +05:30
parent 81dfc15d1f
commit acf3faa11d
8 changed files with 70 additions and 22 deletions

View File

@ -15,13 +15,14 @@ import { StateDropdown } from "@/components/dropdowns";
import { EmptyState } from "@/components/empty-state";
// constants
import { EmptyStateType } from "@/constants/empty-state";
import { ACYCLE_TAB_CHANGED } 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 = {
@ -34,6 +35,7 @@ export const ActiveCycleStats: FC<ActiveCycleStatsProps> = observer((props) => {
const { workspaceSlug, projectId, cycle } = props;
const { storedValue: tab, setValue: setTab } = useLocalStorage("activeCycleTab", "Assignees");
const { captureEvent } = useEventTracker();
const currentValue = (tab: string | null) => {
switch (tab) {
@ -47,6 +49,18 @@ export const ActiveCycleStats: FC<ActiveCycleStatsProps> = observer((props) => {
return 0;
}
};
const getCurrentTab = (index: number) => {
switch (index) {
case 0:
return "Priority-Issues";
case 1:
return "Assignees";
case 2:
return "Labels";
default:
return "Priority-Issues";
}
};
const {
issues: { fetchActiveCycleIssues },
} = useIssues(EIssuesStoreType.CYCLE);
@ -66,17 +80,9 @@ export const ActiveCycleStats: FC<ActiveCycleStatsProps> = observer((props) => {
as={Fragment}
defaultIndex={currentValue(tab)}
onChange={(i) => {
switch (i) {
case 0:
return setTab("Priority-Issues");
case 1:
return setTab("Assignees");
case 2:
return setTab("Labels");
default:
return setTab("Priority-Issues");
}
const currentTab = getCurrentTab(i);
setTab(currentTab);
captureEvent(ACYCLE_TAB_CHANGED, { tab: currentTab });
}}
>
<Tab.List

View File

@ -3,8 +3,10 @@ import { useRouter } from "next/router";
import { Dialog, Transition } from "@headlessui/react";
// ui
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
// constants
import { CYCLE_ARCHIVED } from "@/constants/event-tracker";
// hooks
import { useCycle } from "@/hooks/store";
import { useCycle, useEventTracker } from "@/hooks/store";
type Props = {
workspaceSlug: string;
@ -23,6 +25,7 @@ export const ArchiveCycleModal: React.FC<Props> = (props) => {
const [isArchiving, setIsArchiving] = useState(false);
// store hooks
const { getCycleNameById, archiveCycle } = useCycle();
const {captureEvent} =useEventTracker();
const cycleName = getCycleNameById(cycleId);
@ -42,6 +45,9 @@ export const ArchiveCycleModal: React.FC<Props> = (props) => {
});
onClose();
router.push(`/${workspaceSlug}/projects/${projectId}/cycles`);
captureEvent(CYCLE_ARCHIVED, {
cycle_id: cycleId,
});
})
.catch(() =>
setToast({

View File

@ -10,10 +10,11 @@ import { EmptyState } from "@/components/empty-state";
import { CycleModuleListLayout } from "@/components/ui";
// constants
import { EmptyStateType } from "@/constants/empty-state";
import { CYCLES_FILTER_REMOVED } from "@/constants/event-tracker";
// helpers
import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useCycle, useCycleFilter } from "@/hooks/store";
import { useCycle, useCycleFilter, useEventTracker } from "@/hooks/store";
export const ArchivedCycleLayoutRoot: React.FC = observer(() => {
// router
@ -21,6 +22,7 @@ export const ArchivedCycleLayoutRoot: React.FC = observer(() => {
const { workspaceSlug, projectId } = router.query;
// hooks
const { fetchArchivedCycles, currentProjectArchivedCycleIds, loader } = useCycle();
const { captureEvent } = useEventTracker();
// cycle filters hook
const { clearAllFilters, currentProjectArchivedFilters, updateFilters } = useCycleFilter();
// derived values
@ -43,6 +45,11 @@ export const ArchivedCycleLayoutRoot: React.FC = observer(() => {
if (!value) newValues = [];
else newValues = newValues.filter((val) => val !== value);
captureEvent(CYCLES_FILTER_REMOVED, {
filter_type: key,
filter_property: value,
current_filters: currentProjectArchivedFilters,
});
updateFilters(projectId.toString(), { [key]: newValues }, "archived");
};

View File

@ -7,11 +7,13 @@ import { TCycleFilters } from "@plane/types";
// components
import { CycleFiltersSelection } from "@/components/cycles";
import { FiltersDropdown } from "@/components/issues";
// constants
import { CYCLES_FILTER_APPLIED, CYCLES_FILTER_REMOVED } from "@/constants/event-tracker";
// helpers
import { cn } from "@/helpers/common.helper";
import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useCycleFilter } from "@/hooks/store";
import { useCycleFilter, useEventTracker } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
type Props = {
@ -24,6 +26,7 @@ export const CyclesViewHeader: React.FC<Props> = observer((props) => {
const inputRef = useRef<HTMLInputElement>(null);
// hooks
const { currentProjectFilters, searchQuery, updateFilters, updateSearchQuery } = useCycleFilter();
const { captureEvent } = useEventTracker();
// states
const [isSearchOpen, setIsSearchOpen] = useState(searchQuery !== "" ? true : false);
// outside click detector hook
@ -34,7 +37,7 @@ export const CyclesViewHeader: React.FC<Props> = observer((props) => {
const handleFilters = useCallback(
(key: keyof TCycleFilters, value: string | string[]) => {
if (!projectId) return;
const newValues = currentProjectFilters?.[key] ?? [];
const newValues = Array.from(currentProjectFilters?.[key] ?? []);
if (Array.isArray(value))
value.forEach((val) => {
@ -46,6 +49,14 @@ export const CyclesViewHeader: React.FC<Props> = observer((props) => {
else newValues.push(value);
}
captureEvent(
(currentProjectFilters?.[key] ?? []).length > newValues.length ? CYCLES_FILTER_REMOVED : CYCLES_FILTER_APPLIED,
{
filter_type: key,
filter_property: value,
current_filters: currentProjectFilters,
}
);
updateFilters(projectId, { [key]: newValues });
},
[currentProjectFilters, projectId, updateFilters]

View File

@ -57,7 +57,6 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
() => {
captureEvent(CYCLE_FAVORITED, {
cycle_id: cycleId,
element: "List layout",
state: "SUCCESS",
});
}
@ -87,7 +86,6 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
).then(() => {
captureEvent(CYCLE_UNFAVORITED, {
cycle_id: cycleId,
element: "List layout",
state: "SUCCESS",
});
});

View File

@ -8,6 +8,7 @@ import { ArchiveIcon, ContextMenu, CustomMenu, TContextMenuItem, TOAST_TYPE, set
// components
import { ArchiveCycleModal, CycleCreateUpdateModal, CycleDeleteModal } from "@/components/cycles";
// constants
import { CYCLE_ARCHIVED, CYCLE_RESTORED, E_CYCLES } from "@/constants/event-tracker";
import { EUserProjectRoles } from "@/constants/project";
// helpers
import { cn } from "@/helpers/common.helper";
@ -31,7 +32,7 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
const [archiveCycleModal, setArchiveCycleModal] = useState(false);
const [deleteModal, setDeleteModal] = useState(false);
// store hooks
const { setTrackElement } = useEventTracker();
const { setTrackElement, captureEvent } = useEventTracker();
const {
membership: { currentWorkspaceAllProjectsRole },
} = useUser();
@ -56,7 +57,7 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
const handleOpenInNewTab = () => window.open(`/${cycleLink}`, "_blank");
const handleEditCycle = () => {
setTrackElement("Cycles page list layout");
setTrackElement(E_CYCLES);
setUpdateModal(true);
};
@ -65,6 +66,9 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
const handleRestoreCycle = async () =>
await restoreCycle(workspaceSlug, projectId, cycleId)
.then(() => {
captureEvent(CYCLE_RESTORED, {
cycle_id: cycleId,
});
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Restore success",
@ -81,7 +85,7 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
);
const handleDeleteCycle = () => {
setTrackElement("Cycles page list layout");
setTrackElement(E_CYCLES);
setDeleteModal(true);
};

View File

@ -154,6 +154,12 @@ export const CYCLE_UPDATED = "Cycle updated";
export const CYCLE_DELETED = "Cycle deleted";
export const CYCLE_FAVORITED = "Cycle favorited";
export const CYCLE_UNFAVORITED = "Cycle unfavorited";
export const ACYCLE_TAB_CHANGED = "Active cycle tab changed";
export const CYCLES_FILTER_APPLIED = "Cycles filter applied";
export const CYCLES_FILTER_REMOVED = "Cycles filter removed";
export const CYCLE_ARCHIVED = "Cycle archived";
export const CYCLE_RESTORED = "Cycle restored";
export const CYCLE_LAYOUT_CHANGED = "Cycle layout changed";
// Module Events
export const MODULE_CREATED = "Module created";
export const MODULE_UPDATED = "Module updated";
@ -222,3 +228,6 @@ export const SNOOZED_NOTIFICATIONS = "Snoozed notifications viewed";
export const ARCHIVED_NOTIFICATIONS = "Archived notifications viewed";
// Groups
export const GROUP_WORKSPACE = "Workspace_metrics";
// Elements
export const E_CYCLES = "Cycles";

View File

@ -12,6 +12,7 @@ import { CyclesHeader } from "@/components/headers";
import { CycleModuleListLayout } from "@/components/ui";
// constants
import { EmptyStateType } from "@/constants/empty-state";
import { CYCLES_FILTER_REMOVED } from "@/constants/event-tracker";
// helpers
import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
@ -25,7 +26,7 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => {
// states
const [createModal, setCreateModal] = useState(false);
// store hooks
const { setTrackElement } = useEventTracker();
const { setTrackElement,captureEvent } = useEventTracker();
const { currentProjectCycleIds, loader } = useCycle();
const { getProjectById, currentProjectDetails } = useProject();
// router
@ -45,6 +46,12 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => {
if (!value) newValues = [];
else newValues = newValues.filter((val) => val !== value);
captureEvent(CYCLES_FILTER_REMOVED, {
filter_type: key,
filter_property: value,
current_filters: currentProjectFilters,
});
updateFilters(projectId.toString(), { [key]: newValues });
};