@agilant/toga-blox 1.0.47 → 1.0.49

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.
Files changed (33) hide show
  1. package/dist/components/Badge/Badge.js +1 -1
  2. package/dist/components/Dropdown/Dropdown.js +1 -1
  3. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.d.ts +4 -0
  4. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.js +60 -0
  5. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.stories.d.ts +9 -0
  6. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.stories.js +76 -0
  7. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.test.d.ts +1 -0
  8. package/dist/components/HeaderFilterIcon/HeaderFilterIcon.test.js +104 -0
  9. package/dist/components/HeaderFilterIcon/index.d.ts +2 -0
  10. package/dist/components/HeaderFilterIcon/index.js +2 -0
  11. package/dist/components/HeaderFilterIcon/types.d.ts +22 -0
  12. package/dist/components/HeaderFilterIcon/types.js +1 -0
  13. package/dist/components/Input/Input.js +3 -3
  14. package/dist/components/InputAndCheck/InputAndCheck.js +0 -9
  15. package/dist/components/MagnifyingIcon/MagnifyingIcon.js +1 -1
  16. package/dist/components/MagnifyingIcon/MagnifyingIcon.stories.js +1 -0
  17. package/dist/components/PrimaryTableHeader/PrimaryTableHeader.js +2 -2
  18. package/dist/components/SearchInput/SearchDropdownInput.d.ts +1 -0
  19. package/dist/components/SearchInput/SearchDropdownInput.js +2 -3
  20. package/dist/components/SearchInput/SearchInput.d.ts +1 -1
  21. package/dist/components/SearchInput/SearchInput.js +9 -51
  22. package/dist/components/SearchInput/SearchInput.stories.d.ts +1 -1
  23. package/dist/components/SearchInput/SearchInput.stories.js +32 -53
  24. package/dist/components/SearchInput/SearchInput.test.d.ts +1 -0
  25. package/dist/components/SearchInput/SearchInput.test.js +519 -0
  26. package/dist/components/SearchInput/SearchInput.types.d.ts +8 -12
  27. package/dist/components/SearchInput/SearchInputDatePicker.d.ts +23 -0
  28. package/dist/components/SearchInput/SearchInputDatePicker.js +72 -0
  29. package/dist/components/SearchInput/SearchNumberInput.d.ts +2 -14
  30. package/dist/components/SearchInput/SearchNumberInput.js +16 -35
  31. package/dist/components/SearchInput/SearchTextInput.d.ts +2 -11
  32. package/dist/components/SearchInput/SearchTextInput.js +8 -27
  33. package/package.json +2 -1
@@ -0,0 +1,519 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render, screen, fireEvent } from "@testing-library/react";
3
+ import { describe, expect, test, vi } from "vitest";
4
+ import SearchInput from "./SearchInput";
5
+ const mockOnDropdownOptionSelect = vi.fn();
6
+ const mockSetSearchItems = vi.fn();
7
+ const mockSetToggleStatus = vi.fn();
8
+ const mockSetMinValue = vi.fn();
9
+ const mockSetMaxValue = vi.fn();
10
+ const mockOnDateSelect = vi.fn();
11
+ const mockOnStartDateSelect = vi.fn();
12
+ const mockOnEndDateSelect = vi.fn();
13
+ const mockOnChange = vi.fn();
14
+ const mockHandleIconClick = vi.fn();
15
+ const mockHandleFilter = vi.fn();
16
+ const defaultProps = {
17
+ handleFilter: mockHandleFilter,
18
+ inputType: "text",
19
+ dropdownOptions: ["Option 1", "Option 2"],
20
+ selectedDropdownOption: "Option 1",
21
+ onDropdownOptionSelect: mockOnDropdownOptionSelect,
22
+ searchItems: [],
23
+ setSearchItems: mockSetSearchItems,
24
+ toggleStatus: false,
25
+ setToggleStatus: mockSetToggleStatus,
26
+ minValue: "",
27
+ maxValue: "",
28
+ setMinValue: mockSetMinValue,
29
+ setMaxValue: mockSetMaxValue,
30
+ selectedDate: null,
31
+ onDateSelect: mockOnDateSelect,
32
+ selectedStartDate: null,
33
+ onStartDateSelect: mockOnStartDateSelect,
34
+ selectedEndDate: null,
35
+ onEndDateSelect: mockOnEndDateSelect,
36
+ onChange: mockOnChange,
37
+ selectedValue: [],
38
+ value: [],
39
+ handleIconClick: mockHandleIconClick,
40
+ };
41
+ describe("SearchInput Component", () => {
42
+ describe("Text Input", () => {
43
+ test("renders search input field", () => {
44
+ render(_jsx(SearchInput, { ...defaultProps }));
45
+ expect(screen.getByPlaceholderText("Search")).toBeInTheDocument();
46
+ });
47
+ test("updates input value on change", () => {
48
+ render(_jsx(SearchInput, { ...defaultProps }));
49
+ const input = screen.getByPlaceholderText("Search");
50
+ fireEvent.change(input, { target: { value: "Test Input" } });
51
+ expect(input).toHaveValue("Test Input");
52
+ });
53
+ test("does not add empty search input to search items on enter press", () => {
54
+ render(_jsx(SearchInput, { ...defaultProps }));
55
+ const input = screen.getByPlaceholderText("Search");
56
+ fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
57
+ expect(mockSetSearchItems).toHaveBeenCalled();
58
+ });
59
+ test("adds valid input to search items on enter press", () => {
60
+ render(_jsx(SearchInput, { ...defaultProps }));
61
+ const input = screen.getByPlaceholderText("Search");
62
+ fireEvent.change(input, { target: { value: "New Search" } });
63
+ fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
64
+ expect(mockSetSearchItems).toHaveBeenCalledWith(["New Search"]);
65
+ });
66
+ test("clears input when clear icon is clicked", () => {
67
+ render(_jsx(SearchInput, { ...defaultProps }));
68
+ const input = screen.getByPlaceholderText("Search");
69
+ fireEvent.change(input, { target: { value: "Clear me" } });
70
+ const clearIcon = screen.getByTestId("clear-icon");
71
+ fireEvent.click(clearIcon);
72
+ expect(input).toHaveValue("");
73
+ });
74
+ test("removes search criterion when delete icon is clicked", () => {
75
+ render(_jsx(SearchInput, { ...defaultProps, searchItems: ["Test Item"] }));
76
+ fireEvent.click(screen.getByText("Test Item")); // Assuming clicking the item removes it
77
+ expect(mockSetSearchItems).toHaveBeenCalledWith([]);
78
+ });
79
+ test("renders dropdown with options", () => {
80
+ render(_jsx(SearchInput, { ...defaultProps }));
81
+ const dropdownTrigger = screen.getByText("Option 1"); // Default selected option
82
+ fireEvent.click(dropdownTrigger);
83
+ expect(screen.getByText("Option 2")).toBeInTheDocument();
84
+ });
85
+ test("calls dropdown selection handler when an option is clicked", () => {
86
+ render(_jsx(SearchInput, { ...defaultProps }));
87
+ const dropdownTrigger = screen.getByText("Option 1");
88
+ fireEvent.click(dropdownTrigger);
89
+ const option = screen.getByText("Option 2");
90
+ expect(option).toBeInTheDocument();
91
+ fireEvent.click(option);
92
+ expect(mockOnDropdownOptionSelect).toHaveBeenCalledWith("Option 2");
93
+ });
94
+ test("handles multiple items in search field", () => {
95
+ render(_jsx(SearchInput, { ...defaultProps, searchItems: ["Item 1", "Item 2"] }));
96
+ expect(screen.getByText("Item 1")).toBeInTheDocument();
97
+ expect(screen.getByText("Item 2")).toBeInTheDocument();
98
+ });
99
+ test("removes individual search item when close icon is clicked", () => {
100
+ render(_jsx(SearchInput, { ...defaultProps, searchItems: ["Item 1", "Item 2"] }));
101
+ const item1 = screen.getByText("Item 1");
102
+ fireEvent.click(item1);
103
+ expect(mockSetSearchItems).toHaveBeenCalledWith(["Item 2"]);
104
+ });
105
+ test("clears all search items when clicking on clear button", () => {
106
+ render(_jsx(SearchInput, { ...defaultProps, searchItems: ["Item 1", "Item 2"] }));
107
+ const clearIcons = screen.getAllByTestId("item-clear-icon");
108
+ expect(clearIcons).toHaveLength(2);
109
+ clearIcons.forEach((icon) => fireEvent.click(icon));
110
+ expect(mockSetSearchItems).toHaveBeenCalled();
111
+ });
112
+ test("renders a different dropdown icon when dropdownIconProp is provided", () => {
113
+ render(_jsx(SearchInput, { ...defaultProps, dropdownIconProp: {
114
+ iconClasses: "text-red-500",
115
+ name: "arrowDown",
116
+ weight: "bold",
117
+ } }));
118
+ const dropdownIconContainer = screen.getByTestId("dropdown-icon");
119
+ expect(dropdownIconContainer).toHaveClass("text-red-500");
120
+ console.log(dropdownIconContainer.classList);
121
+ });
122
+ test("does not add input text to search items when non-Enter key is pressed", () => {
123
+ render(_jsx(SearchInput, { ...defaultProps }));
124
+ const input = screen.getByPlaceholderText("Search");
125
+ fireEvent.change(input, { target: { value: "Test Input" } });
126
+ const initialCallCount = mockSetSearchItems.mock.calls.length;
127
+ fireEvent.keyDown(input, { key: "Escape", code: "Escape" });
128
+ expect(mockSetSearchItems.mock.calls.length).toBe(initialCallCount);
129
+ expect(input).toHaveValue("Test Input");
130
+ });
131
+ });
132
+ describe("Number Input", () => {
133
+ test("renders number input fields", () => {
134
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "number" }));
135
+ expect(screen.getByPlaceholderText("Amount")).toBeInTheDocument();
136
+ });
137
+ test("shows min and max fields only when toggle is clicked", () => {
138
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "number", toggleStatus: false }));
139
+ const toggleCheckbox = screen.getByRole("checkbox");
140
+ expect(toggleCheckbox).toBeInTheDocument();
141
+ fireEvent.click(toggleCheckbox);
142
+ expect(mockSetToggleStatus).toHaveBeenCalledWith(true);
143
+ // Re-render the component with the updated state
144
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "number", toggleStatus: true }));
145
+ expect(screen.getByPlaceholderText("Min")).toBeInTheDocument();
146
+ expect(screen.getByPlaceholderText("Max")).toBeInTheDocument();
147
+ });
148
+ test("updates min value on change after toggle is clicked", () => {
149
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "number", toggleStatus: true }));
150
+ const minInput = screen.getByPlaceholderText("Min");
151
+ fireEvent.change(minInput, { target: { value: "10" } });
152
+ expect(mockSetMinValue).toHaveBeenCalledWith("10");
153
+ });
154
+ test("updates max value on change after toggle is clicked", () => {
155
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "number", toggleStatus: true }));
156
+ const maxInput = screen.getByPlaceholderText("Max");
157
+ fireEvent.change(maxInput, { target: { value: "100" } });
158
+ expect(mockSetMaxValue).toHaveBeenCalledWith("100");
159
+ });
160
+ test("Filter button should be present", () => {
161
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "number" }));
162
+ const filterButton = screen.getByText("Filter");
163
+ expect(filterButton).toBeInTheDocument();
164
+ });
165
+ test("updates min value on input change", () => {
166
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "number", toggleStatus: true }));
167
+ const minInput = screen.getByPlaceholderText("Min");
168
+ fireEvent.change(minInput, { target: { value: "25" } });
169
+ expect(mockSetMinValue).toHaveBeenCalledWith("25");
170
+ });
171
+ test("renders a different dropdown icon when dropdownIconProp is provided", () => {
172
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "number", dropdownIconProp: {
173
+ iconClasses: "text-red-500",
174
+ name: "arrowDown",
175
+ weight: "bold",
176
+ } }));
177
+ const dropdownIconContainer = screen.getByTestId("dropdown-icon");
178
+ expect(dropdownIconContainer).toHaveClass("text-red-500");
179
+ });
180
+ });
181
+ describe("Dropdown Input", () => {
182
+ test("renders dropdown input with placeholder", () => {
183
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect" }));
184
+ // Ensure the dropdown renders with the placeholder "Search"
185
+ expect(screen.getByText("Search")).toBeInTheDocument();
186
+ });
187
+ test("opens dropdown and selects an option", async () => {
188
+ const mockOnChange = vi.fn();
189
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", onChange: mockOnChange, dropdownOptions: [
190
+ {
191
+ uuid: "1",
192
+ name: "Option 1",
193
+ value: "option1",
194
+ label: "Option 1",
195
+ },
196
+ {
197
+ uuid: "2",
198
+ name: "Option 2",
199
+ value: "option2",
200
+ label: "Option 2",
201
+ },
202
+ ] }));
203
+ // Open dropdown
204
+ const dropdown = screen.getByText(/Search/i);
205
+ fireEvent.click(dropdown);
206
+ // Wait for "Select All" option to appear
207
+ const option = await screen.findByText("Select All");
208
+ fireEvent.click(option);
209
+ // Assert that onChange received the correct selection
210
+ expect(mockOnChange).toHaveBeenCalled();
211
+ });
212
+ test("clears all selections when Clear button is clicked", () => {
213
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", selectedValue: [{ name: "Option 1", value: "option1" }] }));
214
+ const clearButton = screen.getByRole("button", { name: /clear/i });
215
+ fireEvent.click(clearButton);
216
+ expect(mockOnChange).toHaveBeenCalledWith([]);
217
+ });
218
+ test("Clears when Clear button is clicked", async () => {
219
+ const mockOnChange = vi.fn();
220
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", onChange: mockOnChange, dropdownOptions: [
221
+ {
222
+ uuid: "1",
223
+ name: "Option 1",
224
+ value: "option1",
225
+ label: "Option 1",
226
+ },
227
+ {
228
+ uuid: "2",
229
+ name: "Option 2",
230
+ value: "option2",
231
+ label: "Option 2",
232
+ },
233
+ ] }));
234
+ const dropdown = screen.getByText(/Search/i);
235
+ fireEvent.click(dropdown);
236
+ const ClearButton = await screen.findByText("Clear");
237
+ fireEvent.click(ClearButton);
238
+ expect(mockOnChange).toHaveBeenCalled();
239
+ });
240
+ test("calls handleFilter on Filter button click and stops propagation", async () => {
241
+ const mockHandleFilter = vi.fn();
242
+ const mockStopPropagation = vi.fn();
243
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", handleFilter: mockHandleFilter, dropdownOptions: [
244
+ {
245
+ uuid: "1",
246
+ name: "Option 1",
247
+ value: "option1",
248
+ label: "Option 1",
249
+ },
250
+ {
251
+ uuid: "2",
252
+ name: "Option 2",
253
+ value: "option2",
254
+ label: "Option 2",
255
+ },
256
+ ] }));
257
+ const dropdown = screen.getByText(/Search/i);
258
+ fireEvent.click(dropdown);
259
+ const ClearButton = await screen.findByText("Filter");
260
+ fireEvent.click(ClearButton);
261
+ expect(mockHandleFilter).toHaveBeenCalled();
262
+ });
263
+ });
264
+ describe("Boolean Input", () => {
265
+ const mockOnChange = vi.fn();
266
+ test("renders boolean input with placeholder", () => {
267
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", dropdownOptions: [
268
+ {
269
+ uuid: "1",
270
+ name: "True",
271
+ value: "true",
272
+ label: "True",
273
+ },
274
+ {
275
+ uuid: "2",
276
+ name: "False",
277
+ value: "false",
278
+ label: "False",
279
+ },
280
+ ] }));
281
+ expect(screen.getByText(/Search/i)).toBeInTheDocument();
282
+ });
283
+ test("opens boolean dropdown and selects an option", async () => {
284
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", onChange: mockOnChange, dropdownOptions: [
285
+ {
286
+ uuid: "1",
287
+ name: "True",
288
+ value: "true",
289
+ label: "True",
290
+ },
291
+ {
292
+ uuid: "2",
293
+ name: "False",
294
+ value: "false",
295
+ label: "False",
296
+ },
297
+ ] }));
298
+ // Open dropdown
299
+ const dropdown = screen.getByText(/Search/i);
300
+ fireEvent.click(dropdown);
301
+ const option = await screen.findByText("True");
302
+ fireEvent.click(option);
303
+ expect(mockOnChange).toHaveBeenCalledWith(expect.arrayContaining([{ name: "True", value: "true" }]));
304
+ });
305
+ test("clears all selections when Clear button is clicked", async () => {
306
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "multiSelect", selectedValue: [{ uuid: "1", name: "True", value: "true" }], onChange: mockOnChange, dropdownOptions: [
307
+ {
308
+ uuid: "1",
309
+ name: "True",
310
+ value: "true",
311
+ label: "True",
312
+ },
313
+ {
314
+ uuid: "2",
315
+ name: "False",
316
+ value: "false",
317
+ label: "False",
318
+ },
319
+ ] }));
320
+ // Open dropdown
321
+ const dropdown = screen.getByText("True");
322
+ fireEvent.click(dropdown);
323
+ // Find and click "Clear" button
324
+ const clearButton = await screen.findByText("Clear");
325
+ fireEvent.click(clearButton);
326
+ // Verify clearing of selections
327
+ expect(mockOnChange).toHaveBeenCalledWith([]);
328
+ });
329
+ });
330
+ describe("DateTimePicker Input", () => {
331
+ const mockOnDateSelect = vi.fn();
332
+ const mockOnStartDateSelect = vi.fn();
333
+ const mockOnEndDateSelect = vi.fn();
334
+ const mockSetToggleStatus = vi.fn();
335
+ const mockSetEditingHeader = vi.fn();
336
+ const mockCloseOutSearch = vi.fn();
337
+ const mockSetResetSearch = vi.fn();
338
+ const mockHandleFilter = vi.fn();
339
+ // Mock scrollIntoView to prevent errors in test execution
340
+ Element.prototype.scrollIntoView = vi.fn();
341
+ const defaultProps = {
342
+ handleFilter: mockHandleFilter,
343
+ closeOutSearch: mockCloseOutSearch,
344
+ setResetSearch: mockSetResetSearch,
345
+ setEditingHeader: mockSetEditingHeader,
346
+ toggleStatus: false,
347
+ setToggleStatus: mockSetToggleStatus,
348
+ selectedDate: null,
349
+ onDateSelect: mockOnDateSelect,
350
+ selectedStartDate: null,
351
+ onStartDateSelect: mockOnStartDateSelect,
352
+ selectedEndDate: null,
353
+ onEndDateSelect: mockOnEndDateSelect,
354
+ dropdownOptions: ["Option 1", "Option 2"],
355
+ selectedDropdownOption: "Option 1",
356
+ onDropdownOptionSelect: vi.fn(),
357
+ onChange: mockOnChange,
358
+ selectedValue: [],
359
+ value: [],
360
+ };
361
+ test("renders single date picker input inside SearchInput", () => {
362
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
363
+ expect(screen.getByText("Select Date")).toBeInTheDocument();
364
+ });
365
+ test("opens date picker when input is clicked", () => {
366
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
367
+ const dateInput = screen.getByText("Select Date");
368
+ fireEvent.click(dateInput);
369
+ expect(screen.getByRole("grid")).toBeInTheDocument(); // DayPicker should appear
370
+ });
371
+ test("selects a single date from the picker", () => {
372
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
373
+ fireEvent.click(screen.getByText("Select Date"));
374
+ const today = new Date().getDate();
375
+ fireEvent.click(screen.getByText(today.toString()));
376
+ expect(mockOnDateSelect).toHaveBeenCalled();
377
+ });
378
+ test("renders range date picker inputs when toggle is clicked", () => {
379
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
380
+ expect(screen.getByText("Start Date")).toBeInTheDocument();
381
+ expect(screen.getByText("End Date")).toBeInTheDocument();
382
+ });
383
+ test("opens start date picker when Start Date is clicked", () => {
384
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
385
+ const startDateInput = screen.getByText("Start Date");
386
+ fireEvent.click(startDateInput);
387
+ expect(screen.getByRole("grid")).toBeInTheDocument();
388
+ });
389
+ test("opens end date picker when End Date is clicked", () => {
390
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
391
+ const endDateInput = screen.getByText("End Date");
392
+ fireEvent.click(endDateInput);
393
+ expect(screen.getByRole("grid")).toBeInTheDocument();
394
+ });
395
+ test("selects a start date from the picker", () => {
396
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
397
+ fireEvent.click(screen.getByText("Start Date"));
398
+ const today = new Date().getDate();
399
+ fireEvent.click(screen.getByText(today.toString()));
400
+ expect(mockOnStartDateSelect).toHaveBeenCalled();
401
+ });
402
+ test("selects an end date from the picker", () => {
403
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
404
+ fireEvent.click(screen.getByText("End Date"));
405
+ const tomorrow = new Date();
406
+ tomorrow.setDate(tomorrow.getDate() + 1);
407
+ fireEvent.click(screen.getByText(tomorrow.getDate().toString()));
408
+ expect(mockOnEndDateSelect).toHaveBeenCalled();
409
+ });
410
+ test("closes date picker when clicking outside", () => {
411
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
412
+ const dateInput = screen.getByText("Select Date");
413
+ fireEvent.click(dateInput);
414
+ expect(screen.getByRole("grid")).toBeInTheDocument(); // Calendar is open
415
+ // Simulate clicking outside
416
+ fireEvent.mouseDown(document.body);
417
+ expect(screen.queryByRole("grid")).not.toBeInTheDocument(); // Calendar should be closed
418
+ });
419
+ test("calls handleSubmitClick and closes date picker when Filter button is clicked", () => {
420
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
421
+ fireEvent.click(screen.getByText("Select Date")); // Open the calendar
422
+ expect(screen.getByRole("grid")).toBeInTheDocument();
423
+ fireEvent.click(screen.getByText("Filter")); // Click the filter button
424
+ expect(mockHandleFilter).toHaveBeenCalled();
425
+ expect(screen.queryByRole("grid")).not.toBeInTheDocument(); // Ensure picker is closed
426
+ });
427
+ test("does not close date picker if clicking inside", () => {
428
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
429
+ fireEvent.click(screen.getByText("Select Date")); // Open the calendar
430
+ expect(screen.getByRole("grid")).toBeInTheDocument();
431
+ // Simulate clicking inside
432
+ fireEvent.mouseDown(screen.getByRole("grid"));
433
+ expect(screen.getByRole("grid")).toBeInTheDocument(); // Calendar should remain open
434
+ });
435
+ test("ensures handleSubmitClick closes the date picker and resets active input", () => {
436
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
437
+ fireEvent.click(screen.getByText("Select Date"));
438
+ expect(screen.getByRole("grid")).toBeInTheDocument();
439
+ fireEvent.click(screen.getByText("Filter"));
440
+ expect(mockHandleFilter).toHaveBeenCalled();
441
+ expect(screen.queryByRole("grid")).not.toBeInTheDocument();
442
+ });
443
+ test("ensures clicking on dropdown opens dropdown options", () => {
444
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
445
+ const dropdownTrigger = screen.getByText("Option 1");
446
+ fireEvent.click(dropdownTrigger);
447
+ expect(screen.getByText("Option 2")).toBeInTheDocument();
448
+ });
449
+ test("ensures clicking on an option in dropdown selects it", () => {
450
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
451
+ const dropdownTrigger = screen.getByText("Option 1");
452
+ fireEvent.click(dropdownTrigger);
453
+ const option = screen.getByText("Option 2");
454
+ fireEvent.click(option);
455
+ expect(defaultProps.onDropdownOptionSelect).toHaveBeenCalledWith("Option 2");
456
+ });
457
+ test("ensures toggle button switches mode correctly", () => {
458
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
459
+ const toggleCheckbox = screen.getByRole("checkbox");
460
+ fireEvent.click(toggleCheckbox);
461
+ expect(mockSetToggleStatus).toHaveBeenCalledWith(true);
462
+ });
463
+ test("ensures selecting a start and end date updates state", () => {
464
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
465
+ fireEvent.click(screen.getByText("Start Date"));
466
+ fireEvent.click(screen.getByText(new Date().getDate().toString()));
467
+ expect(mockOnStartDateSelect).toHaveBeenCalled();
468
+ fireEvent.click(screen.getByText("End Date"));
469
+ fireEvent.click(screen.getByText(new Date().getDate().toString()));
470
+ expect(mockOnEndDateSelect).toHaveBeenCalled();
471
+ });
472
+ test("toggles range mode when toggle button is clicked", () => {
473
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
474
+ const toggleCheckbox = screen.getByRole("checkbox");
475
+ fireEvent.click(toggleCheckbox);
476
+ expect(mockSetToggleStatus).toHaveBeenCalledWith(true);
477
+ });
478
+ test("renders selectedStartDate if provided, otherwise shows default text", () => {
479
+ const mockStartDate = new Date(2023, 5, 15); // June 15, 2023
480
+ const { rerender } = render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true, selectedStartDate: null }));
481
+ expect(screen.getByText("Start Date")).toBeInTheDocument();
482
+ rerender(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true, selectedStartDate: mockStartDate }));
483
+ expect(screen.getByText(mockStartDate.toLocaleDateString())).toBeInTheDocument();
484
+ });
485
+ test("calls onStartDateSelect when a start date is selected", () => {
486
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
487
+ // Open the Start Date Picker
488
+ fireEvent.click(screen.getByText("Start Date"));
489
+ // Pick a date (e.g., today's date)
490
+ const today = new Date().getDate();
491
+ fireEvent.click(screen.getByText(today.toString()));
492
+ // Expect the handler to be called
493
+ expect(mockOnStartDateSelect).toHaveBeenCalled();
494
+ });
495
+ test("calls onEndDateSelect when an end date is selected", () => {
496
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date", toggleStatus: true }));
497
+ // Open the End Date Picker
498
+ fireEvent.click(screen.getByText("End Date"));
499
+ const tomorrow = new Date();
500
+ tomorrow.setDate(tomorrow.getDate() + 1);
501
+ fireEvent.click(screen.getByText(tomorrow.getDate().toString()));
502
+ // Expect the handler to be called
503
+ expect(mockOnEndDateSelect).toHaveBeenCalled();
504
+ });
505
+ test("calls onDateSelect when a single date is selected", () => {
506
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date" }));
507
+ // Open the Date Picker
508
+ fireEvent.click(screen.getByText("Select Date"));
509
+ const today = new Date().getDate();
510
+ fireEvent.click(screen.getByText(today.toString()));
511
+ // Expect the handler to be called
512
+ expect(mockOnDateSelect).toHaveBeenCalled();
513
+ });
514
+ test("shows placeholder text when no date is selected", () => {
515
+ render(_jsx(SearchInput, { ...defaultProps, inputType: "date", selectedDate: null }));
516
+ expect(screen.getByText("Select Date")).toBeInTheDocument();
517
+ });
518
+ });
519
+ });
@@ -1,22 +1,13 @@
1
1
  import React from "react";
2
2
  import { Control } from "react-hook-form";
3
- import { Accessor, ColumnInstance } from "react-table";
4
- type ColumnWithAccessor<T extends object> = ColumnInstance<T> & {
5
- accessor?: string | number | symbol | Accessor<T>;
6
- };
7
3
  export type SearchInputProps<T extends object> = {
8
4
  onChange(newSelected: OptionType[]): unknown;
9
5
  selectedValue: any[];
10
6
  value: any[];
11
- closeOutSearch: (value: number | null) => void;
12
- setResetSearch: React.Dispatch<React.SetStateAction<boolean>>;
13
- columHeader?: any;
14
- column: ColumnWithAccessor<T>;
15
- parentIndex?: number;
16
- setEditingHeader: (value: number | null) => void;
7
+ handleFilter: () => void;
17
8
  bgColor?: string;
18
9
  textHighlight?: string;
19
- inputType?: string;
10
+ inputType?: 'text' | 'number' | 'date' | 'boolean' | 'multiSelect';
20
11
  dropdownOptions?: string[] | OptionType[] | number[];
21
12
  selectedDropdownOption?: string | OptionType | number;
22
13
  onDropdownOptionSelect?: (option: string) => void;
@@ -32,6 +23,12 @@ export type SearchInputProps<T extends object> = {
32
23
  control?: Control<any>;
33
24
  valueKey?: string;
34
25
  dynamicDefaultValue?: any;
26
+ selectedDate?: Date;
27
+ onDateSelect?: (date: Date) => void;
28
+ selectedStartDate?: Date;
29
+ onStartDateSelect?: (date: Date) => void;
30
+ selectedEndDate?: Date;
31
+ onEndDateSelect?: (date: Date) => void;
35
32
  };
36
33
  export interface OptionType {
37
34
  uuid: string;
@@ -44,4 +41,3 @@ export type searchDropdownIconProps = {
44
41
  weight: string;
45
42
  iconClasses: string;
46
43
  };
47
- export {};
@@ -0,0 +1,23 @@
1
+ import React from "react";
2
+ import "react-day-picker/dist/style.css";
3
+ import { searchDropdownIconProps } from "./SearchInput.types";
4
+ type SearchDatePickerInputProps<T extends object> = {
5
+ textHighlight?: string;
6
+ dropdownOptions?: string[];
7
+ selectedDropdownOption?: string;
8
+ onDropdownOptionSelect?: (option: string) => void;
9
+ dropdownIconProp?: searchDropdownIconProps;
10
+ toggleStatus?: boolean;
11
+ setToggleStatus?: React.Dispatch<React.SetStateAction<boolean>>;
12
+ themeBgColor?: string;
13
+ lightThemeBg?: string;
14
+ selectedDate?: Date;
15
+ onDateSelect?: (date: Date) => void;
16
+ selectedStartDate?: Date;
17
+ onStartDateSelect?: (date: Date) => void;
18
+ selectedEndDate?: Date;
19
+ onEndDateSelect?: (date: Date) => void;
20
+ handleFilter?: () => void;
21
+ };
22
+ declare function SearchDatePickerInput<T extends object>({ textHighlight, dropdownOptions, selectedDropdownOption, onDropdownOptionSelect, dropdownIconProp, toggleStatus, setToggleStatus, themeBgColor, lightThemeBg, selectedDate, onDateSelect, selectedStartDate, onStartDateSelect, selectedEndDate, onEndDateSelect, handleFilter, }: SearchDatePickerInputProps<T>): import("react/jsx-runtime").JSX.Element;
23
+ export default SearchDatePickerInput;
@@ -0,0 +1,72 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { DayPicker } from "react-day-picker";
4
+ import "react-day-picker/dist/style.css";
5
+ import Dropdown from "../Dropdown/Dropdown";
6
+ import ToggleButton from "../ToggleButton/ToggleButton";
7
+ import BaseButton from "../BaseButton";
8
+ function SearchDatePickerInput({ textHighlight = "text-sky-700", dropdownOptions = [], selectedDropdownOption = "", onDropdownOptionSelect, dropdownIconProp = {
9
+ iconClasses: "text-sky-500",
10
+ name: "chevronDown",
11
+ weight: "solid",
12
+ }, toggleStatus = false, setToggleStatus, themeBgColor = "bg-sky-500", lightThemeBg = "bg-sky-100", selectedDate, onDateSelect, selectedStartDate, onStartDateSelect, selectedEndDate, onEndDateSelect, handleFilter, }) {
13
+ const containerRef = useRef(null);
14
+ // Remove internal state for the date values (they come from props)
15
+ // Internal UI state for showing the calendar and active input remains:
16
+ const [isDatePickerOpen, setIsDatePickerOpen] = useState(false);
17
+ const [activeInput, setActiveInput] = useState(null);
18
+ useEffect(() => {
19
+ containerRef.current?.scrollIntoView();
20
+ }, []);
21
+ // Close calendar(s) when clicking outside the container
22
+ useEffect(() => {
23
+ function handleClickOutside(event) {
24
+ if (containerRef.current &&
25
+ !containerRef.current.contains(event.target)) {
26
+ setIsDatePickerOpen(false);
27
+ setActiveInput(null);
28
+ }
29
+ }
30
+ document.addEventListener("mousedown", handleClickOutside);
31
+ return () => {
32
+ document.removeEventListener("mousedown", handleClickOutside);
33
+ };
34
+ }, []);
35
+ // Handler for the Filter button remains similar,
36
+ // but it now uses the values from props.
37
+ const handleSubmitClick = () => {
38
+ // Close the calendar(s) after filtering
39
+ setIsDatePickerOpen(false);
40
+ setActiveInput(null);
41
+ handleFilter();
42
+ };
43
+ const modifiersClassNames = {
44
+ selected: `${themeBgColor} text-white rounded-full`,
45
+ today: `${lightThemeBg} ${textHighlight}`,
46
+ };
47
+ return (_jsxs("div", { ref: containerRef, className: "relative w-[425px] border-2 p-4", children: [_jsx("div", { className: "flex items-center justify-between h-12", children: toggleStatus ? (
48
+ // Toggle mode: two separate inputs with a "to" between them
49
+ _jsxs("div", { className: "flex items-center w-full", children: [_jsx("button", { onClick: () => setActiveInput("start"), className: "border-2 px-3 py-2 flex-1 h-10 text-left", children: selectedStartDate
50
+ ? selectedStartDate.toLocaleDateString()
51
+ : "Start Date" }), _jsx("span", { className: "mx-2", children: "to" }), _jsx("button", { onClick: () => setActiveInput("end"), className: "border-2 px-3 py-2 flex-1 h-10 text-left", children: selectedEndDate
52
+ ? selectedEndDate.toLocaleDateString()
53
+ : "End Date" })] })) : (
54
+ // Non-toggle mode: Dropdown and a single date input
55
+ _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: () => setIsDatePickerOpen((prev) => !prev), className: "border-2 px-3 py-2 flex-[2] h-10 text-left", children: selectedDate
56
+ ? selectedDate.toLocaleDateString()
57
+ : "Select Date" })] })) }), toggleStatus
58
+ ? 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: (date) => {
59
+ if (onStartDateSelect)
60
+ onStartDateSelect(date);
61
+ setActiveInput(null); // close calendar after selection
62
+ }, modifiersClassNames: modifiersClassNames })) : (_jsx(DayPicker, { mode: "single", selected: selectedEndDate, onSelect: (date) => {
63
+ if (onEndDateSelect)
64
+ onEndDateSelect(date);
65
+ setActiveInput(null); // close calendar after selection
66
+ }, modifiersClassNames: modifiersClassNames })) }))
67
+ : 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: (date) => {
68
+ if (onDateSelect)
69
+ onDateSelect(date);
70
+ }, modifiersClassNames: modifiersClassNames }) })), _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: handleSubmitClick, shape: "rounded-full" })] })] }));
71
+ }
72
+ export default SearchDatePickerInput;