Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: πŸ’‘ Migrate DatePicker to MUI5 #747

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions notes/SQFormDatePicker.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ This is a date time field used inside our forms.

## First time setup

`> npm install @material-ui/pickers@next`
`> npm install @mui/x-date-pickers@next`

From the top of your client code add the LocalizationProvider. The same place the Material-UI theme providers are used. Then pass the MomentAdapter into the `dateAdapter` prop.

```js
import {LocalizationProvider} from '@material-ui/pickers';
import MomentAdapter from '@material-ui/pickers/adapter/moment';
import {LocalizationProvider} from '@mui/x-date-pickers';
import {AdapterMoment} from '@mui/x-date-pickers/AdapterMoment';

<LocalizationProvider dateAdapter={MomentAdapter} locale={'en'}>
<LocalizationProvider dateAdapter={AdapterMoment} locale={'en'}>
<App />
</LocalizationProvider>;
```
Expand Down
56 changes: 20 additions & 36 deletions src/components/SQForm/SQFormDatePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,16 @@
import React from 'react';
import {
ClickAwayListener,
Grid,
makeStyles,
TextField,
} from '@material-ui/core';
import {DatePicker} from '@material-ui/pickers';
import {ClickAwayListener, Grid, TextField} from '@mui/material';
import {DatePicker} from '@mui/x-date-pickers/DatePicker';
import {useForm} from './useForm';
import type {Moment} from 'moment';
import type {InputBaseComponentProps} from '@material-ui/core';
import type {
BasePickerProps,
BaseDatePickerProps,
DatePickerProps,
} from '@material-ui/pickers';
import type {ParsableDate} from '@material-ui/pickers/constants/prop-types';
import type {InputBaseComponentProps} from '@mui/material';
import type {DatePickerProps} from '@mui/x-date-pickers/DatePicker';
import type {BasePickerProps} from '@mui/x-date-pickers/internals';
import type {BaseDatePickerProps} from '@mui/x-date-pickers/DatePicker/shared';
import type {BaseFieldProps} from '../../types';

const useStyles = makeStyles(() => ({
root: {
'& .MuiInputBase-root.Mui-focused, & .MuiInputBase-root:hover:not(.Mui-disabled)':
{
'& .MuiIconButton-root': {
color: 'var(--color-teal)',
},
},
},
}));

type MuiFieldProps<TDate> = BaseDatePickerProps<TDate> &
Omit<
BasePickerProps<ParsableDate<TDate>, TDate | null>,
'value' | 'onChange'
>;
type MuiFieldProps<TDate> = BaseDatePickerProps<TDate, TDate> &
Omit<BasePickerProps<TDate, TDate | null>, 'value' | 'onChange'>;

export type SQFormDatePickerProps = BaseFieldProps & {
/** Disabled property to disable the input if true */
Expand All @@ -53,9 +31,9 @@ export type SQFormDatePickerProps = BaseFieldProps & {
/** Any valid prop for MUI input field - https://material-ui.com/api/text-field/ & https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attributes */
muiTextInputProps?: InputBaseComponentProps;
/** Props provided to the Input component. Most commonly used for adornments. */
InputProps?: DatePickerProps['InputProps'];
InputProps?: DatePickerProps<Moment, Moment>['InputProps'];
/** Props provided to the input adornments. */
InputAdornmentProps?: DatePickerProps['InputAdornmentProps'];
InputAdornmentProps?: DatePickerProps<Moment, Moment>['InputAdornmentProps'];
/** A Boolean flag used when using calendar only; disabled text filed input */
isCalendarOnly?: boolean;
};
Expand Down Expand Up @@ -98,14 +76,12 @@ function SQFormDatePicker({
}
};

const classes = useStyles();

// An empty string will not reset the DatePicker so we have to pass null
const value = field.value || null;

return (
<ClickAwayListener onClickAway={handleClickAway}>
<Grid item sm={size}>
<Grid item={true} sm={size}>
<DatePicker
label={label}
disabled={isDisabled}
Expand All @@ -121,6 +97,7 @@ function SQFormDatePicker({
{...inputProps}
name={name}
color="primary"
variant="standard"
error={isFieldError}
fullWidth={true}
inputProps={{...inputProps.inputProps, ...muiTextInputProps}}
Expand All @@ -135,7 +112,14 @@ function SQFormDatePicker({
? toggleCalendar
: handleClickAway
}
classes={classes}
sx={{
'& .MuiInputBase-root.Mui-focused, & .MuiInputBase-root:hover:not(.Mui-disabled)':
{
'& .MuiIconButton-root': {
color: 'var(--color-teal)',
},
},
}}
/>
);
}}
Expand Down
45 changes: 16 additions & 29 deletions src/components/SQForm/SQFormDatePickerWithDateFNS.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,13 @@
import React from 'react';
import {
ClickAwayListener,
Grid,
makeStyles,
TextField,
} from '@material-ui/core';
import {DatePicker} from '@material-ui/pickers';
import {ClickAwayListener, Grid, TextField} from '@mui/material';
import {DatePicker} from '@mui/x-date-pickers/DatePicker';
import {useForm} from './useForm';
import type {BasePickerProps, BaseDatePickerProps} from '@material-ui/pickers';
import type {ParsableDate} from '@material-ui/pickers/constants/prop-types';
import type {BasePickerProps} from '@mui/x-date-pickers/internals';
import type {BaseDatePickerProps} from '@mui/x-date-pickers/DatePicker/shared';
import type {SQFormDatePickerProps} from 'index';

const useStyles = makeStyles(() => ({
root: {
'& .MuiInputBase-root.Mui-focused, & .MuiInputBase-root:hover:not(.Mui-disabled)':
{
'& .MuiIconButton-root': {
color: 'var(--color-teal)',
},
},
},
}));

type MuiFieldProps<TDate> = BaseDatePickerProps<TDate> &
Omit<
BasePickerProps<ParsableDate<TDate>, TDate | null>,
'value' | 'onChange'
>;
type MuiFieldProps<TDate> = BaseDatePickerProps<TDate, TDate> &
Omit<BasePickerProps<TDate, TDate | null>, 'value' | 'onChange'>;

export type SQFormDatePickerDateFNSProps = Omit<
SQFormDatePickerProps,
Expand Down Expand Up @@ -74,14 +55,12 @@ function SQFormDatePickerWithDateFNS({
}
};

const classes = useStyles();

// An empty string will not reset the DatePicker so we have to pass null
const value = field.value || null;

return (
<ClickAwayListener onClickAway={handleClickAway}>
<Grid item sm={size}>
<Grid item={true} sm={size}>
<DatePicker
label={label}
disabled={isDisabled}
Expand All @@ -97,6 +76,7 @@ function SQFormDatePickerWithDateFNS({
{...inputProps}
name={name}
color="primary"
variant="standard"
error={isFieldError}
fullWidth={true}
inputProps={{...inputProps.inputProps, ...muiTextInputProps}}
Expand All @@ -111,7 +91,14 @@ function SQFormDatePickerWithDateFNS({
? toggleCalendar
: handleClickAway
}
classes={classes}
sx={{
'& .MuiInputBase-root.Mui-focused, & .MuiInputBase-root:hover:not(.Mui-disabled)':
{
'& .MuiIconButton-root': {
color: 'var(--color-teal)',
},
},
}}
/>
);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import * as Yup from 'yup';
import React from 'react';
import * as markdown from '../notes/SQFormDatePicker.md';
import {SQFormDatePicker as SQFormDatePickerComponent} from '../src';
import {createDocsPage} from './utils/createDocsPage';
import {SQFormStoryWrapper} from './components/SQFormStoryWrapper';
import {createDocsPage} from '../old_stories/utils/createDocsPage';
import {SQFormStoryWrapper} from '../old_stories/components/SQFormStoryWrapper';
import type {Story, Meta} from '@storybook/react';
import type {SQFormDatePickerProps} from 'components/SQForm/SQFormDatePicker';
import type {SQFormStoryWrapperProps} from './components/SQFormStoryWrapper';
import type {SQFormStoryWrapperProps} from '../old_stories/components/SQFormStoryWrapper';

export type FormProps = {
initialValues?: SQFormStoryWrapperProps['initialValues'];
Expand Down Expand Up @@ -81,9 +81,6 @@ DatePickerBefore2024.args = {
.max(new Date('2024-01-01'), 'Date must be before 2024')
.typeError('Invalid date'),
}),
muiFieldProps: {
allowSameDateSelection: true,
},
};

export default meta;
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import * as Yup from 'yup';
import React from 'react';
import * as markdown from '../notes/SQFormDatePicker.md';
import {SQFormDatePickerWithDateFNS as SQFormDatePickerComponent} from '../src';
import {createDocsPage} from './utils/createDocsPage';
import {SQFormStoryWrapper} from './components/SQFormStoryWrapper';
import {createDocsPage} from '../old_stories/utils/createDocsPage';
import {SQFormStoryWrapper} from '../old_stories/components/SQFormStoryWrapper';
import type {Story, Meta} from '@storybook/react';
import type {SQFormDatePickerDateFNSProps} from 'components/SQForm/SQFormDatePickerWithDateFNS';
import type {SQFormStoryWrapperProps} from './components/SQFormStoryWrapper';
import type {SQFormStoryWrapperProps} from '../old_stories/components/SQFormStoryWrapper';

export type FormProps = {
initialValues?: SQFormStoryWrapperProps['initialValues'];
Expand Down Expand Up @@ -81,9 +81,6 @@ DatePickerBefore2024.args = {
.max(new Date('2024-01-01'), 'Date must be before 2024')
.typeError('Invalid date'),
}),
muiFieldProps: {
allowSameDateSelection: true,
},
};

export default meta;
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
import MomentAdapter from '@material-ui/pickers/adapter/moment';
import {composeStories} from '@storybook/testing-react';
import {render, screen, within, waitFor} from '@testing-library/react';
import {LocalizationProvider} from '@material-ui/pickers';
import {LocalizationProvider} from '@mui/x-date-pickers';
import {AdapterMoment} from '@mui/x-date-pickers/AdapterMoment';
import * as stories from '../SQFormDatePicker.stories';
import type {SQFormDatePickerProps} from 'components/SQForm/SQFormDatePicker';
import type {FormProps} from '../SQFormDatePicker.stories';
Expand All @@ -20,7 +20,7 @@ const renderDatePicker = (
>
) => {
render(
<LocalizationProvider dateAdapter={MomentAdapter} locale={'en'}>
<LocalizationProvider dateAdapter={AdapterMoment} locale={'en'}>
<BasicDatePicker {...props} />
</LocalizationProvider>
);
Expand Down Expand Up @@ -96,8 +96,8 @@ describe('SQFormDatePicker Tests', () => {
expect(calendarDialog).toBeInTheDocument();
expect(calendarDialog).toBeVisible();

const dateOptions = within(calendarDialog).getAllByRole('cell');
const selectedDate = dateOptions[0];
const dateOptions = within(calendarDialog).getAllByRole('button');
const selectedDate = dateOptions[4];
Copy link
Contributor Author

@aharpt aharpt Aug 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had issues with this story not passing for me. We needed to actually get all of the buttons within the calendarDialog instead of the cells. Not sure if this a different in the new DatePicker markup or what. The 1st of the month corresponds to the fifth button inside the calendarDialog. A bit hacky, but the best I could figure out. I can revisit if needed, but don't think that it is very likely we would be adding/removing buttons that would cause this hard-coded value not to work.

Copy link
Contributor

@laurelbean laurelbean Aug 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will work for now. I already have a line item to go update the tests for this component once we upgrade to version 5.
See Issue #358


userEvent.click(selectedDate);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
import dateFnsAdapter from '@material-ui/pickers/adapter/date-fns';
import enLocale from 'date-fns/locale/en-US';
import {composeStories} from '@storybook/testing-react';
import {render, screen, within, waitFor} from '@testing-library/react';
import {LocalizationProvider} from '@material-ui/pickers';
import {LocalizationProvider} from '@mui/x-date-pickers';
import {AdapterDateFns} from '@mui/x-date-pickers/AdapterDateFns';
import * as stories from '../SQFormDatePickerWithDateFNS.stories';
import type {SQFormDatePickerDateFNSProps} from 'components/SQForm/SQFormDatePickerWithDateFNS';
import type {FormProps} from '../SQFormDatePicker.stories';
Expand All @@ -21,7 +21,7 @@ const renderDatePicker = (
>
) => {
render(
<LocalizationProvider dateAdapter={dateFnsAdapter} locale={enLocale}>
<LocalizationProvider dateAdapter={AdapterDateFns} locale={enLocale}>
<BasicDatePicker {...props} />
</LocalizationProvider>
);
Expand Down Expand Up @@ -97,8 +97,8 @@ describe('SQFormDatePickerWithDateFNS Tests', () => {
expect(calendarDialog).toBeInTheDocument();
expect(calendarDialog).toBeVisible();

const dateOptions = within(calendarDialog).getAllByRole('cell');
const selectedDate = dateOptions[0];
const dateOptions = within(calendarDialog).getAllByRole('button');
const selectedDate = dateOptions[4];

userEvent.click(selectedDate);

Expand Down