rez-table-listing-mui 2.0.12 → 2.0.14

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.
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from "react";
1
+ import { useEffect, useState } from "react";
2
2
  import {
3
3
  Box,
4
4
  Select,
@@ -8,7 +8,6 @@ import {
8
8
  Checkbox,
9
9
  FormControlLabel,
10
10
  Grid,
11
- Alert,
12
11
  } from "@mui/material";
13
12
 
14
13
  import ListingValues from "../common/listing-values";
@@ -22,12 +21,7 @@ import {
22
21
  useSensors,
23
22
  DragEndEvent,
24
23
  } from "@dnd-kit/core";
25
- import {
26
- QuickTabConfigProps,
27
- SettingsQuickTabProps,
28
- } from "../../../types/filter-settings";
29
24
  import { TabsStyles } from "../style";
30
- import InfoAlert from "../common/info-alert";
31
25
  import { craftTableFilterSettingsOptionsProps } from "../../../types/table-options";
32
26
  import { LANE_SELECTS } from "../constants";
33
27
 
@@ -36,14 +30,15 @@ const Lane = ({
36
30
  columnsData,
37
31
  tabsApiData,
38
32
  tabsApiDataLoading,
33
+ selectAttributeData,
39
34
  }: {
40
35
  filterSettingStates: craftTableFilterSettingsOptionsProps;
41
36
  columnsData: any;
42
37
  tabsApiData?: { label: string; value: string }[];
43
38
  tabsApiDataLoading?: boolean;
39
+ selectAttributeData?: { label: string; value: string }[];
44
40
  }) => {
45
- const { settingsData, setSettingsData, saveButtonError, setSaveButtonError } =
46
- filterSettingStates;
41
+ const { settingsData, setSettingsData } = filterSettingStates;
47
42
 
48
43
  const [searchTerm, setSearchTerm] = useState<string>("");
49
44
  const [currentQuickAttribute, setCurrentQuickAttribute] = useState<string>(
@@ -52,7 +47,6 @@ const Lane = ({
52
47
 
53
48
  const quickTabStates = settingsData?.quick_tab as any;
54
49
 
55
- // In case there is no quick tab state from API
56
50
  useEffect(() => {
57
51
  const stateToArray =
58
52
  (quickTabStates && Object.entries(quickTabStates)) || [];
@@ -70,7 +64,6 @@ const Lane = ({
70
64
  }
71
65
  }, [columnsData]);
72
66
 
73
- // When user changes attribute
74
67
  useEffect(() => {
75
68
  if (currentQuickAttribute === settingsData?.quick_tab?.attribute) return;
76
69
 
@@ -88,62 +81,6 @@ const Lane = ({
88
81
  }
89
82
  }, [tabsApiData]);
90
83
 
91
- // Validation when user changes show list or hide list
92
- useEffect(() => {
93
- const showList = quickTabStates?.show_list || [];
94
- const hideList = quickTabStates?.hide_list || [];
95
-
96
- if (showList || hideList) {
97
- // Check if showList is valid (between 1 and 5 items)
98
- const isValidShowList = showList.length > 0 && showList.length <= 5;
99
- const ERROR_CODE = "quick_tab_error";
100
-
101
- if (!isValidShowList) {
102
- const errorMessage = {
103
- type: ERROR_CODE,
104
- message:
105
- showList.length === 0
106
- ? "Quick Lane: Please select at least one item"
107
- : "Quick Lane: Please select no more than 5 items",
108
- };
109
-
110
- // Check if the error is already present in the messages array
111
- const hasQuickTabError = saveButtonError?.messages?.some(
112
- (message) => message.type === ERROR_CODE
113
- );
114
-
115
- // Update the error state
116
-
117
- // Later we can use this to show error message when we will make error logic more simple
118
- // setSaveButtonError((prev) => {
119
- // const otherMessages =
120
- // prev?.messages?.filter((message) => message.type !== ERROR_CODE) ||
121
- // [];
122
-
123
- // return {
124
- // ...prev,
125
- // hasError: true,
126
- // messages: hasQuickTabError
127
- // ? [...prev?.messages]
128
- // : [...otherMessages, errorMessage],
129
- // };
130
- // });
131
- } else {
132
- const hasOtherMessages = saveButtonError?.messages?.some(
133
- (message) => message.type !== ERROR_CODE
134
- );
135
- // Reset error state if the list is valid
136
- // setSaveButtonError((prev) => ({
137
- // ...prev,
138
- // hasError: hasOtherMessages,
139
- // messages:
140
- // prev?.messages?.filter((message) => message.type !== ERROR_CODE) ||
141
- // [],
142
- // }));
143
- }
144
- }
145
- }, [quickTabStates?.hide_list, quickTabStates?.show_list]);
146
-
147
84
  const sortingOptions = [
148
85
  { label: "A-Z", value: "asc" },
149
86
  { label: "Z-A", value: "dsc" },
@@ -152,7 +89,6 @@ const Lane = ({
152
89
  { label: "Custom", value: "custom" },
153
90
  ];
154
91
 
155
- // Convert show_list/hide_list to FilterValue[] for rendering only
156
92
  const showListValues = (quickTabStates?.show_list || [])?.map((id: any) => ({
157
93
  id,
158
94
  label: id?.charAt(0)?.toUpperCase() + id?.slice(1),
@@ -162,160 +98,102 @@ const Lane = ({
162
98
  label: id?.charAt(0)?.toUpperCase() + id?.slice(1),
163
99
  }));
164
100
 
101
+ const filteredListValues = hideListValues.filter((value: any) =>
102
+ value?.label?.toLowerCase().includes(searchTerm.toLowerCase())
103
+ );
104
+
165
105
  const sensors = useSensors(
166
106
  useSensor(MouseSensor),
167
107
  useSensor(TouchSensor),
168
108
  useSensor(KeyboardSensor)
169
109
  );
170
110
 
171
- // Drag and drop logic, update only local state
172
111
  const handleDragEnd = (event: DragEndEvent) => {
173
112
  const { active, over } = event;
174
- if (!over) {
175
- return;
176
- }
113
+ if (!over) return;
114
+
177
115
  const currentContainer = active.data.current?.containerId;
178
116
  const overContainer = over.data.current?.containerId;
179
117
  if (!currentContainer || !overContainer) return;
118
+
119
+ let newShowList = [...(quickTabStates.show_list ?? [])];
120
+ let newHideList = [...(quickTabStates.hide_list ?? [])];
121
+
180
122
  if (currentContainer === overContainer) {
181
- // Reorder within the same list
182
- let newShowList = [...(quickTabStates.show_list ?? [])];
183
- let newHideList = [...(quickTabStates.hide_list ?? [])];
184
- if (currentContainer === "list") {
185
- const oldIndex = newHideList.indexOf(String(active.id));
186
- const newIndex = newHideList.indexOf(String(over.id));
187
- if (oldIndex !== -1 && newIndex !== -1) {
188
- const [removed] = newHideList.splice(oldIndex, 1);
189
- newHideList.splice(newIndex, 0, removed);
190
- }
191
- } else {
192
- const oldIndex = newShowList.indexOf(String(active.id));
193
- const newIndex = newShowList.indexOf(String(over.id));
194
- if (oldIndex !== -1 && newIndex !== -1) {
195
- const [removed] = newShowList.splice(oldIndex, 1);
196
- newShowList.splice(newIndex, 0, removed);
197
- }
198
- }
123
+ const list = currentContainer === "list" ? newHideList : newShowList;
124
+ const oldIndex = list.indexOf(String(active.id));
125
+ const newIndex = list.indexOf(String(over.id));
199
126
 
200
- setSettingsData((prev) => ({
201
- ...prev,
202
- quick_tab: {
203
- ...prev?.quick_tab,
204
- show_list: newShowList,
205
- hide_list: newHideList,
206
- },
207
- }));
127
+ if (oldIndex !== -1 && newIndex !== -1) {
128
+ const [removed] = list.splice(oldIndex, 1);
129
+ list.splice(newIndex, 0, removed);
130
+ }
208
131
  } else {
209
- // Move between lists
210
- let newShowList = [...(quickTabStates.show_list ?? [])];
211
- let newHideList = [...(quickTabStates.hide_list ?? [])];
212
132
  if (currentContainer === "list" && overContainer === "lanes") {
213
- if (newShowList.length >= 5) return; // prevent overflow
214
- // Move from hide to show
215
-
216
133
  const idx = newHideList.indexOf(String(active.id));
217
134
  if (idx !== -1) {
218
135
  newHideList.splice(idx, 1);
219
136
  newShowList.push(String(active.id));
220
137
  }
221
138
  } else if (currentContainer === "lanes" && overContainer === "list") {
222
- // Move from show to hide
223
139
  const idx = newShowList.indexOf(String(active.id));
224
140
  if (idx !== -1) {
225
141
  newShowList.splice(idx, 1);
226
142
  newHideList.push(String(active.id));
227
143
  }
228
144
  }
229
-
230
- setSettingsData((prev) => ({
231
- ...prev,
232
- quick_tab: {
233
- ...prev?.quick_tab,
234
- show_list: newShowList,
235
- hide_list: newHideList,
236
- },
237
- }));
238
145
  }
239
- };
240
-
241
- const filteredListValues = hideListValues.filter((value: any) =>
242
- value?.label?.toLowerCase().includes(searchTerm.toLowerCase())
243
- );
244
-
245
- // Show All/Hide All logic (local only)
246
- const handleShowAll = () => {
247
- const currentShowList = quickTabStates.show_list || [];
248
- const currentHideList = quickTabStates.hide_list || [];
249
-
250
- const availableSlots = 5 - currentShowList.length;
251
-
252
- if (availableSlots <= 0) return; // Already at limit
253
-
254
- const limitedHideList = currentHideList.slice(0, availableSlots);
255
146
 
256
147
  setSettingsData((prev) => ({
257
148
  ...prev,
258
149
  quick_tab: {
259
150
  ...prev?.quick_tab,
260
- show_list: [...currentShowList, ...limitedHideList],
261
- hide_list: currentHideList.filter(
262
- (item: string) => !limitedHideList.includes(item)
263
- ),
151
+ show_list: newShowList,
152
+ hide_list: newHideList,
264
153
  },
265
154
  }));
266
155
  };
267
156
 
268
- const handleHideAll = () => {
157
+ const handleShowAll = () => {
269
158
  setSettingsData((prev) => ({
270
159
  ...prev,
271
160
  quick_tab: {
272
161
  ...prev?.quick_tab,
273
- hide_list: [
274
- ...(prev?.quick_tab?.hide_list || []),
162
+ show_list: [
275
163
  ...(prev?.quick_tab?.show_list || []),
164
+ ...(prev?.quick_tab?.hide_list || []),
276
165
  ],
277
- show_list: [],
166
+ hide_list: [],
278
167
  },
279
168
  }));
280
169
  };
281
170
 
282
- // Checkbox logic (local only)
283
- const handleShowSubLaneChange = (e: React.ChangeEvent<HTMLInputElement>) => {
284
- setSettingsData((prev) => ({
285
- ...prev,
286
- quick_tab: {
287
- ...prev?.quick_tab,
288
- showSubLane: e.target.checked,
289
- },
290
- }));
291
- };
292
-
293
- const handleShowColorColumnsChange = (
294
- e: React.ChangeEvent<HTMLInputElement>
295
- ) => {
171
+ const handleHideAll = () => {
296
172
  setSettingsData((prev) => ({
297
173
  ...prev,
298
174
  quick_tab: {
299
175
  ...prev?.quick_tab,
300
- showColorColumns: e.target.checked,
176
+ hide_list: [
177
+ ...(prev?.quick_tab?.hide_list || []),
178
+ ...(prev?.quick_tab?.show_list || []),
179
+ ],
180
+ show_list: [],
301
181
  },
302
182
  }));
303
183
  };
304
184
 
185
+ /* ---------- ITEM TOGGLE (UNCHANGED) ---------- */
305
186
  const handleItemToggle = (itemId: string, fromContainerId: string) => {
306
187
  const toShowList = [...(quickTabStates.show_list ?? [])];
307
188
  const toHideList = [...(quickTabStates.hide_list ?? [])];
308
189
 
309
190
  if (fromContainerId === "list") {
310
- if (toShowList.length >= 5) return; // prevent overflow
311
- // Move from hide_list to show_list
312
191
  const index = toHideList.indexOf(itemId);
313
192
  if (index > -1) {
314
193
  toHideList.splice(index, 1);
315
194
  toShowList.push(itemId);
316
195
  }
317
- } else if (fromContainerId === "lanes") {
318
- // Move from show_list to hide_list
196
+ } else {
319
197
  const index = toShowList.indexOf(itemId);
320
198
  if (index > -1) {
321
199
  toShowList.splice(index, 1);
@@ -333,176 +211,133 @@ const Lane = ({
333
211
  }));
334
212
  };
335
213
 
336
- const enableDND = quickTabStates?.sorting === "custom" ? true : false;
214
+ const enableDND = quickTabStates?.sorting === "custom";
337
215
 
216
+ /* ================== RENDER ================== */
338
217
  return (
339
- <Box
340
- sx={{
341
- display: "flex",
342
- flexDirection: "column",
343
- // gap: "0.5rem",
344
- height: "100%",
345
- }}
346
- >
218
+ <Box sx={{ display: "flex", flexDirection: "column", height: "100%" }}>
347
219
  <Typography variant="caption" sx={TabsStyles.mainTabsHeader}>
348
- *Quick filter settings will be reflected in vertical lanes
220
+ **Quick filter settings will be reflected in vertical lanes
349
221
  </Typography>
350
- <Box>
351
- <Grid sx={{ position: "relative" }} container>
222
+
223
+ <Grid sx={{ position: "relative" }} container>
224
+ {/* Attribute + Sort */}
225
+ <Grid size={12}>
226
+ <Grid sx={TabsStyles.mainTabDropdown} size={6}>
227
+ <FormControl sx={TabsStyles.mainTabSelect} size="small">
228
+ <Select
229
+ value={quickTabStates?.attribute || ""}
230
+ onChange={(e) =>
231
+ setSettingsData((prev) => ({
232
+ ...prev,
233
+ quick_tab: {
234
+ ...prev?.quick_tab,
235
+ attribute: e.target.value,
236
+ },
237
+ }))
238
+ }
239
+ >
240
+ {selectAttributeData?.map((lane: any) => (
241
+ <MenuItem key={lane?.key} value={lane?.value}>
242
+ {lane?.value}
243
+ </MenuItem>
244
+ ))}
245
+ </Select>
246
+ </FormControl>
247
+
248
+ <FormControl sx={TabsStyles.selectDropdownSeparator} size="small">
249
+ <Select
250
+ value={quickTabStates?.sorting || "asc"}
251
+ onChange={(e) =>
252
+ setSettingsData((prev) => ({
253
+ ...prev,
254
+ quick_tab: {
255
+ ...prev?.quick_tab,
256
+ sorting: e.target.value,
257
+ },
258
+ }))
259
+ }
260
+ >
261
+ {sortingOptions.map((option) => (
262
+ <MenuItem key={option.value} value={option.value}>
263
+ {option.label}
264
+ </MenuItem>
265
+ ))}
266
+ </Select>
267
+ </FormControl>
268
+ </Grid>
269
+ </Grid>
270
+
271
+ {/* Lists */}
272
+ <DndContext
273
+ sensors={sensors}
274
+ collisionDetection={closestCenter}
275
+ onDragEnd={handleDragEnd}
276
+ >
277
+ <Grid sx={{ mt: 2 }} container spacing={2} size={12}>
278
+ <ListingValues
279
+ buttonText="Show All"
280
+ onClick={handleShowAll}
281
+ headerText="List of Values"
282
+ filteredValues={filteredListValues}
283
+ searchTerm={searchTerm}
284
+ setSearchTerm={setSearchTerm}
285
+ containerId="list"
286
+ tabsApiDataLoading={tabsApiDataLoading}
287
+ onItemToggle={handleItemToggle}
288
+ enableDragAndDrop={enableDND}
289
+ />
290
+
291
+ <ListingValues
292
+ buttonText="Hide All"
293
+ onClick={handleHideAll}
294
+ headerText="View as Lanes"
295
+ filteredValues={showListValues}
296
+ containerId="lanes"
297
+ onItemToggle={handleItemToggle}
298
+ enableDragAndDrop={enableDND}
299
+ />
300
+ </Grid>
301
+ </DndContext>
302
+
303
+ {quickTabStates?.attribute === "Stage Group" && (
352
304
  <Grid size={12}>
353
- <Box>
354
- <Grid sx={TabsStyles.mainTabDropdown} size={6}>
355
- <FormControl sx={TabsStyles.mainTabSelect} size="small">
356
- <Select
357
- value={quickTabStates?.attribute || ""}
358
- onChange={(e) =>
359
- setSettingsData((prev) => ({
360
- ...prev,
361
- quick_tab: {
362
- ...prev?.quick_tab,
363
- attribute: e.target.value,
364
- },
365
- }))
366
- }
367
- displayEmpty
368
- renderValue={(selected) => {
369
- if (!selected) {
370
- return <em>Select Attribute</em>;
371
- }
372
- return selected;
373
- }}
374
- >
375
- {LANE_SELECTS?.map((lane: any) => (
376
- <MenuItem key={lane?.key} value={lane?.value}>
377
- {lane?.value}
378
- </MenuItem>
379
- ))}
380
- </Select>
381
- </FormControl>
382
- <FormControl
383
- sx={TabsStyles.selectDropdownSeparator}
384
- size="small"
385
- >
386
- <Select
387
- value={quickTabStates?.sorting || "asc"}
305
+ <Box sx={TabsStyles.checkboxStyle}>
306
+ <FormControlLabel
307
+ control={
308
+ <Checkbox
309
+ checked={quickTabStates?.showSubLane || false}
388
310
  onChange={(e) =>
389
311
  setSettingsData((prev) => ({
390
312
  ...prev,
391
313
  quick_tab: {
392
314
  ...prev?.quick_tab,
393
- sorting: e.target.value,
315
+ showSubLane: e.target.checked,
394
316
  },
395
317
  }))
396
318
  }
397
- displayEmpty
398
- renderValue={(selected) => {
399
- if (!selected) {
400
- return <em>Sort by</em>;
401
- }
402
- const option = sortingOptions.find(
403
- (opt) => opt.value === selected
404
- );
405
- return option?.label || selected;
406
- }}
407
- >
408
- {sortingOptions.map((option) => (
409
- <MenuItem key={option?.value} value={option?.value}>
410
- {option?.label}
411
- </MenuItem>
412
- ))}
413
- </Select>
414
- </FormControl>
415
- </Grid>
416
- </Box>
417
- </Grid>
418
- <Grid>
419
- {/* <Alert
420
- severity="info"
421
- sx={{
422
- fontSize: "12px",
423
- color: "#088AB2",
424
- }}
425
- >
426
- Please select at least 1 and at most 5 values to display as lanes.
427
- </Alert> */}
428
- </Grid>
429
- <DndContext
430
- sensors={sensors}
431
- collisionDetection={closestCenter}
432
- onDragEnd={handleDragEnd}
433
- >
434
- <Grid sx={{ mt: 2 }} container spacing={2} size={12}>
435
- <ListingValues
436
- buttonText="Show All"
437
- onClick={handleShowAll}
438
- headerText="List of Values"
439
- filteredValues={filteredListValues}
440
- searchTerm={searchTerm}
441
- setSearchTerm={setSearchTerm}
442
- containerId="list"
443
- tabsApiDataLoading={tabsApiDataLoading}
444
- onItemToggle={handleItemToggle}
445
- enableDragAndDrop={enableDND}
446
- />
447
- <ListingValues
448
- buttonText="Hide All"
449
- onClick={handleHideAll}
450
- headerText="View as Lanes"
451
- filteredValues={showListValues}
452
- containerId="lanes"
453
- // tabsApiDataLoading={tabsApiDataLoading}
454
- onItemToggle={handleItemToggle}
455
- enableDragAndDrop={enableDND}
456
- AlertComponenet={
457
- <InfoAlert
458
- message="Please select at least 1 and at most 5 values to display as
459
- lanes."
460
- width={"49%"}
461
- position="absolute"
462
- color="#088AB2"
463
- top={10}
464
- zIndex={1}
465
- />
466
- }
467
- />
468
- </Grid>
469
- </DndContext>
470
- <Grid size={12}>
471
- <Box sx={TabsStyles.checkboxStyle}>
472
- <FormControlLabel
473
- control={
474
- <Checkbox
475
- checked={quickTabStates?.showSubLane || false}
476
- onChange={handleShowSubLaneChange}
477
319
  size="small"
478
- sx={{
479
- "&.Mui-checked": {
480
- color: "#7A5AF8",
481
- },
482
- }}
483
320
  />
484
321
  }
485
322
  label="Show Sublane"
486
323
  />
487
- <FormControlLabel
488
- control={
489
- <Checkbox
490
- checked={quickTabStates?.showColorColumns || false}
491
- onChange={handleShowColorColumnsChange}
492
- size="small"
493
- sx={{
494
- "&.Mui-checked": {
495
- color: "#7A5AF8",
496
- },
497
- }}
498
- />
499
- }
500
- label="Show Color columns"
501
- />
502
324
  </Box>
503
325
  </Grid>
504
- </Grid>
505
- </Box>
326
+ )}
327
+
328
+ {quickTabStates?.attribute === "Stage Group" &&
329
+ quickTabStates?.showSubLane && (
330
+ <Grid size={12}>
331
+ <Grid sx={TabsStyles.mainTabDropdown} size={6}>
332
+ <FormControl sx={TabsStyles.mainTabSelect} size="small">
333
+ <Select value="Stage" disabled>
334
+ <MenuItem value="Stage">Stage</MenuItem>
335
+ </Select>
336
+ </FormControl>
337
+ </Grid>
338
+ </Grid>
339
+ )}
340
+ </Grid>
506
341
  </Box>
507
342
  );
508
343
  };
@@ -38,6 +38,7 @@ const QuickTab = ({
38
38
  tabsApiDataLoading,
39
39
  activeTab,
40
40
  columnTabAttributes,
41
+ isFlatJson,
41
42
  }: SettingsQuickTabProps) => {
42
43
  const {
43
44
  settingsData,
@@ -65,6 +66,10 @@ const QuickTab = ({
65
66
  // // tab?.tab_name?.label?.toLowerCase() == activeTab?.toLowerCase()
66
67
  // );
67
68
  // In case there is no quick tab state from API
69
+ const normalizeTabItem = (item: any) => ({
70
+ label: item.label,
71
+ value: isFlatJson ? item.label : item.value,
72
+ });
68
73
  useEffect(() => {
69
74
  const stateToArray =
70
75
  (quickTabStates && Object.entries(quickTabStates)) || [];
@@ -86,12 +91,14 @@ const QuickTab = ({
86
91
  useEffect(() => {
87
92
  if (currentQuickAttribute === settingsData?.quick_tab?.attribute) return;
88
93
 
94
+ const normalizedTabs = tabsApiData?.map(normalizeTabItem) || [];
95
+
89
96
  if (tabsApiData?.length) {
90
97
  setSettingsData((prev) => ({
91
98
  ...prev,
92
99
  quick_tab: {
93
100
  ...prev?.quick_tab,
94
- hide_list: tabsApiData,
101
+ hide_list: normalizedTabs,
95
102
  show_list: [],
96
103
  },
97
104
  }));
@@ -178,10 +185,14 @@ const QuickTab = ({
178
185
  // Convert show_list/hide_list to FilterValue[] for rendering only
179
186
 
180
187
  const constructHideList = () => {
181
- return tabsApiData?.filter(
182
- (tab) => !showListValues?.find((i) => i.value === tab.value)
188
+ const normalizedTabs = tabsApiData?.map(normalizeTabItem) || [];
189
+
190
+ // remove items already in show_list (value-safe comparison)
191
+ return normalizedTabs?.filter(
192
+ (tab) => !showListValues?.some((i) => i?.value === tab?.value)
183
193
  );
184
194
  };
195
+
185
196
  const showListValues = quickTabStates?.show_list || [];
186
197
  const hideListValues = constructHideList() || [];
187
198