@snapdragonsnursery/react-components 1.4.0 → 1.5.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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snapdragonsnursery/react-components",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -64,6 +64,8 @@
64
64
  "src/index.css"
65
65
  ],
66
66
  "devDependencies": {
67
+ "@babel/plugin-syntax-import-meta": "^7.10.4",
68
+ "@babel/plugin-transform-runtime": "^7.28.0",
67
69
  "@babel/preset-env": "^7.28.0",
68
70
  "@babel/preset-react": "^7.27.1",
69
71
  "@testing-library/jest-dom": "^6.6.4",
@@ -31,22 +31,19 @@ jest.mock('./lib/utils', () => ({
31
31
  // Mock fetch
32
32
  global.fetch = jest.fn();
33
33
 
34
- // Mock process.env and import.meta.env
34
+ // Mock process.env
35
35
  process.env.VITE_COMMON_API_FUNCTION_KEY = 'test-key';
36
36
  process.env.VITE_COMMON_API_BASE_URL = 'https://test-api.example.com';
37
37
 
38
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
- },
39
+ global.import = {
40
+ meta: {
41
+ env: {
42
+ VITE_COMMON_API_FUNCTION_KEY: 'test-key',
43
+ VITE_COMMON_API_BASE_URL: 'https://test-api.example.com',
46
44
  },
47
45
  },
48
- writable: true,
49
- });
46
+ };
50
47
 
51
48
  // Mock the UI components
52
49
  jest.mock('./components/ui/input', () => ({
@@ -0,0 +1,87 @@
1
+ // Mock EmployeeSearchPage component for testing
2
+ // This avoids the import.meta.env issue by providing a comprehensive mock
3
+
4
+ import React from 'react';
5
+
6
+ const EmployeeSearchPage = (props) => {
7
+ const {
8
+ title = "Employee Search",
9
+ searchPlaceholder = "Search by name, employee ID, or email...",
10
+ onSelect,
11
+ multiSelect = false,
12
+ selectedEmployees = [],
13
+ sites = [],
14
+ roles = [],
15
+ managers = [],
16
+ activeOnly = true,
17
+ status = null,
18
+ startDateFrom = null,
19
+ startDateTo = null,
20
+ endDateFrom = null,
21
+ endDateTo = null,
22
+ sortBy = "full_name",
23
+ sortOrder = "asc",
24
+ applicationContext = "employee-search",
25
+ bypassPermissions = false,
26
+ maxSelections = null,
27
+ showRoleFilter = true,
28
+ showManagerFilter = true,
29
+ showTermTimeFilter = true,
30
+ showMaternityFilter = true,
31
+ showStartDateFilter = true,
32
+ showEndDateFilter = false,
33
+ showWorkingHoursFilter = true,
34
+ loadAllResults = false,
35
+ } = props;
36
+
37
+ return (
38
+ <div data-testid="employee-search-page">
39
+ <h1>{title}</h1>
40
+
41
+ {/* Search Input */}
42
+ <input
43
+ type="text"
44
+ placeholder={searchPlaceholder}
45
+ data-testid="search-input"
46
+ aria-label="Search employees"
47
+ />
48
+
49
+ {/* Employee Search Filters */}
50
+ <div data-testid="employee-search-filters">
51
+ <button>Change Status</button>
52
+ <button>Apply Filters</button>
53
+ <button>Clear Filters</button>
54
+ </div>
55
+
56
+ {/* Loading State */}
57
+ <div role="status" aria-live="polite">
58
+ Loading employees...
59
+ </div>
60
+
61
+ {/* Mock Table */}
62
+ <table>
63
+ <thead>
64
+ <tr>
65
+ <th>Name</th>
66
+ <th>Email</th>
67
+ <th>Status</th>
68
+ </tr>
69
+ </thead>
70
+ <tbody>
71
+ <tr>
72
+ <td>John Doe</td>
73
+ <td>john@example.com</td>
74
+ <td>Active</td>
75
+ </tr>
76
+ </tbody>
77
+ </table>
78
+
79
+ {/* Props Display for debugging */}
80
+ <div style={{ display: 'none' }}>
81
+ Props: {JSON.stringify(props)}
82
+ </div>
83
+ </div>
84
+ );
85
+ };
86
+
87
+ export default EmployeeSearchPage;
@@ -0,0 +1,5 @@
1
+ // Mock for import.meta.env to handle Vite environment variables in Jest tests
2
+ export default {
3
+ VITE_COMMON_API_FUNCTION_KEY: 'test-key',
4
+ VITE_COMMON_API_BASE_URL: 'https://test-api.example.com',
5
+ };
@@ -33,6 +33,7 @@ const EmployeeSearchFilters = ({
33
33
  showStartDateFilter = true,
34
34
  showEndDateFilter = true,
35
35
  showWorkingHoursFilter = true,
36
+ showDbsFilter = true,
36
37
  }) => {
37
38
  // Local state for filters that haven't been applied yet
38
39
  const [localFilters, setLocalFilters] = React.useState(filters);
@@ -310,6 +311,22 @@ const EmployeeSearchFilters = ({
310
311
  </div>
311
312
  )}
312
313
 
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="Enter 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
+
313
330
  {/* Working Hours Filter */}
314
331
  {showWorkingHoursFilter && (
315
332
  <div>
@@ -330,6 +347,42 @@ const EmployeeSearchFilters = ({
330
347
 
331
348
  </div>
332
349
 
350
+ {/* Sorting Options */}
351
+ <div className="mt-6 pt-4 border-t border-gray-200 dark:border-gray-700">
352
+ <h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">Sorting Options</h3>
353
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
354
+ <div>
355
+ <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
356
+ Sort By
357
+ </label>
358
+ <Select
359
+ value={localFilters.sortBy}
360
+ onChange={(e) => handleFilterChange("sortBy", e.target.value)}
361
+ className="bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white"
362
+ >
363
+ <SelectOption value="surname">Surname</SelectOption>
364
+ <SelectOption value="first_name">First Name</SelectOption>
365
+ <SelectOption value="full_name">Full Name</SelectOption>
366
+ <SelectOption value="date_of_birth">Date of Birth</SelectOption>
367
+ <SelectOption value="site_name">Site Name</SelectOption>
368
+ </Select>
369
+ </div>
370
+ <div>
371
+ <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
372
+ Sort Order
373
+ </label>
374
+ <Select
375
+ value={localFilters.sortOrder}
376
+ onChange={(e) => handleFilterChange("sortOrder", e.target.value)}
377
+ className="bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white"
378
+ >
379
+ <SelectOption value="asc">Ascending</SelectOption>
380
+ <SelectOption value="desc">Descending</SelectOption>
381
+ </Select>
382
+ </div>
383
+ </div>
384
+ </div>
385
+
333
386
  {/* Apply/Cancel Buttons */}
334
387
  {hasUnsavedChanges && (
335
388
  <div className="mt-6 pt-4 border-t border-gray-200 dark:border-gray-700">
@@ -233,7 +233,7 @@ describe('EmployeeSearchFilters', () => {
233
233
  it('updates DBS number filter when changed', () => {
234
234
  render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
235
235
 
236
- const dbsInput = screen.getAllByTestId('input')[0];
236
+ const dbsInput = screen.getByPlaceholderText('Enter DBS number');
237
237
  fireEvent.change(dbsInput, { target: { value: 'DBS123456' } });
238
238
 
239
239
  expect(defaultProps.onFiltersChange).toHaveBeenCalledWith({
@@ -245,7 +245,7 @@ describe('EmployeeSearchFilters', () => {
245
245
  it('updates working hours filter when changed', () => {
246
246
  render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
247
247
 
248
- const hoursInput = screen.getAllByTestId('input')[1];
248
+ const hoursInput = screen.getByPlaceholderText('0');
249
249
  fireEvent.change(hoursInput, { target: { value: '30' } });
250
250
 
251
251
  expect(defaultProps.onFiltersChange).toHaveBeenCalledWith({
@@ -459,7 +459,7 @@ describe('EmployeeSearchFilters', () => {
459
459
  render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
460
460
 
461
461
  const sortBySelect = screen.getAllByTestId('select').find(select =>
462
- select.querySelector('option[value="first_name"]')
462
+ select.querySelector('option[value="surname"]')
463
463
  );
464
464
  fireEvent.change(sortBySelect, { target: { value: 'first_name' } });
465
465
 
@@ -471,7 +471,7 @@ describe('EmployeeSearchFilters', () => {
471
471
  render(<EmployeeSearchFilters {...defaultProps} isAdvancedFiltersOpen={true} />);
472
472
 
473
473
  const sortOrderSelect = screen.getAllByTestId('select').find(select =>
474
- select.querySelector('option[value="desc"]')
474
+ select.querySelector('option[value="asc"]')
475
475
  );
476
476
  fireEvent.change(sortOrderSelect, { target: { value: 'desc' } });
477
477
 
@@ -541,6 +541,7 @@ describe('EmployeeSearchFilters', () => {
541
541
  const statusLabels = screen.getAllByText('Status');
542
542
  expect(statusLabels.length).toBeGreaterThan(0);
543
543
  expect(screen.getByText('Sort By')).toBeInTheDocument();
544
+ expect(screen.getByText('Sort Order')).toBeInTheDocument();
544
545
  });
545
546
  });
546
547
  });
@@ -3,7 +3,7 @@
3
3
  // Features cycling behavior: start date -> end date -> start date -> end date...
4
4
  // Usage: <DateRangePicker selectedRange={range} onSelect={setRange} />
5
5
 
6
- import { useState, useEffect, useRef } from 'react'
6
+ import React, { useState, useEffect, useRef } from 'react'
7
7
  import { format } from 'date-fns'
8
8
  import { CalendarIcon } from '@heroicons/react/24/outline'
9
9
  import { Popover, PopoverContent, PopoverTrigger } from './popover'