From 78abec7be5cabc1a7e2a164f94037e93ea09a5af Mon Sep 17 00:00:00 2001 From: clukhei Date: Wed, 14 Aug 2024 14:30:37 +0800 Subject: [PATCH 1/2] fix(datepicker): call onChangeDate when keyboard enter valid date(s) --- src/DatePicker/Calendar.tsx | 7 ++++ src/DatePicker/DatePicker.tsx | 12 ++++--- tests/DatePicker/DatePicker.test.tsx | 50 ++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/DatePicker/Calendar.tsx b/src/DatePicker/Calendar.tsx index f64c5b49..68d405f0 100644 --- a/src/DatePicker/Calendar.tsx +++ b/src/DatePicker/Calendar.tsx @@ -52,11 +52,18 @@ export const Calendar = React.forwardRef( } = React.useContext(DatePickerContext); const handleClick = (e: React.MouseEvent) => { + + const day = e.currentTarget.getAttribute('data-day')!; const displayDateClone = new Date(props.displayDate); const newSelectedDate = setTimeToNoon(displayDateClone); newSelectedDate.setDate(parseInt(day)); + + // if (props.mode === "range" && (props.selectedDate as RangeSelectionValue)?.start) { + // props.changeDate({start: (props.selectedDate as RangeSelectionValue)?.start, end: newSelectedDate}) + // } props.changeDate(newSelectedDate); + }; /** diff --git a/src/DatePicker/DatePicker.tsx b/src/DatePicker/DatePicker.tsx index d6caa19e..b316bf9d 100644 --- a/src/DatePicker/DatePicker.tsx +++ b/src/DatePicker/DatePicker.tsx @@ -365,8 +365,9 @@ export const DatePicker: BsPrefixRefForwardingComponent< })); if (newSelectedDates.end) { dropdownToggleRef?.current?.click(); + // onChangeDate calls only when both start and end dates are selected + props.onChangeDate?.(newSelectedDates); } - props.onChangeDate?.(newSelectedDates); }; const focusOnDateCalendar = () => { @@ -548,7 +549,8 @@ export const DatePicker: BsPrefixRefForwardingComponent< selectedDate: parsedDate, invalid: false, })); - updateFocusedDate(parsedDate); + updateFocusedDate(setTimeToNoon(parsedDate)); + props.onChangeDate?.(setTimeToNoon(parsedDate)); return; } @@ -557,6 +559,7 @@ export const DatePicker: BsPrefixRefForwardingComponent< inputDate: enteredDate, })); updateFocusedDate(displayDate); + }; const enterDateRange = (event: React.ChangeEvent) => { @@ -600,13 +603,14 @@ export const DatePicker: BsPrefixRefForwardingComponent< ...prevState, inputDate: inputDate, selectedDate: { - start: dateStart, - end: dateEnd, + start: setTimeToNoon(dateStart), + end: setTimeToNoon(dateEnd), }, displayDate: dateEnd, invalid: false, })); updateFocusedDate(dateEnd); + props.onChangeDate?.({start: setTimeToNoon(dateStart), end: setTimeToNoon(dateEnd) }) return; } diff --git a/tests/DatePicker/DatePicker.test.tsx b/tests/DatePicker/DatePicker.test.tsx index 114b0e6c..4154f0cc 100644 --- a/tests/DatePicker/DatePicker.test.tsx +++ b/tests/DatePicker/DatePicker.test.tsx @@ -214,6 +214,42 @@ describe('DatePicker', () => { expect(container.querySelector('button')).toHaveAttribute('disabled'); }); + it('onChangeDate fn fires when a valid date is typed in the Datepicker Input', async () => { + const mockFn = jest.fn(); + const { container } = render(); + const input = container.querySelector('input') as HTMLInputElement; + input?.focus(); + fireEvent.change(input, { target: { value: '24/05/2024' } }); + expect(mockFn).toHaveBeenCalled(); + }); + it('onChangeDate fn does not fire when an invalid date is typed in the Datepicker Input', async () => { + const mockFn = jest.fn(); + const { container } = render(); + const input = container.querySelector('input') as HTMLInputElement; + input?.focus(); + fireEvent.change(input, { target: { value: '24/05/1000' } }); + expect(mockFn).not.toHaveBeenCalled(); + }); + it('when mode=range, onChangeDate fn only fires when an start and end valid dates are typed in the Datepicker Input', async () => { + const mockFn = jest.fn(); + const { container } = render( + + ); + const input = container.querySelector('input') as HTMLInputElement; + input?.focus(); + // valid start date only + fireEvent.change(input, { target: { value: '24/05/2024' } }); + expect(mockFn).not.toHaveBeenCalled(); + // invalid end date + fireEvent.change(input, { target: { value: '24/05/2024 - 30/02/2024' } }); + expect(mockFn).not.toHaveBeenCalled(); + // clear input + fireEvent.change(input, { target: { value: '' } }); + expect(mockFn).not.toHaveBeenCalled(); + //valid start and end date + fireEvent.change(input, { target: { value: '24/05/2024 - 30/03/2024' } }); + expect(mockFn).toHaveBeenCalled(); + }); it('onChangeDate fn fires when dates clicked', async () => { const mockFn = jest.fn(); const { getByText, container } = render( @@ -226,6 +262,20 @@ describe('DatePicker', () => { fireEvent.click(getByText('1')); await waitFor(() => expect(mockFn).toHaveBeenCalled()); }); + it('in mode=range, onChangeDate fn fires only after both dates clicked', async () => { + const mockFn = jest.fn(); + const { getByText, container } = render( + + ); + fireEvent.click(container.querySelector('button.dropdown-toggle')!); + await waitFor(() => + expect(container.querySelector('.dropdown-menu.show')).toBeInTheDocument() + ); + fireEvent.click(getByText('1')); + expect(mockFn).not.toHaveBeenCalled(); + fireEvent.click(getByText('3')); + expect(mockFn).toHaveBeenCalled(); + }); it('onChange and onClear fn fires when click on Clear button', async () => { const onChangeDate = jest.fn(); From 1c444414369aeaa4508eace9879f1c996f0db082 Mon Sep 17 00:00:00 2001 From: clukhei Date: Wed, 14 Aug 2024 14:38:36 +0800 Subject: [PATCH 2/2] chore(*): cleanup --- src/DatePicker/Calendar.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/DatePicker/Calendar.tsx b/src/DatePicker/Calendar.tsx index 68d405f0..f64c5b49 100644 --- a/src/DatePicker/Calendar.tsx +++ b/src/DatePicker/Calendar.tsx @@ -52,18 +52,11 @@ export const Calendar = React.forwardRef( } = React.useContext(DatePickerContext); const handleClick = (e: React.MouseEvent) => { - - const day = e.currentTarget.getAttribute('data-day')!; const displayDateClone = new Date(props.displayDate); const newSelectedDate = setTimeToNoon(displayDateClone); newSelectedDate.setDate(parseInt(day)); - - // if (props.mode === "range" && (props.selectedDate as RangeSelectionValue)?.start) { - // props.changeDate({start: (props.selectedDate as RangeSelectionValue)?.start, end: newSelectedDate}) - // } props.changeDate(newSelectedDate); - }; /**