@agilant/toga-blox 1.0.72 → 1.0.73
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.
|
@@ -8,11 +8,34 @@ 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
|
-
|
|
11
|
+
/**
|
|
12
|
+
* A helper to convert a Date object to 'YYYY-MM-DD'
|
|
13
|
+
* so we don't get slashes in the final string.
|
|
14
|
+
*/
|
|
15
|
+
function formatAsYMD(date) {
|
|
16
|
+
if (!date)
|
|
17
|
+
return "";
|
|
18
|
+
// date.toISOString() is 'YYYY-MM-DDTHH:mm:ss.sssZ'
|
|
19
|
+
// slice(0,10) => 'YYYY-MM-DD'
|
|
20
|
+
return date.toISOString().slice(0, 10);
|
|
21
|
+
}
|
|
22
|
+
function SearchDatePickerInput({
|
|
23
|
+
// theming
|
|
24
|
+
themeBgColor = "bg-sky-500", lightThemeBg = "bg-sky-100",
|
|
25
|
+
// style/config
|
|
26
|
+
pillColor = "bg-sky-500", textHighlight = "text-sky-700", dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, dropdownIconProp = {
|
|
12
27
|
iconClasses: "text-sky-500",
|
|
13
28
|
name: "chevronDown",
|
|
14
29
|
weight: "solid",
|
|
15
|
-
},
|
|
30
|
+
},
|
|
31
|
+
// toggle
|
|
32
|
+
toggleStatus = false, setToggleStatus,
|
|
33
|
+
// single date
|
|
34
|
+
selectedDate, onDateSelect,
|
|
35
|
+
// range
|
|
36
|
+
selectedStartDate, onStartDateSelect, selectedEndDate, onEndDateSelect,
|
|
37
|
+
// local-storage logic
|
|
38
|
+
searchItems = [], setSearchItems, handleFilter, setSearchCriteria, column, setEditingHeader, localStorageKey = "searchCriteria", }) {
|
|
16
39
|
const containerRef = useRef(null);
|
|
17
40
|
const [isDatePickerOpen, setIsDatePickerOpen] = useState(false);
|
|
18
41
|
const [activeInput, setActiveInput] = useState(null);
|
|
@@ -27,6 +50,7 @@ function SearchDatePickerInput({ themeBgColor = "bg-sky-500", lightThemeBg = "bg
|
|
|
27
50
|
const parsed = JSON.parse(stored);
|
|
28
51
|
const existing = parsed.find((criterion) => criterion.searchColumn.id === column.id);
|
|
29
52
|
if (existing && setSearchItems) {
|
|
53
|
+
// e.g. "2025-02-27" or "2024-12-01 - 2024-12-28"
|
|
30
54
|
setSearchItems([existing.submittedSearchText]);
|
|
31
55
|
}
|
|
32
56
|
}
|
|
@@ -35,7 +59,7 @@ function SearchDatePickerInput({ themeBgColor = "bg-sky-500", lightThemeBg = "bg
|
|
|
35
59
|
}
|
|
36
60
|
}
|
|
37
61
|
}, [canStore, column?.id, localStorageKey, setSearchItems]);
|
|
38
|
-
//
|
|
62
|
+
// Close date pickers on outside click
|
|
39
63
|
useEffect(() => {
|
|
40
64
|
function handleClickOutside(e) {
|
|
41
65
|
if (containerRef.current &&
|
|
@@ -45,9 +69,7 @@ function SearchDatePickerInput({ themeBgColor = "bg-sky-500", lightThemeBg = "bg
|
|
|
45
69
|
}
|
|
46
70
|
}
|
|
47
71
|
document.addEventListener("mousedown", handleClickOutside);
|
|
48
|
-
return () =>
|
|
49
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
50
|
-
};
|
|
72
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
51
73
|
}, []);
|
|
52
74
|
const updateLocalStorage = (criteria) => {
|
|
53
75
|
localStorage.setItem(localStorageKey, JSON.stringify(criteria));
|
|
@@ -64,30 +86,40 @@ function SearchDatePickerInput({ themeBgColor = "bg-sky-500", lightThemeBg = "bg
|
|
|
64
86
|
});
|
|
65
87
|
}
|
|
66
88
|
};
|
|
67
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Build a string in 'YYYY-MM-DD' (or range) format,
|
|
91
|
+
* so it won't break in your URL as "mm%2Fdd%2Fyyyy"
|
|
92
|
+
*/
|
|
68
93
|
const buildDateString = () => {
|
|
69
94
|
if (toggleStatus) {
|
|
95
|
+
// range mode
|
|
70
96
|
if (selectedStartDate && selectedEndDate) {
|
|
71
|
-
return `${selectedStartDate
|
|
97
|
+
return `${formatAsYMD(selectedStartDate)} - ${formatAsYMD(selectedEndDate)}`;
|
|
72
98
|
}
|
|
73
99
|
else if (selectedStartDate) {
|
|
74
|
-
return `Start: ${selectedStartDate
|
|
100
|
+
return `Start: ${formatAsYMD(selectedStartDate)}`;
|
|
75
101
|
}
|
|
76
102
|
else if (selectedEndDate) {
|
|
77
|
-
return `End: ${selectedEndDate
|
|
103
|
+
return `End: ${formatAsYMD(selectedEndDate)}`;
|
|
78
104
|
}
|
|
79
105
|
return "";
|
|
80
106
|
}
|
|
81
|
-
|
|
107
|
+
else {
|
|
108
|
+
// single-date mode
|
|
109
|
+
return selectedDate ? formatAsYMD(selectedDate) : "";
|
|
110
|
+
}
|
|
82
111
|
};
|
|
83
112
|
/**
|
|
84
113
|
* If empty => remove all queries for col
|
|
85
114
|
* If non-empty => APPEND
|
|
86
115
|
* (do NOT filter out old queries for that column)
|
|
116
|
+
*
|
|
117
|
+
* But now the stored string is "YYYY-MM-DD" or "YYYY-MM-DD - YYYY-MM-DD"
|
|
87
118
|
*/
|
|
88
119
|
const handleFilterClick = () => {
|
|
89
120
|
const dateString = buildDateString().trim();
|
|
90
121
|
if (!dateString) {
|
|
122
|
+
// remove existing for col
|
|
91
123
|
if (canStore) {
|
|
92
124
|
setSearchCriteria?.((prev) => {
|
|
93
125
|
const newCriteria = prev.filter((c) => c.searchColumn.id !== column.id);
|
|
@@ -97,12 +129,12 @@ function SearchDatePickerInput({ themeBgColor = "bg-sky-500", lightThemeBg = "bg
|
|
|
97
129
|
}
|
|
98
130
|
}
|
|
99
131
|
else {
|
|
132
|
+
// append
|
|
100
133
|
if (!searchItems.includes(dateString)) {
|
|
101
134
|
setSearchItems?.([...searchItems, dateString]);
|
|
102
135
|
}
|
|
103
136
|
if (canStore) {
|
|
104
137
|
setSearchCriteria?.((prev) => {
|
|
105
|
-
// KEY: no filtering out old queries => we let them accumulate
|
|
106
138
|
const newCriteria = [
|
|
107
139
|
...prev,
|
|
108
140
|
{
|
|
@@ -120,7 +152,7 @@ function SearchDatePickerInput({ themeBgColor = "bg-sky-500", lightThemeBg = "bg
|
|
|
120
152
|
setIsDatePickerOpen(false);
|
|
121
153
|
setActiveInput(null);
|
|
122
154
|
};
|
|
123
|
-
// styling
|
|
155
|
+
// DayPicker styling
|
|
124
156
|
const modifiersClassNames = {
|
|
125
157
|
selected: `${themeBgColor} text-white rounded-full`,
|
|
126
158
|
today: `${lightThemeBg} ${textHighlight}`,
|
|
@@ -138,12 +170,16 @@ function SearchDatePickerInput({ themeBgColor = "bg-sky-500", lightThemeBg = "bg
|
|
|
138
170
|
setActiveInput(null);
|
|
139
171
|
setIsDatePickerOpen((prev) => !prev);
|
|
140
172
|
};
|
|
141
|
-
return (_jsxs("div", { ref: containerRef, className: "relative w-[425px] border-2 p-4", children: [_jsx("div", { className: "flex items-center justify-between h-12 mb-2", children: toggleStatus ? (
|
|
142
|
-
|
|
173
|
+
return (_jsxs("div", { ref: containerRef, className: "relative w-[425px] border-2 p-4", children: [_jsx("div", { className: "flex items-center justify-between h-12 mb-2", children: toggleStatus ? (
|
|
174
|
+
// Range mode
|
|
175
|
+
_jsxs("div", { className: "flex items-center w-full", children: [_jsx("button", { onClick: openStartPicker, className: "border-2 px-3 py-2 flex-1 h-10 text-left", children: selectedStartDate
|
|
176
|
+
? formatAsYMD(selectedStartDate)
|
|
143
177
|
: "Start Date" }), _jsx("span", { className: "mx-2", children: "to" }), _jsx("button", { onClick: openEndPicker, className: "border-2 px-3 py-2 flex-1 h-10 text-left", children: selectedEndDate
|
|
144
|
-
? selectedEndDate
|
|
145
|
-
: "End Date" })] })) : (
|
|
146
|
-
|
|
178
|
+
? formatAsYMD(selectedEndDate)
|
|
179
|
+
: "End Date" })] })) : (
|
|
180
|
+
// Single-date mode
|
|
181
|
+
_jsxs(_Fragment, { children: [_jsx(Dropdown, { options: dropdownOptions, selectedOption: selectedDropdownOption, onOptionSelect: onDropdownOptionSelect, optionClasses: "px-4 h-full flex items-center", menuClasses: "bg-white min-w-[150px] top-[-8px] left-[-2px]", dropdownClasses: "border-2 border-r-0 flex-[1] h-10 w-auto", icon: dropdownIconProp }), _jsx("button", { onClick: openSinglePicker, className: "border-2 px-3 py-2 flex-[2] h-10 text-left min-w-40", children: selectedDate
|
|
182
|
+
? formatAsYMD(selectedDate)
|
|
147
183
|
: "Select Date" })] })) }), toggleStatus
|
|
148
184
|
? activeInput && (_jsx("div", { className: "absolute p-4 top-16 w-auto z-50 shadow-lg bg-white", children: activeInput === "start" ? (_jsx(DayPicker, { mode: "single", selected: selectedStartDate, onSelect: (day) => {
|
|
149
185
|
onStartDateSelect?.(day || undefined);
|
|
@@ -156,6 +192,17 @@ function SearchDatePickerInput({ themeBgColor = "bg-sky-500", lightThemeBg = "bg
|
|
|
156
192
|
}, modifiersClassNames: modifiersClassNames })) }))
|
|
157
193
|
: isDatePickerOpen && (_jsx("div", { className: "absolute p-4 top-16 w-auto z-50 shadow-lg bg-white", children: _jsx(DayPicker, { mode: "single", selected: selectedDate, onSelect: (day) => {
|
|
158
194
|
onDateSelect?.(day || undefined);
|
|
159
|
-
}, modifiersClassNames: modifiersClassNames }) })), searchItems?.length ? (_jsx("div", { className: "flex flex-wrap bg-white py-2 px-2 mt-2 rounded-md", children: searchItems.map((item, index) => (_jsx(Badge, { backgroundColor: pillColor, borderRadius: "rounded-full", hasRightIcon: true, icon: _jsx("div", { className: "text-white text-xxs", children: getFontAwesomeIcon("xmark", "solid") }), iconSize: "text-sm", mobileIconLabel: item, onClick: () =>
|
|
195
|
+
}, modifiersClassNames: modifiersClassNames }) })), searchItems?.length ? (_jsx("div", { className: "flex flex-wrap bg-white py-2 px-2 mt-2 rounded-md", children: searchItems.map((item, index) => (_jsx(Badge, { backgroundColor: pillColor, borderRadius: "rounded-full", hasRightIcon: true, icon: _jsx("div", { className: "text-white text-xxs", children: getFontAwesomeIcon("xmark", "solid") }), iconSize: "text-sm", mobileIconLabel: item, onClick: () => {
|
|
196
|
+
const newSearchItems = searchItems.filter((x) => x !== item);
|
|
197
|
+
setSearchItems?.(newSearchItems);
|
|
198
|
+
if (canStore) {
|
|
199
|
+
setSearchCriteria?.((prev) => {
|
|
200
|
+
const filtered = prev.filter((crit) => crit.submittedSearchText !==
|
|
201
|
+
item);
|
|
202
|
+
updateLocalStorage(filtered);
|
|
203
|
+
return filtered;
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}, text: _jsx(Text, { color: "text-white", fontFamily: "font-serif", size: "text-sm", tag: "span", text: item }), badgeContainerClasses: `${pillColor} p-1 max-w-fit min-w-20 rounded-full flex justify-between items-center text-white text-xs px-4 border-none mr-4 mb-1`, type: "span" }, index))) })) : null, _jsxs("div", { className: "flex justify-between items-end bg-white px-2 rounded-md mt-4", 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" })] })] }));
|
|
160
207
|
}
|
|
161
208
|
export default SearchDatePickerInput;
|