@snapdragonsnursery/react-components 1.3.3 → 1.4.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/ChildSearchPage.jsx
CHANGED
|
@@ -451,8 +451,8 @@ const ChildSearchPage = ({
|
|
|
451
451
|
const endItem = Math.min(pagination.page * pagination.pageSize, actualTotalCount);
|
|
452
452
|
|
|
453
453
|
return (
|
|
454
|
-
<div className="
|
|
455
|
-
<div className="
|
|
454
|
+
<div className="min-h-full">
|
|
455
|
+
<div className="w-full py-6">
|
|
456
456
|
{/* Header */}
|
|
457
457
|
<div className="mb-8">
|
|
458
458
|
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
|
|
@@ -29,7 +29,7 @@ const ChildSearchPageDemo = () => {
|
|
|
29
29
|
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
|
|
30
30
|
{/* Demo Controls */}
|
|
31
31
|
<div className="bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 p-4">
|
|
32
|
-
<div className="
|
|
32
|
+
<div className="w-full px-4">
|
|
33
33
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">
|
|
34
34
|
ChildSearchPage Demo
|
|
35
35
|
</h2>
|
|
@@ -55,7 +55,7 @@ const EmployeeSearchDemo = () => {
|
|
|
55
55
|
|
|
56
56
|
return (
|
|
57
57
|
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
|
|
58
|
-
<div className="
|
|
58
|
+
<div className="w-full px-4 sm:px-6 lg:px-8 py-8">
|
|
59
59
|
{/* Header */}
|
|
60
60
|
<div className="mb-8">
|
|
61
61
|
<h1 className="text-3xl font-bold text-gray-900 dark:text-white mb-4">
|
|
@@ -53,7 +53,7 @@ const EmployeeSearchPage = ({
|
|
|
53
53
|
startDateTo = null,
|
|
54
54
|
endDateFrom = null,
|
|
55
55
|
endDateTo = null,
|
|
56
|
-
sortBy = "
|
|
56
|
+
sortBy = "full_name",
|
|
57
57
|
sortOrder = "asc",
|
|
58
58
|
applicationContext = "employee-search",
|
|
59
59
|
bypassPermissions = false,
|
|
@@ -67,15 +67,25 @@ const EmployeeSearchPage = ({
|
|
|
67
67
|
showTermTimeFilter = true,
|
|
68
68
|
showMaternityFilter = true,
|
|
69
69
|
showStartDateFilter = true,
|
|
70
|
-
showEndDateFilter =
|
|
71
|
-
showDbsFilter = true,
|
|
70
|
+
showEndDateFilter = false,
|
|
72
71
|
showWorkingHoursFilter = true,
|
|
72
|
+
loadAllResults = false, // If true, loads all results instead of paginating
|
|
73
73
|
}) => {
|
|
74
74
|
const [searchTerm, setSearchTerm] = useState("");
|
|
75
75
|
const [employees, setEmployees] = useState([]);
|
|
76
76
|
const [loading, setLoading] = useState(false);
|
|
77
77
|
const [error, setError] = useState(null);
|
|
78
78
|
const [pagination, setPagination] = useState({
|
|
79
|
+
page: 1,
|
|
80
|
+
pageSize: loadAllResults ? 10000 : 20, // Use large page size if loading all results
|
|
81
|
+
totalCount: 0,
|
|
82
|
+
totalPages: 0,
|
|
83
|
+
hasNextPage: false,
|
|
84
|
+
hasPreviousPage: false,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Local pagination state for when loadAllResults is true
|
|
88
|
+
const [localPagination, setLocalPagination] = useState({
|
|
79
89
|
page: 1,
|
|
80
90
|
pageSize: 20,
|
|
81
91
|
totalCount: 0,
|
|
@@ -83,6 +93,9 @@ const EmployeeSearchPage = ({
|
|
|
83
93
|
hasNextPage: false,
|
|
84
94
|
hasPreviousPage: false,
|
|
85
95
|
});
|
|
96
|
+
|
|
97
|
+
// All employees when loadAllResults is true
|
|
98
|
+
const [allEmployees, setAllEmployees] = useState([]);
|
|
86
99
|
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
|
|
87
100
|
const [isAdvancedFiltersOpen, setIsAdvancedFiltersOpen] = useState(false);
|
|
88
101
|
const [advancedFilters, setAdvancedFilters] = useState({
|
|
@@ -96,10 +109,7 @@ const EmployeeSearchPage = ({
|
|
|
96
109
|
endDateTo: endDateTo || "",
|
|
97
110
|
termTimeOnly: "",
|
|
98
111
|
onMaternityLeave: "",
|
|
99
|
-
dbsNumber: "",
|
|
100
112
|
minHoursPerWeek: "",
|
|
101
|
-
sortBy: sortBy,
|
|
102
|
-
sortOrder: sortOrder,
|
|
103
113
|
});
|
|
104
114
|
|
|
105
115
|
// Table sorting state
|
|
@@ -198,6 +208,15 @@ const EmployeeSearchPage = ({
|
|
|
198
208
|
<span>{row.original.role_name}</span>
|
|
199
209
|
),
|
|
200
210
|
}),
|
|
211
|
+
// Manager column - sortable
|
|
212
|
+
columnHelper.accessor("manager_name", {
|
|
213
|
+
header: createSortableHeader("manager_name", "Manager"),
|
|
214
|
+
cell: ({ row }) => (
|
|
215
|
+
<span className="text-sm">
|
|
216
|
+
{row.original.manager_name || "N/A"}
|
|
217
|
+
</span>
|
|
218
|
+
),
|
|
219
|
+
}),
|
|
201
220
|
// Email column
|
|
202
221
|
columnHelper.accessor("email", {
|
|
203
222
|
header: "Email",
|
|
@@ -326,6 +345,10 @@ const EmployeeSearchPage = ({
|
|
|
326
345
|
return () => clearTimeout(timer);
|
|
327
346
|
}, [advancedFilters]);
|
|
328
347
|
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
|
|
329
352
|
// Search employees
|
|
330
353
|
const searchEmployees = useCallback(async () => {
|
|
331
354
|
if (!instance || !accounts[0]) {
|
|
@@ -342,12 +365,17 @@ const EmployeeSearchPage = ({
|
|
|
342
365
|
const params = new URLSearchParams({
|
|
343
366
|
entra_id: accounts[0].localAccountId,
|
|
344
367
|
search_term: debouncedSearchTerm,
|
|
345
|
-
page: pagination.page,
|
|
346
|
-
page_size: pagination.pageSize,
|
|
368
|
+
page: loadAllResults ? 1 : pagination.page,
|
|
369
|
+
page_size: loadAllResults ? 10000 : pagination.pageSize,
|
|
347
370
|
application_context: applicationContext,
|
|
348
371
|
bypass_permissions: bypassPermissions.toString(),
|
|
349
372
|
});
|
|
350
373
|
|
|
374
|
+
// Add load_all_results parameter when needed
|
|
375
|
+
if (loadAllResults) {
|
|
376
|
+
params.append("load_all_results", "true");
|
|
377
|
+
}
|
|
378
|
+
|
|
351
379
|
// Handle site filtering
|
|
352
380
|
if (siteIds && siteIds.length > 0) {
|
|
353
381
|
params.append("site_ids", siteIds.join(","));
|
|
@@ -400,19 +428,14 @@ const EmployeeSearchPage = ({
|
|
|
400
428
|
params.append("on_maternity_leave", debouncedAdvancedFilters.onMaternityLeave);
|
|
401
429
|
}
|
|
402
430
|
|
|
403
|
-
// Add DBS number filter
|
|
404
|
-
if (debouncedAdvancedFilters.dbsNumber) {
|
|
405
|
-
params.append("dbs_number", debouncedAdvancedFilters.dbsNumber);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
431
|
// Add working hours filter
|
|
409
432
|
if (debouncedAdvancedFilters.minHoursPerWeek) {
|
|
410
433
|
params.append("min_hours_per_week", debouncedAdvancedFilters.minHoursPerWeek);
|
|
411
434
|
}
|
|
412
435
|
|
|
413
|
-
// Add sorting
|
|
414
|
-
params.append("sort_by",
|
|
415
|
-
params.append("sort_order",
|
|
436
|
+
// Add sorting (using default values since sort options were removed from filters)
|
|
437
|
+
params.append("sort_by", sortBy);
|
|
438
|
+
params.append("sort_order", sortOrder);
|
|
416
439
|
|
|
417
440
|
const apiResponse = await fetch(
|
|
418
441
|
`${
|
|
@@ -441,8 +464,36 @@ const EmployeeSearchPage = ({
|
|
|
441
464
|
totalPages: data.data.pagination.totalPages
|
|
442
465
|
});
|
|
443
466
|
|
|
444
|
-
|
|
445
|
-
|
|
467
|
+
if (loadAllResults) {
|
|
468
|
+
// Store all employees and handle local pagination
|
|
469
|
+
setAllEmployees(data.data.employees);
|
|
470
|
+
setLocalPagination({
|
|
471
|
+
page: 1,
|
|
472
|
+
pageSize: 20,
|
|
473
|
+
totalCount: data.data.employees.length,
|
|
474
|
+
totalPages: Math.ceil(data.data.employees.length / 20),
|
|
475
|
+
hasNextPage: data.data.employees.length > 20,
|
|
476
|
+
hasPreviousPage: false,
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
// Set current page employees
|
|
480
|
+
const startIndex = 0;
|
|
481
|
+
const endIndex = 20;
|
|
482
|
+
setEmployees(data.data.employees.slice(startIndex, endIndex));
|
|
483
|
+
setPagination({
|
|
484
|
+
page: 1,
|
|
485
|
+
pageSize: 20,
|
|
486
|
+
totalCount: data.data.employees.length,
|
|
487
|
+
totalPages: Math.ceil(data.data.employees.length / 20),
|
|
488
|
+
hasNextPage: data.data.employees.length > 20,
|
|
489
|
+
hasPreviousPage: false,
|
|
490
|
+
});
|
|
491
|
+
} else {
|
|
492
|
+
// Normal server-side pagination
|
|
493
|
+
setEmployees(data.data.employees);
|
|
494
|
+
setPagination(data.data.pagination);
|
|
495
|
+
}
|
|
496
|
+
|
|
446
497
|
trackEvent("employee_search_success", {
|
|
447
498
|
searchTerm: debouncedSearchTerm,
|
|
448
499
|
resultCount: data.data.employees.length,
|
|
@@ -478,12 +529,12 @@ const EmployeeSearchPage = ({
|
|
|
478
529
|
// Track if component has mounted
|
|
479
530
|
const hasMounted = React.useRef(false);
|
|
480
531
|
|
|
481
|
-
// Search when debounced term changes or
|
|
532
|
+
// Search when debounced term changes, pagination changes, or filters change
|
|
482
533
|
useEffect(() => {
|
|
483
534
|
if (instance && accounts[0] && hasMounted.current) {
|
|
484
535
|
searchEmployees();
|
|
485
536
|
}
|
|
486
|
-
}, [debouncedSearchTerm, pagination.page, instance, accounts]);
|
|
537
|
+
}, [debouncedSearchTerm, debouncedAdvancedFilters, pagination.page, instance, accounts]);
|
|
487
538
|
|
|
488
539
|
// Initial search on component mount
|
|
489
540
|
useEffect(() => {
|
|
@@ -494,7 +545,29 @@ const EmployeeSearchPage = ({
|
|
|
494
545
|
}, [instance, accounts]);
|
|
495
546
|
|
|
496
547
|
const handlePageChange = (newPage) => {
|
|
497
|
-
|
|
548
|
+
if (loadAllResults) {
|
|
549
|
+
// Handle local pagination
|
|
550
|
+
const startIndex = (newPage - 1) * localPagination.pageSize;
|
|
551
|
+
const endIndex = startIndex + localPagination.pageSize;
|
|
552
|
+
setEmployees(allEmployees.slice(startIndex, endIndex));
|
|
553
|
+
|
|
554
|
+
setLocalPagination((prev) => ({
|
|
555
|
+
...prev,
|
|
556
|
+
page: newPage,
|
|
557
|
+
hasNextPage: endIndex < allEmployees.length,
|
|
558
|
+
hasPreviousPage: newPage > 1,
|
|
559
|
+
}));
|
|
560
|
+
|
|
561
|
+
setPagination((prev) => ({
|
|
562
|
+
...prev,
|
|
563
|
+
page: newPage,
|
|
564
|
+
hasNextPage: endIndex < allEmployees.length,
|
|
565
|
+
hasPreviousPage: newPage > 1,
|
|
566
|
+
}));
|
|
567
|
+
} else {
|
|
568
|
+
// Normal server-side pagination
|
|
569
|
+
setPagination((prev) => ({ ...prev, page: newPage }));
|
|
570
|
+
}
|
|
498
571
|
};
|
|
499
572
|
|
|
500
573
|
const handleEmployeeSelect = (employee) => {
|
|
@@ -536,10 +609,7 @@ const EmployeeSearchPage = ({
|
|
|
536
609
|
endDateTo: "",
|
|
537
610
|
termTimeOnly: "",
|
|
538
611
|
onMaternityLeave: "",
|
|
539
|
-
dbsNumber: "",
|
|
540
612
|
minHoursPerWeek: "",
|
|
541
|
-
sortBy: "surname",
|
|
542
|
-
sortOrder: "asc",
|
|
543
613
|
};
|
|
544
614
|
setAdvancedFilters(clearedFilters);
|
|
545
615
|
setDebouncedAdvancedFilters(clearedFilters); // Clear immediately
|
|
@@ -547,15 +617,15 @@ const EmployeeSearchPage = ({
|
|
|
547
617
|
|
|
548
618
|
// Calculate pagination display values
|
|
549
619
|
const actualTotalCount = pagination.totalCount || employees.length;
|
|
550
|
-
const startItem = actualTotalCount > 0 ? (pagination.page - 1) * pagination.pageSize + 1 : 0;
|
|
551
|
-
const endItem = Math.min(pagination.page * pagination.pageSize, actualTotalCount);
|
|
620
|
+
const startItem = loadAllResults ? 1 : (actualTotalCount > 0 ? (pagination.page - 1) * pagination.pageSize + 1 : 0);
|
|
621
|
+
const endItem = loadAllResults ? actualTotalCount : Math.min(pagination.page * pagination.pageSize, actualTotalCount);
|
|
552
622
|
|
|
553
623
|
return (
|
|
554
|
-
<div className="
|
|
555
|
-
<div className="
|
|
624
|
+
<div className="min-h-full" style={{ width: '100%', maxWidth: '100%', overflow: 'hidden' }}>
|
|
625
|
+
<div className="py-6" style={{ width: '100%', maxWidth: '100%' }}>
|
|
556
626
|
{/* Header */}
|
|
557
|
-
<div className="mb-
|
|
558
|
-
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
|
|
627
|
+
<div className="mb-6">
|
|
628
|
+
<h1 className="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-white">
|
|
559
629
|
{title}
|
|
560
630
|
</h1>
|
|
561
631
|
{multiSelect && (
|
|
@@ -569,8 +639,8 @@ const EmployeeSearchPage = ({
|
|
|
569
639
|
</div>
|
|
570
640
|
|
|
571
641
|
{/* Search Input */}
|
|
572
|
-
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 mb-6">
|
|
573
|
-
<div className="p-
|
|
642
|
+
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 mb-6" style={{ width: '100%', maxWidth: '100%' }}>
|
|
643
|
+
<div className="p-4">
|
|
574
644
|
<div className="relative">
|
|
575
645
|
<Input
|
|
576
646
|
type="text"
|
|
@@ -578,6 +648,7 @@ const EmployeeSearchPage = ({
|
|
|
578
648
|
value={searchTerm}
|
|
579
649
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
580
650
|
className="pl-4"
|
|
651
|
+
style={{ width: '100%' }}
|
|
581
652
|
/>
|
|
582
653
|
</div>
|
|
583
654
|
</div>
|
|
@@ -601,12 +672,11 @@ const EmployeeSearchPage = ({
|
|
|
601
672
|
showMaternityFilter={showMaternityFilter}
|
|
602
673
|
showStartDateFilter={showStartDateFilter}
|
|
603
674
|
showEndDateFilter={showEndDateFilter}
|
|
604
|
-
showDbsFilter={showDbsFilter}
|
|
605
675
|
showWorkingHoursFilter={showWorkingHoursFilter}
|
|
606
676
|
/>
|
|
607
677
|
|
|
608
678
|
{/* Results */}
|
|
609
|
-
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
|
679
|
+
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700" style={{ width: '100%', maxWidth: '100%', overflow: 'hidden' }}>
|
|
610
680
|
{loading && (
|
|
611
681
|
<div className="flex items-center justify-center p-8" role="status" aria-label="Loading employees">
|
|
612
682
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
|
|
@@ -614,7 +684,7 @@ const EmployeeSearchPage = ({
|
|
|
614
684
|
)}
|
|
615
685
|
|
|
616
686
|
{error && (
|
|
617
|
-
<div className="p-
|
|
687
|
+
<div className="p-4 text-center">
|
|
618
688
|
<div className="text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20 p-4 rounded-lg">
|
|
619
689
|
{error}
|
|
620
690
|
</div>
|
|
@@ -624,11 +694,13 @@ const EmployeeSearchPage = ({
|
|
|
624
694
|
{!loading && !error && (
|
|
625
695
|
<>
|
|
626
696
|
{/* Results Header */}
|
|
627
|
-
<div className="px-
|
|
697
|
+
<div className="px-4 py-4 border-b border-gray-200 dark:border-gray-700">
|
|
628
698
|
<div className="flex items-center justify-between">
|
|
629
699
|
<div className="text-sm text-gray-600 dark:text-gray-400">
|
|
630
700
|
{(pagination.totalCount > 0 || employees.length > 0)
|
|
631
|
-
?
|
|
701
|
+
? loadAllResults
|
|
702
|
+
? `Showing all ${actualTotalCount} employees`
|
|
703
|
+
: `Showing ${startItem} to ${endItem} of ${actualTotalCount} employees`
|
|
632
704
|
: "No employees found"}
|
|
633
705
|
</div>
|
|
634
706
|
</div>
|
|
@@ -636,60 +708,89 @@ const EmployeeSearchPage = ({
|
|
|
636
708
|
|
|
637
709
|
{/* Table */}
|
|
638
710
|
{employees.length > 0 ? (
|
|
639
|
-
<div className="
|
|
640
|
-
|
|
641
|
-
|
|
711
|
+
<div className="mb-6" style={{
|
|
712
|
+
width: '100%',
|
|
713
|
+
maxWidth: '100%',
|
|
714
|
+
overflow: 'auto',
|
|
715
|
+
overflowY: 'hidden'
|
|
716
|
+
}}>
|
|
717
|
+
<table className="caption-bottom text-sm" style={{
|
|
718
|
+
tableLayout: 'fixed',
|
|
719
|
+
width: '1400px'
|
|
720
|
+
}}>
|
|
721
|
+
<thead className="[&_tr]:border-b">
|
|
642
722
|
{table.getHeaderGroups().map((headerGroup) => (
|
|
643
|
-
<
|
|
644
|
-
{headerGroup.headers.map((header) =>
|
|
645
|
-
|
|
723
|
+
<tr key={headerGroup.id} className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted">
|
|
724
|
+
{headerGroup.headers.map((header, index) => {
|
|
725
|
+
// Define generous column widths to avoid truncation - table will scroll if too wide
|
|
726
|
+
const columnWidths = {
|
|
727
|
+
0: multiSelect ? '50px' : '250px', // Select checkbox or Name
|
|
728
|
+
1: multiSelect ? '250px' : '180px', // Name or Site
|
|
729
|
+
2: multiSelect ? '180px' : '150px', // Site or Role
|
|
730
|
+
3: multiSelect ? '150px' : '180px', // Role or Manager
|
|
731
|
+
4: multiSelect ? '180px' : '300px', // Manager or Email
|
|
732
|
+
5: multiSelect ? '300px' : '150px', // Email or Start Date
|
|
733
|
+
6: multiSelect ? '150px' : '120px', // Start Date or Status
|
|
734
|
+
7: multiSelect ? '120px' : '100px', // Status or Hours/Week
|
|
735
|
+
8: multiSelect ? '100px' : '90px', // Hours/Week or Term Time
|
|
736
|
+
9: multiSelect ? '90px' : '90px', // Term Time or Maternity
|
|
737
|
+
10: '90px' // Maternity (only if multiSelect)
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
return (
|
|
741
|
+
<th
|
|
742
|
+
key={header.id}
|
|
743
|
+
className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0"
|
|
744
|
+
style={{ width: columnWidths[index] || '120px', minWidth: columnWidths[index] || '120px' }}
|
|
745
|
+
>
|
|
646
746
|
{header.isPlaceholder
|
|
647
747
|
? null
|
|
648
748
|
: flexRender(
|
|
649
749
|
header.column.columnDef.header,
|
|
650
750
|
header.getContext()
|
|
651
751
|
)}
|
|
652
|
-
</
|
|
653
|
-
|
|
654
|
-
|
|
752
|
+
</th>
|
|
753
|
+
);
|
|
754
|
+
})}
|
|
755
|
+
</tr>
|
|
655
756
|
))}
|
|
656
|
-
</
|
|
657
|
-
<
|
|
757
|
+
</thead>
|
|
758
|
+
<tbody className="[&_tr:last-child]:border-0">
|
|
658
759
|
{table.getRowModel().rows?.length ? (
|
|
659
760
|
table.getRowModel().rows.map((row) => (
|
|
660
|
-
<
|
|
761
|
+
<tr
|
|
661
762
|
key={row.id}
|
|
662
763
|
data-state={row.getIsSelected() && "selected"}
|
|
663
764
|
onClick={() => handleEmployeeSelect(row.original)}
|
|
664
|
-
className="cursor-pointer"
|
|
765
|
+
className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted cursor-pointer"
|
|
665
766
|
>
|
|
666
767
|
{row.getVisibleCells().map((cell) => (
|
|
667
|
-
<
|
|
768
|
+
<td key={cell.id} className="p-4 align-middle [&:has([role=checkbox])]:pr-0">
|
|
668
769
|
{flexRender(
|
|
669
770
|
cell.column.columnDef.cell,
|
|
670
771
|
cell.getContext()
|
|
671
772
|
)}
|
|
672
|
-
</
|
|
773
|
+
</td>
|
|
673
774
|
))}
|
|
674
|
-
</
|
|
775
|
+
</tr>
|
|
675
776
|
))
|
|
676
777
|
) : (
|
|
677
|
-
<
|
|
678
|
-
<
|
|
778
|
+
<tr className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted">
|
|
779
|
+
<td
|
|
679
780
|
colSpan={columns.length}
|
|
680
|
-
className="h-24 text-center"
|
|
781
|
+
className="h-24 text-center p-4 align-middle [&:has([role=checkbox])]:pr-0"
|
|
681
782
|
>
|
|
682
783
|
{debouncedSearchTerm
|
|
683
784
|
? "No employees found matching your search."
|
|
684
785
|
: "Start typing to search for employees."}
|
|
685
|
-
</
|
|
686
|
-
</
|
|
786
|
+
</td>
|
|
787
|
+
</tr>
|
|
687
788
|
)}
|
|
688
|
-
</
|
|
689
|
-
</
|
|
789
|
+
</tbody>
|
|
790
|
+
</table>
|
|
690
791
|
</div>
|
|
691
792
|
) : (
|
|
692
|
-
<div className="p-
|
|
793
|
+
<div className="p-4 text-center text-gray-500 dark:text-gray-400 mb-6">
|
|
693
794
|
{debouncedSearchTerm
|
|
694
795
|
? "No employees found matching your search."
|
|
695
796
|
: "Start typing to search for employees."}
|
|
@@ -697,8 +798,8 @@ const EmployeeSearchPage = ({
|
|
|
697
798
|
)}
|
|
698
799
|
|
|
699
800
|
{/* Pagination */}
|
|
700
|
-
{(pagination.totalCount > 0 || employees.length > 0) && (
|
|
701
|
-
<div className="px-
|
|
801
|
+
{(pagination.totalCount > 0 || employees.length > 0) && !loadAllResults && (
|
|
802
|
+
<div className="px-4 py-6 border-t border-gray-200 dark:border-gray-700">
|
|
702
803
|
{/* Pagination Controls */}
|
|
703
804
|
{(pagination.totalPages > 1 || employees.length > 0) && (
|
|
704
805
|
<div className="flex justify-center">
|
|
@@ -26,13 +26,28 @@ jest.mock('./lib/utils', () => ({
|
|
|
26
26
|
cn: (...classes) => classes.filter(Boolean).join(' '),
|
|
27
27
|
}));
|
|
28
28
|
|
|
29
|
+
|
|
30
|
+
|
|
29
31
|
// Mock fetch
|
|
30
32
|
global.fetch = jest.fn();
|
|
31
33
|
|
|
32
|
-
// Mock process.env
|
|
34
|
+
// Mock process.env and import.meta.env
|
|
33
35
|
process.env.VITE_COMMON_API_FUNCTION_KEY = 'test-key';
|
|
34
36
|
process.env.VITE_COMMON_API_BASE_URL = 'https://test-api.example.com';
|
|
35
37
|
|
|
38
|
+
// Mock import.meta.env for Vite environment variables
|
|
39
|
+
Object.defineProperty(globalThis, 'import', {
|
|
40
|
+
value: {
|
|
41
|
+
meta: {
|
|
42
|
+
env: {
|
|
43
|
+
VITE_COMMON_API_FUNCTION_KEY: 'test-key',
|
|
44
|
+
VITE_COMMON_API_BASE_URL: 'https://test-api.example.com',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
writable: true,
|
|
49
|
+
});
|
|
50
|
+
|
|
36
51
|
// Mock the UI components
|
|
37
52
|
jest.mock('./components/ui/input', () => ({
|
|
38
53
|
Input: ({ value, onChange, placeholder, ...props }) => {
|
|
@@ -237,4 +252,6 @@ describe('EmployeeSearchPage', () => {
|
|
|
237
252
|
expect(screen.getByPlaceholderText('Custom placeholder')).toBeInTheDocument();
|
|
238
253
|
});
|
|
239
254
|
});
|
|
255
|
+
|
|
256
|
+
|
|
240
257
|
});
|
|
@@ -32,7 +32,6 @@ const EmployeeSearchFilters = ({
|
|
|
32
32
|
showMaternityFilter = true,
|
|
33
33
|
showStartDateFilter = true,
|
|
34
34
|
showEndDateFilter = true,
|
|
35
|
-
showDbsFilter = true,
|
|
36
35
|
showWorkingHoursFilter = true,
|
|
37
36
|
}) => {
|
|
38
37
|
// Local state for filters that haven't been applied yet
|
|
@@ -130,8 +129,8 @@ const EmployeeSearchFilters = ({
|
|
|
130
129
|
};
|
|
131
130
|
|
|
132
131
|
return (
|
|
133
|
-
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 mb-6">
|
|
134
|
-
<div className="p-
|
|
132
|
+
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 mb-6" style={{ width: '100%', maxWidth: '100%', overflow: 'hidden' }}>
|
|
133
|
+
<div className="p-4">
|
|
135
134
|
{/* Advanced Filters Toggle */}
|
|
136
135
|
<div className="flex items-center justify-between">
|
|
137
136
|
<button
|
|
@@ -311,22 +310,6 @@ const EmployeeSearchFilters = ({
|
|
|
311
310
|
</div>
|
|
312
311
|
)}
|
|
313
312
|
|
|
314
|
-
{/* DBS Number Filter */}
|
|
315
|
-
{showDbsFilter && (
|
|
316
|
-
<div>
|
|
317
|
-
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
|
318
|
-
DBS Number
|
|
319
|
-
</label>
|
|
320
|
-
<Input
|
|
321
|
-
type="text"
|
|
322
|
-
value={localFilters.dbsNumber}
|
|
323
|
-
onChange={(e) => handleFilterChange("dbsNumber", e.target.value)}
|
|
324
|
-
placeholder="Search by DBS number"
|
|
325
|
-
className="bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white"
|
|
326
|
-
/>
|
|
327
|
-
</div>
|
|
328
|
-
)}
|
|
329
|
-
|
|
330
313
|
{/* Working Hours Filter */}
|
|
331
314
|
{showWorkingHoursFilter && (
|
|
332
315
|
<div>
|
|
@@ -345,42 +328,6 @@ const EmployeeSearchFilters = ({
|
|
|
345
328
|
</div>
|
|
346
329
|
)}
|
|
347
330
|
|
|
348
|
-
{/* Sort By */}
|
|
349
|
-
<div>
|
|
350
|
-
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
|
351
|
-
Sort By
|
|
352
|
-
</label>
|
|
353
|
-
<Select
|
|
354
|
-
value={localFilters.sortBy}
|
|
355
|
-
onChange={(e) => handleFilterChange("sortBy", e.target.value)}
|
|
356
|
-
className="bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white"
|
|
357
|
-
>
|
|
358
|
-
<SelectOption value="surname">Surname</SelectOption>
|
|
359
|
-
<SelectOption value="first_name">First Name</SelectOption>
|
|
360
|
-
<SelectOption value="full_name">Full Name</SelectOption>
|
|
361
|
-
<SelectOption value="site_name">Site</SelectOption>
|
|
362
|
-
<SelectOption value="role_name">Role</SelectOption>
|
|
363
|
-
<SelectOption value="start_date">Start Date</SelectOption>
|
|
364
|
-
<SelectOption value="employee_status">Status</SelectOption>
|
|
365
|
-
<SelectOption value="created">Created Date</SelectOption>
|
|
366
|
-
<SelectOption value="modified">Modified Date</SelectOption>
|
|
367
|
-
</Select>
|
|
368
|
-
</div>
|
|
369
|
-
|
|
370
|
-
{/* Sort Order */}
|
|
371
|
-
<div>
|
|
372
|
-
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
|
373
|
-
Sort Order
|
|
374
|
-
</label>
|
|
375
|
-
<Select
|
|
376
|
-
value={localFilters.sortOrder}
|
|
377
|
-
onChange={(e) => handleFilterChange("sortOrder", e.target.value)}
|
|
378
|
-
className="bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white"
|
|
379
|
-
>
|
|
380
|
-
<SelectOption value="asc">Ascending</SelectOption>
|
|
381
|
-
<SelectOption value="desc">Descending</SelectOption>
|
|
382
|
-
</Select>
|
|
383
|
-
</div>
|
|
384
331
|
</div>
|
|
385
332
|
|
|
386
333
|
{/* Apply/Cancel Buttons */}
|