@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.
- package/dist/components/Badge/Badge.js +1 -1
- package/dist/components/Dropdown/Dropdown.js +1 -1
- package/dist/components/HeaderFilterIcon/HeaderFilterIcon.d.ts +4 -0
- package/dist/components/HeaderFilterIcon/HeaderFilterIcon.js +60 -0
- package/dist/components/HeaderFilterIcon/HeaderFilterIcon.stories.d.ts +9 -0
- package/dist/components/HeaderFilterIcon/HeaderFilterIcon.stories.js +76 -0
- package/dist/components/HeaderFilterIcon/HeaderFilterIcon.test.d.ts +1 -0
- package/dist/components/HeaderFilterIcon/HeaderFilterIcon.test.js +104 -0
- package/dist/components/HeaderFilterIcon/index.d.ts +2 -0
- package/dist/components/HeaderFilterIcon/index.js +2 -0
- package/dist/components/HeaderFilterIcon/types.d.ts +22 -0
- package/dist/components/HeaderFilterIcon/types.js +1 -0
- package/dist/components/Input/Input.js +3 -3
- package/dist/components/InputAndCheck/InputAndCheck.js +0 -9
- package/dist/components/MagnifyingIcon/MagnifyingIcon.js +1 -1
- package/dist/components/MagnifyingIcon/MagnifyingIcon.stories.js +1 -0
- package/dist/components/PrimaryTableHeader/PrimaryTableHeader.js +2 -2
- package/dist/components/SearchInput/SearchDropdownInput.d.ts +1 -0
- package/dist/components/SearchInput/SearchDropdownInput.js +2 -3
- package/dist/components/SearchInput/SearchInput.d.ts +1 -1
- package/dist/components/SearchInput/SearchInput.js +9 -51
- package/dist/components/SearchInput/SearchInput.stories.d.ts +1 -1
- package/dist/components/SearchInput/SearchInput.stories.js +32 -53
- package/dist/components/SearchInput/SearchInput.test.d.ts +1 -0
- package/dist/components/SearchInput/SearchInput.test.js +519 -0
- package/dist/components/SearchInput/SearchInput.types.d.ts +8 -12
- package/dist/components/SearchInput/SearchInputDatePicker.d.ts +23 -0
- package/dist/components/SearchInput/SearchInputDatePicker.js +72 -0
- package/dist/components/SearchInput/SearchNumberInput.d.ts +2 -14
- package/dist/components/SearchInput/SearchNumberInput.js +16 -35
- package/dist/components/SearchInput/SearchTextInput.d.ts +2 -11
- package/dist/components/SearchInput/SearchTextInput.js +8 -27
- 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
|
-
|
|
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?:
|
|
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;
|