diff --git a/plane-src/apps/web/core/components/common/sorting-dropdown.tsx b/plane-src/apps/web/core/components/common/sorting-dropdown.tsx new file mode 100644 index 0000000..b9297d5 --- /dev/null +++ b/plane-src/apps/web/core/components/common/sorting-dropdown.tsx @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2023-present Plane Software, Inc. and contributors + * SPDX-License-Identifier: AGPL-3.0-only + * See the LICENSE file for details. + */ + +import type { ReactNode } from "react"; +import type { Placement } from "@popperjs/core"; +import { FiltersDropdown, FilterOption } from "@/components/issues/issue-layouts/filters/header"; + +export type TSortingDropdownOption = { + key: string; + title: ReactNode; + icon?: ReactNode; + isChecked: boolean; + onClick: () => void; + shouldRender?: boolean; + disabled?: boolean; +}; + +export type TSortingDropdownSection = { + key: string; + options: TSortingDropdownOption[]; +}; + +type Props = { + disabled?: boolean; + menuButton: ReactNode; + placement?: Placement; + sections: TSortingDropdownSection[]; + title?: ReactNode; +}; + +export function SortingDropdown(props: Props) { + const { disabled = false, menuButton, placement = "bottom-end", sections, title = "Order by" } = props; + + const renderedSections = sections + .map((section) => ({ + ...section, + options: section.options.filter((option) => option.shouldRender !== false), + })) + .filter((section) => section.options.length > 0); + + return ( + +
+
+ {title} +
+ {renderedSections.map((section, index) => ( +
+ {section.options.map((option) => ( + + ))} +
+ ))} +
+
+ ); +} diff --git a/plane-src/apps/web/core/components/inbox/inbox-filter/sorting/order-by.tsx b/plane-src/apps/web/core/components/inbox/inbox-filter/sorting/order-by.tsx index adbba4a..212303f 100644 --- a/plane-src/apps/web/core/components/inbox/inbox-filter/sorting/order-by.tsx +++ b/plane-src/apps/web/core/components/inbox/inbox-filter/sorting/order-by.tsx @@ -10,7 +10,7 @@ import { INBOX_ISSUE_ORDER_BY_OPTIONS, INBOX_ISSUE_SORT_BY_OPTIONS } from "@plan import { useTranslation } from "@plane/i18n"; import { CheckIcon, ChevronDownIcon } from "@plane/propel/icons"; import type { TInboxIssueSortingOrderByKeys, TInboxIssueSortingSortByKeys } from "@plane/types"; -import { CustomMenu } from "@plane/ui"; +import { SortingDropdown } from "@/components/common/sorting-dropdown"; // constants // helpers import { cn } from "@plane/utils"; @@ -59,33 +59,32 @@ export const InboxIssueOrderByDropdown = observer(function InboxIssueOrderByDrop ); return ( - - {INBOX_ISSUE_ORDER_BY_OPTIONS.map((option) => ( - handleInboxIssueSorting("order_by", option.key as TInboxIssueSortingOrderByKeys)} - > - {t(option.i18n_label)} - {inboxSorting?.order_by?.includes(option.key) && } - - ))} -
- {INBOX_ISSUE_SORT_BY_OPTIONS.map((option) => ( - handleInboxIssueSorting("sort_by", option.key as TInboxIssueSortingSortByKeys)} - > - {t(option.i18n_label)} - {inboxSorting?.sort_by?.includes(option.key) && } - - ))} -
+ title={t("common.order_by.label")} + sections={[ + { + key: "field", + options: INBOX_ISSUE_ORDER_BY_OPTIONS.map((option) => ({ + key: option.key, + title: t(option.i18n_label), + isChecked: !!inboxSorting?.order_by?.includes(option.key), + onClick: () => handleInboxIssueSorting("order_by", option.key as TInboxIssueSortingOrderByKeys), + icon: inboxSorting?.order_by?.includes(option.key) ? : undefined, + })), + }, + { + key: "direction", + options: INBOX_ISSUE_SORT_BY_OPTIONS.map((option) => ({ + key: option.key, + title: t(option.i18n_label), + isChecked: !!inboxSorting?.sort_by?.includes(option.key), + onClick: () => handleInboxIssueSorting("sort_by", option.key as TInboxIssueSortingSortByKeys), + icon: inboxSorting?.sort_by?.includes(option.key) ? : undefined, + })), + }, + ]} + /> ); }); diff --git a/plane-src/apps/web/core/components/issues/issue-layouts/filters/header/helpers/filter-option.tsx b/plane-src/apps/web/core/components/issues/issue-layouts/filters/header/helpers/filter-option.tsx index 6f97e2c..7626b12 100644 --- a/plane-src/apps/web/core/components/issues/issue-layouts/filters/header/helpers/filter-option.tsx +++ b/plane-src/apps/web/core/components/issues/issue-layouts/filters/header/helpers/filter-option.tsx @@ -7,6 +7,7 @@ import { CheckIcon } from "@plane/propel/icons"; type Props = { + disabled?: boolean; icon?: React.ReactNode; isChecked: boolean; title: React.ReactNode; @@ -16,13 +17,14 @@ type Props = { }; export function FilterOption(props: Props) { - const { icon, isChecked, onClick, title, activePulse = false } = props; + const { disabled = false, icon, isChecked, onClick, title, activePulse = false } = props; return (