mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: cycle events updated
This commit is contained in:
parent
bce768daf6
commit
801f135012
@ -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
|
||||
|
@ -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");
|
||||
};
|
||||
|
||||
|
@ -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"
|
||||
>
|
||||
|
@ -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}
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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]
|
||||
);
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
|
@ -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 });
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user