IO-3252 Reschedule Job with Existing Data
Signed-off-by: Allan Carr <allan@imexsystems.ca>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { DatePicker, Space, TimePicker } from "antd";
|
import { DatePicker, Space, TimePicker } from "antd";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import React, { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
@@ -94,7 +94,24 @@ const DateTimePicker = ({
|
|||||||
showTime={false}
|
showTime={false}
|
||||||
format="MM/DD/YYYY"
|
format="MM/DD/YYYY"
|
||||||
value={value ? dayjs(value) : null}
|
value={value ? dayjs(value) : null}
|
||||||
onChange={handleChange}
|
onChange={(dateValue) => {
|
||||||
|
if (dateValue) {
|
||||||
|
// When date changes, preserve the existing time if it exists
|
||||||
|
if (value && dayjs(value).isValid()) {
|
||||||
|
const existingTime = dayjs(value);
|
||||||
|
const newDateTime = dayjs(dateValue)
|
||||||
|
.hour(existingTime.hour())
|
||||||
|
.minute(existingTime.minute())
|
||||||
|
.second(existingTime.second());
|
||||||
|
handleChange(newDateTime);
|
||||||
|
} else {
|
||||||
|
// If no existing time, just set the date without time
|
||||||
|
handleChange(dateValue);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleChange(dateValue);
|
||||||
|
}
|
||||||
|
}}
|
||||||
placeholder={t("general.labels.date")}
|
placeholder={t("general.labels.date")}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
disabledDate={handleDisabledDate}
|
disabledDate={handleDisabledDate}
|
||||||
@@ -105,13 +122,25 @@ const DateTimePicker = ({
|
|||||||
<TimePicker
|
<TimePicker
|
||||||
format="hh:mm a"
|
format="hh:mm a"
|
||||||
minuteStep={15}
|
minuteStep={15}
|
||||||
|
value={value && dayjs(value).hour() === 0 && dayjs(value).minute() === 0 ? null : dayjs(value)}
|
||||||
defaultOpenValue={dayjs(value)
|
defaultOpenValue={dayjs(value)
|
||||||
.hour(dayjs().hour())
|
.hour(dayjs().hour())
|
||||||
.minute(Math.floor(dayjs().minute() / 15) * 15)
|
.minute(Math.floor(dayjs().minute() / 15) * 15)
|
||||||
.second(0)}
|
.second(0)}
|
||||||
onChange={(value) => {
|
onChange={(timeValue) => {
|
||||||
handleChange(value);
|
if (timeValue) {
|
||||||
onBlur();
|
// When time changes, combine it with the existing date
|
||||||
|
const existingDate = dayjs(value);
|
||||||
|
const newDateTime = existingDate
|
||||||
|
.hour(timeValue.hour())
|
||||||
|
.minute(timeValue.minute())
|
||||||
|
.second(0);
|
||||||
|
handleChange(newDateTime);
|
||||||
|
} else {
|
||||||
|
// If time is cleared, just update with null time but keep date
|
||||||
|
handleChange(timeValue);
|
||||||
|
}
|
||||||
|
if (onBlur) onBlur();
|
||||||
}}
|
}}
|
||||||
placeholder={t("general.labels.time")}
|
placeholder={t("general.labels.time")}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
|||||||
@@ -385,7 +385,9 @@ export function ScheduleEventComponent({
|
|||||||
previousEvent: event.id,
|
previousEvent: event.id,
|
||||||
color: event.color,
|
color: event.color,
|
||||||
alt_transport: event.job && event.job.alt_transport,
|
alt_transport: event.job && event.job.alt_transport,
|
||||||
note: event.note
|
note: event.note,
|
||||||
|
scheduled_in: event.job && event.job.scheduled_in,
|
||||||
|
scheduled_completion: event.job && event.job.scheduled_completion
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -673,7 +673,9 @@ export function JobsDetailHeaderActions({
|
|||||||
context: {
|
context: {
|
||||||
jobId: job.id,
|
jobId: job.id,
|
||||||
job: job,
|
job: job,
|
||||||
alt_transport: job.alt_transport
|
alt_transport: job.alt_transport,
|
||||||
|
scheduled_in: job.scheduled_in,
|
||||||
|
scheduled_completion: job.scheduled_completion
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1090,11 +1092,7 @@ export function JobsDetailHeaderActions({
|
|||||||
{t("menus.jobsactions.deletejob")}
|
{t("menus.jobsactions.deletejob")}
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
) : (
|
) : (
|
||||||
<Popconfirm
|
<Popconfirm title={t("jobs.labels.deletewatchers")} onClick={(e) => e.stopPropagation()} showCancel={false}>
|
||||||
title={t("jobs.labels.deletewatchers")}
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
showCancel={false}
|
|
||||||
>
|
|
||||||
{t("menus.jobsactions.deletejob")}
|
{t("menus.jobsactions.deletejob")}
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useMutation, useQuery } from "@apollo/client";
|
import { useMutation, useQuery } from "@apollo/client";
|
||||||
import { Form, Modal } from "antd";
|
import { Form, Modal } from "antd";
|
||||||
import dayjs from "../../utils/day";
|
import { useEffect, useState } from "react";
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
import {
|
import {
|
||||||
CANCEL_APPOINTMENT_BY_ID,
|
CANCEL_APPOINTMENT_BY_ID,
|
||||||
@@ -19,9 +19,9 @@ import { selectSchedule } from "../../redux/modals/modals.selectors";
|
|||||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import { DateTimeFormat } from "../../utils/DateFormatter";
|
import { DateTimeFormat } from "../../utils/DateFormatter";
|
||||||
|
import dayjs from "../../utils/day";
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
import ScheduleJobModalComponent from "./schedule-job-modal.component";
|
import ScheduleJobModalComponent from "./schedule-job-modal.component";
|
||||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -72,7 +72,7 @@ export function ScheduleJobModalContainer({
|
|||||||
variables: { jobid: jobId },
|
variables: { jobid: jobId },
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
nextFetchPolicy: "network-only",
|
nextFetchPolicy: "network-only",
|
||||||
skip: !open || !!!jobId
|
skip: !open || !jobId
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -93,12 +93,12 @@ export function ScheduleJobModalContainer({
|
|||||||
logImEXEvent("schedule_new_appointment");
|
logImEXEvent("schedule_new_appointment");
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
if (!!previousEvent) {
|
if (previousEvent) {
|
||||||
const cancelAppt = await cancelAppointment({
|
const cancelAppt = await cancelAppointment({
|
||||||
variables: { appid: previousEvent }
|
variables: { appid: previousEvent }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!cancelAppt.errors) {
|
if (cancelAppt.errors) {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("appointments.errors.canceling", {
|
message: t("appointments.errors.canceling", {
|
||||||
message: JSON.stringify(cancelAppt.errors)
|
message: JSON.stringify(cancelAppt.errors)
|
||||||
@@ -146,7 +146,7 @@ export function ScheduleJobModalContainer({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!appt.errors) {
|
if (appt.errors) {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("appointments.errors.saving", {
|
message: t("appointments.errors.saving", {
|
||||||
message: JSON.stringify(appt.errors)
|
message: JSON.stringify(appt.errors)
|
||||||
@@ -172,7 +172,7 @@ export function ScheduleJobModalContainer({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!jobUpdate.errors) {
|
if (jobUpdate.errors) {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("appointments.errors.saving", {
|
message: t("appointments.errors.saving", {
|
||||||
message: JSON.stringify(jobUpdate.errors)
|
message: JSON.stringify(jobUpdate.errors)
|
||||||
@@ -222,9 +222,9 @@ export function ScheduleJobModalContainer({
|
|||||||
initialValues={{
|
initialValues={{
|
||||||
notifyCustomer: !!(job && job.ownr_ea),
|
notifyCustomer: !!(job && job.ownr_ea),
|
||||||
email: (job && job.ownr_ea) || "",
|
email: (job && job.ownr_ea) || "",
|
||||||
start: null,
|
|
||||||
// smartDates: [],
|
// smartDates: [],
|
||||||
scheduled_completion: null,
|
start: context.scheduled_in,
|
||||||
|
scheduled_completion: context.scheduled_completion ,
|
||||||
color: context.color,
|
color: context.color,
|
||||||
alt_transport: context.alt_transport,
|
alt_transport: context.alt_transport,
|
||||||
note: context.note
|
note: context.note
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ export const QUERY_ALL_ACTIVE_APPOINTMENTS = gql`
|
|||||||
color
|
color
|
||||||
note
|
note
|
||||||
job {
|
job {
|
||||||
|
scheduled_in
|
||||||
|
scheduled_completion
|
||||||
alt_transport
|
alt_transport
|
||||||
ro_number
|
ro_number
|
||||||
ownr_ln
|
ownr_ln
|
||||||
|
|||||||
Reference in New Issue
Block a user