@snapdragonsnursery/react-components 1.19.7 → 1.20.0
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/package.json
CHANGED
package/src/ChildSearchModal.jsx
CHANGED
|
@@ -57,6 +57,7 @@ const ChildSearchModal = ({
|
|
|
57
57
|
const [advancedFilters, setAdvancedFilters] = useState({
|
|
58
58
|
status: status || (activeOnly ? "active" : "all"),
|
|
59
59
|
selectedSiteId: siteId || "",
|
|
60
|
+
selectedRoomId: "",
|
|
60
61
|
dobFrom: dobFrom || "",
|
|
61
62
|
dobTo: dobTo || "",
|
|
62
63
|
ageFrom: ageFrom || "",
|
|
@@ -64,6 +65,7 @@ const ChildSearchModal = ({
|
|
|
64
65
|
sortBy: sortBy,
|
|
65
66
|
sortOrder: sortOrder,
|
|
66
67
|
});
|
|
68
|
+
const [rooms, setRooms] = useState([]);
|
|
67
69
|
|
|
68
70
|
// State for multi-select mode
|
|
69
71
|
const initialSelectedChildren = useMemo(
|
|
@@ -209,6 +211,11 @@ const ChildSearchModal = ({
|
|
|
209
211
|
params.append("active_only", "true");
|
|
210
212
|
}
|
|
211
213
|
|
|
214
|
+
// Add room filter
|
|
215
|
+
if (advancedFilters.selectedRoomId) {
|
|
216
|
+
params.append("room_id", advancedFilters.selectedRoomId.toString());
|
|
217
|
+
}
|
|
218
|
+
|
|
212
219
|
// Add date of birth filters
|
|
213
220
|
if (advancedFilters.dobFrom) {
|
|
214
221
|
params.append("dob_from", advancedFilters.dobFrom);
|
|
@@ -288,6 +295,35 @@ const ChildSearchModal = ({
|
|
|
288
295
|
}
|
|
289
296
|
}, [debouncedSearchTerm, pagination.page, isOpen, searchChildren]);
|
|
290
297
|
|
|
298
|
+
// Fetch rooms for selected site
|
|
299
|
+
useEffect(() => {
|
|
300
|
+
const fetchRooms = async () => {
|
|
301
|
+
if (!advancedFilters.selectedSiteId) return;
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
// Find the selected site and extract its rooms
|
|
305
|
+
if (sites && sites.length > 0) {
|
|
306
|
+
const selectedSite = sites.find(
|
|
307
|
+
(site) => site.site_id === parseInt(advancedFilters.selectedSiteId, 10)
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
if (selectedSite && selectedSite.rooms) {
|
|
311
|
+
setRooms(selectedSite.rooms);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// If not available from sites, clear rooms
|
|
317
|
+
setRooms([]);
|
|
318
|
+
} catch (err) {
|
|
319
|
+
console.error("Error fetching rooms:", err);
|
|
320
|
+
setRooms([]);
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
fetchRooms();
|
|
325
|
+
}, [advancedFilters.selectedSiteId, sites]);
|
|
326
|
+
|
|
291
327
|
// Reset selection when modal opens (for multi-select mode)
|
|
292
328
|
useEffect(() => {
|
|
293
329
|
if (isOpen && multiSelect) {
|
|
@@ -618,6 +654,7 @@ const ChildSearchModal = ({
|
|
|
618
654
|
setAdvancedFilters((prev) => ({
|
|
619
655
|
...prev,
|
|
620
656
|
selectedSiteId: e.target.value,
|
|
657
|
+
selectedRoomId: "", // Reset room when site changes
|
|
621
658
|
}))
|
|
622
659
|
}
|
|
623
660
|
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md text-sm dark:bg-gray-600 dark:text-white"
|
|
@@ -632,6 +669,32 @@ const ChildSearchModal = ({
|
|
|
632
669
|
</div>
|
|
633
670
|
)}
|
|
634
671
|
|
|
672
|
+
{/* Room Filter */}
|
|
673
|
+
{advancedFilters.selectedSiteId && rooms && rooms.length > 0 && (
|
|
674
|
+
<div>
|
|
675
|
+
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
|
676
|
+
Room
|
|
677
|
+
</label>
|
|
678
|
+
<select
|
|
679
|
+
value={advancedFilters.selectedRoomId}
|
|
680
|
+
onChange={(e) =>
|
|
681
|
+
setAdvancedFilters((prev) => ({
|
|
682
|
+
...prev,
|
|
683
|
+
selectedRoomId: e.target.value,
|
|
684
|
+
}))
|
|
685
|
+
}
|
|
686
|
+
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md text-sm dark:bg-gray-600 dark:text-white"
|
|
687
|
+
>
|
|
688
|
+
<option value="">All Rooms</option>
|
|
689
|
+
{rooms.map((room) => (
|
|
690
|
+
<option key={room.room_id} value={room.room_id}>
|
|
691
|
+
{room.room_name}
|
|
692
|
+
</option>
|
|
693
|
+
))}
|
|
694
|
+
</select>
|
|
695
|
+
</div>
|
|
696
|
+
)}
|
|
697
|
+
|
|
635
698
|
{/* Date of Birth Range */}
|
|
636
699
|
<div>
|
|
637
700
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
|
@@ -756,6 +819,7 @@ const ChildSearchModal = ({
|
|
|
756
819
|
setAdvancedFilters({
|
|
757
820
|
status: activeOnly ? "active" : "all",
|
|
758
821
|
selectedSiteId: "",
|
|
822
|
+
selectedRoomId: "",
|
|
759
823
|
dobFrom: "",
|
|
760
824
|
dobTo: "",
|
|
761
825
|
ageFrom: "",
|
|
@@ -908,6 +972,14 @@ const ChildSearchModal = ({
|
|
|
908
972
|
</div>
|
|
909
973
|
<div className="mt-1 text-sm text-gray-600 dark:text-gray-300">
|
|
910
974
|
<span>{child.site_name}</span>
|
|
975
|
+
{child.current_room_name && (
|
|
976
|
+
<>
|
|
977
|
+
<span className="mx-2">•</span>
|
|
978
|
+
<span className="font-medium">
|
|
979
|
+
{child.current_room_name}
|
|
980
|
+
</span>
|
|
981
|
+
</>
|
|
982
|
+
)}
|
|
911
983
|
{child.date_of_birth && (
|
|
912
984
|
<>
|
|
913
985
|
<span className="mx-2">•</span>
|
package/src/ChildSearchPage.jsx
CHANGED
|
@@ -82,6 +82,7 @@ const ChildSearchPage = ({
|
|
|
82
82
|
const [advancedFilters, setAdvancedFilters] = useState({
|
|
83
83
|
status: status || (activeOnly ? "active" : "all"),
|
|
84
84
|
selectedSiteId: siteId || "",
|
|
85
|
+
selectedRoomId: "",
|
|
85
86
|
dobFrom: dobFrom || "",
|
|
86
87
|
dobTo: dobTo || "",
|
|
87
88
|
ageFrom: ageFrom || "",
|
|
@@ -89,6 +90,7 @@ const ChildSearchPage = ({
|
|
|
89
90
|
sortBy: sortBy,
|
|
90
91
|
sortOrder: sortOrder,
|
|
91
92
|
});
|
|
93
|
+
const [rooms, setRooms] = useState([]);
|
|
92
94
|
|
|
93
95
|
// Table sorting state
|
|
94
96
|
const [sorting, setSorting] = useState([]);
|
|
@@ -179,6 +181,15 @@ const ChildSearchPage = ({
|
|
|
179
181
|
<span>{row.original.site_name}</span>
|
|
180
182
|
),
|
|
181
183
|
}),
|
|
184
|
+
// Room column
|
|
185
|
+
columnHelper.accessor("current_room_name", {
|
|
186
|
+
header: "Room",
|
|
187
|
+
cell: ({ row }) => (
|
|
188
|
+
<span>
|
|
189
|
+
{row.original.current_room_name || "N/A"}
|
|
190
|
+
</span>
|
|
191
|
+
),
|
|
192
|
+
}),
|
|
182
193
|
// Date of Birth column - sortable
|
|
183
194
|
columnHelper.accessor("date_of_birth", {
|
|
184
195
|
header: createSortableHeader("date_of_birth", "Date of Birth"),
|
|
@@ -343,6 +354,11 @@ const ChildSearchPage = ({
|
|
|
343
354
|
params.append("active_only", "true");
|
|
344
355
|
}
|
|
345
356
|
|
|
357
|
+
// Add room filter
|
|
358
|
+
if (debouncedAdvancedFilters.selectedRoomId) {
|
|
359
|
+
params.append("room_id", debouncedAdvancedFilters.selectedRoomId.toString());
|
|
360
|
+
}
|
|
361
|
+
|
|
346
362
|
// Add date of birth filters
|
|
347
363
|
if (debouncedAdvancedFilters.dobFrom) {
|
|
348
364
|
params.append("dob_from", debouncedAdvancedFilters.dobFrom);
|
|
@@ -468,6 +484,7 @@ const ChildSearchPage = ({
|
|
|
468
484
|
const clearedFilters = {
|
|
469
485
|
status: activeOnly ? "active" : "all",
|
|
470
486
|
selectedSiteId: "",
|
|
487
|
+
selectedRoomId: "",
|
|
471
488
|
dobFrom: "",
|
|
472
489
|
dobTo: "",
|
|
473
490
|
ageFrom: "",
|
|
@@ -26,12 +26,37 @@ const ChildSearchFilters = ({
|
|
|
26
26
|
// Local state for filters that haven't been applied yet
|
|
27
27
|
const [localFilters, setLocalFilters] = React.useState(filters);
|
|
28
28
|
const [hasUnsavedChanges, setHasUnsavedChanges] = React.useState(false);
|
|
29
|
+
const [rooms, setRooms] = React.useState([]);
|
|
29
30
|
|
|
30
31
|
// Update local filters when props change
|
|
31
32
|
React.useEffect(() => {
|
|
32
33
|
setLocalFilters(filters);
|
|
33
34
|
setHasUnsavedChanges(false);
|
|
34
35
|
}, [filters]);
|
|
36
|
+
|
|
37
|
+
// Fetch rooms for selected site
|
|
38
|
+
React.useEffect(() => {
|
|
39
|
+
if (!localFilters.selectedSiteId || !sites) {
|
|
40
|
+
setRooms([]);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
// Find the selected site and extract its rooms
|
|
46
|
+
const selectedSite = sites.find(
|
|
47
|
+
(site) => site.site_id === parseInt(localFilters.selectedSiteId, 10)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (selectedSite && selectedSite.rooms) {
|
|
51
|
+
setRooms(selectedSite.rooms);
|
|
52
|
+
} else {
|
|
53
|
+
setRooms([]);
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.error("Error fetching rooms:", err);
|
|
57
|
+
setRooms([]);
|
|
58
|
+
}
|
|
59
|
+
}, [localFilters.selectedSiteId, sites]);
|
|
35
60
|
// Convert existing date strings to DateRangePicker format
|
|
36
61
|
const getDateRange = () => {
|
|
37
62
|
if (localFilters.dobFrom || localFilters.dobTo) {
|
|
@@ -146,7 +171,10 @@ const ChildSearchFilters = ({
|
|
|
146
171
|
</label>
|
|
147
172
|
<Select
|
|
148
173
|
value={localFilters.selectedSiteId}
|
|
149
|
-
onChange={(e) =>
|
|
174
|
+
onChange={(e) => {
|
|
175
|
+
handleFilterChange("selectedSiteId", e.target.value);
|
|
176
|
+
handleFilterChange("selectedRoomId", ""); // Reset room when site changes
|
|
177
|
+
}}
|
|
150
178
|
className="bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white"
|
|
151
179
|
>
|
|
152
180
|
<SelectOption value="">All Sites</SelectOption>
|
|
@@ -159,6 +187,27 @@ const ChildSearchFilters = ({
|
|
|
159
187
|
</div>
|
|
160
188
|
)}
|
|
161
189
|
|
|
190
|
+
{/* Room Filter */}
|
|
191
|
+
{localFilters.selectedSiteId && rooms && rooms.length > 0 && (
|
|
192
|
+
<div>
|
|
193
|
+
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
|
194
|
+
Room
|
|
195
|
+
</label>
|
|
196
|
+
<Select
|
|
197
|
+
value={localFilters.selectedRoomId}
|
|
198
|
+
onChange={(e) => handleFilterChange("selectedRoomId", e.target.value)}
|
|
199
|
+
className="bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white"
|
|
200
|
+
>
|
|
201
|
+
<SelectOption value="">All Rooms</SelectOption>
|
|
202
|
+
{rooms.map((room) => (
|
|
203
|
+
<SelectOption key={room.room_id} value={room.room_id}>
|
|
204
|
+
{room.room_name}
|
|
205
|
+
</SelectOption>
|
|
206
|
+
))}
|
|
207
|
+
</Select>
|
|
208
|
+
</div>
|
|
209
|
+
)}
|
|
210
|
+
|
|
162
211
|
{/* Date of Birth Range */}
|
|
163
212
|
<div>
|
|
164
213
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
|
@@ -37,6 +37,8 @@ export function DateRangePicker({
|
|
|
37
37
|
// New: allow styling popover content and calendar for layout control
|
|
38
38
|
contentClassName,
|
|
39
39
|
calendarClassName,
|
|
40
|
+
// New: allow hiding the calendar icon
|
|
41
|
+
showIcon = true,
|
|
40
42
|
...props
|
|
41
43
|
}) {
|
|
42
44
|
const [isOpen, setIsOpen] = useState(false);
|
|
@@ -180,7 +182,7 @@ export function DateRangePicker({
|
|
|
180
182
|
disabled={disabled}
|
|
181
183
|
{...props}
|
|
182
184
|
>
|
|
183
|
-
<CalendarIcon className="mr-2 h-4 w-4" />
|
|
185
|
+
{showIcon && <CalendarIcon className="mr-2 h-4 w-4 shrink-0" />}
|
|
184
186
|
{internalRange?.from ? (
|
|
185
187
|
internalRange.to ? (
|
|
186
188
|
<>
|
|
@@ -291,6 +293,8 @@ export function DatePicker({
|
|
|
291
293
|
disabled,
|
|
292
294
|
disableFuture = false,
|
|
293
295
|
displayFormat = "PPP",
|
|
296
|
+
// New: allow hiding the calendar icon
|
|
297
|
+
showIcon = true,
|
|
294
298
|
...props
|
|
295
299
|
}) {
|
|
296
300
|
const [isOpen, setIsOpen] = useState(false);
|
|
@@ -313,7 +317,7 @@ export function DatePicker({
|
|
|
313
317
|
disabled={disabled}
|
|
314
318
|
{...props}
|
|
315
319
|
>
|
|
316
|
-
<CalendarIcon className="mr-2 h-4 w-4" />
|
|
320
|
+
{showIcon && <CalendarIcon className="mr-2 h-4 w-4 shrink-0" />}
|
|
317
321
|
{selectedDate ? (
|
|
318
322
|
format(selectedDate, displayFormat)
|
|
319
323
|
) : (
|