@availity/mui-datepicker
Version:
Availity MUI Datepicker Component - part of the @availity/element design system
295 lines (259 loc) • 8.1 kB
Markdown
# DateRangePicker Docs
The `element` library has a `Datepicker` component that can be used to create your own `DateRangePicker`. There is not a `DateRangePicker` exported from the library.
## Example
The following code block shows an example `DateRangePicker` using the `Datepicker` and `Grid` components.
```tsx
import { Datepicker, Grid } from '@availity/element';
import type { Dayjs } from 'dayjs';
type DateRangePickerProps = {
startDate: Dayjs | null;
endDate: Dayjs | null;
onStartDateChange: (date: Dayjs | null) => void;
onEndDateChange: (date: Dayjs | null) => void;
startFieldProps?: {
label?: string;
helperText?: string;
helpTopicId?: string;
fullWidth?: boolean;
};
endFieldProps?: {
label?: string;
helperText?: string;
helpTopicId?: string;
fullWidth?: boolean;
};
};
const DateRangePicker = ({
startDate,
endDate,
onStartDateChange,
onEndDateChange,
startFieldProps = {
label: 'Start Date',
helperText: 'Select start date',
},
endFieldProps = {
label: 'End Date',
helperText: 'Select end date',
},
}: DateRangePickerProps) => {
return (
<>
<Grid container spacing={2}>
<Grid size={{xs: 12, sm: 6}}>
<Datepicker
value={startDate}
onChange={onStartDateChange}
FieldProps={startFieldProps}
maxDate={endDate ?? undefined} // Prevent selecting start date after end date
views={['day', 'month', 'year']}
/>
</Grid>
<Grid size={{xs: 12, sm: 6}}>
<Datepicker
value={endDate}
onChange={onEndDateChange}
FieldProps={endFieldProps}
minDate={startDate ?? undefined} // Prevent selecting end date before start date
views={['day', 'month', 'year']}
/>
</Grid>
</Grid>
</>
);
};
```
### Simple Usage
Below is an example of the `DateRangePicker` component we made above.
<Source />
```tsx
import { useState } from 'react';
import { Dayjs } from 'dayjs';
import { DateRangePicker } from './DateRangePicker';
const MyComponent = () => {
const [startDate, setStartDate] = useState<Dayjs | null>(null);
const [endDate, setEndDate] = useState<Dayjs | null>(null);
return (
<DateRangePicker
// Required props
startDate={startDate}
endDate={endDate}
onStartDateChange={setStartDate}
onEndDateChange={setEndDate}
// Optional props with default values shown
startFieldProps={{
label: 'Start Date',
helperText: 'Select start date',
helpTopicId: '1234', // Optional help topic ID
fullWidth: false, // Optional width control
}}
endFieldProps={{
label: 'End Date',
helperText: 'Select end date',
helpTopicId: '1234', // Optional help topic ID
fullWidth: false, // Optional width control
}}
/>
);
};
```
### Validation
The recommended way to validate the `DateRangePicker` is to use `yup`. Below we have an example of validating that the `endDate` is after the `startDate`.
```tsx
import * as yup from 'yup';
import { Dayjs } from 'dayjs';
const dateRangeSchema = yup.object().shape({
startDate: yup.mixed<Dayjs | null>().nullable().required('Start date is required'),
endDate: yup
.mixed<Dayjs | null>()
.nullable()
.required('End date is required')
.test('is-after-start', 'End date must be after start date', function (endDate, context) {
const { startDate } = context.parent;
if (!startDate || !endDate) {
return true;
}
return endDate.isAfter(startDate) || endDate.isSame(startDate);
}),
});
```
You can then use the created component and validation schema in a form with `react-hook-form`.
```tsx
import { useForm, Controller } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
import { Dayjs } from 'dayjs';
import { DateRangePicker } from './DateRangePicker';
interface DateRangeForm {
startDate: Dayjs | null;
endDate: Dayjs | null;
}
const dateRangeSchema = yup.object().shape({
startDate: yup.mixed<Dayjs | null>().nullable().required('Start date is required'),
endDate: yup
.mixed<Dayjs | null>()
.nullable()
.required('End date is required')
.test('is-after-start', 'End date must be after start date', function (endDate, context) {
const { startDate } = context.parent;
if (!startDate || !endDate) {
return true;
}
return endDate.isAfter(startDate) || endDate.isSame(startDate);
}),
});
const DateRangeForm = () => {
const {
control,
handleSubmit,
formState: { errors },
} = useForm<DateRangeForm>({
resolver: yupResolver(dateRangeSchema),
defaultValues: {
startDate: null,
endDate: null,
},
});
const DateRangeForm = () => {
const {
control,
handleSubmit,
formState: { errors },
watch,
} = useForm<DateRangeForm>({
resolver: yupResolver(dateRangeSchema),
defaultValues: {
startDate: null,
endDate: null,
},
mode: 'onChange', // Enable real-time validation
});
// Watch for changes in dates
const startDate = watch('startDate');
const endDate = watch('endDate');
// Optional: Add side effects when dates change
useEffect(() => {
if (startDate && endDate) {
// Perform any additional validation or business logic
console.log('Date range changed:', { startDate, endDate });
}
}, [startDate, endDate]);
const onSubmit = (data: DateRangeForm) => {
console.log('Form submitted:', data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="startDate"
control={control}
render={({ field: { onChange, value } }) => (
<Controller
name="endDate"
control={control}
render={({ field: { onChange: onEndChange, value: endValue } }) => (
<DateRangePicker
startDate={value}
endDate={endValue}
onStartDateChange={onChange}
onEndDateChange={onEndChange}
startFieldProps={{
helperText: errors.startDate?.message,
error: Boolean(errors.startDate),
label: 'Start Date',
fullWidth: true,
}}
endFieldProps={{
helperText: errors.endDate?.message,
error: Boolean(errors.endDate),
label: 'End Date',
fullWidth: true,
}}
/>
)}
/>
)}
/>
<button type="submit" style={{ marginTop: '16px' }}>
Submit
</button>
</form>
);
};
const onSubmit = (data: DateRangeForm) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="startDate"
control={control}
render={({ field: { onChange, value } }) => (
<Controller
name="endDate"
control={control}
render={({ field: { onChange: onEndChange, value: endValue } }) => (
<DateRangePicker
startDate={value}
endDate={endValue}
onStartDateChange={onChange}
onEndDateChange={onEndChange}
startFieldProps={{
helperText: errors.startDate?.message,
error: Boolean(errors.startDate),
label: 'Start Date',
}}
endFieldProps={{
helperText: errors.endDate?.message,
error: Boolean(errors.endDate),
label: 'End Date',
}}
/>
)}
/>
)}
/>
<button type="submit">Submit</button>
</form>
);
};
```