Merged in feature/IO-2834-Enhance-DateTime-Picker (pull request #1660)
- Final DateTimePicker update
This commit is contained in:
@@ -3,7 +3,7 @@ import PropTypes from "prop-types";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import dayjs from "../../utils/day";
|
||||
import { dateFormats, dateTimeFormats } from "./formats.js";
|
||||
import { fuzzyMatchDate } from "./formats.js";
|
||||
|
||||
const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, onlyToday, isDateOnly = false, ...restProps }) => {
|
||||
const [isManualInput, setIsManualInput] = useState(false);
|
||||
@@ -11,79 +11,34 @@ const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, onlyToday, is
|
||||
|
||||
const handleChange = useCallback(
|
||||
(newDate) => {
|
||||
if (newDate === null && onChange) {
|
||||
onChange(null);
|
||||
} else if (newDate && onChange) {
|
||||
onChange(newDate);
|
||||
if (onChange) {
|
||||
onChange(newDate || null);
|
||||
}
|
||||
setIsManualInput(false);
|
||||
},
|
||||
[onChange]
|
||||
);
|
||||
|
||||
const normalizeDateTimeString = (input) => {
|
||||
const upperV = input.toUpperCase().replaceAll(".", "/").replaceAll("-", "/");
|
||||
|
||||
const [datePart, ...timeParts] = upperV.split(" ");
|
||||
|
||||
if (timeParts.length === 0) {
|
||||
return datePart; // If there's no time part, just return the date part.
|
||||
}
|
||||
|
||||
const timePart = timeParts.join(" "); // In case there are multiple spaces, join them back
|
||||
|
||||
// Normalize the time part by ensuring there's a space before AM/PM if not already present
|
||||
const normalizedTime = timePart.replace(/(\d{1,2})(:\d{2})?\s?(AM|PM)/, "$1$2 $3");
|
||||
|
||||
// Combine the date part with the normalized time part
|
||||
return `${datePart} ${normalizedTime}`.trim();
|
||||
};
|
||||
|
||||
const handleBlur = useCallback(
|
||||
(e) => {
|
||||
// Bail if this is not a manual input
|
||||
if (!isManualInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset manual input flag
|
||||
setIsManualInput(false);
|
||||
|
||||
const v = e.target.value;
|
||||
const v = e?.target?.value;
|
||||
|
||||
if (!v) return;
|
||||
|
||||
const upperV = normalizeDateTimeString(v);
|
||||
let parsedDate;
|
||||
let parsedDate = isDateOnly ? fuzzyMatchDate(v)?.startOf("day") : fuzzyMatchDate(v);
|
||||
|
||||
for (const format of isDateOnly ? dateFormats : dateTimeFormats) {
|
||||
parsedDate = dayjs(upperV, format);
|
||||
if (parsedDate.isValid()) break;
|
||||
}
|
||||
|
||||
if (parsedDate && parsedDate.isValid()) {
|
||||
if (isDateOnly) {
|
||||
parsedDate = parsedDate.startOf("day");
|
||||
}
|
||||
|
||||
if (value && value.isValid && value.isValid()) {
|
||||
parsedDate = parsedDate.set({
|
||||
hours: value.hours(),
|
||||
minutes: value.minutes(),
|
||||
seconds: value.seconds(),
|
||||
milliseconds: value.milliseconds()
|
||||
});
|
||||
}
|
||||
|
||||
if (onlyFuture) {
|
||||
if (dayjs().subtract(1, "day").isBefore(parsedDate)) {
|
||||
onChange(parsedDate);
|
||||
} else {
|
||||
onChange(dayjs().startOf("day"));
|
||||
}
|
||||
} else {
|
||||
onChange(parsedDate);
|
||||
}
|
||||
if (parsedDate && onChange) {
|
||||
onChange(parsedDate);
|
||||
}
|
||||
},
|
||||
[isManualInput, isDateOnly, onlyFuture, onChange, value]
|
||||
[isManualInput, isDateOnly, onChange]
|
||||
);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
|
||||
@@ -1,96 +1,63 @@
|
||||
export const dateTimeFormats = [
|
||||
// Four-digit year with time
|
||||
"M/D/YYYY h:mm A", // Example: 1/5/2023 9:00 AM
|
||||
"M/D/YYYY h:mmA", // Example: 1/5/2023 9:00AM
|
||||
"M/D/YYYY h A", // Example: 1/5/2023 9 AM
|
||||
"M/D/YYYY hA", // Example: 1/5/2023 9AM
|
||||
"M/D/YYYY hh:mm A", // Example: 1/5/2023 02:25 PM
|
||||
"M/D/YYYY hh:mm:ss A", // Example: 1/5/2023 02:25:45 PM
|
||||
import dayjs from "../../utils/day";
|
||||
|
||||
"MM/D/YYYY h:mm A", // Example: 12/5/2023 9:00 AM
|
||||
"MM/D/YYYY h:mmA", // Example: 12/5/2023 9:00AM
|
||||
"MM/D/YYYY h A", // Example: 12/5/2023 9 AM
|
||||
"MM/D/YYYY hA", // Example: 12/5/2023 9AM
|
||||
"MM/D/YYYY hh:mm A", // Example: 12/5/2023 02:25 PM
|
||||
"MM/D/YYYY hh:mm:ss A", // Example: 12/5/2023 02:25:45 PM
|
||||
|
||||
"M/DD/YYYY h:mm A", // Example: 1/25/2023 9:00 AM
|
||||
"M/DD/YYYY h:mmA", // Example: 1/25/2023 9:00AM
|
||||
"M/DD/YYYY h A", // Example: 1/25/2023 9 AM
|
||||
"M/DD/YYYY hA", // Example: 1/25/2023 9AM
|
||||
"M/DD/YYYY hh:mm A", // Example: 1/25/2023 02:25 PM
|
||||
"M/DD/YYYY hh:mm:ss A", // Example: 1/25/2023 02:25:45 PM
|
||||
|
||||
"MM/DD/YYYY h:mm A", // Example: 12/25/2023 9:00 AM
|
||||
"MM/DD/YYYY h:mmA", // Example: 12/25/2023 9:00AM
|
||||
"MM/DD/YYYY h A", // Example: 12/25/2023 9 AM
|
||||
"MM/DD/YYYY hA", // Example: 12/25/2023 9AM
|
||||
"MM/DD/YYYY hh:mm A", // Example: 12/25/2023 02:25 PM
|
||||
"MM/DD/YYYY hh:mm:ss A", // Example: 12/25/2023 02:25:45 PM
|
||||
|
||||
// Two-digit year with time
|
||||
"M/D/YY h:mm A", // Example: 1/5/23 9:00 AM
|
||||
"M/D/YY h:mmA", // Example: 1/5/23 9:00AM
|
||||
"M/D/YY h A", // Example: 1/5/23 9 AM
|
||||
"M/D/YY hA", // Example: 1/5/23 9AM
|
||||
"M/D/YY hh:mm A", // Example: 1/5/23 02:25 PM
|
||||
"M/D/YY hh:mm:ss A", // Example: 1/5/23 02:25:45 PM
|
||||
|
||||
"MM/D/YY h:mm A", // Example: 12/5/23 9:00 AM
|
||||
"MM/D/YY h:mmA", // Example: 12/5/23 9:00AM
|
||||
"MM/D/YY h A", // Example: 12/5/23 9 AM
|
||||
"MM/D/YY hA", // Example: 12/5/23 9AM
|
||||
"MM/D/YY hh:mm A", // Example: 12/5/23 02:25 PM
|
||||
"MM/D/YY hh:mm:ss A", // Example: 12/5/23 02:25:45 PM
|
||||
|
||||
"M/DD/YY h:mm A", // Example: 1/25/23 9:00 AM
|
||||
"M/DD/YY h:mmA", // Example: 1/25/23 9:00AM
|
||||
"M/DD/YY h A", // Example: 1/25/23 9 AM
|
||||
"M/DD/YY hA", // Example: 1/25/23 9AM
|
||||
"M/DD/YY hh:mm A", // Example: 1/25/23 02:25 PM
|
||||
"M/DD/YY hh:mm:ss A", // Example: 1/25/23 02:25:45 PM
|
||||
|
||||
"MM/DD/YY h:mm A", // Example: 12/25/23 9:00 AM
|
||||
"MM/DD/YY h:mmA", // Example: 12/25/23 9:00AM
|
||||
"MM/DD/YY h A", // Example: 12/25/23 9 AM
|
||||
"MM/DD/YY hA", // Example: 12/25/23 9AM
|
||||
"MM/DD/YY hh:mm A", // Example: 12/25/23 02:25 PM
|
||||
"MM/DD/YY hh:mm:ss A", // Example: 12/25/23 02:25:45 PM
|
||||
|
||||
// Four-digit year without time
|
||||
"M/D/YYYY", // Example: 1/5/2023
|
||||
"MM/D/YYYY", // Example: 12/5/2023
|
||||
"M/DD/YYYY", // Example: 1/25/2023
|
||||
"MM/DD/YYYY", // Example: 12/25/2023
|
||||
|
||||
// Two-digit year without time
|
||||
"M/D/YY", // Example: 1/5/23
|
||||
"MM/D/YY", // Example: 12/5/23
|
||||
"M/DD/YY", // Example: 1/25/23
|
||||
"MM/DD/YY" // Example: 12/25/23
|
||||
];
|
||||
|
||||
// CONFIRMED
|
||||
export const dateFormats = [
|
||||
const dateFormats = [
|
||||
"MMDDYYYY",
|
||||
"MMDDYY",
|
||||
// Four-digit year
|
||||
"M/D/YYYY", // Example: 1/5/2023
|
||||
"MM/D/YYYY", // Example: 12/5/2023
|
||||
"M/DD/YYYY", // Example: 1/25/2023
|
||||
"MM/DD/YYYY", // Example: 12/25/2023
|
||||
|
||||
// Two-digit year
|
||||
"M/D/YY", // Example: 1/5/23
|
||||
"MM/D/YY", // Example: 12/5/23
|
||||
"M/DD/YY", // Example: 1/25/23
|
||||
"MM/DD/YY", // Example: 12/25/23
|
||||
|
||||
// Explicitly handle single-digit month and day
|
||||
"M/D/YY", // Example: 1/5/23
|
||||
"M/D/YYYY", // Example: 1/5/2023
|
||||
"M/DD/YY", // Example: 1/25/23
|
||||
"M/DD/YYYY", // Example: 1/25/2023
|
||||
"MM/D/YY", // Example: 12/5/23
|
||||
"MM/D/YYYY" // Example: 12/5/2023
|
||||
"M/D/YYYY",
|
||||
"MM/D/YYYY",
|
||||
"M/DD/YYYY",
|
||||
"MM/DD/YYYY",
|
||||
"M/D/YY",
|
||||
"MM/D/YY",
|
||||
"M/DD/YY",
|
||||
"MM/DD/YY"
|
||||
];
|
||||
|
||||
const timeFormats = ["h:mm A", "h:mmA", "h A", "hA", "hh:mm A", "hh:mm:ss A"];
|
||||
|
||||
const dateTimeFormats = [
|
||||
...["M/D/YYYY", "MM/D/YYYY", "M/DD/YYYY", "MM/DD/YYYY", "M/D/YY", "MM/D/YY", "M/DD/YY", "MM/DD/YY"].flatMap(
|
||||
(dateFormat) => timeFormats.map((timeFormat) => `${dateFormat} ${timeFormat}`)
|
||||
),
|
||||
|
||||
...["MMDDYYYY", "MMDDYY"].flatMap((dateFormat) => timeFormats.map((timeFormat) => `${dateFormat} ${timeFormat}`)),
|
||||
|
||||
"M/D/YYYY",
|
||||
"MM/D/YYYY",
|
||||
"M/DD/YYYY",
|
||||
"MM/DD/YYYY",
|
||||
"M/D/YY",
|
||||
"MM/D/YY",
|
||||
"M/DD/YY",
|
||||
"MM/DD/YY",
|
||||
"MMDDYYYY",
|
||||
"MMDDYY"
|
||||
];
|
||||
|
||||
const sanitizeInput = (input) =>
|
||||
input
|
||||
.trim()
|
||||
.toUpperCase()
|
||||
.replace(/\s*(am|pm)\s*/i, " $1")
|
||||
.replaceAll(".", "/")
|
||||
.replaceAll("-", "/");
|
||||
|
||||
export const fuzzyMatchDate = (dateString) => {
|
||||
const sanitizedInput = sanitizeInput(dateString);
|
||||
|
||||
for (const format of dateFormats) {
|
||||
const parsedDate = dayjs(sanitizedInput, format, true);
|
||||
if (parsedDate.isValid()) {
|
||||
return parsedDate;
|
||||
}
|
||||
}
|
||||
|
||||
for (const format of dateTimeFormats) {
|
||||
const parsedDateTime = dayjs(sanitizedInput, format, true);
|
||||
if (parsedDateTime.isValid()) {
|
||||
return parsedDateTime; // Return the dayjs object
|
||||
}
|
||||
}
|
||||
|
||||
return null; // If no matching format is found
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user