@agilant/toga-blox 1.0.75 → 1.0.77
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.
- package/dist/components/SearchInput/SearchDropdownInput.js +4 -7
- package/dist/components/SearchInput/SearchInput.js +1 -1
- package/dist/components/SearchInput/SearchInput.test.js +12 -12
- package/dist/components/SearchInput/SearchInput.types.d.ts +6 -1
- package/dist/components/SearchInput/SearchInputDatePicker.js +4 -6
- package/dist/components/SearchInput/SearchNumberInput.d.ts +24 -1
- package/dist/components/SearchInput/SearchNumberInput.js +146 -24
- package/dist/components/SearchInput/SearchTextInput.js +4 -7
- package/dist/utils/updateLocalStorage.d.ts +2 -0
- package/dist/utils/updateLocalStorage.js +4 -0
- package/package.json +1 -1
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect } from "react";
|
|
3
3
|
import MultiSelectInput from "../MultiSelect/MultiSelect";
|
|
4
|
+
import updateLocalStorage from "../../utils/updateLocalStorage";
|
|
4
5
|
const DEFAULT_STORAGE_KEY = "searchCriteria";
|
|
5
6
|
const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, placeholder = "Select", disabled = false, hasSelectAll = true, bgColor = "bg-sky-500", textHighlight = "text-sky-700", handleFilter, searchItems = [], setSearchItems, setSearchCriteria, column, setEditingHeader, localStorageKey = DEFAULT_STORAGE_KEY, ...rest }) => {
|
|
6
7
|
// Are we able to store filters for this column?
|
|
7
8
|
const canStore = !!column?.id && !!setSearchCriteria;
|
|
8
|
-
/** Helper: write the entire searchCriteria array to localStorage */
|
|
9
|
-
const updateLocalStorage = (criteria) => {
|
|
10
|
-
localStorage.setItem(localStorageKey, JSON.stringify(criteria));
|
|
11
|
-
};
|
|
12
9
|
useEffect(() => {
|
|
13
10
|
if (!canStore)
|
|
14
11
|
return;
|
|
@@ -52,7 +49,7 @@ const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, place
|
|
|
52
49
|
if (isEmpty) {
|
|
53
50
|
setSearchCriteria?.((prev) => {
|
|
54
51
|
const newCriteria = prev.filter((c) => c.searchColumn.id !== column.id);
|
|
55
|
-
updateLocalStorage(newCriteria);
|
|
52
|
+
updateLocalStorage(newCriteria, localStorageKey);
|
|
56
53
|
return newCriteria;
|
|
57
54
|
});
|
|
58
55
|
}
|
|
@@ -66,7 +63,7 @@ const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, place
|
|
|
66
63
|
submittedSearchText: selectedLabels,
|
|
67
64
|
},
|
|
68
65
|
];
|
|
69
|
-
updateLocalStorage(newCriteria);
|
|
66
|
+
updateLocalStorage(newCriteria, localStorageKey);
|
|
70
67
|
return newCriteria;
|
|
71
68
|
});
|
|
72
69
|
}
|
|
@@ -78,7 +75,7 @@ const SearchDropdownInput = ({ options = [], selectedValue = [], onChange, place
|
|
|
78
75
|
if (canStore) {
|
|
79
76
|
setSearchCriteria?.((prev) => {
|
|
80
77
|
const newCriteria = prev.filter((c) => c.searchColumn.id !== column.id);
|
|
81
|
-
updateLocalStorage(newCriteria);
|
|
78
|
+
updateLocalStorage(newCriteria, localStorageKey);
|
|
82
79
|
return newCriteria;
|
|
83
80
|
});
|
|
84
81
|
setSearchItems?.([]);
|
|
@@ -19,7 +19,7 @@ const SearchInput = ({ bgColor = "bg-sky-500", textHighlight = "text-sky-500", i
|
|
|
19
19
|
case "text":
|
|
20
20
|
return (_jsx(SearchTextInput, { dropdownIconProp: dropdownIconProp, dropdownOptions: dropdownOptions, selectedDropdownOption: selectedDropdownOption, onDropdownOptionSelect: onDropdownOptionSelect, searchItems: searchItems, setSearchItems: setSearchItems, handleFilter: handleFilter, setSearchCriteria: setSearchCriteria, column: column, setEditingHeader: setEditingHeader, pillColor: pillColor, firstIconClasses: firstIconClasses }));
|
|
21
21
|
case "number":
|
|
22
|
-
return (_jsx(SearchNumberInput, { dropdownIconProp: dropdownIconProp, dropdownOptions: dropdownOptions, selectedDropdownOption: selectedDropdownOption, onDropdownOptionSelect: onDropdownOptionSelect, toggleStatus: toggleStatus, setToggleStatus: setToggleStatus, minValue: minValue, maxValue: maxValue, setMinValue: setMinValue, setMaxValue: setMaxValue, handleFilter: handleFilter }));
|
|
22
|
+
return (_jsx(SearchNumberInput, { dropdownIconProp: dropdownIconProp, dropdownOptions: dropdownOptions, selectedDropdownOption: selectedDropdownOption, onDropdownOptionSelect: onDropdownOptionSelect, toggleStatus: toggleStatus, setToggleStatus: setToggleStatus, minValue: minValue, maxValue: maxValue, setMinValue: setMinValue, setMaxValue: setMaxValue, handleFilter: handleFilter, setSearchCriteria: setSearchCriteria, column: column }));
|
|
23
23
|
case "multiSelect":
|
|
24
24
|
return (_jsx(SearchDropdownInput, { options: dropdownOptions, placeholder: "Search", additionalClasses: "", onChange: onChange, selectedValue: selectedValue, bgColor: bgColor, textHighlight: textHighlight, handleFilter: handleFilter, column: column, setSearchCriteria: setSearchCriteria }));
|
|
25
25
|
case "date":
|
|
@@ -191,13 +191,13 @@ describe("SearchInput Component", () => {
|
|
|
191
191
|
uuid: "1",
|
|
192
192
|
name: "Option 1",
|
|
193
193
|
value: "option1",
|
|
194
|
-
label: "Option 1",
|
|
194
|
+
// label: "Option 1",
|
|
195
195
|
},
|
|
196
196
|
{
|
|
197
197
|
uuid: "2",
|
|
198
198
|
name: "Option 2",
|
|
199
199
|
value: "option2",
|
|
200
|
-
label: "Option 2",
|
|
200
|
+
// label: "Option 2",
|
|
201
201
|
},
|
|
202
202
|
] }));
|
|
203
203
|
// Open dropdown
|
|
@@ -222,13 +222,13 @@ describe("SearchInput Component", () => {
|
|
|
222
222
|
uuid: "1",
|
|
223
223
|
name: "Option 1",
|
|
224
224
|
value: "option1",
|
|
225
|
-
label: "Option 1",
|
|
225
|
+
// label: "Option 1",
|
|
226
226
|
},
|
|
227
227
|
{
|
|
228
228
|
uuid: "2",
|
|
229
229
|
name: "Option 2",
|
|
230
230
|
value: "option2",
|
|
231
|
-
label: "Option 2",
|
|
231
|
+
// label: "Option 2",
|
|
232
232
|
},
|
|
233
233
|
] }));
|
|
234
234
|
const dropdown = screen.getByText(/Search/i);
|
|
@@ -245,13 +245,13 @@ describe("SearchInput Component", () => {
|
|
|
245
245
|
uuid: "1",
|
|
246
246
|
name: "Option 1",
|
|
247
247
|
value: "option1",
|
|
248
|
-
label: "Option 1",
|
|
248
|
+
// label: "Option 1",
|
|
249
249
|
},
|
|
250
250
|
{
|
|
251
251
|
uuid: "2",
|
|
252
252
|
name: "Option 2",
|
|
253
253
|
value: "option2",
|
|
254
|
-
label: "Option 2",
|
|
254
|
+
// label: "Option 2",
|
|
255
255
|
},
|
|
256
256
|
] }));
|
|
257
257
|
const dropdown = screen.getByText(/Search/i);
|
|
@@ -269,13 +269,13 @@ describe("SearchInput Component", () => {
|
|
|
269
269
|
uuid: "1",
|
|
270
270
|
name: "True",
|
|
271
271
|
value: "true",
|
|
272
|
-
label: "True",
|
|
272
|
+
// label: "True",
|
|
273
273
|
},
|
|
274
274
|
{
|
|
275
275
|
uuid: "2",
|
|
276
276
|
name: "False",
|
|
277
277
|
value: "false",
|
|
278
|
-
label: "False",
|
|
278
|
+
// label: "False",
|
|
279
279
|
},
|
|
280
280
|
] }));
|
|
281
281
|
expect(screen.getByText(/Search/i)).toBeInTheDocument();
|
|
@@ -286,13 +286,13 @@ describe("SearchInput Component", () => {
|
|
|
286
286
|
uuid: "1",
|
|
287
287
|
name: "True",
|
|
288
288
|
value: "true",
|
|
289
|
-
label: "True",
|
|
289
|
+
// label: "True",
|
|
290
290
|
},
|
|
291
291
|
{
|
|
292
292
|
uuid: "2",
|
|
293
293
|
name: "False",
|
|
294
294
|
value: "false",
|
|
295
|
-
label: "False",
|
|
295
|
+
// label: "False",
|
|
296
296
|
},
|
|
297
297
|
] }));
|
|
298
298
|
// Open dropdown
|
|
@@ -308,13 +308,13 @@ describe("SearchInput Component", () => {
|
|
|
308
308
|
uuid: "1",
|
|
309
309
|
name: "True",
|
|
310
310
|
value: "true",
|
|
311
|
-
label: "True",
|
|
311
|
+
// label: "True",
|
|
312
312
|
},
|
|
313
313
|
{
|
|
314
314
|
uuid: "2",
|
|
315
315
|
name: "False",
|
|
316
316
|
value: "false",
|
|
317
|
-
label: "False",
|
|
317
|
+
// label: "False",
|
|
318
318
|
},
|
|
319
319
|
] }));
|
|
320
320
|
// Open dropdown
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Control } from "react-hook-form";
|
|
3
|
+
export type MixedOption = string | {
|
|
4
|
+
uuid: string;
|
|
5
|
+
name: string;
|
|
6
|
+
value: string;
|
|
7
|
+
};
|
|
3
8
|
export type SearchInputProps<T extends object> = {
|
|
4
9
|
onChange(newSelected: OptionType[]): unknown;
|
|
5
10
|
selectedValue: any[];
|
|
@@ -8,7 +13,7 @@ export type SearchInputProps<T extends object> = {
|
|
|
8
13
|
bgColor?: string;
|
|
9
14
|
textHighlight?: string;
|
|
10
15
|
inputType?: "text" | "number" | "date" | "boolean" | "multiSelect";
|
|
11
|
-
dropdownOptions?:
|
|
16
|
+
dropdownOptions?: MixedOption[] | number[];
|
|
12
17
|
selectedDropdownOption?: string | OptionType | number;
|
|
13
18
|
onDropdownOptionSelect?: (option: string) => void;
|
|
14
19
|
dropdownIconProp?: searchDropdownIconProps;
|
|
@@ -8,6 +8,7 @@ import BaseButton from "../BaseButton";
|
|
|
8
8
|
import Badge from "../Badge/Badge";
|
|
9
9
|
import Text from "../Text";
|
|
10
10
|
import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
|
|
11
|
+
import updateLocalStorage from "../../utils/updateLocalStorage";
|
|
11
12
|
/**
|
|
12
13
|
* A helper to convert a Date object to 'YYYY-MM-DD'
|
|
13
14
|
* so we don't get slashes in the final string.
|
|
@@ -71,9 +72,6 @@ searchItems = [], setSearchItems, handleFilter, setSearchCriteria, column, setEd
|
|
|
71
72
|
document.addEventListener("mousedown", handleClickOutside);
|
|
72
73
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
73
74
|
}, []);
|
|
74
|
-
const updateLocalStorage = (criteria) => {
|
|
75
|
-
localStorage.setItem(localStorageKey, JSON.stringify(criteria));
|
|
76
|
-
};
|
|
77
75
|
/**
|
|
78
76
|
* Build a string in 'YYYY-MM-DD' (or range) format,
|
|
79
77
|
* so it won't break in your URL as "mm%2Fdd%2Fyyyy"
|
|
@@ -111,7 +109,7 @@ searchItems = [], setSearchItems, handleFilter, setSearchCriteria, column, setEd
|
|
|
111
109
|
if (canStore) {
|
|
112
110
|
setSearchCriteria?.((prev) => {
|
|
113
111
|
const newCriteria = prev.filter((c) => c.searchColumn.id !== column.id);
|
|
114
|
-
updateLocalStorage(newCriteria);
|
|
112
|
+
updateLocalStorage(newCriteria, localStorageKey);
|
|
115
113
|
return newCriteria;
|
|
116
114
|
});
|
|
117
115
|
}
|
|
@@ -130,7 +128,7 @@ searchItems = [], setSearchItems, handleFilter, setSearchCriteria, column, setEd
|
|
|
130
128
|
submittedSearchText: dateString,
|
|
131
129
|
},
|
|
132
130
|
];
|
|
133
|
-
updateLocalStorage(newCriteria);
|
|
131
|
+
updateLocalStorage(newCriteria, localStorageKey);
|
|
134
132
|
return newCriteria;
|
|
135
133
|
});
|
|
136
134
|
}
|
|
@@ -188,7 +186,7 @@ searchItems = [], setSearchItems, handleFilter, setSearchCriteria, column, setEd
|
|
|
188
186
|
setSearchCriteria?.((prev) => {
|
|
189
187
|
const filtered = prev.filter((crit) => crit.submittedSearchText !==
|
|
190
188
|
item);
|
|
191
|
-
updateLocalStorage(filtered);
|
|
189
|
+
updateLocalStorage(filtered, localStorageKey);
|
|
192
190
|
return filtered;
|
|
193
191
|
});
|
|
194
192
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { ColumnInstance } from "react-table";
|
|
2
3
|
import { searchDropdownIconProps } from "./SearchInput.types";
|
|
4
|
+
/** The parent can pass these props to replicate local-storage filter usage. */
|
|
3
5
|
type SearchNumberInputProps<T extends object> = {
|
|
4
6
|
pillColor?: string;
|
|
5
7
|
textHighlight?: string;
|
|
@@ -13,7 +15,28 @@ type SearchNumberInputProps<T extends object> = {
|
|
|
13
15
|
setMinValue?: React.Dispatch<React.SetStateAction<string>>;
|
|
14
16
|
maxValue?: string;
|
|
15
17
|
setMaxValue?: React.Dispatch<React.SetStateAction<string>>;
|
|
18
|
+
/** Called after we store or remove the filter in localStorage. */
|
|
16
19
|
handleFilter?: () => void;
|
|
20
|
+
/** The array of “badges” (previously added filters) for this column. */
|
|
21
|
+
searchItems?: string[];
|
|
22
|
+
setSearchItems?: React.Dispatch<React.SetStateAction<string[]>>;
|
|
23
|
+
/** The full array of all filters for the table. */
|
|
24
|
+
setSearchCriteria?: React.Dispatch<React.SetStateAction<any[]>>;
|
|
25
|
+
/** The column object must have an .id so we know which filter is ours. */
|
|
26
|
+
column?: ColumnInstance<any> | {
|
|
27
|
+
id: string;
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
};
|
|
30
|
+
/** If you want to close the popover or overlay once we filter/clear */
|
|
31
|
+
setEditingHeader?: React.Dispatch<React.SetStateAction<any>>;
|
|
32
|
+
/** localStorage key to store all the table’s filters (default "searchCriteria"). */
|
|
33
|
+
localStorageKey?: string;
|
|
17
34
|
};
|
|
18
|
-
|
|
35
|
+
/**
|
|
36
|
+
* A numeric filter component that:
|
|
37
|
+
* 1. Uses toggleStatus to switch single vs. range
|
|
38
|
+
* 2. On Filter => either remove or store a string in localStorage
|
|
39
|
+
* 3. On mount => read any existing filter for this column, parse, and set min/max
|
|
40
|
+
*/
|
|
41
|
+
declare const SearchNumberInput: <T extends object>({ textHighlight, dropdownIconProp, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, toggleStatus, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue, handleFilter, searchItems, setSearchItems, setSearchCriteria, column, setEditingHeader, localStorageKey, }: SearchNumberInputProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
19
42
|
export default SearchNumberInput;
|
|
@@ -1,41 +1,163 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef } from "react";
|
|
2
|
+
import { useEffect, useRef, useCallback } from "react";
|
|
3
3
|
import { Input } from "../Input";
|
|
4
4
|
import Dropdown from "../Dropdown/Dropdown";
|
|
5
5
|
import ToggleButton from "../ToggleButton/ToggleButton";
|
|
6
6
|
import BaseButton from "../BaseButton";
|
|
7
7
|
import Text from "../Text";
|
|
8
|
+
const DEFAULT_STORAGE_KEY = "searchCriteria";
|
|
9
|
+
/**
|
|
10
|
+
* A numeric filter component that:
|
|
11
|
+
* 1. Uses toggleStatus to switch single vs. range
|
|
12
|
+
* 2. On Filter => either remove or store a string in localStorage
|
|
13
|
+
* 3. On mount => read any existing filter for this column, parse, and set min/max
|
|
14
|
+
*/
|
|
8
15
|
const SearchNumberInput = ({ textHighlight = "text-sky-500", dropdownIconProp = {
|
|
9
|
-
iconClasses:
|
|
16
|
+
iconClasses: "text-sky-500",
|
|
10
17
|
name: "chevronDown",
|
|
11
18
|
weight: "solid",
|
|
12
|
-
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, toggleStatus, setToggleStatus, minValue, setMinValue, maxValue, setMaxValue, handleFilter,
|
|
19
|
+
}, dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, toggleStatus = false, setToggleStatus, minValue = "", setMinValue, maxValue = "", setMaxValue, handleFilter,
|
|
20
|
+
// local-storage
|
|
21
|
+
searchItems = [], setSearchItems, setSearchCriteria, column, setEditingHeader, localStorageKey = DEFAULT_STORAGE_KEY, }) => {
|
|
13
22
|
const containerRef = useRef(null);
|
|
14
23
|
const inputRef = useRef(null);
|
|
15
|
-
|
|
24
|
+
/** Decide if we can store for this column */
|
|
25
|
+
const canStore = !!column?.id && !!setSearchCriteria;
|
|
26
|
+
/** On mount, read localStorage once => if there's a saved filter => parse & set */
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (!canStore)
|
|
29
|
+
return;
|
|
30
|
+
// Make sure this runs only once
|
|
31
|
+
const stored = localStorage.getItem(localStorageKey);
|
|
32
|
+
if (!stored)
|
|
33
|
+
return;
|
|
34
|
+
try {
|
|
35
|
+
const parsed = JSON.parse(stored);
|
|
36
|
+
const existing = parsed.find((c) => c.searchColumn?.id === column?.id);
|
|
37
|
+
if (existing) {
|
|
38
|
+
const savedString = existing.submittedSearchText;
|
|
39
|
+
if (savedString && typeof savedString === "string") {
|
|
40
|
+
if (savedString.includes(" - ")) {
|
|
41
|
+
// It's a range: "100 - 200"
|
|
42
|
+
setToggleStatus?.(true);
|
|
43
|
+
const [minPart, maxPart] = savedString.split(" - ");
|
|
44
|
+
setMinValue?.(minPart.trim());
|
|
45
|
+
setMaxValue?.(maxPart.trim());
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Single e.g. "Exactly 123" or "default 2" or just "2"
|
|
49
|
+
setToggleStatus?.(false);
|
|
50
|
+
const segments = savedString.split(" ");
|
|
51
|
+
// If the first word is in your dropdown => use it, else treat as pure number
|
|
52
|
+
if (segments.length > 1 &&
|
|
53
|
+
dropdownOptions.includes(segments[0])) {
|
|
54
|
+
onDropdownOptionSelect?.(segments[0]);
|
|
55
|
+
setMinValue?.(segments[1]);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// no prefix => assume it's just the number
|
|
59
|
+
setMinValue?.(savedString);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Also set searchItems so the "badge" might show
|
|
63
|
+
setSearchItems?.([savedString]);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
console.error("Error reading stored number filter:", err);
|
|
69
|
+
}
|
|
70
|
+
// empty dependency array => only once on mount
|
|
71
|
+
}, []);
|
|
72
|
+
/** Focus on mount if needed */
|
|
16
73
|
useEffect(() => {
|
|
17
74
|
inputRef.current?.focus();
|
|
18
75
|
}, []);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Build the final string to store.
|
|
78
|
+
*
|
|
79
|
+
* 1) If toggleStatus => "minValue - maxValue"
|
|
80
|
+
* 2) If single => skip "default" prefix
|
|
81
|
+
*/
|
|
82
|
+
const buildNumberString = useCallback(() => {
|
|
83
|
+
if (toggleStatus) {
|
|
84
|
+
// Range mode => "min - max"
|
|
85
|
+
if (minValue && maxValue) {
|
|
86
|
+
return `${minValue} - ${maxValue}`;
|
|
87
|
+
}
|
|
88
|
+
else if (minValue) {
|
|
89
|
+
return `${minValue} - `;
|
|
90
|
+
}
|
|
91
|
+
else if (maxValue) {
|
|
92
|
+
return ` - ${maxValue}`;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
return ""; // no input => empty
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// Single value mode => e.g. "Exactly 123" or "2"
|
|
100
|
+
const prefix = selectedDropdownOption?.toLowerCase() === "default"
|
|
101
|
+
? "" // if your dropdown used "default" for something
|
|
102
|
+
: selectedDropdownOption;
|
|
103
|
+
if (prefix && minValue) {
|
|
104
|
+
return `${prefix} ${minValue}`;
|
|
105
|
+
}
|
|
106
|
+
else if (minValue) {
|
|
107
|
+
return minValue; // fallback
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
return "";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}, [toggleStatus, minValue, maxValue, selectedDropdownOption]);
|
|
114
|
+
/**
|
|
115
|
+
* Called when user clicks "Filter" button at the bottom.
|
|
116
|
+
* We remove or store the built string, then call handleFilter.
|
|
117
|
+
*/
|
|
118
|
+
const handleFilterClick = () => {
|
|
119
|
+
const finalString = buildNumberString().trim();
|
|
120
|
+
if (!finalString) {
|
|
121
|
+
// remove existing filter for this column
|
|
122
|
+
if (canStore) {
|
|
123
|
+
setSearchCriteria?.((prev) => {
|
|
124
|
+
const newCriteria = prev.filter((c) => c.searchColumn.id !== column?.id);
|
|
125
|
+
localStorage.setItem(localStorageKey, JSON.stringify(newCriteria));
|
|
126
|
+
return newCriteria;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
// store it
|
|
132
|
+
if (!searchItems.includes(finalString)) {
|
|
133
|
+
setSearchItems?.([...searchItems, finalString]);
|
|
134
|
+
}
|
|
135
|
+
if (canStore) {
|
|
136
|
+
setSearchCriteria?.((prev) => {
|
|
137
|
+
// remove old for this column if you want only one number filter per column
|
|
138
|
+
const filtered = prev.filter((c) => c.searchColumn.id !== column?.id);
|
|
139
|
+
const newCriteria = [
|
|
140
|
+
...filtered,
|
|
141
|
+
{
|
|
142
|
+
searchColumn: column,
|
|
143
|
+
submittedSearchText: finalString,
|
|
144
|
+
},
|
|
145
|
+
];
|
|
146
|
+
localStorage.setItem(localStorageKey, JSON.stringify(newCriteria));
|
|
147
|
+
return newCriteria;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Optionally close the popover
|
|
152
|
+
setEditingHeader?.(null);
|
|
153
|
+
// Let the parent know a filter was applied
|
|
154
|
+
handleFilter?.();
|
|
24
155
|
};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return (_jsx("div", { ref: containerRef, className: "w-[425px]", children: _jsxs("div", { className: `flex flex-col p-4 h-[130px] border-2 border-navy-200 rounded-md`, children: [_jsx("div", { className: `flex flex-[1] ${toggleStatus ? "" : "border-2"} h-full max-h-11 items-center justify-around`, children: toggleStatus ? (_jsxs(_Fragment, { children: [_jsx(Input, { focusRingColor: "focus:ring-2", hasAutoFocus: true, value: minValue, iconColor: "text-navy-400",
|
|
32
|
-
// onKeyDown={handleKeyDown}
|
|
33
|
-
required: false, id: "", name: "", type: "number", onChange: handleInputChange, additionalClasses: "min-w-[180px] max-w-[180px] h-10 text-gray flex focus:border-l-2 ", placeholder: "Min" }), _jsx(Text, { size: "text-md", tag: "span", text: "to", additionalClasses: "px-2" }), _jsx(Input, { focusRingColor: "focus:ring-2", value: maxValue, iconColor: "text-navy-400",
|
|
34
|
-
// onKeyDown={handleKeyDown}
|
|
35
|
-
required: false, id: "", name: "", type: "number", onChange: handleMaximumInputChange, additionalClasses: "min-w-[180px] max-w-[180px] h-10 text-gray flex border-2 focus:border-l-2 focus:border- ", placeholder: "Max", hasIcons: true, iconPosition: "both" })] })) : (_jsxs(_Fragment, { children: [_jsx(Dropdown, { options: dropdownOptions, selectedOption: selectedDropdownOption, onOptionSelect: onDropdownOptionSelect, optionClasses: "px-4 h-full flex items-center", menuClasses: "bg-white w-min-[150px] top-[-8px] left-[-2px]", dropdownClasses: "border-0 w-auto", icon: dropdownIconProp }), _jsx(Input, { focusRingColor: "focus:ring-transparent", hasAutoFocus: true, value: minValue, iconColor: "text-navy-400",
|
|
36
|
-
// onKeyDown={handleKeyDown}
|
|
37
|
-
required: false, id: "", name: "", type: "number", onChange: handleInputChange, additionalClasses: "min-w-[200px] h-10 text-gray flex border-l-2 ", placeholder: "Amount", hasIcons: true, iconPosition: "both" })] })) }), _jsxs("div", { className: "flex flex-[1] justify-between items-end bg-white px-2 ", children: [_jsx(ToggleButton, { initialStatus: toggleStatus, onClick: () => {
|
|
38
|
-
setToggleStatus(!toggleStatus);
|
|
39
|
-
}, activeColorBackground: "bg-sky-500", activeColorBorder: "border-sky-500", activeLabel: "Range", activeTextColor: "text-sky-500", additionalClasses: "flex items-center", inactiveColorBackground: "bg-gray-300", inactiveColorBorder: "border-gray-300", inactiveLabel: "Range", inactiveTextColor: "text-gray-500", pillHeight: "h-8", textPosition: "right", textSize: "text-sm", smallToggle: false, borderStyle: false }), _jsx(BaseButton, { text: "Filter", backgroundColor: "bg-sky-500", additionalClasses: "py-1.5 px-6 text-white", borderColor: "border-none", onClick: handleFilter, shape: "rounded-full" })] })] }) }));
|
|
156
|
+
return (_jsx("div", { ref: containerRef, className: "w-[425px]", children: _jsxs("div", { className: "flex flex-col p-4 h-[130px] border-2 border-navy-200 rounded-md", children: [_jsx("div", { className: `flex flex-[1] ${toggleStatus ? "" : "border-2"}
|
|
157
|
+
h-full max-h-11 items-center justify-around`, children: toggleStatus ? (
|
|
158
|
+
// Range mode
|
|
159
|
+
_jsxs(_Fragment, { children: [_jsx(Input, { focusRingColor: "focus:ring-2", hasAutoFocus: true, value: minValue, iconColor: "text-navy-400", required: false, id: "", name: "", type: "number", onChange: (e) => setMinValue?.(e.target.value), additionalClasses: "min-w-[180px] max-w-[180px] h-10 text-gray flex focus:border-l-2 ", placeholder: "Min" }), _jsx(Text, { size: "text-md", tag: "span", text: "to", additionalClasses: "px-2" }), _jsx(Input, { focusRingColor: "focus:ring-2", value: maxValue, iconColor: "text-navy-400", required: false, id: "", name: "", type: "number", onChange: (e) => setMaxValue?.(e.target.value), additionalClasses: "min-w-[180px] max-w-[180px] h-10 text-gray flex border-2 focus:border-l-2 ", placeholder: "Max" })] })) : (
|
|
160
|
+
// Single value mode
|
|
161
|
+
_jsxs(_Fragment, { children: [_jsx(Dropdown, { options: dropdownOptions, selectedOption: selectedDropdownOption, onOptionSelect: onDropdownOptionSelect, optionClasses: "px-4 h-full flex items-center", menuClasses: "bg-white w-min-[150px] top-[-8px] left-[-2px]", dropdownClasses: "border-0 w-auto", icon: dropdownIconProp }), _jsx(Input, { ref: inputRef, focusRingColor: "focus:ring-transparent", hasAutoFocus: true, value: minValue, iconColor: "text-navy-400", required: false, id: "", name: "", type: "number", onChange: (e) => setMinValue?.(e.target.value), additionalClasses: "min-w-[200px] h-10 text-gray flex border-l-2 ", placeholder: "Amount", hasIcons: true, iconPosition: "both" })] })) }), _jsxs("div", { className: "flex flex-[1] justify-between items-end bg-white px-2", children: [_jsx(ToggleButton, { initialStatus: toggleStatus, onClick: () => setToggleStatus?.(!toggleStatus), activeColorBackground: "bg-sky-500", activeColorBorder: "border-sky-500", activeLabel: "Range", activeTextColor: "text-sky-500", additionalClasses: "flex items-center", inactiveColorBackground: "bg-gray-300", inactiveColorBorder: "border-gray-300", inactiveLabel: "Range", inactiveTextColor: "text-gray-500", pillHeight: "h-8", textPosition: "right", textSize: "text-sm", smallToggle: false, borderStyle: false }), _jsx(BaseButton, { text: "Filter", backgroundColor: "bg-sky-500", additionalClasses: "py-1.5 px-6 text-white", borderColor: "border-none", onClick: handleFilterClick, shape: "rounded-full" })] })] }) }));
|
|
40
162
|
};
|
|
41
163
|
export default SearchNumberInput;
|
|
@@ -6,6 +6,7 @@ import { getFontAwesomeIcon } from "../../utils/getFontAwesomeIcon";
|
|
|
6
6
|
import Dropdown from "../Dropdown/Dropdown";
|
|
7
7
|
import Badge from "../Badge/Badge";
|
|
8
8
|
import Text from "../Text";
|
|
9
|
+
import updateLocalStorage from "../../utils/updateLocalStorage";
|
|
9
10
|
const SearchTextInput = ({ pillColor = "bg-sky-500", textHighlight = "text-sky-500", dropdownIconProp = {
|
|
10
11
|
iconClasses: textHighlight,
|
|
11
12
|
name: "chevronDown",
|
|
@@ -31,10 +32,6 @@ const SearchTextInput = ({ pillColor = "bg-sky-500", textHighlight = "text-sky-5
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
}, [column.id, localStorageKey]);
|
|
34
|
-
// Helper to update local storage.
|
|
35
|
-
const updateLocalStorage = (criteria) => {
|
|
36
|
-
localStorage.setItem(localStorageKey, JSON.stringify(criteria));
|
|
37
|
-
};
|
|
38
35
|
const handleInputChange = (event) => {
|
|
39
36
|
setLocalSearchText(event.target.value);
|
|
40
37
|
};
|
|
@@ -46,7 +43,7 @@ const SearchTextInput = ({ pillColor = "bg-sky-500", textHighlight = "text-sky-5
|
|
|
46
43
|
// Remove corresponding criterion from searchCriteria.
|
|
47
44
|
setSearchCriteria((prev) => {
|
|
48
45
|
const newCriteria = prev.filter((crit) => crit.submittedSearchText !== item);
|
|
49
|
-
updateLocalStorage(newCriteria);
|
|
46
|
+
updateLocalStorage(newCriteria, localStorageKey);
|
|
50
47
|
console.log("Removed badge criterion, newCriteria:", newCriteria);
|
|
51
48
|
return newCriteria;
|
|
52
49
|
});
|
|
@@ -70,7 +67,7 @@ const SearchTextInput = ({ pillColor = "bg-sky-500", textHighlight = "text-sky-5
|
|
|
70
67
|
// Remove any criteria for this column.
|
|
71
68
|
setSearchCriteria((prev) => {
|
|
72
69
|
const newCriteria = prev.filter((c) => c.searchColumn.id !== column.id);
|
|
73
|
-
updateLocalStorage(newCriteria);
|
|
70
|
+
updateLocalStorage(newCriteria, localStorageKey);
|
|
74
71
|
console.log("Removed criterion, newCriteria:", newCriteria);
|
|
75
72
|
return newCriteria;
|
|
76
73
|
});
|
|
@@ -82,7 +79,7 @@ const SearchTextInput = ({ pillColor = "bg-sky-500", textHighlight = "text-sky-5
|
|
|
82
79
|
...prev,
|
|
83
80
|
{ searchColumn: column, submittedSearchText: trimmed },
|
|
84
81
|
];
|
|
85
|
-
updateLocalStorage(newCriteria);
|
|
82
|
+
updateLocalStorage(newCriteria, localStorageKey);
|
|
86
83
|
console.log("Appended criterion, newCriteria:", newCriteria);
|
|
87
84
|
return newCriteria;
|
|
88
85
|
});
|