@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
- function SearchDatePickerInput({ themeBgColor = "bg-sky-500", lightThemeBg = "bg-sky-100", pillColor = "bg-sky-500", textHighlight = "text-sky-700", dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, dropdownIconProp = {
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
- }, toggleStatus = false, setToggleStatus, selectedDate, onDateSelect, selectedStartDate, onStartDateSelect, selectedEndDate, onEndDateSelect, searchItems = [], setSearchItems, handleFilter, setSearchCriteria, column, setEditingHeader, localStorageKey = "searchCriteria", }) {
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
- // close datepickers on outside click
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
- // build single or range
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.toLocaleDateString()} - ${selectedEndDate.toLocaleDateString()}`;
97
+ return `${formatAsYMD(selectedStartDate)} - ${formatAsYMD(selectedEndDate)}`;
72
98
  }
73
99
  else if (selectedStartDate) {
74
- return `Start: ${selectedStartDate.toLocaleDateString()}`;
100
+ return `Start: ${formatAsYMD(selectedStartDate)}`;
75
101
  }
76
102
  else if (selectedEndDate) {
77
- return `End: ${selectedEndDate.toLocaleDateString()}`;
103
+ return `End: ${formatAsYMD(selectedEndDate)}`;
78
104
  }
79
105
  return "";
80
106
  }
81
- return selectedDate ? selectedDate.toLocaleDateString() : "";
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 for day picker
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 ? (_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
142
- ? selectedStartDate.toLocaleDateString()
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.toLocaleDateString()
145
- : "End Date" })] })) : (_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
146
- ? selectedDate.toLocaleDateString()
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: () => handleSearchBadgeClick(item), 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" })] })] }));
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;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agilant/toga-blox",
3
3
  "private": false,
4
- "version": "1.0.72",
4
+ "version": "1.0.73",
5
5
  "description": "",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",