- enhancements / improvements / stuff
Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -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 (
|
|
||||||
<div>
|
|
||||||
<DatePicker
|
|
||||||
ref={ref}
|
|
||||||
value={value ? dayjs(value) : null}
|
|
||||||
format={dateFormat}
|
|
||||||
onBlur={onBlur}
|
|
||||||
showToday={false}
|
|
||||||
disabledDate={(d) => {
|
|
||||||
if (onlyToday) {
|
|
||||||
return !dayjs().isSame(d, "day");
|
|
||||||
} else if (onlyFuture) {
|
|
||||||
return dayjs().subtract(1, "day").isAfter(d);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
{...restProps}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(FormDateTimePickerEnhanced);
|
|
||||||
@@ -1,205 +1,135 @@
|
|||||||
import React, { forwardRef, useState } from "react";
|
import React, { useCallback, useState } from "react";
|
||||||
import { DatePicker } from "antd";
|
import { DatePicker } from "antd";
|
||||||
import dayjs from "../../utils/day";
|
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 }) => {
|
||||||
|
|
||||||
const DateTimePicker = (
|
|
||||||
{ value, onChange, onBlur, id, onlyFuture, onlyToday, isDateOnly = false, ...restProps },
|
|
||||||
ref
|
|
||||||
) => {
|
|
||||||
const [isManualInput, setIsManualInput] = useState(false);
|
const [isManualInput, setIsManualInput] = useState(false);
|
||||||
|
|
||||||
const handleChange = (newDate) => {
|
const handleChange = useCallback(
|
||||||
if (newDate && onChange) {
|
(newDate) => {
|
||||||
onChange(newDate);
|
if (newDate === null && onChange) {
|
||||||
}
|
onChange(null);
|
||||||
setIsManualInput(false); // Reset the manual input flag when using GUI
|
} else if (newDate && onChange) {
|
||||||
};
|
onChange(newDate);
|
||||||
|
|
||||||
const handleKeyDown = (e) => {
|
|
||||||
setIsManualInput(true); // User is typing, so set the manual input flag
|
|
||||||
|
|
||||||
if (e.key.toLowerCase() === "t") {
|
|
||||||
if (onChange) {
|
|
||||||
onChange(dayjs());
|
|
||||||
}
|
}
|
||||||
} else if (e.key.toLowerCase() === "enter") {
|
setIsManualInput(false);
|
||||||
handleBlur(e);
|
},
|
||||||
}
|
[onChange]
|
||||||
};
|
);
|
||||||
|
|
||||||
const handleBlur = (e) => {
|
const handleBlur = useCallback(
|
||||||
if (!isManualInput) {
|
(e) => {
|
||||||
// If the input is not manual, skip the format processing
|
if (!isManualInput) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsManualInput(false); // Reset the flag after processing
|
setIsManualInput(false);
|
||||||
|
|
||||||
const v = e.target.value;
|
const v = e.target.value;
|
||||||
if (!v) return;
|
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
|
for (const format of shorthandFormats) {
|
||||||
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) {
|
|
||||||
_a = dayjs(upperV, format);
|
_a = dayjs(upperV, format);
|
||||||
if (_a.isValid()) break;
|
if (_a.isValid()) break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (_a && _a.isValid()) {
|
if (!_a || !_a.isValid()) {
|
||||||
if (isDateOnly) {
|
for (const format of formats) {
|
||||||
_a = _a.startOf("day"); // Only apply startOf("day") when isDateOnly is true
|
_a = dayjs(upperV, format);
|
||||||
}
|
if (_a.isValid()) break;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
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 (
|
return (
|
||||||
<div onKeyDown={handleKeyDown} id={id} style={{ width: "100%" }}>
|
<div onKeyDown={handleKeyDown} id={id} style={{ width: "100%" }}>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
ref={ref}
|
showTime={
|
||||||
showTime={isDateOnly ? false : { format: "hh:mm a", minuteStep: 15 }}
|
isDateOnly
|
||||||
|
? false
|
||||||
|
: {
|
||||||
|
format: "hh:mm a",
|
||||||
|
minuteStep: 15,
|
||||||
|
defaultValue: dayjs(dayjs(), "HH:mm:ss")
|
||||||
|
}
|
||||||
|
}
|
||||||
format={isDateOnly ? "MM/DD/YYYY" : "MM/DD/YYYY hh:mm a"}
|
format={isDateOnly ? "MM/DD/YYYY" : "MM/DD/YYYY hh:mm a"}
|
||||||
value={value ? dayjs(value) : null}
|
value={value ? dayjs(value) : null}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onBlur={onBlur || handleBlur}
|
onBlur={onBlur || handleBlur}
|
||||||
disabledDate={(d) => {
|
disabledDate={handleDisabledDate}
|
||||||
if (onlyToday) {
|
|
||||||
return !dayjs().isSame(d, "day");
|
|
||||||
} else if (onlyFuture) {
|
|
||||||
return dayjs().subtract(1, "day").isAfter(d);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}}
|
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
93
client/src/components/form-date-time-picker/formats.js
Normal file
93
client/src/components/form-date-time-picker/formats.js
Normal file
@@ -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"
|
||||||
|
];
|
||||||
@@ -7,7 +7,6 @@ import dayjs from "../../utils/day";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component.jsx";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component.jsx";
|
||||||
import JobSearchSelectComponent from "../job-search-select/job-search-select.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";
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@@ -279,12 +278,7 @@ export function TaskUpsertModalComponent({
|
|||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<FormDateTimePickerEnhanced
|
<DateTimePicker onlyFuture presets={generatePresets(selectedJobDetails)} />
|
||||||
onlyFuture
|
|
||||||
showTime
|
|
||||||
minuteStep={15}
|
|
||||||
presets={generatePresets(selectedJobDetails)}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
Reference in New Issue
Block a user