-
+
p.nextservicedate !== c.nextservicedate}>
{() => {
@@ -260,7 +256,7 @@ export default function CourtesyCarCreateFormComponent({
-
+
p.registrationexpires !== c.registrationexpires}>
{() => {
@@ -293,7 +289,7 @@ export default function CourtesyCarCreateFormComponent({
}
]}
>
-
+
p.insuranceexpires !== c.insuranceexpires}>
{() => {
diff --git a/client/src/components/courtesy-car-return-modal/courtesy-car-return-modal.component.jsx b/client/src/components/courtesy-car-return-modal/courtesy-car-return-modal.component.jsx
index 589c97ad4..3a7ec4c6b 100644
--- a/client/src/components/courtesy-car-return-modal/courtesy-car-return-modal.component.jsx
+++ b/client/src/components/courtesy-car-return-modal/courtesy-car-return-modal.component.jsx
@@ -2,7 +2,7 @@ import { Form, InputNumber } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
-import FormDatePicker from "../form-date-picker/form-date-picker.component";
+import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
export default function CourtesyCarReturnModalComponent() {
const { t } = useTranslation();
@@ -19,7 +19,7 @@ export default function CourtesyCarReturnModalComponent() {
}
]}
>
-
+
-
+
diff --git a/client/src/components/eula/eula.component.jsx b/client/src/components/eula/eula.component.jsx
index 7399c279b..8d2227e02 100644
--- a/client/src/components/eula/eula.component.jsx
+++ b/client/src/components/eula/eula.component.jsx
@@ -4,7 +4,6 @@ import Markdown from "react-markdown";
import { createStructuredSelector } from "reselect";
import { selectCurrentEula, selectCurrentUser } from "../../redux/user/user.selectors";
import { connect } from "react-redux";
-import { FormDatePicker } from "../form-date-picker/form-date-picker.component";
import { INSERT_EULA_ACCEPTANCE } from "../../graphql/user.queries";
import { useMutation } from "@apollo/client";
import { acceptEula } from "../../redux/user/user.actions";
@@ -12,6 +11,7 @@ import { useTranslation } from "react-i18next";
import day from "../../utils/day";
import "./eula.styles.scss";
+import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
const Eula = ({ currentEula, currentUser, acceptEula }) => {
const [formReady, setFormReady] = useState(false);
@@ -216,7 +216,7 @@ const EulaFormComponent = ({ form, handleChange, onFinish, t }) => (
}
]}
>
-
+
diff --git a/client/src/components/form-date-picker/form-date-picker.component.jsx b/client/src/components/form-date-picker/form-date-picker.component.jsx
deleted file mode 100644
index 500e22d45..000000000
--- a/client/src/components/form-date-picker/form-date-picker.component.jsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import { DatePicker } from "antd";
-import dayjs from "../../utils/day";
-import React, { useRef } from "react";
-
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectBodyshop } from "../../redux/user/user.selectors";
-
-const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop
-});
-const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
-});
-export default connect(mapStateToProps, mapDispatchToProps)(FormDatePicker);
-
-const dateFormat = "MM/DD/YYYY";
-
-export function FormDatePicker({
- bodyshop,
- value,
- onChange,
- onBlur,
- onlyFuture,
- onlyToday,
- isDateOnly = true,
- ...restProps
-}) {
- const ref = useRef();
-
- const handleChange = (newDate) => {
- if (value !== newDate && onChange) {
- onChange(isDateOnly ? newDate && newDate.format("YYYY-MM-DD") : newDate);
- }
- };
-
- const handleKeyDown = (e) => {
- if (e.key.toLowerCase() === "t") {
- if (onChange) {
- onChange(isDateOnly ? dayjs().format("YYYY-MM-DD") : dayjs());
- }
- } else if (e.key.toLowerCase() === "enter") {
- if (ref.current && ref.current.blur) ref.current.blur();
- }
- };
-
- const handleBlur = (e) => {
- const v = e.target.value;
- if (!v) return;
-
- 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"
- ];
-
- let _a;
-
- // Iterate through formats to find the correct one
- for (let format of formats) {
- _a = dayjs(v, format);
- if (v === _a.format(format)) {
- break;
- }
- }
-
- if (_a.isValid() && value && value.isValid && value.isValid()) {
- _a.set({
- hours: value.hours(),
- minutes: value.minutes(),
- seconds: value.seconds(),
- milliseconds: value.milliseconds()
- });
- }
-
- if (_a.isValid() && onChange) {
- if (onlyFuture) {
- if (dayjs().subtract(1, "day").isBefore(_a)) {
- onChange(isDateOnly ? _a.format("YYYY-MM-DD") : _a);
- } else {
- onChange(isDateOnly ? dayjs().format("YYYY-MM-DD") : dayjs());
- }
- } else {
- onChange(isDateOnly ? _a.format("YYYY-MM-DD") : _a);
- }
- }
- };
-
- return (
-
- {
- if (onlyToday) {
- return !dayjs().isSame(d, "day");
- } else if (onlyFuture) {
- return dayjs().subtract(1, "day").isAfter(d);
- }
- }}
- {...restProps}
- />
-
- );
-}
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
index 5d41fc5e3..cdabfdfb5 100644
--- 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
@@ -12,7 +12,6 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
-export default connect(mapStateToProps, mapDispatchToProps)(FormDateTimePickerEnhanced);
const dateFormat = "MM/DD/YYYY h:mm a";
@@ -46,3 +45,5 @@ export function FormDateTimePickerEnhanced({
);
}
+
+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 23af7008a..c1bf6f749 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,45 +1,204 @@
-import React, { forwardRef } from "react";
-//import DatePicker from "react-datepicker";
-//import "react-datepicker/src/stylesheets/datepicker.scss";
-import { Space, TimePicker } from "antd";
+import React, { forwardRef, useState } from "react";
+import { DatePicker } from "antd";
import dayjs from "../../utils/day";
-import FormDatePicker from "../form-date-picker/form-date-picker.component";
-//To be used as a form element only.
-const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, ...restProps }, ref) => {
- // const handleChange = (newDate) => {
- // if (value !== newDate && onChange) {
- // onChange(newDate);
- // }
- // };
+// To be used as a form element only.
+
+const DateTimePicker = (
+ { value, onChange, onBlur, id, onlyFuture, onlyToday, isDateOnly = false, ...restProps },
+ ref
+) => {
+ 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());
+ }
+ } else if (e.key.toLowerCase() === "enter") {
+ handleBlur(e);
+ }
+ };
+
+ const handleBlur = (e) => {
+ if (!isManualInput) {
+ // If the input is not manual, skip the format processing
+ return;
+ }
+
+ setIsManualInput(false); // Reset the flag after processing
+
+ 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();
+
+ 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) {
+ _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"));
+ }
+ } else {
+ onChange(_a);
+ }
+ }
+ };
return (
-
- dayjs().subtract(1, "day").isAfter(d)
- })}
- value={value}
- onBlur={onBlur}
- onChange={onChange}
- onlyFuture={onlyFuture}
- isDateOnly={false}
- />
-
-
+ dayjs().isAfter(d)
- })}
- onChange={onChange}
- disableSeconds={true}
- minuteStep={15}
- onBlur={onBlur}
- format="hh:mm a"
+ onChange={handleChange}
+ onBlur={onBlur || handleBlur}
+ disabledDate={(d) => {
+ if (onlyToday) {
+ return !dayjs().isSame(d, "day");
+ } else if (onlyFuture) {
+ return dayjs().subtract(1, "day").isAfter(d);
+ }
+ return false;
+ }}
{...restProps}
/>
-
+
);
};
diff --git a/client/src/components/job-scoreboard-add-button/job-scoreboard-add-button.component.jsx b/client/src/components/job-scoreboard-add-button/job-scoreboard-add-button.component.jsx
index a8c673552..e17368ed9 100644
--- a/client/src/components/job-scoreboard-add-button/job-scoreboard-add-button.component.jsx
+++ b/client/src/components/job-scoreboard-add-button/job-scoreboard-add-button.component.jsx
@@ -10,8 +10,8 @@ import {
QUERY_SCOREBOARD_ENTRY,
UPDATE_SCOREBOARD_ENTRY
} from "../../graphql/scoreboard.queries";
-import FormDatePicker from "../form-date-picker/form-date-picker.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
+import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
export default function ScoreboardAddButton({ job, disabled, ...otherBtnProps }) {
const { t } = useTranslation();
@@ -86,7 +86,7 @@ export default function ScoreboardAddButton({ job, disabled, ...otherBtnProps })
}
]}
>
-