@snapdragonsnursery/react-components 1.19.0 → 1.19.3
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 +1 -1
- package/src/ChildSearchModal.jsx +67 -34
- package/src/EmployeeSearchModal.jsx +50 -29
package/package.json
CHANGED
package/src/ChildSearchModal.jsx
CHANGED
|
@@ -107,8 +107,8 @@ const ChildSearchModal = ({
|
|
|
107
107
|
const viewportHeight = window.innerHeight;
|
|
108
108
|
const expectedHeight = viewportHeight * 0.9;
|
|
109
109
|
const expectedContentHeight = expectedHeight - 300;
|
|
110
|
-
|
|
111
|
-
console.log(
|
|
110
|
+
|
|
111
|
+
console.log("🔍 Modal Debug:", {
|
|
112
112
|
modalHeight: rect.height,
|
|
113
113
|
modalTop: rect.top,
|
|
114
114
|
modalBottom: rect.bottom,
|
|
@@ -119,15 +119,15 @@ const ChildSearchModal = ({
|
|
|
119
119
|
loading,
|
|
120
120
|
error,
|
|
121
121
|
modalStyle: modal.style,
|
|
122
|
-
modalComputedStyle: window.getComputedStyle(modal)
|
|
122
|
+
modalComputedStyle: window.getComputedStyle(modal),
|
|
123
123
|
});
|
|
124
|
-
|
|
124
|
+
|
|
125
125
|
// Check if modal is overflowing
|
|
126
126
|
if (rect.bottom > window.innerHeight) {
|
|
127
|
-
console.warn(
|
|
127
|
+
console.warn("⚠️ Modal is overflowing bottom of viewport!");
|
|
128
128
|
}
|
|
129
129
|
if (rect.top < 0) {
|
|
130
|
-
console.warn(
|
|
130
|
+
console.warn("⚠️ Modal is overflowing top of viewport!");
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
}, [isOpen, children.length, loading, error]);
|
|
@@ -363,14 +363,43 @@ const ChildSearchModal = ({
|
|
|
363
363
|
};
|
|
364
364
|
|
|
365
365
|
const formatAge = (years, months) => {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
366
|
+
const numericYears =
|
|
367
|
+
typeof years === "number" && Number.isFinite(years)
|
|
368
|
+
? years
|
|
369
|
+
: typeof years === "string" && years.trim() !== ""
|
|
370
|
+
? Number.parseInt(years, 10)
|
|
371
|
+
: null;
|
|
372
|
+
const numericMonths =
|
|
373
|
+
typeof months === "number" && Number.isFinite(months)
|
|
374
|
+
? months
|
|
375
|
+
: typeof months === "string" && months.trim() !== ""
|
|
376
|
+
? Number.parseInt(months, 10)
|
|
377
|
+
: null;
|
|
378
|
+
|
|
379
|
+
let displayYears = numericYears;
|
|
380
|
+
let displayMonths = numericMonths;
|
|
381
|
+
|
|
382
|
+
if (displayMonths !== null && displayMonths >= 12) {
|
|
383
|
+
const additionalYears = Math.floor(displayMonths / 12);
|
|
384
|
+
if (additionalYears > 0) {
|
|
385
|
+
displayYears = (displayYears ?? 0) + additionalYears;
|
|
386
|
+
displayMonths = displayMonths % 12;
|
|
387
|
+
}
|
|
372
388
|
}
|
|
373
|
-
|
|
389
|
+
|
|
390
|
+
const parts = [];
|
|
391
|
+
if (displayYears !== null && !Number.isNaN(displayYears)) {
|
|
392
|
+
parts.push(`${displayYears}y`);
|
|
393
|
+
}
|
|
394
|
+
if (
|
|
395
|
+
displayMonths !== null &&
|
|
396
|
+
!Number.isNaN(displayMonths) &&
|
|
397
|
+
displayMonths > 0
|
|
398
|
+
) {
|
|
399
|
+
parts.push(`${displayMonths}m`);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return parts.join(" ");
|
|
374
403
|
};
|
|
375
404
|
|
|
376
405
|
const formatDate = (dateString) => {
|
|
@@ -381,16 +410,19 @@ const ChildSearchModal = ({
|
|
|
381
410
|
if (!isOpen) return null;
|
|
382
411
|
|
|
383
412
|
return (
|
|
384
|
-
<div
|
|
413
|
+
<div
|
|
414
|
+
className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 overflow-hidden"
|
|
415
|
+
style={{ zIndex }}
|
|
416
|
+
>
|
|
385
417
|
<div
|
|
386
418
|
ref={modalRef}
|
|
387
419
|
className={`bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-4xl w-full flex flex-col overflow-hidden ${className}`}
|
|
388
420
|
style={{
|
|
389
421
|
maxHeight: `${maxHeightVh}vh`,
|
|
390
422
|
height: `${maxHeightVh}vh`,
|
|
391
|
-
display:
|
|
392
|
-
flexDirection:
|
|
393
|
-
position:
|
|
423
|
+
display: "flex",
|
|
424
|
+
flexDirection: "column",
|
|
425
|
+
position: "relative",
|
|
394
426
|
}}
|
|
395
427
|
>
|
|
396
428
|
{/* Header */}
|
|
@@ -688,20 +720,20 @@ const ChildSearchModal = ({
|
|
|
688
720
|
</div>
|
|
689
721
|
|
|
690
722
|
{/* Content */}
|
|
691
|
-
<div
|
|
723
|
+
<div
|
|
692
724
|
className="overflow-hidden"
|
|
693
|
-
style={{
|
|
694
|
-
height:
|
|
695
|
-
maxHeight:
|
|
696
|
-
overflow:
|
|
697
|
-
flex:
|
|
698
|
-
position:
|
|
725
|
+
style={{
|
|
726
|
+
height: "calc(90vh - 300px)",
|
|
727
|
+
maxHeight: "calc(90vh - 300px)",
|
|
728
|
+
overflow: "hidden",
|
|
729
|
+
flex: "none",
|
|
730
|
+
position: "relative",
|
|
699
731
|
}}
|
|
700
732
|
ref={(el) => {
|
|
701
733
|
if (el) {
|
|
702
734
|
const rect = el.getBoundingClientRect();
|
|
703
735
|
const computedStyle = window.getComputedStyle(el);
|
|
704
|
-
console.log(
|
|
736
|
+
console.log("📦 Content Area Debug:", {
|
|
705
737
|
contentHeight: rect.height,
|
|
706
738
|
contentTop: rect.top,
|
|
707
739
|
contentBottom: rect.bottom,
|
|
@@ -712,7 +744,7 @@ const ChildSearchModal = ({
|
|
|
712
744
|
height: computedStyle.height,
|
|
713
745
|
overflow: computedStyle.overflow,
|
|
714
746
|
styleMaxHeight: el.style.maxHeight,
|
|
715
|
-
styleHeight: el.style.height
|
|
747
|
+
styleHeight: el.style.height,
|
|
716
748
|
});
|
|
717
749
|
}
|
|
718
750
|
}}
|
|
@@ -732,18 +764,18 @@ const ChildSearchModal = ({
|
|
|
732
764
|
)}
|
|
733
765
|
|
|
734
766
|
{!loading && !error && (
|
|
735
|
-
<div
|
|
767
|
+
<div
|
|
736
768
|
className="overflow-y-auto h-full max-h-full"
|
|
737
|
-
style={{
|
|
738
|
-
maxHeight:
|
|
739
|
-
height:
|
|
740
|
-
overflowY:
|
|
769
|
+
style={{
|
|
770
|
+
maxHeight: "100% !important",
|
|
771
|
+
height: "100% !important",
|
|
772
|
+
overflowY: "auto !important",
|
|
741
773
|
}}
|
|
742
774
|
ref={(el) => {
|
|
743
775
|
if (el) {
|
|
744
776
|
const rect = el.getBoundingClientRect();
|
|
745
777
|
const computedStyle = window.getComputedStyle(el);
|
|
746
|
-
console.log(
|
|
778
|
+
console.log("📜 Scrollable Content Debug:", {
|
|
747
779
|
scrollHeight: el.scrollHeight,
|
|
748
780
|
clientHeight: el.clientHeight,
|
|
749
781
|
scrollTop: el.scrollTop,
|
|
@@ -754,7 +786,7 @@ const ChildSearchModal = ({
|
|
|
754
786
|
height: computedStyle.height,
|
|
755
787
|
overflowY: computedStyle.overflowY,
|
|
756
788
|
styleMaxHeight: el.style.maxHeight,
|
|
757
|
-
styleHeight: el.style.height
|
|
789
|
+
styleHeight: el.style.height,
|
|
758
790
|
});
|
|
759
791
|
}
|
|
760
792
|
}}
|
|
@@ -909,7 +941,8 @@ const ChildSearchModal = ({
|
|
|
909
941
|
{multiSelect && (
|
|
910
942
|
<div className="p-6 border-t border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
|
911
943
|
<div className="text-sm text-gray-600 dark:text-gray-300">
|
|
912
|
-
{selectedChildrenState.length} selected
|
|
944
|
+
{selectedChildrenState.length} selected
|
|
945
|
+
{maxSelections ? ` / ${maxSelections}` : ""}
|
|
913
946
|
</div>
|
|
914
947
|
<div className="flex items-center gap-2">
|
|
915
948
|
<button
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Employee Search Modal Component
|
|
2
2
|
// Provides a modal interface for employee search with advanced filtering and selection capabilities
|
|
3
|
-
// Usage: <EmployeeSearchModal isOpen={isOpen} onClose={onClose} onSelect={handleSelect} />
|
|
3
|
+
// Usage: <EmployeeSearchModal isOpen={isOpen} onClose={onClose} onSelect={handleSelect} showFiltersPanel={false} />
|
|
4
4
|
|
|
5
5
|
import React, { useState, useEffect, useCallback } from "react";
|
|
6
6
|
import { useMsal } from "@azure/msal-react";
|
|
@@ -47,7 +47,7 @@ const EmployeeSearchModal = ({
|
|
|
47
47
|
onClose,
|
|
48
48
|
onSelect,
|
|
49
49
|
title = "Select Employee",
|
|
50
|
-
searchPlaceholder = "Search by name, ID, or email address...",
|
|
50
|
+
searchPlaceholder = "Search by name, Employee ID, or email address...",
|
|
51
51
|
siteId = null,
|
|
52
52
|
siteIds = null,
|
|
53
53
|
sites = null,
|
|
@@ -90,6 +90,8 @@ const EmployeeSearchModal = ({
|
|
|
90
90
|
visibleColumns = null,
|
|
91
91
|
columnLabels = {},
|
|
92
92
|
columnRenderers = {},
|
|
93
|
+
showFiltersPanel = true,
|
|
94
|
+
dataProfile = "full",
|
|
93
95
|
}) => {
|
|
94
96
|
const [searchTerm, setSearchTerm] = useState("");
|
|
95
97
|
const [employees, setEmployees] = useState([]);
|
|
@@ -219,7 +221,9 @@ const EmployeeSearchModal = ({
|
|
|
219
221
|
}
|
|
220
222
|
}
|
|
221
223
|
|
|
222
|
-
console.warn(
|
|
224
|
+
console.warn(
|
|
225
|
+
`Failed to fetch profile picture for ${entraId}: Non-200 response`
|
|
226
|
+
);
|
|
223
227
|
} catch (error) {
|
|
224
228
|
console.warn(`Error fetching profile picture for ${entraId}:`, error);
|
|
225
229
|
} finally {
|
|
@@ -315,7 +319,7 @@ const EmployeeSearchModal = ({
|
|
|
315
319
|
});
|
|
316
320
|
|
|
317
321
|
// Define default data columns (excluding optional select)
|
|
318
|
-
const
|
|
322
|
+
const basicColumns = [
|
|
319
323
|
columnHelper.accessor("full_name", {
|
|
320
324
|
header: createSortableHeader(
|
|
321
325
|
"full_name",
|
|
@@ -327,9 +331,11 @@ const EmployeeSearchModal = ({
|
|
|
327
331
|
) : (
|
|
328
332
|
<div>
|
|
329
333
|
<div className="font-medium">{row.original.full_name}</div>
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
334
|
+
{dataProfile !== "basic" && row.original.employee_id ? (
|
|
335
|
+
<div className="text-sm text-gray-500">
|
|
336
|
+
ID: {row.original.employee_id}
|
|
337
|
+
</div>
|
|
338
|
+
) : null}
|
|
333
339
|
</div>
|
|
334
340
|
),
|
|
335
341
|
}),
|
|
@@ -366,6 +372,9 @@ const EmployeeSearchModal = ({
|
|
|
366
372
|
<span className="text-sm">{row.original.email}</span>
|
|
367
373
|
),
|
|
368
374
|
}),
|
|
375
|
+
];
|
|
376
|
+
|
|
377
|
+
const extendedColumns = [
|
|
369
378
|
columnHelper.accessor("start_date", {
|
|
370
379
|
header: createSortableHeader(
|
|
371
380
|
"start_date",
|
|
@@ -429,6 +438,11 @@ const EmployeeSearchModal = ({
|
|
|
429
438
|
}),
|
|
430
439
|
];
|
|
431
440
|
|
|
441
|
+
const defaultDataColumns =
|
|
442
|
+
dataProfile === "basic"
|
|
443
|
+
? basicColumns
|
|
444
|
+
: [...basicColumns, ...extendedColumns];
|
|
445
|
+
|
|
432
446
|
const selectColumn = columnHelper.display({
|
|
433
447
|
id: "select",
|
|
434
448
|
header: ({ table }) => (
|
|
@@ -608,6 +622,10 @@ const EmployeeSearchModal = ({
|
|
|
608
622
|
bypass_permissions: bypassPermissions.toString(),
|
|
609
623
|
});
|
|
610
624
|
|
|
625
|
+
if (dataProfile && dataProfile !== "full") {
|
|
626
|
+
params.append("data_profile", dataProfile);
|
|
627
|
+
}
|
|
628
|
+
|
|
611
629
|
// Handle site filtering
|
|
612
630
|
if (siteIds && siteIds.length > 0) {
|
|
613
631
|
params.append("site_ids", siteIds.join(","));
|
|
@@ -745,6 +763,7 @@ const EmployeeSearchModal = ({
|
|
|
745
763
|
debouncedAdvancedFilters,
|
|
746
764
|
applicationContext,
|
|
747
765
|
bypassPermissions,
|
|
766
|
+
dataProfile,
|
|
748
767
|
]);
|
|
749
768
|
|
|
750
769
|
// Search when debounced term changes
|
|
@@ -885,28 +904,30 @@ const EmployeeSearchModal = ({
|
|
|
885
904
|
</div>
|
|
886
905
|
|
|
887
906
|
{/* Advanced Filters */}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
907
|
+
{showFiltersPanel && (
|
|
908
|
+
<EmployeeSearchFilters
|
|
909
|
+
filters={advancedFilters}
|
|
910
|
+
onFiltersChange={setAdvancedFilters}
|
|
911
|
+
onApplyFilters={setAdvancedFilters}
|
|
912
|
+
sites={sites}
|
|
913
|
+
roles={roles}
|
|
914
|
+
managers={managers}
|
|
915
|
+
activeOnly={activeOnly}
|
|
916
|
+
isAdvancedFiltersOpen={isAdvancedFiltersOpen}
|
|
917
|
+
onToggleAdvancedFilters={() =>
|
|
918
|
+
setIsAdvancedFiltersOpen(!isAdvancedFiltersOpen)
|
|
919
|
+
}
|
|
920
|
+
onClearFilters={clearFilters}
|
|
921
|
+
showRoleFilter={showRoleFilter}
|
|
922
|
+
showManagerFilter={showManagerFilter}
|
|
923
|
+
showTermTimeFilter={showTermTimeFilter}
|
|
924
|
+
showMaternityFilter={showMaternityFilter}
|
|
925
|
+
showStartDateFilter={showStartDateFilter}
|
|
926
|
+
showEndDateFilter={showEndDateFilter}
|
|
927
|
+
showDbsFilter={showDbsFilter}
|
|
928
|
+
showWorkingHoursFilter={showWorkingHoursFilter}
|
|
929
|
+
/>
|
|
930
|
+
)}
|
|
910
931
|
|
|
911
932
|
{/* Results */}
|
|
912
933
|
<div className="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700">
|