import { useEffect, useState } from 'react'; import { DateTimePicker, DateTimePickerProps } from 'react-datetime-picker'; import classnames from 'classnames'; import parseISO from 'date-fns/parseISO'; import { InjectedFieldProps } from '../Field/InjectedFieldProps'; import { FormDefaults } from '../FormDefaults'; import Group, { GroupProps } from '../Group'; // Represents a single date/date string, or null type DateTimePickerValuePiece = Date | string | null; // Represents either a single date/date string, a pair of dates/date strings for a range, or null type DateTimePickerValue = | DateTimePickerValuePiece | [DateTimePickerValuePiece, DateTimePickerValuePiece]; export interface DateTimePickerGroupProps extends InjectedFieldProps, Omit< DateTimePickerProps, keyof InjectedFieldProps | 'name' | 'value' | 'className' >, Omit | 'children'> { convert: (date: Date) => T; } /** * Field for inputting date and time. Uses `` and ``. * * Uses [react-datetime-picker](https://www.npmjs.com/package/react-datetime-picker) */ export default function DateTimePickerGroup({ input, meta, label, helpText, className, required, disabled, convert, maxDate = new Date(9999, 11, 31), minDate = new Date(1000, 0, 1), ...rest }: DateTimePickerGroupProps) { const [displayDateTime, setDisplayDateTime] = useState(null); useEffect(() => { const inputValue = input.value; if (!inputValue) { setDisplayDateTime(null); } else if (typeof inputValue === 'string') { const parsedDateTime = convertISODateTimeStringToDate(inputValue); setDisplayDateTime(parsedDateTime); } else if (inputValue instanceof Date) { setDisplayDateTime(inputValue); } }, [setDisplayDateTime, input.value]); return (
{ // Manually trigger Formik's onBlur when the user clicks away from the date picker input.onBlur(); }}>
); function handleChange(newDateTime: DateTimePickerValue) { const { onChange } = input; if (onChange === null) { return; } if (!newDateTime) { onChange(undefined); setDisplayDateTime(null); return; } else if (typeof newDateTime === 'string') { const parsedDateTime = parseISO(newDateTime); setDisplayDateTime(parsedDateTime); onChange(convert(parsedDateTime)); } else if (newDateTime instanceof Date) { setDisplayDateTime(newDateTime); onChange(convert(newDateTime)); } } } function convertISODateTimeStringToDate(isoDateTimeString: string) { const isoDateTimeRegex = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?)([+-]\d{2}:\d{2}|Z)?$/; const isValidIsoDateTimeString = isoDateTimeRegex.test(isoDateTimeString); if (isValidIsoDateTimeString) { return new Date(isoDateTimeString); } const errorMessage = `Invalid "date time" value of ${isoDateTimeString} provided to DateTimePickerGroup component. Please provide ISO 8601 string that includes the time zone designator. Sample strings: 2022-09-24T:08:54:12+00:00, 2022-09-24T:08:54:12Z, 2022-09-24T:08:54:12.123-05:00`; if (process.env.NODE_ENV !== 'production') { throw new Error(errorMessage); } else { console.error(errorMessage); } return null; }