chore: cycle events updated

This commit is contained in:
LAKHAN BAHETI 2024-05-02 12:20:36 +05:30
parent bce768daf6
commit 801f135012
13 changed files with 107 additions and 35 deletions

View File

@ -14,13 +14,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 { useEventTracker, useIssues, useProject } from "@/hooks/store";
import useLocalStorage from "@/hooks/use-local-storage";
export type ActiveCycleStatsProps = {
@ -51,6 +52,7 @@ export const ActiveCycleStats: FC<ActiveCycleStatsProps> = observer((props) => {
} = useIssues(EIssuesStoreType.CYCLE);
const { currentProjectDetails } = useProject();
const { captureEvent } = useEventTracker();
const { data: activeCycleIssues } = useSWR(
workspaceSlug && projectId && cycle.id ? CYCLE_ISSUES_WITH_PARAMS(cycle.id, { priority: "urgent,high" }) : null,
@ -65,17 +67,25 @@ export const ActiveCycleStats: FC<ActiveCycleStatsProps> = observer((props) => {
as={Fragment}
defaultIndex={currentValue(tab)}
onChange={(i) => {
let tab: string;
switch (i) {
case 0:
return setTab("Priority-Issues");
tab = "Priority-Issues";
break;
case 1:
return setTab("Assignees");
tab = "Assignees";
break;
case 2:
return setTab("Labels");
tab = "Labels";
break;
default:
return setTab("Priority-Issues");
tab = "Priority-Issues";
break;
}
setTab(tab);
captureEvent(ACYCLE_TAB_CHANGED, {
tab: tab,
});
}}
>
<Tab.List

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

@ -5,13 +5,16 @@ import { CustomMenu } from "@plane/ui";
// icon
// constants
import { CYCLE_VIEW_LAYOUTS } from "@/constants/cycle";
import { CYCLE_LAYOUT_CHANGED } from "@/constants/event-tracker";
// hooks
import { useCycleFilter, useProject } from "@/hooks/store";
import { useCycleFilter, useEventTracker, useProject } from "@/hooks/store";
const CyclesListMobileHeader = observer(() => {
const { currentProjectDetails } = useProject();
// hooks
const { currentProjectDetails } = useProject();
const { updateDisplayFilters } = useCycleFilter();
const { captureEvent } = useEventTracker();
return (
<div className="flex justify-center sm:hidden">
<CustomMenu
@ -36,6 +39,9 @@ const CyclesListMobileHeader = observer(() => {
updateDisplayFilters(currentProjectDetails!.id, {
layout: layout.key,
});
captureEvent(CYCLE_LAYOUT_CHANGED, {
layout: layout.key,
});
}}
className="flex items-center gap-2"
>

View File

@ -11,10 +11,16 @@ import { CycleFiltersSelection } from "@/components/cycles";
import { FiltersDropdown } from "@/components/issues";
// constants
import { CYCLE_TABS_LIST, CYCLE_VIEW_LAYOUTS } from "@/constants/cycle";
import {
CYCLES_FILTER_APPLIED,
CYCLES_FILTER_REMOVED,
CYCLE_LAYOUT_CHANGED,
CYCLE_TAB_CHANGED,
} from "@/constants/event-tracker";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import { useCycleFilter } from "@/hooks/store";
import { useCycleFilter, useEventTracker } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
@ -36,6 +42,7 @@ export const CyclesViewHeader: React.FC<Props> = observer((props) => {
updateSearchQuery,
} = useCycleFilter();
const { isMobile } = usePlatformOS();
const { captureEvent } = useEventTracker();
// states
const [isSearchOpen, setIsSearchOpen] = useState(searchQuery !== "" ? true : false);
// outside click detector hook
@ -48,7 +55,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) => {
@ -59,7 +66,14 @@ export const CyclesViewHeader: React.FC<Props> = observer((props) => {
if (currentProjectFilters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
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]
@ -81,6 +95,11 @@ export const CyclesViewHeader: React.FC<Props> = observer((props) => {
{CYCLE_TABS_LIST.map((tab) => (
<Tab
key={tab.key}
onClick={() =>
captureEvent(CYCLE_TAB_CHANGED, {
tab: tab.key,
})
}
className={({ selected }) =>
`border-b-2 p-4 text-sm font-medium outline-none ${
selected ? "border-custom-primary-100 text-custom-primary-100" : "border-transparent"
@ -146,11 +165,14 @@ export const CyclesViewHeader: React.FC<Props> = observer((props) => {
className={`group grid h-[22px] w-7 place-items-center overflow-hidden rounded transition-all hover:bg-custom-background-100 ${
activeLayout == layout.key ? "bg-custom-background-100 shadow-custom-shadow-2xs" : ""
}`}
onClick={() =>
onClick={() => {
updateDisplayFilters(projectId, {
layout: layout.key,
})
}
});
captureEvent(CYCLE_LAYOUT_CHANGED, {
layout: layout.key,
});
}}
>
<layout.icon
strokeWidth={2}

View File

@ -8,7 +8,7 @@ import { ArchiveIcon, CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
// components
import { ArchiveCycleModal, CycleCreateUpdateModal, CycleDeleteModal } from "@/components/cycles";
// constants
import { E_CYCLES_LIST_LAYOUT } from "@/constants/event-tracker";
import { CYCLE_ARCHIVED, CYCLE_RESTORED, E_CYCLES } from "@/constants/event-tracker";
import { EUserProjectRoles } from "@/constants/project";
// helpers
import { copyUrlToClipboard } from "@/helpers/string.helper";
@ -31,7 +31,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();
@ -59,7 +59,7 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
const handleEditCycle = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
e.stopPropagation();
setTrackElement(E_CYCLES_LIST_LAYOUT);
setTrackElement(E_CYCLES);
setUpdateModal(true);
};
@ -67,6 +67,10 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
e.preventDefault();
e.stopPropagation();
setArchiveCycleModal(true);
captureEvent(CYCLE_ARCHIVED, {
cycleId: cycleId,
element: E_CYCLES,
});
};
const handleRestoreCycle = async (e: React.MouseEvent<HTMLButtonElement>) => {
@ -79,6 +83,10 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
title: "Restore success",
message: "Your cycle can be found in project cycles.",
});
captureEvent(CYCLE_RESTORED, {
cycleId: cycleId,
element: E_CYCLES,
});
router.push(`/${workspaceSlug}/projects/${projectId}/archives/cycles`);
})
.catch(() =>
@ -93,7 +101,7 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
const handleDeleteCycle = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
e.stopPropagation();
setTrackElement(E_CYCLES_LIST_LAYOUT);
setTrackElement(E_CYCLES);
setDeleteModal(true);
};

View File

@ -120,7 +120,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
const handleFiltersUpdate = useCallback(
(key: keyof IIssueFilterOptions, value: string | string[]) => {
if (!workspaceSlug || !projectId) return;
const newValues = issueFilters?.filters?.[key] ?? [];
const newValues = Array.from(issueFilters?.filters?.[key] ?? []);
if (Array.isArray(value)) {
// this validation is majorly for the filter start_date, target_date custom
@ -133,9 +133,10 @@ export const CycleIssuesHeader: React.FC = observer(() => {
else newValues.push(value);
}
const event = newValues.length > (issueFilters?.filters?.[key] ?? []).length ? FILTER_APPLIED : FILTER_REMOVED;
updateFilters(workspaceSlug, projectId, EIssueFilterType.FILTERS, { [key]: newValues }, cycleId).then(() =>
captureIssuesFilterEvent({
eventName: (issueFilters?.filters?.[key] ?? []).length > newValues.length ? FILTER_REMOVED : FILTER_APPLIED,
eventName: event,
payload: {
routePath: router.asPath,
filters: issueFilters,

View File

@ -48,7 +48,7 @@ export const GlobalIssuesHeader: React.FC = observer(() => {
const handleFiltersUpdate = useCallback(
(key: keyof IIssueFilterOptions, value: string | string[]) => {
if (!workspaceSlug || !globalViewId) return;
const newValues = issueFilters?.filters?.[key] ?? [];
const newValues = Array.from(issueFilters?.filters?.[key] ?? []);
if (Array.isArray(value)) {
// this validation is majorly for the filter start_date, target_date custom
@ -61,6 +61,7 @@ export const GlobalIssuesHeader: React.FC = observer(() => {
else newValues.push(value);
}
const event = (issueFilters?.filters?.[key] ?? []).length > newValues.length ? FILTER_REMOVED : FILTER_APPLIED;
updateFilters(
workspaceSlug.toString(),
undefined,
@ -69,7 +70,7 @@ export const GlobalIssuesHeader: React.FC = observer(() => {
globalViewId.toString()
).then(() => {
captureIssuesFilterEvent({
eventName: (issueFilters?.filters?.[key] ?? []).length > newValues.length ? FILTER_REMOVED : FILTER_APPLIED,
eventName: event,
payload: {
routePath: router.asPath,
filters: issueFilters,

View File

@ -121,7 +121,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
const handleFiltersUpdate = useCallback(
(key: keyof IIssueFilterOptions, value: string | string[]) => {
if (!projectId) return;
const newValues = issueFilters?.filters?.[key] ?? [];
const newValues = Array.from(issueFilters?.filters?.[key] ?? []);
if (Array.isArray(value)) {
// this validation is majorly for the filter start_date, target_date custom
@ -134,9 +134,10 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
else newValues.push(value);
}
const event = (issueFilters?.filters?.[key] ?? []).length > newValues.length ? FILTER_REMOVED : FILTER_APPLIED;
updateFilters(projectId.toString(), EIssueFilterType.FILTERS, { [key]: newValues }).then(() => {
captureIssuesFilterEvent({
eventName: (issueFilters?.filters?.[key] ?? []).length > newValues.length ? FILTER_REMOVED : FILTER_APPLIED,
eventName: event,
payload: {
routePath: router.asPath,
filters: issueFilters,

View File

@ -67,7 +67,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
const handleFiltersUpdate = useCallback(
(key: keyof IIssueFilterOptions, value: string | string[]) => {
if (!workspaceSlug || !projectId) return;
const newValues = issueFilters?.filters?.[key] ?? [];
const newValues = Array.from(issueFilters?.filters?.[key] ?? []);
if (Array.isArray(value)) {
// this validation is majorly for the filter start_date, target_date custom
@ -80,9 +80,10 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
else newValues.push(value);
}
const event = (issueFilters?.filters?.[key] ?? []).length > newValues.length ? FILTER_REMOVED : FILTER_APPLIED;
updateFilters(workspaceSlug, projectId, EIssueFilterType.FILTERS, { [key]: newValues }).then(() =>
captureIssuesFilterEvent({
eventName: (issueFilters?.filters?.[key] ?? []).length > newValues.length ? FILTER_REMOVED : FILTER_APPLIED,
eventName: event,
payload: {
routePath: router.asPath,
filters: issueFilters,

View File

@ -86,7 +86,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
const handleFiltersUpdate = useCallback(
(key: keyof IIssueFilterOptions, value: string | string[]) => {
if (!workspaceSlug || !projectId || !viewId) return;
const newValues = issueFilters?.filters?.[key] ?? [];
const newValues = Array.from(issueFilters?.filters?.[key] ?? []);
if (Array.isArray(value)) {
// this validation is majorly for the filter start_date, target_date custom
@ -98,24 +98,24 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
else newValues.push(value);
}
const event = (issueFilters?.filters?.[key] ?? []).length > newValues.length ? FILTER_REMOVED : FILTER_APPLIED;
updateFilters(
workspaceSlug.toString(),
projectId.toString(),
EIssueFilterType.FILTERS,
{ [key]: newValues },
viewId.toString()
).then(() => {
).then(() =>
captureIssuesFilterEvent({
eventName: (issueFilters?.filters?.[key] ?? []).length > newValues.length ? FILTER_REMOVED : FILTER_APPLIED,
eventName: event,
payload: {
routePath: router.asPath,
filters: issueFilters,
filter_property: value,
filter_type: key,
},
});
});
})
);
},
[workspaceSlug, projectId, viewId, issueFilters, updateFilters, captureIssuesFilterEvent, router.asPath]
);

View File

@ -13,7 +13,7 @@ import { EUserProjectRoles } from "@/constants/project";
// helpers
import { copyUrlToClipboard } from "@/helpers/string.helper";
// hooks
import { useModule, useEventTracker, useUser, useModuleFilter } from "@/hooks/store";
import { useModule, useEventTracker, useUser } from "@/hooks/store";
type Props = {
moduleId: string;

View File

@ -196,6 +196,15 @@ 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 CYCLES_LAYOUT_CHANGED = "cycles layout changed";
export const CYCLES_SORT_UPDATED = "cycle sort updated";
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";
export const CYCLE_TAB_CHANGED = "Cycle tab changed";
export const ACYCLE_TAB_CHANGED = "Active cycle tab changed";
// Module Events
export const MODULE_CREATED = "Module created";
export const MODULE_UPDATED = "Module updated";

View File

@ -18,7 +18,7 @@ import { CyclesHeader } from "@/components/headers";
import { CycleModuleBoardLayout, CycleModuleListLayout, GanttLayoutLoader } from "@/components/ui";
import { CYCLE_TABS_LIST } from "@/constants/cycle";
import { EmptyStateType } from "@/constants/empty-state";
import { E_CYCLES_EMPTY_STATE } from "@/constants/event-tracker";
import { CYCLES_FILTER_REMOVED, E_CYCLES_EMPTY_STATE } from "@/constants/event-tracker";
import { calculateTotalFilters } from "@/helpers/filter.helper";
import { useEventTracker, useCycle, useProject, useCycleFilter } from "@/hooks/store";
// layouts
@ -37,6 +37,7 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => {
const { setTrackElement } = useEventTracker();
const { currentProjectCycleIds, loader } = useCycle();
const { getProjectById, currentProjectDetails } = useProject();
const { captureEvent } = useEventTracker();
// router
const router = useRouter();
const { workspaceSlug, projectId, peekCycle } = router.query;
@ -58,6 +59,11 @@ 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 });
};