diff --git a/client/src/components/form-date-time-picker-enhanced/form-date-time-picker-enhanced.component.jsx b/client/src/components/form-date-time-picker-enhanced/form-date-time-picker-enhanced.component.jsx deleted file mode 100644 index cdabfdfb5..000000000 --- a/client/src/components/form-date-time-picker-enhanced/form-date-time-picker-enhanced.component.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import { DatePicker } from "antd"; -import dayjs from "../../utils/day.js"; -import React, { useRef } from "react"; - -import { connect } from "react-redux"; -import { createStructuredSelector } from "reselect"; -import { selectBodyshop } from "../../redux/user/user.selectors.js"; - -const mapStateToProps = createStructuredSelector({ - bodyshop: selectBodyshop -}); -const mapDispatchToProps = (dispatch) => ({ - //setUserLanguage: language => dispatch(setUserLanguage(language)) -}); - -const dateFormat = "MM/DD/YYYY h:mm a"; - -export function FormDateTimePickerEnhanced({ - bodyshop, - value, - onBlur, - onlyFuture, - onlyToday, - isDateOnly = true, - ...restProps -}) { - const ref = useRef(); - return ( -
- { - if (onlyToday) { - return !dayjs().isSame(d, "day"); - } else if (onlyFuture) { - return dayjs().subtract(1, "day").isAfter(d); - } - }} - {...restProps} - /> -
- ); -} - -export default connect(mapStateToProps, mapDispatchToProps)(FormDateTimePickerEnhanced); diff --git a/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx b/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx index c1bf6f749..90f5fc16d 100644 --- a/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx +++ b/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx @@ -1,205 +1,135 @@ -import React, { forwardRef, useState } from "react"; +import React, { useCallback, useState } from "react"; import { DatePicker } from "antd"; import dayjs from "../../utils/day"; +import { formats, shorthandFormats } from "./formats.js"; +import PropTypes from "prop-types"; -// To be used as a form element only. - -const DateTimePicker = ( - { value, onChange, onBlur, id, onlyFuture, onlyToday, isDateOnly = false, ...restProps }, - ref -) => { +const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, onlyToday, isDateOnly = false, ...restProps }) => { const [isManualInput, setIsManualInput] = useState(false); - const handleChange = (newDate) => { - if (newDate && onChange) { - onChange(newDate); - } - setIsManualInput(false); // Reset the manual input flag when using GUI - }; - - const handleKeyDown = (e) => { - setIsManualInput(true); // User is typing, so set the manual input flag - - if (e.key.toLowerCase() === "t") { - if (onChange) { - onChange(dayjs()); + const handleChange = useCallback( + (newDate) => { + if (newDate === null && onChange) { + onChange(null); + } else if (newDate && onChange) { + onChange(newDate); } - } else if (e.key.toLowerCase() === "enter") { - handleBlur(e); - } - }; + setIsManualInput(false); + }, + [onChange] + ); - const handleBlur = (e) => { - if (!isManualInput) { - // If the input is not manual, skip the format processing - return; - } + const handleBlur = useCallback( + (e) => { + if (!isManualInput) { + return; + } - setIsManualInput(false); // Reset the flag after processing + setIsManualInput(false); - const v = e.target.value; - if (!v) return; + const v = e.target.value; + if (!v) return; - // Convert input to uppercase to handle 'am/pm' as well as 'AM/PM' - const upperV = v.toUpperCase(); + const upperV = v.toUpperCase(); - let _a; + let _a; - // Handling common shorthand datetime inputs - const shorthandFormats = [ - "M/D/YY hA", - "M/D/YY h:mmA", - "M/D/YYYY hA", - "M/D/YYYY h:mmA", - "M/D/YY ha", - "M/D/YY h:mma", - "M/D/YYYY ha", - "M/D/YYYY h:mma" - ]; - - for (let format of shorthandFormats) { - _a = dayjs(upperV, format); - if (_a.isValid()) break; - } - - // If shorthand parsing didn't work, fall back to existing formats - if (!_a || !_a.isValid()) { - const formats = [ - "MMDDYY", - "MMDDYYYY", - "MM/DD/YY", - "MM/DD/YYYY", - "M/DD/YY", - "M/DD/YYYY", - "MM/D/YY", - "MM/D/YYYY", - "M/D/YY", - "M/D/YYYY", - "D/MM/YY", - "D/MM/YYYY", - "DD/M/YY", - "DD/M/YYYY", - "D/M/YY", - "D/M/YYYY", - "MMDDYY hh:mm A", - "MMDDYYYY hh:mm A", - "MM/DD/YY hh:mm A", - "MM/DD/YYYY hh:mm A", - "M/DD/YY hh:mm A", - "M/DD/YYYY hh:mm A", - "MM/D/YY hh:mm A", - "MM/D/YYYY hh:mm A", - "M/D/YY hh:mm A", - "M/D/YYYY hh:mm A", - "D/MM/YY hh:mm A", - "D/MM/YYYY hh:mm A", - "DD/M/YY hh:mm A", - "DD/M/YYYY hh:mm A", - "D/M/YY hh:mm A", - "D/M/YYYY hh:mm A", - "MMDDYY hh:mm:ss A", - "MMDDYYYY hh:mm:ss A", - "MM/DD/YY hh:mm:ss A", - "MM/DD/YYYY hh:mm:ss A", - "M/DD/YY hh:mm:ss A", - "M/DD/YYYY hh:mm:ss A", - "MM/D/YY hh:mm:ss A", - "MM/D/YYYY hh:mm:ss A", - "M/D/YY hh:mm:ss A", - "M/D/YYYY hh:mm:ss A", - "D/MM/YY hh:mm:ss A", - "D/MM/YYYY hh:mm:ss A", - "DD/M/YY hh:mm:ss A", - "DD/M/YYYY hh:mm:ss A", - "D/M/YY hh:mm:ss A", - "D/M/YYYY hh:mm:ss A", - "MMDDYY HH:mm", - "MMDDYYYY HH:mm", - "MM/DD/YY HH:mm", - "MM/DD/YYYY HH:mm", - "M/DD/YY HH:mm", - "M/DD/YYYY HH:mm", - "MM/D/YY HH:mm", - "MM/D/YYYY HH:mm", - "M/D/YY HH:mm", - "M/D/YYYY HH:mm", - "D/MM/YY HH:mm", - "D/MM/YYYY HH:mm", - "DD/M/YY HH:mm", - "DD/M/YYYY HH:mm", - "D/M/YY HH:mm", - "D/M/YYYY HH:mm", - "MMDDYY HH:mm:ss", - "MMDDYYYY HH:mm:ss", - "MM/DD/YY HH:mm:ss", - "MM/DD/YYYY HH:mm:ss", - "M/DD/YY HH:mm:ss", - "M/DD/YYYY HH:mm:ss", - "MM/D/YY HH:mm:ss", - "MM/D/YYYY HH:mm:ss", - "M/D/YY HH:mm:ss", - "M/D/YYYY HH:mm:ss", - "D/MM/YY HH:mm:ss", - "D/MM/YYYY HH:mm:ss", - "DD/M/YY HH:mm:ss", - "DD/M/YYYY HH:mm:ss", - "D/M/YY HH:mm:ss", - "D/M/YYYY HH:mm:ss" - ]; - - for (let format of formats) { + for (const format of shorthandFormats) { _a = dayjs(upperV, format); if (_a.isValid()) break; } - } - if (_a && _a.isValid()) { - if (isDateOnly) { - _a = _a.startOf("day"); // Only apply startOf("day") when isDateOnly is true - } - - if (value && value.isValid && value.isValid()) { - _a.set({ - hours: value.hours(), - minutes: value.minutes(), - seconds: value.seconds(), - milliseconds: value.milliseconds() - }); - } - - if (onlyFuture) { - if (dayjs().subtract(1, "day").isBefore(_a)) { - onChange(_a); - } else { - onChange(dayjs().startOf("day")); + if (!_a || !_a.isValid()) { + for (const format of formats) { + _a = dayjs(upperV, format); + if (_a.isValid()) break; } - } else { - onChange(_a); } - } - }; + + if (_a && _a.isValid()) { + if (isDateOnly) { + _a = _a.startOf("day"); + } + + if (value && value.isValid && value.isValid()) { + _a.set({ + hours: value.hours(), + minutes: value.minutes(), + seconds: value.seconds(), + milliseconds: value.milliseconds() + }); + } + + if (onlyFuture) { + if (dayjs().subtract(1, "day").isBefore(_a)) { + onChange(_a); + } else { + onChange(dayjs().startOf("day")); + } + } else { + onChange(_a); + } + } + }, + [isManualInput, isDateOnly, onlyFuture, onChange, value] + ); + + const handleKeyDown = useCallback( + (e) => { + setIsManualInput(true); + + if (e.key.toLowerCase() === "t" && onChange) { + onChange(dayjs()); + } else if (e.key.toLowerCase() === "enter") { + handleBlur(e); + } + }, + [onChange, handleBlur] + ); + + const handleDisabledDate = useCallback( + (current) => { + if (onlyToday) { + return !dayjs().isSame(current, "day"); + } else if (onlyFuture) { + return dayjs().subtract(1, "day").isAfter(current); + } + return false; + }, + [onlyToday, onlyFuture] + ); return (
{ - if (onlyToday) { - return !dayjs().isSame(d, "day"); - } else if (onlyFuture) { - return dayjs().subtract(1, "day").isAfter(d); - } - return false; - }} + disabledDate={handleDisabledDate} {...restProps} />
); }; -export default forwardRef(DateTimePicker); +DateTimePicker.propTypes = { + value: PropTypes.any, + onChange: PropTypes.func, + onBlur: PropTypes.func, + id: PropTypes.string, + onlyFuture: PropTypes.bool, + onlyToday: PropTypes.bool, + isDateOnly: PropTypes.bool +}; + +export default React.memo(DateTimePicker); diff --git a/client/src/components/form-date-time-picker/formats.js b/client/src/components/form-date-time-picker/formats.js new file mode 100644 index 000000000..7683f9990 --- /dev/null +++ b/client/src/components/form-date-time-picker/formats.js @@ -0,0 +1,93 @@ +export const shorthandFormats = [ + "M/D/YY hA", + "M/D/YY h:mmA", + "M/D/YYYY hA", + "M/D/YYYY h:mmA", + "M/D/YY ha", + "M/D/YY h:mma", + "M/D/YYYY ha", + "M/D/YYYY h:mma" +]; + +export const formats = [ + "MMDDYY", + "MMDDYYYY", + "MM/DD/YY", + "MM/DD/YYYY", + "M/DD/YY", + "M/DD/YYYY", + "MM/D/YY", + "MM/D/YYYY", + "M/D/YY", + "M/D/YYYY", + "D/MM/YY", + "D/MM/YYYY", + "DD/M/YY", + "DD/M/YYYY", + "D/M/YY", + "D/M/YYYY", + "MMDDYY hh:mm A", + "MMDDYYYY hh:mm A", + "MM/DD/YY hh:mm A", + "MM/DD/YYYY hh:mm A", + "M/DD/YY hh:mm A", + "M/DD/YYYY hh:mm A", + "MM/D/YY hh:mm A", + "MM/D/YYYY hh:mm A", + "M/D/YY hh:mm A", + "M/D/YYYY hh:mm A", + "D/MM/YY hh:mm A", + "D/MM/YYYY hh:mm A", + "DD/M/YY hh:mm A", + "DD/M/YYYY hh:mm A", + "D/M/YY hh:mm A", + "D/M/YYYY hh:mm A", + "MMDDYY hh:mm:ss A", + "MMDDYYYY hh:mm:ss A", + "MM/DD/YY hh:mm:ss A", + "MM/DD/YYYY hh:mm:ss A", + "M/DD/YY hh:mm:ss A", + "M/DD/YYYY hh:mm:ss A", + "MM/D/YY hh:mm:ss A", + "MM/D/YYYY hh:mm:ss A", + "M/D/YY hh:mm:ss A", + "M/D/YYYY hh:mm:ss A", + "D/MM/YY hh:mm:ss A", + "D/MM/YYYY hh:mm:ss A", + "DD/M/YY hh:mm:ss A", + "DD/M/YYYY hh:mm:ss A", + "D/M/YY hh:mm:ss A", + "D/M/YYYY hh:mm:ss A", + "MMDDYY HH:mm", + "MMDDYYYY HH:mm", + "MM/DD/YY HH:mm", + "MM/DD/YYYY HH:mm", + "M/DD/YY HH:mm", + "M/DD/YYYY HH:mm", + "MM/D/YY HH:mm", + "MM/D/YYYY HH:mm", + "M/D/YY HH:mm", + "M/D/YYYY HH:mm", + "D/MM/YY HH:mm", + "D/MM/YYYY HH:mm", + "DD/M/YY HH:mm", + "DD/M/YYYY HH:mm", + "D/M/YY HH:mm", + "D/M/YYYY HH:mm", + "MMDDYY HH:mm:ss", + "MMDDYYYY HH:mm:ss", + "MM/DD/YY HH:mm:ss", + "MM/DD/YYYY HH:mm:ss", + "M/DD/YY HH:mm:ss", + "M/DD/YYYY HH:mm:ss", + "MM/D/YY HH:mm:ss", + "MM/D/YYYY HH:mm:ss", + "M/D/YY HH:mm:ss", + "M/D/YYYY HH:mm:ss", + "D/MM/YY HH:mm:ss", + "D/MM/YYYY HH:mm:ss", + "DD/M/YY HH:mm:ss", + "DD/M/YYYY HH:mm:ss", + "D/M/YY HH:mm:ss", + "D/M/YYYY HH:mm:ss" +]; diff --git a/client/src/components/task-upsert-modal/task-upsert-modal.component.jsx b/client/src/components/task-upsert-modal/task-upsert-modal.component.jsx index 7d498efc3..562141a40 100644 --- a/client/src/components/task-upsert-modal/task-upsert-modal.component.jsx +++ b/client/src/components/task-upsert-modal/task-upsert-modal.component.jsx @@ -7,7 +7,6 @@ import dayjs from "../../utils/day"; import { connect } from "react-redux"; import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component.jsx"; import JobSearchSelectComponent from "../job-search-select/job-search-select.component.jsx"; -import { FormDateTimePickerEnhanced } from "../form-date-time-picker-enhanced/form-date-time-picker-enhanced.component.jsx"; import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx"; const mapStateToProps = createStructuredSelector({ @@ -279,12 +278,7 @@ export function TaskUpsertModalComponent({ } ]} > - +