diff --git a/web/components/core/sidebar/sidebar-progress-stats.tsx b/web/components/core/sidebar/sidebar-progress-stats.tsx index db9d94a8fd..0194ba01f1 100644 --- a/web/components/core/sidebar/sidebar-progress-stats.tsx +++ b/web/components/core/sidebar/sidebar-progress-stats.tsx @@ -1,5 +1,5 @@ import React from "react"; - +import { observer } from "mobx-react"; import Image from "next/image"; // headless ui import { Tab } from "@headlessui/react"; @@ -15,6 +15,7 @@ import { // hooks import { Avatar, StateGroupIcon } from "@plane/ui"; import { SingleProgressStats } from "@/components/core"; +import { useProjectState } from "@/hooks/store"; import useLocalStorage from "@/hooks/use-local-storage"; // images import emptyLabel from "public/empty-state/empty_label.svg"; @@ -44,20 +45,23 @@ type Props = { handleFiltersUpdate: (key: keyof IIssueFilterOptions, value: string | string[]) => void; }; -export const SidebarProgressStats: React.FC = ({ - distribution, - groupedIssues, - totalIssues, - module, - roundedTab, - noBackground, - isPeekView = false, - isCompleted = false, - filters, - handleFiltersUpdate, -}) => { +export const SidebarProgressStats: React.FC = observer((props) => { + const { + distribution, + groupedIssues, + totalIssues, + module, + roundedTab, + noBackground, + isPeekView = false, + isCompleted = false, + filters, + handleFiltersUpdate, + } = props; const { storedValue: tab, setValue: setTab } = useLocalStorage("tab", "Assignees"); + const { groupedProjectStates } = useProjectState(); + const currentValue = (tab: string | null) => { switch (tab) { case "Assignees": @@ -71,6 +75,12 @@ export const SidebarProgressStats: React.FC = ({ } }; + const getStateGroupState = (stateGroup: string) => { + const stateGroupStates = groupedProjectStates?.[stateGroup]; + const stateGroupStatesId = stateGroupStates?.map((state) => state.id); + return stateGroupStatesId; + }; + return ( = ({ } completed={groupedIssues[group]} total={totalIssues} + {...(!isPeekView && + !isCompleted && { + onClick: () => handleFiltersUpdate("state", getStateGroupState(group) ?? []), + })} /> ))} ); -}; +}); diff --git a/web/components/cycles/sidebar.tsx b/web/components/cycles/sidebar.tsx index 2aa3afc48c..b2562aa771 100644 --- a/web/components/cycles/sidebar.tsx +++ b/web/components/cycles/sidebar.tsx @@ -1,5 +1,6 @@ import React, { useCallback, useEffect, useState } from "react"; import isEmpty from "lodash/isEmpty"; +import isEqual from "lodash/isEqual"; import { observer } from "mobx-react"; import { useRouter } from "next/router"; import { Controller, useForm } from "react-hook-form"; @@ -199,14 +200,18 @@ export const CycleDetailsSidebar: React.FC = observer((props) => { const handleFiltersUpdate = useCallback( (key: keyof IIssueFilterOptions, value: string | string[]) => { if (!workspaceSlug || !projectId) return; - const newValues = issueFilters?.filters?.[key] ?? []; + let newValues = issueFilters?.filters?.[key] ?? []; if (Array.isArray(value)) { - // this validation is majorly for the filter start_date, target_date custom - value.forEach((val) => { - if (!newValues.includes(val)) newValues.push(val); - else newValues.splice(newValues.indexOf(val), 1); - }); + if (key === "state") { + if (isEqual(newValues, value)) newValues = []; + else newValues = value; + } else { + value.forEach((val) => { + if (!newValues.includes(val)) newValues.push(val); + else newValues.splice(newValues.indexOf(val), 1); + }); + } } else { if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1); else newValues.push(value); diff --git a/web/components/modules/sidebar.tsx b/web/components/modules/sidebar.tsx index d2c847eccd..15163b188c 100644 --- a/web/components/modules/sidebar.tsx +++ b/web/components/modules/sidebar.tsx @@ -1,4 +1,5 @@ import React, { useCallback, useEffect, useState } from "react"; +import isEqual from "lodash/isEqual"; import { observer } from "mobx-react-lite"; import { useRouter } from "next/router"; import { Controller, useForm } from "react-hook-form"; @@ -252,14 +253,18 @@ export const ModuleDetailsSidebar: React.FC = observer((props) => { const handleFiltersUpdate = useCallback( (key: keyof IIssueFilterOptions, value: string | string[]) => { if (!workspaceSlug || !projectId) return; - const newValues = issueFilters?.filters?.[key] ?? []; + let newValues = issueFilters?.filters?.[key] ?? []; if (Array.isArray(value)) { - // this validation is majorly for the filter start_date, target_date custom - value.forEach((val) => { - if (!newValues.includes(val)) newValues.push(val); - else newValues.splice(newValues.indexOf(val), 1); - }); + if (key === "state") { + if (isEqual(newValues, value)) newValues = []; + else newValues = value; + } else { + value.forEach((val) => { + if (!newValues.includes(val)) newValues.push(val); + else newValues.splice(newValues.indexOf(val), 1); + }); + } } else { if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1); else newValues.push(value);