Skip to content

Commit

Permalink
[DateRangePicker] Fix when typed invalid value, then closed and reope…
Browse files Browse the repository at this point in the history
…ned the DateRangePicker(#1755)

* [DateRangePicker] Fix crashing when invalid date input applied as valiue

* Do not run `findClosestEnabledDate` for DateRangePicker calendars

* Remove inline style from <Calendar />, closes #1679

* [DateRangePicker] Keep input values even if they are invalid

* Fix missing import

* [DateRangePicker] Make impossible to navigate to the date after min/max date from calendar

* Fix issues found by ts
  • Loading branch information
dmtrKovalenko authored May 7, 2020
1 parent 6c5ee13 commit efd9556
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 143 deletions.
69 changes: 0 additions & 69 deletions docs/prop-types.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 11 additions & 11 deletions lib/.size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
{
"build/dist/material-ui-pickers.esm.js": {
"bundled": 188885,
"minified": 101313,
"gzipped": 26393,
"bundled": 188938,
"minified": 101335,
"gzipped": 26402,
"treeshaked": {
"rollup": {
"code": 83394,
"code": 83375,
"import_statements": 2121
},
"webpack": {
"code": 92872
"code": 92851
}
}
},
"build/dist/material-ui-pickers.umd.js": {
"bundled": 299785,
"minified": 116974,
"gzipped": 33364
"bundled": 299832,
"minified": 116954,
"gzipped": 33374
},
"build/dist/material-ui-pickers.umd.min.js": {
"bundled": 258439,
"minified": 107835,
"gzipped": 30612
"bundled": 258486,
"minified": 107815,
"gzipped": 30601
}
}
25 changes: 13 additions & 12 deletions lib/src/DateRangePicker/DateRangePickerInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { RangeInput, DateRange } from './RangeTypes';
import { useUtils } from '../_shared/hooks/useUtils';
import { makeStyles } from '@material-ui/core/styles';
import { MaterialUiPickersDate } from '../typings/date';
import { CurrentlySelectingRangeEndProps } from './RangeTypes';
Expand Down Expand Up @@ -62,26 +63,26 @@ export interface DateRangeInputProps
}

export const DateRangePickerInput: React.FC<DateRangeInputProps> = ({
rawValue,
onChange,
rawValue: [start, end],
parsedDateValue: [parsedStart, parsedEnd],
open,
containerRef,
forwardedRef,
currentlySelectingRangeEnd,
setCurrentlySelectingRangeEnd,
openPicker,
disableOpenPicker,
startText,
endText,
forwardedRef,
onBlur,
onChange,
open,
openPicker,
rawValue,
readOnly,
renderInput,
setCurrentlySelectingRangeEnd,
startText,
TextFieldProps,
onBlur,
rawValue: [start, end],
validationError: [startValidationError, endValidationError],
...other
}) => {
const utils = useUtils();
const classes = useStyles();
const startRef = React.useRef<HTMLInputElement>(null);
const endRef = React.useRef<HTMLInputElement>(null);
Expand All @@ -108,11 +109,11 @@ export const DateRangePickerInput: React.FC<DateRangeInputProps> = ({
);

const handleStartChange = (date: MaterialUiPickersDate, inputString?: string) => {
lazyHandleChangeCallback([date, parsedEnd], inputString);
lazyHandleChangeCallback([date, utils.date(end)], inputString);
};

const handleEndChange = (date: MaterialUiPickersDate, inputString?: string) => {
lazyHandleChangeCallback([parsedStart, date], inputString);
lazyHandleChangeCallback([utils.date(start), date], inputString);
};

const openRangeStartSelection = () => {
Expand Down
20 changes: 13 additions & 7 deletions lib/src/DateRangePicker/DateRangePickerViewDesktop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ import { makeStyles } from '@material-ui/core/styles';
import { MaterialUiPickersDate } from '../typings/date';
import { calculateRangePreview } from './date-range-manager';
import { Calendar, CalendarProps } from '../views/Calendar/Calendar';
import { isWithinRange, isStartOfRange, isEndOfRange } from '../_helpers/date-utils';
import { defaultMinDate, defaultMaxDate } from '../constants/prop-types';
import { ArrowSwitcher, ExportedArrowSwitcherProps } from '../_shared/ArrowSwitcher';
import {
usePreviousMonthDisabled,
useNextMonthDisabled,
} from '../_shared/hooks/date-helpers-hooks';
import {
isWithinRange,
isStartOfRange,
isEndOfRange,
DateValidationProps,
} from '../_helpers/date-utils';

export interface ExportedDesktopDateRangeCalendarProps {
/**
Expand All @@ -24,6 +30,7 @@ export interface ExportedDesktopDateRangeCalendarProps {
interface DesktopDateRangeCalendarProps
extends ExportedDesktopDateRangeCalendarProps,
CalendarProps,
DateValidationProps,
ExportedArrowSwitcherProps {
date: DateRange;
changeMonth: (date: MaterialUiPickersDate) => void;
Expand Down Expand Up @@ -82,14 +89,17 @@ export const DateRangePickerViewDesktop: React.FC<DesktopDateRangeCalendarProps>
onChange,
disableFuture,
disablePast,
minDate,
maxDate,
minDate: __minDate,
maxDate: __maxDate,
currentlySelectingRangeEnd,
currentMonth,
...other
}) => {
const utils = useUtils();
const classes = useStyles();
const minDate = __minDate || utils.date(defaultMinDate);
const maxDate = __maxDate || utils.date(defaultMaxDate);

const [rangePreviewDay, setRangePreviewDay] = React.useState<MaterialUiPickersDate>(null);

const isNextMonthDisabled = useNextMonthDisabled(currentMonth, { disableFuture, maxDate });
Expand Down Expand Up @@ -161,10 +171,6 @@ export const DateRangePickerViewDesktop: React.FC<DesktopDateRangeCalendarProps>
{...other}
key={index}
date={date}
minDate={minDate}
maxDate={maxDate}
disablePast={disablePast}
disableFuture={disableFuture}
className={classes.calendar}
onChange={handleDayChange}
currentMonth={monthOnIteration}
Expand Down
15 changes: 14 additions & 1 deletion lib/src/DateRangePicker/DateRangePickerViewMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@ import { useUtils } from '../_shared/hooks/useUtils';
import { MaterialUiPickersDate } from '../typings/date';
import { Calendar, CalendarProps } from '../views/Calendar/Calendar';
import { ExportedArrowSwitcherProps } from '../_shared/ArrowSwitcher';
import { isWithinRange, isStartOfRange, isEndOfRange } from '../_helpers/date-utils';
import { defaultMinDate, defaultMaxDate } from '../constants/prop-types';
import {
isWithinRange,
isStartOfRange,
isEndOfRange,
DateValidationProps,
} from '../_helpers/date-utils';

export interface ExportedMobileDateRangeCalendarProps {}

interface DesktopDateRangeCalendarProps
extends ExportedMobileDateRangeCalendarProps,
CalendarProps,
DateValidationProps,
ExportedArrowSwitcherProps {
date: DateRange;
changeMonth: (date: MaterialUiPickersDate) => void;
Expand All @@ -30,9 +37,13 @@ export const DateRangePickerViewMobile: React.FC<DesktopDateRangeCalendarProps>
rightArrowButtonText,
rightArrowIcon,
onChange,
minDate: __minDate,
maxDate: __maxDate,
...other
}) => {
const utils = useUtils();
const minDate = __minDate || utils.date(defaultMinDate);
const maxDate = __maxDate || utils.date(defaultMaxDate);

return (
<>
Expand All @@ -47,6 +58,8 @@ export const DateRangePickerViewMobile: React.FC<DesktopDateRangeCalendarProps>
rightArrowButtonProps={rightArrowButtonProps}
rightArrowButtonText={rightArrowButtonText}
rightArrowIcon={rightArrowIcon}
minDate={minDate}
maxDate={maxDate}
{...other}
/>

Expand Down
34 changes: 30 additions & 4 deletions lib/src/__tests__/DateRangePicker.test.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
// Note that most of use cases are covered in cypress tests e2e/integration/DateRange.spec.ts
import * as React from 'react';
import { isWeekend } from 'date-fns';
import { TextField } from '@material-ui/core';
import { mount, utilsToUse } from './test-utils';
import { TextField, TextFieldProps } from '@material-ui/core';
import { DesktopDateRangePicker } from '../DateRangePicker/DateRangePicker';

const defaultRangeRenderInput = (startProps: TextFieldProps, endProps: TextFieldProps) => (
<>
<TextField {...startProps} />
<TextField {...endProps} />
</>
);

describe('DateRangePicker', () => {
test('allows select range', () => {
const component = mount(
<DesktopDateRangePicker
renderInput={props => <TextField {...props} />}
open
renderInput={defaultRangeRenderInput}
onChange={jest.fn()}
value={[
utilsToUse.date(new Date('2018-01-01T00:00:00.000Z')),
Expand All @@ -25,8 +32,8 @@ describe('DateRangePicker', () => {
test('allows disabling dates', () => {
const component = mount(
<DesktopDateRangePicker
renderInput={props => <TextField {...props} />}
open
renderInput={defaultRangeRenderInput}
minDate={new Date('2005-01-01')}
shouldDisableDate={date => isWeekend(utilsToUse.toJsDate(date))}
onChange={jest.fn()}
Expand All @@ -47,8 +54,8 @@ describe('DateRangePicker', () => {
test('prop: calendars', () => {
const component = mount(
<DesktopDateRangePicker
renderInput={props => <TextField {...props} />}
open
renderInput={defaultRangeRenderInput}
calendars={3}
onChange={jest.fn()}
value={[
Expand All @@ -61,4 +68,23 @@ describe('DateRangePicker', () => {
expect(component.find('Calendar').length).toBe(3);
expect(component.find('button[data-mui-test="DateRangeDay"]').length).toBe(90);
});

test(`doesn't crashes if opening picker with invalid date input`, () => {
const component = mount(
<DesktopDateRangePicker
open
renderInput={defaultRangeRenderInput}
calendars={3}
onChange={jest.fn()}
value={[utilsToUse.date(new Date(NaN)), utilsToUse.date('2018-01-31T00:00:00.000')]}
/>
);

component
.find('input')
.at(1)
.simulate('focus');

expect(component.find('div[role="tooltip"]').length).toBe(1);
});
});
15 changes: 10 additions & 5 deletions lib/src/__tests__/test-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import LocalizationProvider from '../LocalizationProvider';
import { IUtils } from '@date-io/core/IUtils';
import { DatePickerProps } from '../DatePicker';
import { MaterialUiPickersDate } from '../typings/date';
import { BasePickerProps } from '../typings/BasePicker';
import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles';

interface WithUtilsProps {
Expand Down Expand Up @@ -43,10 +44,14 @@ export const mount = <P extends WithUtilsProps>(element: React.ReactElement<P>)
</ThemeProvider>
);

export const mountPickerWithState = (
defaultValue: MaterialUiPickersDate,
render: (props: Pick<DatePickerProps, 'onChange' | 'value' | 'renderInput'>) => React.ReactElement
) => {
export function mountPickerWithState<TValue>(
defaultValue: TValue,
render: (
props: Pick<BasePickerProps<TValue, TValue>, 'onChange' | 'value'> & {
renderInput: DatePickerProps['renderInput'];
}
) => React.ReactElement
) {
const PickerMountComponent = () => {
const [value, setDate] = React.useState(defaultValue);

Expand All @@ -58,7 +63,7 @@ export const mountPickerWithState = (
};

return mount(<PickerMountComponent />);
};
}

export const shallowRender = (render: (props: any) => React.ReactElement<any>) => {
return enzyme.shallow(render({ utils: utilsToUse, classes: {} as any, theme: {} as any }));
Expand Down
2 changes: 1 addition & 1 deletion lib/src/_helpers/date-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export function parseRangeInputValue(
{ value = [null, null] }: BasePickerProps<RangeInput, DateRange>
) {
return value.map(date =>
date === null ? null : utils.startOfDay(utils.date(date))
!utils.isValid(date) || date === null ? null : utils.startOfDay(utils.date(date))
) as DateRange;
}

Expand Down
Loading

0 comments on commit efd9556

Please sign in to comment.