|
|
|
|
@@ -1,5 +1,5 @@
|
|
|
|
|
import { AlertFilled } from "@ant-design/icons";
|
|
|
|
|
import { useMutation } from "@apollo/client";
|
|
|
|
|
import { useLazyQuery, useMutation } from "@apollo/client";
|
|
|
|
|
import { Button, Divider, Dropdown, Form, Input, Popover, Select, Space } from "antd";
|
|
|
|
|
import parsePhoneNumber from "libphonenumber-js";
|
|
|
|
|
import queryString from "query-string";
|
|
|
|
|
@@ -8,24 +8,30 @@ import { useTranslation } from "react-i18next";
|
|
|
|
|
import { connect } from "react-redux";
|
|
|
|
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
|
|
|
|
import { createStructuredSelector } from "reselect";
|
|
|
|
|
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
|
|
|
|
import { useSocket } from "../../contexts/SocketIO/useSocket.js";
|
|
|
|
|
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
|
|
|
|
|
import { GET_JOB_BY_PK_QUICK_INTAKE, JOB_PRODUCTION_TOGGLE } from "../../graphql/jobs.queries";
|
|
|
|
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
|
|
|
|
import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions";
|
|
|
|
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
|
|
|
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
|
|
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
|
|
|
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
|
|
|
|
import { DateTimeFormatterFunction } from "../../utils/DateFormatter";
|
|
|
|
|
import dayjs from "../../utils/day";
|
|
|
|
|
import { GenerateDocument } from "../../utils/RenderTemplate";
|
|
|
|
|
import { TemplateList } from "../../utils/TemplateConstants";
|
|
|
|
|
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
|
|
|
|
|
import DataLabel from "../data-label/data-label.component";
|
|
|
|
|
import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
|
|
|
|
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
|
|
|
|
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
|
|
|
|
|
import ScheduleManualEvent from "../schedule-manual-event/schedule-manual-event.component";
|
|
|
|
|
import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component";
|
|
|
|
|
import ScheduleAtChange from "./job-at-change.component";
|
|
|
|
|
import ScheduleEventColor from "./schedule-event.color.component";
|
|
|
|
|
import ScheduleEventNote from "./schedule-event.note.component";
|
|
|
|
|
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
|
|
|
|
|
|
|
|
|
const mapStateToProps = createStructuredSelector({
|
|
|
|
|
bodyshop: selectBodyshop
|
|
|
|
|
@@ -33,7 +39,8 @@ const mapStateToProps = createStructuredSelector({
|
|
|
|
|
const mapDispatchToProps = (dispatch) => ({
|
|
|
|
|
setScheduleContext: (context) => dispatch(setModalContext({ context: context, modal: "schedule" })),
|
|
|
|
|
openChatByPhone: (phone) => dispatch(openChatByPhone(phone)),
|
|
|
|
|
setMessage: (text) => dispatch(setMessage(text))
|
|
|
|
|
setMessage: (text) => dispatch(setMessage(text)),
|
|
|
|
|
insertAuditTrail: ({ jobid, operation }) => dispatch(insertAuditTrail({ jobid, operation }))
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export function ScheduleEventComponent({
|
|
|
|
|
@@ -43,16 +50,36 @@ export function ScheduleEventComponent({
|
|
|
|
|
event,
|
|
|
|
|
refetch,
|
|
|
|
|
handleCancel,
|
|
|
|
|
setScheduleContext
|
|
|
|
|
setScheduleContext,
|
|
|
|
|
insertAuditTrail
|
|
|
|
|
}) {
|
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
const [open, setOpen] = useState(false);
|
|
|
|
|
const history = useNavigate();
|
|
|
|
|
const searchParams = queryString.parse(useLocation().search);
|
|
|
|
|
const [updateAppointment] = useMutation(UPDATE_APPOINTMENT);
|
|
|
|
|
const [mutationUpdateJob] = useMutation(JOB_PRODUCTION_TOGGLE);
|
|
|
|
|
const [title, setTitle] = useState(event.title);
|
|
|
|
|
const { socket } = useSocket();
|
|
|
|
|
const notification = useNotification();
|
|
|
|
|
const [form] = Form.useForm();
|
|
|
|
|
const [popOverVisible, setPopOverVisible] = useState(false);
|
|
|
|
|
|
|
|
|
|
const [getJobDetails] = useLazyQuery(GET_JOB_BY_PK_QUICK_INTAKE, {
|
|
|
|
|
variables: { id: event.job.id },
|
|
|
|
|
onCompleted: (data) => {
|
|
|
|
|
if (data?.jobs_by_pk) {
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
actual_in: data.jobs_by_pk.actual_in ? data.jobs_by_pk.actual_in : dayjs(),
|
|
|
|
|
scheduled_completion: data.jobs_by_pk.scheduled_completion,
|
|
|
|
|
actual_completion: data.jobs_by_pk.actual_completion,
|
|
|
|
|
scheduled_delivery: data.jobs_by_pk.scheduled_delivery,
|
|
|
|
|
actual_delivery: data.jobs_by_pk.actual_delivery
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
fetchPolicy: "network-only"
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const blockContent = (
|
|
|
|
|
<Space direction="vertical" wrap>
|
|
|
|
|
@@ -89,6 +116,74 @@ export function ScheduleEventComponent({
|
|
|
|
|
</Space>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const handleConvert = async (values) => {
|
|
|
|
|
const res = await mutationUpdateJob({
|
|
|
|
|
variables: {
|
|
|
|
|
jobId: event.job.id,
|
|
|
|
|
job: {
|
|
|
|
|
...values,
|
|
|
|
|
status: bodyshop.md_ro_statuses.default_arrived,
|
|
|
|
|
inproduction: true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!res.errors) {
|
|
|
|
|
notification["success"]({
|
|
|
|
|
message: t("jobs.successes.converted")
|
|
|
|
|
});
|
|
|
|
|
insertAuditTrail({
|
|
|
|
|
jobid: event.job.id,
|
|
|
|
|
operation: AuditTrailMapping.jobintake(
|
|
|
|
|
res.data.update_jobs.returning[0].status,
|
|
|
|
|
DateTimeFormatterFunction(values.scheduled_completion)
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
setPopOverVisible(false);
|
|
|
|
|
refetch();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const popMenu = (
|
|
|
|
|
<div onClick={(e) => e.stopPropagation()}>
|
|
|
|
|
<Form layout="vertical" form={form} onFinish={handleConvert}>
|
|
|
|
|
<Form.Item
|
|
|
|
|
name={["actual_in"]}
|
|
|
|
|
label={t("jobs.fields.actual_in")}
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true
|
|
|
|
|
//message: t("general.validation.required"),
|
|
|
|
|
}
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<FormDateTimePickerComponent disabled={event.ro_number} />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
<Form.Item
|
|
|
|
|
name={["scheduled_completion"]}
|
|
|
|
|
label={t("jobs.fields.scheduled_completion")}
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true
|
|
|
|
|
//message: t("general.validation.required"),
|
|
|
|
|
}
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<FormDateTimePickerComponent disabled={event.ro_number} />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
<Form.Item name={["scheduled_delivery"]} label={t("jobs.fields.scheduled_delivery")}>
|
|
|
|
|
<FormDateTimePickerComponent disabled={event.ro_number} />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Space wrap>
|
|
|
|
|
<Button type="primary" onClick={() => form.submit()}>
|
|
|
|
|
{t("general.actions.save")}
|
|
|
|
|
</Button>
|
|
|
|
|
</Space>
|
|
|
|
|
</Form>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const popoverContent = (
|
|
|
|
|
<div style={{ maxWidth: "40vw" }}>
|
|
|
|
|
{!event.isintake ? (
|
|
|
|
|
@@ -294,7 +389,7 @@ export function ScheduleEventComponent({
|
|
|
|
|
) : (
|
|
|
|
|
<ScheduleManualEvent event={event} />
|
|
|
|
|
)}
|
|
|
|
|
{event.isintake ? (
|
|
|
|
|
{event.isintake && HasFeatureAccess({ featureName: "checklist", bodyshop }) ? (
|
|
|
|
|
<Link
|
|
|
|
|
to={{
|
|
|
|
|
pathname: `/manage/jobs/${event.job && event.job.id}/intake`,
|
|
|
|
|
@@ -303,7 +398,21 @@ export function ScheduleEventComponent({
|
|
|
|
|
>
|
|
|
|
|
<Button disabled={event.arrived}>{t("appointments.actions.intake")}</Button>
|
|
|
|
|
</Link>
|
|
|
|
|
) : null}
|
|
|
|
|
) : (
|
|
|
|
|
<Popover //open={open}
|
|
|
|
|
content={popMenu}
|
|
|
|
|
open={popOverVisible}
|
|
|
|
|
onOpenChange={setPopOverVisible}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
getJobDetails();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
}}
|
|
|
|
|
getPopupContainer={(trigger) => trigger.parentNode}
|
|
|
|
|
trigger="click"
|
|
|
|
|
>
|
|
|
|
|
<Button disabled={event.arrived}>{t("jobs.actions.intake_quick")}</Button>
|
|
|
|
|
</Popover>
|
|
|
|
|
)}
|
|
|
|
|
</Space>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|