Skip to content

Commit

Permalink
[pickers] Keep the existing time when looking for closest enabled date (
Browse files Browse the repository at this point in the history
@LukasTy) (#12410)

Signed-off-by: Lukas <[email protected]>
Co-authored-by: Lukas <[email protected]>
  • Loading branch information
github-actions[bot] and LukasTy authored Mar 11, 2024
1 parent 9fdf893 commit 94a70b2
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import { createPickerRenderer, AdapterClassToUse, adapterToUse } from 'test/util
const isJSDOM = /jsdom/.test(window.navigator.userAgent);

describe('<DateCalendar />', () => {
const { render, clock } = createPickerRenderer({ clock: 'fake' });
const { render, clock } = createPickerRenderer({
clock: 'fake',
clockConfig: new Date('2019-01-02'),
});

it('switches between views uncontrolled', () => {
const handleViewChange = spy();
Expand Down Expand Up @@ -146,6 +149,26 @@ describe('<DateCalendar />', () => {
expect(screen.getAllByRole('rowheader').length).to.equal(5);
});

// test: https://github.com/mui/mui-x/issues/12373
it('should not reset day to `startOfDay` if value already exists when finding the closest enabled date', () => {
const onChange = spy();
const defaultDate = adapterToUse.date('2019-01-02T11:12:13');
render(<DateCalendar onChange={onChange} disablePast defaultValue={defaultDate} />);

userEvent.mousePress(
screen.getByRole('button', { name: 'calendar view is open, switch to year view' }),
);
userEvent.mousePress(screen.getByRole('radio', { name: '2020' }));
userEvent.mousePress(screen.getByRole('gridcell', { name: '1' }));
userEvent.mousePress(
screen.getByRole('button', { name: 'calendar view is open, switch to year view' }),
);
// select the current year with a date in the past to trigger "findClosestEnabledDate"
userEvent.mousePress(screen.getByRole('radio', { name: '2019' }));

expect(onChange.lastCall.firstArg).toEqualDateTime(defaultDate);
});

describe('view: day', () => {
it('renders day calendar standalone', () => {
render(<DateCalendar defaultValue={adapterToUse.date(new Date(2019, 0, 1))} />);
Expand Down
20 changes: 20 additions & 0 deletions packages/x-date-pickers/src/internals/utils/date-utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expect } from 'chai';
import { adapterToUse } from 'test/utils/pickers';
import { useFakeTimers } from 'sinon';
import { findClosestEnabledDate } from './date-utils';

describe('findClosestEnabledDate', () => {
Expand Down Expand Up @@ -99,6 +100,25 @@ describe('findClosestEnabledDate', () => {
expect(adapterToUse.isSameDay(result, today)).to.equal(true);
});

it('should return now with given time part if disablePast and now is valid', () => {
const clock = useFakeTimers({ now: new Date('2000-01-02') });

const tryDate = adapterToUse.date('2000-01-01T11:12:13');
const result = findClosestEnabledDate({
date: tryDate,
minDate: adapterToUse.date('1900-01-01'),
maxDate: adapterToUse.date('2100-01-01'),
utils: adapterToUse,
isDateDisabled: () => false,
disableFuture: false,
disablePast: true,
timezone: 'default',
})!;

expect(result).toEqualDateTime(adapterToUse.addDays(tryDate, 1));
clock.reset();
});

it('should fallback to today if disablePast+disableFuture and now is invalid', () => {
const today = adapterToUse.date();
const result = findClosestEnabledDate({
Expand Down
29 changes: 14 additions & 15 deletions packages/x-date-pickers/src/internals/utils/date-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@ import { DateView, FieldValueType, MuiPickersAdapter, PickersTimezone } from '..
import { DateOrTimeViewWithMeridiem } from '../models';
import { areViewsEqual } from './views';

export const mergeDateAndTime = <TDate>(
utils: MuiPickersAdapter<TDate>,
dateParam: TDate,
timeParam: TDate,
) => {
let mergedDate = dateParam;
mergedDate = utils.setHours(mergedDate, utils.getHours(timeParam));
mergedDate = utils.setMinutes(mergedDate, utils.getMinutes(timeParam));
mergedDate = utils.setSeconds(mergedDate, utils.getSeconds(timeParam));

return mergedDate;
};

interface FindClosestDateParams<TDate> {
date: TDate;
disableFuture?: boolean;
Expand All @@ -23,8 +36,7 @@ export const findClosestEnabledDate = <TDate>({
utils,
timezone,
}: FindClosestDateParams<TDate>) => {
const today = utils.startOfDay(utils.dateWithTimezone(undefined, timezone));

const today = mergeDateAndTime(utils, utils.dateWithTimezone(undefined, timezone), date);
if (disablePast && utils.isBefore(minDate!, today)) {
minDate = today;
}
Expand Down Expand Up @@ -111,19 +123,6 @@ export const getMonthsInYear = <TDate>(utils: MuiPickersAdapter<TDate>, year: TD
return months;
};

export const mergeDateAndTime = <TDate>(
utils: MuiPickersAdapter<TDate>,
dateParam: TDate,
timeParam: TDate,
) => {
let mergedDate = dateParam;
mergedDate = utils.setHours(mergedDate, utils.getHours(timeParam));
mergedDate = utils.setMinutes(mergedDate, utils.getMinutes(timeParam));
mergedDate = utils.setSeconds(mergedDate, utils.getSeconds(timeParam));

return mergedDate;
};

export const getTodayDate = <TDate>(
utils: MuiPickersAdapter<TDate>,
timezone: PickersTimezone,
Expand Down

0 comments on commit 94a70b2

Please sign in to comment.