Skip to content

Commit

Permalink
feat(DateInput): add prop onApply (#7929)
Browse files Browse the repository at this point in the history
* feat(DateInput): add prop `onApply`

* fix(DateInput): run prettier

* test(DateInput): add tests

* fix(Calendar): add time props from Calendar
  • Loading branch information
EldarMuhamethanov authored Dec 4, 2024
1 parent 8475760 commit 0c266b0
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 3 deletions.
72 changes: 72 additions & 0 deletions packages/vkui/src/components/DateInput/DateInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,76 @@ describe('DateInput', () => {

expect(container.contains(document.activeElement)).toBeFalsy();
});

it('should call onApply when clicking Done button', async () => {
jest.useFakeTimers();
const onApply = jest.fn();
const onChange = jest.fn();
const onCalendarOpenChanged = jest.fn();
render(
<DateInput
value={date}
onChange={onChange}
onApply={onApply}
enableTime={true}
onCalendarOpenChanged={onCalendarOpenChanged}
{...testIds}
calendarTestsProps={{
dayTestId,
doneButtonTestId: 'done-button',
}}
/>,
);

const [dates] = getInputsLike();
fireEvent.click(dates);

expect(onCalendarOpenChanged).toHaveBeenCalledTimes(1);

const doneButton = screen.getByTestId('done-button');
fireEvent.click(doneButton);

expect(onApply).toHaveBeenCalledWith(date);
expect(onChange).toHaveBeenCalledWith(date);
});

it('should not call onChange when selecting date in calendar with enableTime', async () => {
jest.useFakeTimers();
const onChange = jest.fn();
render(
<DateInput
value={date}
onChange={onChange}
enableTime={true}
changeMonthLabel=""
changeYearLabel=""
changeDayLabel=""
changeHoursLabel=""
changeMinutesLabel=""
{...testIds}
calendarTestsProps={{
dayTestId,
}}
/>,
);

const [dates] = getInputsLike();
await userEvent.click(dates);

const resultDate = subDays(date, 1);
fireEvent.click(screen.getByTestId(dayTestId(resultDate)));

const inputLikes = getInputsLike();
const normalizedDate = convertInputsToNumbers(inputLikes);

expect(normalizedDate).toEqual([
resultDate.getDate(),
resultDate.getMonth() + 1,
resultDate.getFullYear(),
resultDate.getHours(),
resultDate.getMinutes(),
]);

expect(onChange).not.toHaveBeenCalled();
});
});
39 changes: 36 additions & 3 deletions packages/vkui/src/components/DateInput/DateInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useExternRef } from '../../hooks/useExternRef';
import { callMultiple } from '../../lib/callMultiple';
import { format, isMatch, parse } from '../../lib/date';
import type { PlacementWithAuto } from '../../lib/floating';
import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';
import type { HasRootRef } from '../../types';
import { Calendar, type CalendarProps, type CalendarTestsProps } from '../Calendar/Calendar';
import { FormField, type FormFieldProps } from '../FormField/FormField';
Expand Down Expand Up @@ -77,6 +78,10 @@ export interface DateInputProps
showCalendarLabel?: string;
disableCalendar?: boolean;
onCalendarOpenChanged?: (opened: boolean) => void;
/**
* Колбэк срабатывающий при нажатии на кнопку "Done". Используется совместно с флагом `enableTime`.
*/
onApply?: (value?: Date) => void;
}

const elementsConfig = (index: number) => {
Expand Down Expand Up @@ -129,7 +134,7 @@ export const DateInput = ({
disablePast,
minDateTime,
maxDateTime,
value,
value: valueProp,
onChange,
calendarPlacement = 'bottom-start',
style,
Expand Down Expand Up @@ -170,16 +175,25 @@ export const DateInput = ({
yearFieldTestId,
hourFieldTestId,
minuteFieldTestId,
onApply,
...props
}: DateInputProps): React.ReactNode => {
const daysRef = React.useRef<HTMLSpanElement>(null);
const monthsRef = React.useRef<HTMLSpanElement>(null);
const yearsRef = React.useRef<HTMLSpanElement>(null);
const hoursRef = React.useRef<HTMLSpanElement>(null);
const minutesRef = React.useRef<HTMLSpanElement>(null);
const [value, setValue] = React.useState<Date | undefined>(valueProp);

const maxElement = enableTime ? 4 : 2;

useIsomorphicLayoutEffect(
function updateLocalValue() {
setValue(valueProp);
},
[valueProp],
);

const onInternalValueChange = React.useCallback(
(internalValue: string[]) => {
for (let i = 0; i <= maxElement; i += 1) {
Expand Down Expand Up @@ -238,16 +252,35 @@ export const DateInput = ({

const handleRootRef = useExternRef(rootRef, getRootRef);

useIsomorphicLayoutEffect(
function resetValueOnCloseCalendar() {
if (!open) {
setValue(valueProp);
}
},
[open, valueProp],
);

const onCalendarChange = React.useCallback(
(value?: Date | undefined) => {
if (enableTime) {
setValue(value);
return;
}
onChange?.(value);
if (closeOnChange && !enableTime) {
if (closeOnChange) {
removeFocusFromField();
}
},
[onChange, removeFocusFromField, closeOnChange, enableTime],
);

const onDoneButtonClick = React.useCallback(() => {
onApply?.(value);
onChange?.(value);
removeFocusFromField();
}, [onApply, onChange, removeFocusFromField, value]);

return (
<FormField
style={style}
Expand Down Expand Up @@ -350,7 +383,7 @@ export const DateInput = ({
disablePast={disablePast}
disableFuture={disableFuture}
shouldDisableDate={shouldDisableDate}
onDoneButtonClick={removeFocusFromField}
onDoneButtonClick={onDoneButtonClick}
getRootRef={calendarRef}
doneButtonText={doneButtonText}
DoneButton={DoneButton}
Expand Down

0 comments on commit 0c266b0

Please sign in to comment.