@@ -69,7 +73,7 @@ export const ArchivedIssuesHeader: FC = observer(() => {
{/* filter options */}
-
+
= (props) => {
- const { children, icon, title = "Dropdown", placement, disabled = false, tabIndex, menuButton } = props;
+ const {
+ children,
+ icon,
+ title = "Dropdown",
+ placement,
+ disabled = false,
+ tabIndex,
+ menuButton,
+ isFiltersApplied = false,
+ } = props;
const [referenceElement, setReferenceElement] = useState(null);
const [popperElement, setPopperElement] = useState(null);
@@ -50,10 +61,16 @@ export const FiltersDropdown: React.FC = (props) => {
}
tabIndex={tabIndex}
+ className="relative"
>
-
- {title}
-
+ <>
+
+ {title}
+
+ {isFiltersApplied && (
+
+ )}
+ >
)}
@@ -73,7 +90,9 @@ export const FiltersDropdown: React.FC = (props) => {
style={styles.popper}
{...attributes.popper}
>
- {children}
+
+ {children}
+
diff --git a/web/components/issues/issues-mobile-header.tsx b/web/components/issues/issues-mobile-header.tsx
index de1c088e0..72df560a9 100644
--- a/web/components/issues/issues-mobile-header.tsx
+++ b/web/components/issues/issues-mobile-header.tsx
@@ -1,18 +1,21 @@
import { useCallback, useState } from "react";
import { observer } from "mobx-react";
import router from "next/router";
-// components
-import { Calendar, ChevronDown, Kanban, List } from "lucide-react";
-import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types";
-import { CustomMenu } from "@plane/ui";
// icons
-// constants
+import { Calendar, ChevronDown, Kanban, List } from "lucide-react";
+// types
+import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types";
+// ui
+import { CustomMenu } from "@plane/ui";
+// components
import { ProjectAnalyticsModal } from "@/components/analytics";
+import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues/issue-layouts";
+// constants
import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "@/constants/issue";
+// helpers
+import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store";
-// layouts
-import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "./issue-layouts";
export const IssuesMobileHeader = observer(() => {
const layouts = [
@@ -83,6 +86,8 @@ export const IssuesMobileHeader = observer(() => {
[workspaceSlug, projectId, updateFilters]
);
+ const isFiltersApplied = calculateTotalFilters(issueFilters?.filters ?? {}) !== 0;
+
return (
<>
{
}
+ isFiltersApplied={isFiltersApplied}
>
{
}
};
+ const isFiltersApplied = calculateTotalFilters(currentProjectArchivedFilters ?? {}) !== 0;
+
return (
@@ -128,7 +131,12 @@ export const ArchivedModulesHeader: FC = observer(() => {
});
}}
/>
-
} title="Filters" placement="bottom-end">
+
}
+ title="Filters"
+ placement="bottom-end"
+ isFiltersApplied={isFiltersApplied}
+ >
{
const [analyticsModal, setAnalyticsModal] = useState(false);
@@ -86,6 +88,8 @@ export const ModuleMobileHeader = observer(() => {
[workspaceSlug, projectId, moduleId, updateFilters]
);
+ const isFiltersApplied = calculateTotalFilters(issueFilters?.filters ?? {}) !== 0;
+
return (
{
}
+ isFiltersApplied={isFiltersApplied}
>
{
useOutsideClickDetector(inputRef, () => {
if (isSearchOpen && searchQuery.trim() === "") setIsSearchOpen(false);
});
+
+ const isFiltersApplied = calculateTotalFilters(filters ?? {}) !== 0;
+
return (
@@ -135,7 +142,12 @@ export const ModuleViewHeader: FC = observer(() => {
});
}}
/>
-
} title="Filters" placement="bottom-end">
+
}
+ title="Filters"
+ placement="bottom-end"
+ isFiltersApplied={isFiltersApplied}
+ >
= observer((props) => {
[filters.filters, updateFilters]
);
+ const isFiltersApplied = calculateTotalFilters(filters?.filters ?? {}) !== 0;
+
return (
<>
@@ -59,7 +61,12 @@ export const PagesListHeaderRoot: React.FC
= observer((props) => {
if (val.order) updateFilters("sortBy", val.order);
}}
/>
- } title="Filters" placement="bottom-end">
+ }
+ title="Filters"
+ placement="bottom-end"
+ isFiltersApplied={isFiltersApplied}
+ >
{
// router
@@ -93,6 +96,8 @@ export const ProfileIssuesFilter = observer(() => {
[workspaceSlug, updateFilters, userId]
);
+ const isFiltersApplied = calculateTotalFilters(issueFilters?.filters ?? {}) !== 0;
+
return (
{
selectedLayout={activeLayout}
/>
-
+
{
// router
const router = useRouter();
@@ -99,6 +100,9 @@ const ProfileIssuesMobileHeader = observer(() => {
},
[workspaceSlug, updateFilters, userId]
);
+
+ const isFiltersApplied = calculateTotalFilters(issueFilters?.filters ?? {}) !== 0;
+
return (
{
}
+ isFiltersApplied={isFiltersApplied}
>
{
const {
@@ -44,6 +46,8 @@ const ProjectsMobileHeader = observer(() => {
[filters, updateFilters, workspaceSlug]
);
+ const isFiltersApplied = calculateTotalFilters(filters ?? {}) !== 0;
+
return (
}
+ isFiltersApplied={isFiltersApplied}
>
= observer((props) => {
// derived values
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
- // @ts-expect-error key types are not compatible
+
const totalFilters = calculateTotalFilters(view.filters ?? {});
// handlers
diff --git a/web/helpers/filter.helper.ts b/web/helpers/filter.helper.ts
index c204f00be..670d6d0e0 100644
--- a/web/helpers/filter.helper.ts
+++ b/web/helpers/filter.helper.ts
@@ -1,23 +1,18 @@
import differenceInCalendarDays from "date-fns/differenceInCalendarDays";
// helpers
import { getDate } from "./date-time.helper";
-// types
// import { IIssueFilterOptions } from "@plane/types";
-type TFilters = {
- [key: string]: boolean | string[] | null;
-};
-
/**
* @description calculates the total number of filters applied
- * @param {TFilters} filters
+ * @param {T} filters
* @returns {number}
*/
-export const calculateTotalFilters = (filters: TFilters): number =>
+export const calculateTotalFilters = (filters: T): number =>
filters && Object.keys(filters).length > 0
? Object.keys(filters)
.map((key) => {
- const value = filters[key as keyof TFilters];
+ const value = filters[key as keyof T];
if (value === null) return 0;
if (Array.isArray(value)) return value.length;
if (typeof value === "boolean") return value ? 1 : 0;
@@ -25,7 +20,6 @@ export const calculateTotalFilters = (filters: TFilters): number =>
})
.reduce((curr, prev) => curr + prev, 0)
: 0;
-
/**
* @description checks if the date satisfies the filter
* @param {Date} date