rez-table-listing-mui 1.0.32 → 1.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/index.d.ts +11 -4
  2. package/dist/index.js +1 -1
  3. package/dist/index.mjs +1 -1
  4. package/package.json +1 -1
  5. package/src/App.tsx +31 -29
  6. package/src/components/filter/components/attributes-filter.tsx +186 -13
  7. package/src/components/filter/components/forms/components/Date.tsx +94 -16
  8. package/src/components/filter/components/forms/components/Dropdown.tsx +12 -7
  9. package/src/components/filter/components/forms/components/Filter-criteria.tsx +47 -40
  10. package/src/components/filter/components/forms/components/Multi-Select.tsx +6 -1
  11. package/src/components/filter/components/forms/components/Select.tsx +9 -0
  12. package/src/components/filter/components/forms/components/Textfield.tsx +6 -0
  13. package/src/components/filter/components/forms/index.tsx +135 -211
  14. package/src/components/filter/components/main-filter.tsx +2 -7
  15. package/src/components/filter/components/saved-edit-filter.tsx +15 -17
  16. package/src/components/filter/components/saved-filter.tsx +2 -1
  17. package/src/components/filter/components/search/index.tsx +0 -1
  18. package/src/components/filter/components/tabs/custom-tab-panel.tsx +7 -3
  19. package/src/components/filter/components/tabs/index.tsx +8 -8
  20. package/src/components/filter/index.tsx +187 -172
  21. package/src/components/filter/style.ts +106 -0
  22. package/src/components/index-table.tsx +87 -63
  23. package/src/components/index.scss +33 -0
  24. package/src/components/topbar/index.tsx +7 -33
  25. package/src/index.ts +2 -0
  26. package/src/libs/utils/common.ts +1 -1
  27. package/src/types/filter.ts +1 -0
  28. package/src/types/table.ts +7 -2
  29. package/src/components/filter/components/forms/components/Attributes-select.tsx +0 -192
package/src/App.tsx CHANGED
@@ -16,15 +16,17 @@ import {
16
16
  useFetchData,
17
17
  } from "./libs/hooks/useEntityTableHooks";
18
18
  import LoginButton from "./components/login";
19
+ import { CraftTableFilter } from ".";
19
20
  // import { ENTITY_TYPE } from "./libs/utils/common";
20
21
 
21
22
  function App() {
22
- const [mockLoading, setMockLoading] = useState<boolean>(true);
23
+ // const [mockLoading, setMockLoading] = useState<boolean>(true);
23
24
  // const [jsonData] = useState<any[]>([]);
24
25
  const [columns, setColumns] = useState<any[]>([]);
26
+ const [showFilter, setShowFilter] = useState<boolean>(true);
25
27
  const [searchTerm, setSearchTerm] = useState("");
26
28
  // const [data, setData] = useState<Person[]>(() => makeData(50, 3, 2));
27
- // const [entity_type] = useState(ENTITY_TYPE); //OR NTM BRD
29
+ // const [entity_type] = useState(ENTITY_TYPE); //OR UPR BRD
28
30
 
29
31
  const [selectedTab, setSelectedTab] = useState("ALL");
30
32
 
@@ -33,32 +35,27 @@ function App() {
33
35
 
34
36
  const { defaultColumns } = useDefaultColumns();
35
37
 
36
- const { metaQuery } = useFetchData("NTM");
38
+ const { metaQuery } = useFetchData("UPR");
37
39
  const { detailsQuery } = useDetailsQueryAPI(
38
40
  filterMaster?.saved_filters?.selectedId
39
41
  ? filterMaster?.saved_filters?.selectedId
40
42
  : metaQuery?.data?.default_filter?.value
41
43
  );
42
44
 
43
- //API CALL FOR SAVED FILTER
44
- const { savedMutation } = useSavedFilterAPI();
45
-
46
- //API FOR DELETING FILTER
47
- const { deleteMutation } = useDeleteFilterAPI();
48
-
49
- //API FOR UPDATE FILTER
50
- const { updateMutation } = useUpdateFilterAPI();
45
+ const { savedMutation } = useSavedFilterAPI(); //API CALL FOR SAVED FILTER
46
+ const { deleteMutation } = useDeleteFilterAPI(); //API FOR DELETING FILTER
47
+ const { updateMutation } = useUpdateFilterAPI(); //API FOR UPDATE FILTER
51
48
 
52
49
  const { dropdownData } = useCommonDropdownAPI(metaQuery.data);
53
50
 
54
51
  useEffect(() => {
55
- setTimeout(() => {
56
- setMockLoading(false);
57
- }, 1000);
52
+ // setTimeout(() => {
53
+ // setMockLoading(false);
54
+ // }, 1000);
58
55
 
59
56
  const fetchMeta = async () => {
60
57
  try {
61
- const { res } = await entityTableMetaMaster("NTM");
58
+ const { res } = await entityTableMetaMaster("UPR");
62
59
  setColumns(res);
63
60
  } catch (error) {
64
61
  console.error("Failed to fetch metadata:", error);
@@ -77,7 +74,7 @@ function App() {
77
74
  const { tableData, isTableDataPending } = useEntityTableAPI({
78
75
  page: 0,
79
76
  size: 50,
80
- entity_type: "NTM",
77
+ entity_type: "UPR",
81
78
  tabs: {
82
79
  columnName: "status",
83
80
  sortBy: "ASC",
@@ -156,7 +153,7 @@ function App() {
156
153
  const payload = {
157
154
  name,
158
155
  is_default: false,
159
- mapped_entity_type: "NTM", // For that entity type
156
+ mapped_entity_type: "UPR", // For that entity type
160
157
  status: "ACTIVE",
161
158
  entity_type: "SFM", // FIXED entity type
162
159
  filterDetails: quickFilter,
@@ -171,7 +168,7 @@ function App() {
171
168
  name: filterToDelete?.label,
172
169
  id: filterToDelete?.value,
173
170
  is_default: false,
174
- mapped_entity_type: "NTM",
171
+ mapped_entity_type: "UPR",
175
172
  status: "INACTIVE",
176
173
  entity_type: "SFM",
177
174
  };
@@ -192,7 +189,7 @@ function App() {
192
189
  name: filterMaster?.saved_filters?.selectedName, // Name of the filter
193
190
  is_default: false,
194
191
  id: filterMaster?.saved_filters?.selectedId,
195
- mapped_entity_type: "NTM",
192
+ mapped_entity_type: "UPR",
196
193
  status: "ACTIVE",
197
194
  entity_type: "SFM",
198
195
  filterDetails: quickFilter,
@@ -237,16 +234,7 @@ function App() {
237
234
  searchValue: searchTerm,
238
235
  onSearchChange: (val) => setSearchTerm(val),
239
236
  showFilterToggle: true,
240
- filterOptions: {
241
- tableStates: tableStates,
242
- tableData: tableData,
243
- columnsData: metaQuery.data || [],
244
- defaultFilters: detailsQuery.data || [],
245
- dropdownData: dropdownData || [],
246
- onDeleteFilter: handleRemoveFilter,
247
- onSaveFilter: handleSaveFilter,
248
- onUpdateFilter: handleUpdateFilter,
249
- },
237
+ onFilterButtonClick: () => setShowFilter(!showFilter),
250
238
  }}
251
239
  paginationOptions={{
252
240
  showPagination: true,
@@ -258,6 +246,20 @@ function App() {
258
246
  renderStatus: handleRenderStatus,
259
247
  renderAction: handleRenderAction,
260
248
  }}
249
+ filterOptions={{
250
+ show: showFilter,
251
+ component: (
252
+ <CraftTableFilter
253
+ tableStates={tableStates}
254
+ columnsData={metaQuery.data || []}
255
+ dropdownData={dropdownData || []}
256
+ onDeleteFilter={handleRemoveFilter}
257
+ onSaveFilter={handleSaveFilter}
258
+ onUpdateFilter={handleUpdateFilter}
259
+ onClose={() => setShowFilter(false)}
260
+ />
261
+ ),
262
+ }}
261
263
  />
262
264
  </div>
263
265
  );
@@ -1,6 +1,19 @@
1
- import { Box } from "@mui/material";
2
- import { AttributesFilterProps } from "../../../types/filter";
3
- import SelectAttribute from "./forms/components/Attributes-select";
1
+ import {
2
+ Box,
3
+ FormControl,
4
+ FormControlLabel,
5
+ MenuItem,
6
+ Radio,
7
+ RadioGroup,
8
+ Select,
9
+ SelectChangeEvent,
10
+ } from "@mui/material";
11
+ import {
12
+ AttributesFilterProps,
13
+ FilterMasterStateProps,
14
+ } from "../../../types/filter";
15
+ import CustomSearch from "./search";
16
+ import { useMemo } from "react";
4
17
 
5
18
  const AttributesFilter = ({
6
19
  columnsData,
@@ -10,17 +23,177 @@ const AttributesFilter = ({
10
23
  setSearchTerm,
11
24
  tabValue,
12
25
  }: AttributesFilterProps) => {
26
+ const { filterMaster, setFilterMaster, filters, setFilters } = tableStates;
27
+
28
+ const selectedAttribute = filterMaster?.attributes?.selected;
29
+
30
+ // Get the current filter value to set radio button state
31
+ const currentFilterValue = useMemo(() => {
32
+ if (!selectedAttribute) return "";
33
+
34
+ const matchingColumn = columnsData.column_list.find(
35
+ (column) => column.datasource_list === selectedAttribute
36
+ );
37
+
38
+ if (!matchingColumn) return "";
39
+
40
+ const existingFilter = filters.find(
41
+ (filter) => filter.filter_attribute === matchingColumn.attribute_key
42
+ );
43
+
44
+ return existingFilter?.filter_value || "";
45
+ }, [selectedAttribute, filters, columnsData]);
46
+
47
+ const handleSelectChange = (event: SelectChangeEvent) => {
48
+ const attributeKey = event.target.value as string;
49
+
50
+ setFilterMaster(
51
+ (prev) =>
52
+ ({
53
+ ...prev,
54
+ attributes: {
55
+ ...prev?.attributes,
56
+ selected: attributeKey,
57
+ radio: "", // Reset radio selection when changing attribute
58
+ },
59
+ } as FilterMasterStateProps)
60
+ );
61
+ };
62
+
63
+ const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
64
+ event.preventDefault();
65
+
66
+ const selectedValue = event.target.value;
67
+
68
+ setFilterMaster(
69
+ (prev) =>
70
+ ({
71
+ ...prev,
72
+ attributes: {
73
+ ...prev?.attributes,
74
+ radio: selectedValue,
75
+ },
76
+ activeFilterTabIndex: tabValue,
77
+ } as FilterMasterStateProps)
78
+ );
79
+
80
+ const selectedAttribute = filterMaster?.attributes.selected;
81
+ if (selectedAttribute) {
82
+ const matchingColumn = columnsData.column_list.find(
83
+ (column) => column.datasource_list === selectedAttribute
84
+ );
85
+ if (matchingColumn) {
86
+ const defaultOperator =
87
+ columnsData.operation_list[matchingColumn.data_type]?.[0]?.value ||
88
+ "equals";
89
+ const newFilter = {
90
+ filter_attribute: matchingColumn.attribute_key,
91
+ filter_operator: defaultOperator,
92
+ filter_value: selectedValue,
93
+ };
94
+
95
+ setFilters([newFilter]);
96
+ }
97
+ }
98
+ };
99
+
100
+ const selectedAttributeOptions = useMemo(() => {
101
+ const selected = columnsData.column_list.find(
102
+ (col) => col.datasource_list === selectedAttribute
103
+ )?.attribute_key;
104
+
105
+ return selected ? dropdownData[selected] : [];
106
+ }, [selectedAttribute, dropdownData]);
107
+
13
108
  return (
14
- <Box>
15
- {/* Render select Attributes */}
16
- <SelectAttribute
17
- columnsData={columnsData}
18
- tableStates={tableStates}
19
- dropdownData={dropdownData}
20
- searchTerm={searchTerm}
21
- setSearchTerm={setSearchTerm}
22
- tabValue={tabValue}
23
- />
109
+ <Box
110
+ sx={{
111
+ display: "flex",
112
+ flexDirection: "column",
113
+ gap: "1.25rem",
114
+ }}
115
+ >
116
+ <FormControl fullWidth size="small">
117
+ <Select
118
+ value={selectedAttribute || ""}
119
+ onChange={handleSelectChange}
120
+ displayEmpty
121
+ renderValue={(selected) => {
122
+ if (!selected) {
123
+ return <span>Select Attribute</span>;
124
+ }
125
+ return columnsData?.column_list?.find(
126
+ (col) => col.datasource_list === selected
127
+ )?.name;
128
+ }}
129
+ sx={{
130
+ "& .MuiOutlinedInput-root": {
131
+ borderRadius: "6px",
132
+ fontSize: "14px",
133
+ bgcolor: "#fafafa",
134
+ "& fieldset": {
135
+ borderColor: "#7a5af8 !important",
136
+ },
137
+ "&:hover fieldset": {
138
+ borderColor: "#7a5af8 !important",
139
+ },
140
+ "&.Mui-focused fieldset": {
141
+ borderColor: "#7a5af8 !important",
142
+ boxShadow: "none",
143
+ },
144
+ },
145
+ "& .MuiSelect-select": {
146
+ padding: "8px 14px",
147
+ },
148
+ }}
149
+ >
150
+ {columnsData?.column_list
151
+ ?.filter((column) => column.data_type.includes("select"))
152
+ .map((column, index) => (
153
+ <MenuItem
154
+ key={index}
155
+ value={column.datasource_list}
156
+ disabled={column.datasource_list === selectedAttribute}
157
+ >
158
+ {column.name}
159
+ </MenuItem>
160
+ ))}
161
+ </Select>
162
+ </FormControl>
163
+
164
+ <Box>
165
+ {selectedAttribute && (
166
+ <CustomSearch value={searchTerm} onChange={setSearchTerm} />
167
+ )}
168
+
169
+ {dropdownData && (
170
+ <Box sx={{ mt: 2 }}>
171
+ <FormControl>
172
+ <RadioGroup
173
+ onChange={handleRadioChange}
174
+ value={currentFilterValue} // Set the value from current filter
175
+ >
176
+ {selectedAttributeOptions
177
+ ?.filter((option) => {
178
+ if (!searchTerm) return true;
179
+
180
+ return option.label
181
+ .toLowerCase()
182
+ .includes(searchTerm.toLowerCase());
183
+ })
184
+ .map((option) => (
185
+ <FormControlLabel
186
+ key={option.value}
187
+ value={option.value}
188
+ control={<Radio />}
189
+ label={option.label}
190
+ />
191
+ ))}
192
+ </RadioGroup>
193
+ </FormControl>
194
+ </Box>
195
+ )}
196
+ </Box>
24
197
  </Box>
25
198
  );
26
199
  };
@@ -6,20 +6,24 @@ import moment from "moment";
6
6
  import { UpdatedFilterStateProps } from "../../../../../types/filter";
7
7
  import { SxProps, Theme } from "@mui/material";
8
8
 
9
- const FormDatePicker = ({
10
- filter,
11
- control,
12
- }: {
9
+ type FormDatePickerProps = {
13
10
  filter: UpdatedFilterStateProps;
14
11
  control: any;
15
12
  sx?: SxProps<Theme>;
16
- }) => {
17
- const range = filter.filter_operator === "between";
18
- console.log("range+++", range);
13
+ views?: Array<"year" | "month" | "day">;
14
+ onValueChange?: () => void;
15
+ };
19
16
 
17
+ const FormDatePicker = ({
18
+ filter,
19
+ control,
20
+ sx,
21
+ views = ["day", "month", "year"], // default to full date picker
22
+ onValueChange,
23
+ }: FormDatePickerProps) => {
20
24
  return (
21
25
  <Controller
22
- name={`${filter?.name}.value`} // or use a consistent structure like `filters.${index}.filter_value`
26
+ name={`${filter?.name}.value`} // Use consistent field structure
23
27
  control={control}
24
28
  defaultValue={
25
29
  filter.filter_value
@@ -29,25 +33,40 @@ const FormDatePicker = ({
29
33
  render={({ field }) => (
30
34
  <LocalizationProvider dateAdapter={AdapterDateFns}>
31
35
  <DatePicker
32
- sx={{
33
- "& .MuiOutlinedInput-input": {
34
- padding: "12px 20px",
35
- },
36
- }}
37
36
  {...field}
37
+ views={views}
38
38
  value={
39
39
  field.value ? moment(field.value, "DD-MM-YYYY").toDate() : null
40
40
  }
41
41
  onChange={(date) => {
42
- const formatted = date ? moment(date).format("DD-MM-YYYY") : "";
42
+ let formatted = "";
43
+ if (date) {
44
+ if (views?.length === 1 && views[0] === "year") {
45
+ formatted = moment(date).format("YYYY");
46
+ } else {
47
+ formatted = moment(date).format("DD-MM-YYYY");
48
+ }
49
+ }
43
50
  field.onChange(formatted);
51
+ onValueChange?.();
52
+ }}
53
+ format={
54
+ views?.length === 1 && views[0] === "year" ? "yyyy" : "dd-MM-yyyy"
55
+ }
56
+ sx={{
57
+ "& .MuiOutlinedInput-input": {
58
+ padding: "12px 20px",
59
+ },
60
+ ...sx,
44
61
  }}
45
- format="dd-MM-yyyy"
46
62
  slotProps={{
47
63
  textField: {
48
64
  size: "small",
49
65
  fullWidth: true,
50
- placeholder: "DD-MM-YYYY",
66
+ placeholder:
67
+ views?.length === 1 && views[0] === "year"
68
+ ? "YYYY"
69
+ : "DD-MM-YYYY",
51
70
  },
52
71
  }}
53
72
  />
@@ -58,3 +77,62 @@ const FormDatePicker = ({
58
77
  };
59
78
 
60
79
  export default FormDatePicker;
80
+
81
+ // import { Controller } from "react-hook-form";
82
+ // import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
83
+ // import { DatePicker } from "@mui/x-date-pickers/DatePicker";
84
+ // import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";
85
+ // import moment from "moment";
86
+ // import { UpdatedFilterStateProps } from "../../../../../types/filter";
87
+ // import { SxProps, Theme } from "@mui/material";
88
+
89
+ // const FormDatePicker = ({
90
+ // filter,
91
+ // control,
92
+ // sx,
93
+ // }: {
94
+ // filter: UpdatedFilterStateProps;
95
+ // control: any;
96
+ // sx?: SxProps<Theme>;
97
+ // }) => {
98
+ // return (
99
+ // <Controller
100
+ // name={`${filter?.name}.value`} // or use a consistent structure like `filters.${index}.filter_value`
101
+ // control={control}
102
+ // defaultValue={
103
+ // filter.filter_value
104
+ // ? moment(filter.filter_value, "DD-MM-YYYY").toDate()
105
+ // : null
106
+ // }
107
+ // render={({ field }) => (
108
+ // <LocalizationProvider dateAdapter={AdapterDateFns}>
109
+ // <DatePicker
110
+ // sx={{
111
+ // "& .MuiOutlinedInput-input": {
112
+ // padding: "12px 20px",
113
+ // },
114
+ // }}
115
+ // {...field}
116
+ // value={
117
+ // field.value ? moment(field.value, "DD-MM-YYYY").toDate() : null
118
+ // }
119
+ // onChange={(date) => {
120
+ // const formatted = date ? moment(date).format("DD-MM-YYYY") : "";
121
+ // field.onChange(formatted);
122
+ // }}
123
+ // format="dd-MM-yyyy"
124
+ // slotProps={{
125
+ // textField: {
126
+ // size: "small",
127
+ // fullWidth: true,
128
+ // placeholder: "DD-MM-YYYY",
129
+ // },
130
+ // }}
131
+ // />
132
+ // </LocalizationProvider>
133
+ // )}
134
+ // />
135
+ // );
136
+ // };
137
+
138
+ // export default FormDatePicker;
@@ -11,6 +11,7 @@ interface FormDropdownProps {
11
11
  }[];
12
12
  isLoading?: boolean;
13
13
  sx?: SxProps<Theme>;
14
+ onValueChange?: () => void;
14
15
  }
15
16
 
16
17
  const FormDropdown = ({
@@ -19,6 +20,7 @@ const FormDropdown = ({
19
20
  dropdownList,
20
21
  isLoading = false,
21
22
  sx,
23
+ onValueChange,
22
24
  }: FormDropdownProps) => {
23
25
  return (
24
26
  <Controller
@@ -36,7 +38,7 @@ const FormDropdown = ({
36
38
  border: "none",
37
39
  boxShadow: "none",
38
40
  "& .MuiSelect-icon": {
39
- top: "45%", // move up
41
+ top: "45%",
40
42
  transform: "translateY(-50%)",
41
43
  "& .MuiOutlinedInput-input": {
42
44
  padding: "12px 20px",
@@ -45,13 +47,16 @@ const FormDropdown = ({
45
47
  }}
46
48
  disabled={isLoading}
47
49
  disableUnderline
50
+ onChange={(e) => {
51
+ field.onChange(e); // ✅ sync with RHF
52
+ onValueChange?.(); // ✅ trigger debounce
53
+ }}
48
54
  >
49
- {dropdownList &&
50
- dropdownList.map((item, idx) => (
51
- <MenuItem key={idx} value={item.value}>
52
- {item.label}
53
- </MenuItem>
54
- ))}
55
+ {dropdownList?.map((item, idx) => (
56
+ <MenuItem key={idx} value={item.value}>
57
+ {item.label}
58
+ </MenuItem>
59
+ ))}
55
60
  </Select>
56
61
  </FormControl>
57
62
  )}
@@ -5,7 +5,6 @@ import {
5
5
  List,
6
6
  ListItem,
7
7
  Paper,
8
- ListSubheader,
9
8
  ListItemText,
10
9
  } from "@mui/material";
11
10
  import { useState, useRef } from "react";
@@ -22,12 +21,16 @@ const FilterCriteria = ({
22
21
  columnsData,
23
22
  tableStates,
24
23
  setSelectedFilters,
24
+ searchTerm,
25
+ setSearchTerm,
25
26
  }: {
26
27
  columnsData: FilterColumnsDataProps;
27
28
  tableStates: CraftTableOptionsProps;
28
29
  setSelectedFilters: React.Dispatch<
29
30
  React.SetStateAction<UpdatedFilterStateProps[]>
30
31
  >;
32
+ searchTerm: string;
33
+ setSearchTerm: React.Dispatch<React.SetStateAction<string>>;
31
34
  }) => {
32
35
  const FilterButton = styled(Button)(({ theme }) => ({
33
36
  borderRadius: 20,
@@ -112,11 +115,10 @@ const FilterCriteria = ({
112
115
  {showFilterOptions && (
113
116
  <Paper
114
117
  sx={{
115
- mt: 2,
116
118
  width: filterButtonRef.current?.offsetWidth || 360, // Dynamic width based on button
117
119
  p: 1,
118
- maxHeight: "300px",
119
- overflowY: "auto",
120
+ mt: 2,
121
+ // overflowY: "auto",
120
122
  cursor: "pointer",
121
123
  position: "absolute",
122
124
  zIndex: 1300,
@@ -124,46 +126,51 @@ const FilterCriteria = ({
124
126
  >
125
127
  <Box
126
128
  sx={{
127
- maxHeight: "300px", // Adjust height as needed
128
129
  overflowY: "auto", // Enable vertical scrolling
129
130
  width: "100%", // Adjust width as needed
130
131
  }}
131
132
  >
132
- <List
133
- subheader={
134
- <ListSubheader
135
- component="div"
136
- sx={{
137
- fontWeight: "bold",
138
- bgcolor: "#f5f5f9",
139
- borderRadius: "6px",
140
- }}
141
- >
142
- {/* Filter by... */}
143
- {/* <CustomSearch placeholder="Filter by..." /> */}
144
- </ListSubheader>
145
- }
146
- >
147
- {columnsData?.column_list?.map((column, index) => {
148
- const isAlreadySelected = filters?.some(
149
- (filter) => filter.filter_attribute === column.attribute_key
150
- );
151
-
152
- return (
153
- <ListItem
154
- key={index}
155
- onClick={() =>
156
- !isAlreadySelected && handleAddFilter(column)
157
- } // Prevent click if already selected
158
- sx={{
159
- opacity: isAlreadySelected ? 0.5 : 1,
160
- cursor: isAlreadySelected ? "not-allowed" : "pointer",
161
- }}
162
- >
163
- <ListItemText primary={column.name} />
164
- </ListItem>
165
- );
166
- })}
133
+ <List>
134
+ <CustomSearch
135
+ placeholder="Filter by..."
136
+ value={searchTerm}
137
+ onChange={setSearchTerm}
138
+ />
139
+
140
+ <Box
141
+ sx={{
142
+ my: 2,
143
+ maxHeight: `calc(100vh - 360px)`,
144
+ overflowY: "auto",
145
+ transition: "all 0.4s ease-in-out",
146
+ }}
147
+ >
148
+ {columnsData?.column_list
149
+ ?.filter((column) =>
150
+ column.name.toLowerCase().includes(searchTerm.toLowerCase())
151
+ )
152
+ .map((column, index) => {
153
+ const isAlreadySelected = filters?.some(
154
+ (filter) =>
155
+ filter.filter_attribute === column.attribute_key
156
+ );
157
+
158
+ return (
159
+ <ListItem
160
+ key={index}
161
+ onClick={() =>
162
+ !isAlreadySelected && handleAddFilter(column)
163
+ } // Prevent click if already selected
164
+ sx={{
165
+ opacity: isAlreadySelected ? 0.5 : 1,
166
+ cursor: isAlreadySelected ? "not-allowed" : "pointer",
167
+ }}
168
+ >
169
+ <ListItemText primary={column.name} />
170
+ </ListItem>
171
+ );
172
+ })}
173
+ </Box>
167
174
  </List>
168
175
  </Box>
169
176
  </Paper>
@@ -8,11 +8,13 @@ const FormMultiSelect = ({
8
8
  control,
9
9
  dropdownData,
10
10
  sx,
11
+ onValueChange,
11
12
  }: {
12
13
  filter: UpdatedFilterStateProps;
13
14
  control: any;
14
15
  dropdownData: Record<string, DropdownOption[]>;
15
16
  sx?: SxProps<Theme>;
17
+ onValueChange?: () => void;
16
18
  }) => {
17
19
  const options = dropdownData[filter.filter_attribute] || [];
18
20
 
@@ -32,7 +34,10 @@ const FormMultiSelect = ({
32
34
  }}
33
35
  multiple
34
36
  value={field.value || []}
35
- onChange={(e) => field.onChange(e.target.value)}
37
+ onChange={(e) => {
38
+ field.onChange(e.target.value);
39
+ onValueChange?.();
40
+ }}
36
41
  renderValue={(selected: string[]) =>
37
42
  selected
38
43
  .map(