All files / src/features/ChangeLog/filter-components CategoryFilter.tsx

77.77% Statements 21/27
53.84% Branches 7/13
63.63% Functions 7/11
82.6% Lines 19/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99                            117x         24x 24x   24x     24x       24x 1x     24x       24x         24x 1x   1x     1x 1x       1x     120x     30x   1x     24x                                                                    
import { useState } from "react";
import { SelectorOption } from "@common/TableFilters/SelectorOption";
import ContextualMenu from "@shared/ContextualMenu/ContextualMenu";
import ContextualMenuHeader from "@shared/ContextualMenu/ContextualMenuHeader";
import FilterItem from "./FilterItem";
import useListCategories from "../hooks/useListCategories";
import { useCustomThemeV2 } from "@theme/hooks/useCustomThemeV2";
 
interface ICategoryFilterProps {
  merchantId: number;
  selectedCategories: SelectorOption[];
  onApply: (categories: SelectorOption[]) => void;
}
 
const CategoryFilter = ({
  merchantId,
  selectedCategories = [],
  onApply,
}: ICategoryFilterProps) => {
  const { isMobileView } = useCustomThemeV2();
  const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
 
  const { data } = useListCategories({ merchantId });
 
  const title =
    selectedCategories.length > 0
      ? `Category (${selectedCategories.length})`
      : "Category";
 
  const handleOpen = (e: React.MouseEvent<HTMLElement>) => {
    setAnchorEl(e.currentTarget);
  };
 
  const handleClose = () => {
    setAnchorEl(null);
  };
 
  const handleReset = (e: React.MouseEvent) => {
    e.stopPropagation();
    onApply([]);
  };
 
  const handleToggleCategory = (categoryId: number | string) => {
    const exists = selectedCategories.find((c) => c.id === categoryId);
    let newSelection;
    Iif (exists) {
      newSelection = selectedCategories.filter((c) => c.id !== categoryId);
    } else {
      const option = data.find((d) => d.id === categoryId);
      newSelection = option
        ? [...selectedCategories, option]
        : selectedCategories;
    }
    onApply(newSelection);
  };
 
  const options = data.map((category) => ({
    text: category.label,
    id: category.id,
    showCheckedIcon: selectedCategories.some((s) => s.id === category.id),
    checkedIconType: "Check" as const,
    onClick: () => handleToggleCategory(category.id),
  }));
 
  return (
    <>
      <FilterItem
        isSelected={selectedCategories.length > 0}
        title={title}
        onClick={handleOpen}
        onCancel={handleReset}
        isOpen={Boolean(anchorEl)}
      />
      {/* High z-index to ensure menu appears above GiveDraggableModal */}
      <ContextualMenu
        anchorEl={anchorEl}
        handleClose={handleClose}
        color={isMobileView ? "primary" : "tertiary"}
        texture={isMobileView ? "solid" : "blurred"}
        options={options}
        isMultiSelect
        menuWidth={280}
        Header={
          isMobileView ? (
            <ContextualMenuHeader
              onBackClick={handleClose}
              title="Categories"
            />
          ) : undefined
        }
        horizontalOrigin="left"
        drawerZIndex={1000000}
      />
    </>
  );
};
 
export default CategoryFilter;