302 lines
9.0 KiB
JavaScript
302 lines
9.0 KiB
JavaScript
import { useMutation, useQuery } from "@apollo/client";
|
|
import { Form, Modal } from "antd";
|
|
import React, { useEffect, useMemo, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { connect } from "react-redux";
|
|
import { createStructuredSelector } from "reselect";
|
|
import { MUTATION_INSERT_NEW_TASK, MUTATION_UPDATE_TASK, QUERY_GET_TASK_BY_ID } from "../../graphql/tasks.queries";
|
|
import { GET_JOB_BY_PK, QUERY_GET_TASKS_JOB_DETAILS_BY_ID } from "../../graphql/jobs.queries.js";
|
|
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
|
import { selectTaskUpsert } from "../../redux/modals/modals.selectors";
|
|
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
|
import TaskUpsertModalComponent from "./task-upsert-modal.component";
|
|
import { replaceUndefinedWithNull } from "../../utils/undefinedtonull.js";
|
|
import { useLocation, useNavigate } from "react-router-dom";
|
|
import { insertAuditTrail } from "../../redux/application/application.actions.js";
|
|
import AuditTrailMapping from "../../utils/AuditTrailMappings.js";
|
|
import { isEqual } from "lodash";
|
|
import refetchRouteMappings from "./task-upsert-modal.route.mappings";
|
|
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
|
|
|
const mapStateToProps = createStructuredSelector({
|
|
currentUser: selectCurrentUser,
|
|
bodyshop: selectBodyshop,
|
|
taskUpsert: selectTaskUpsert
|
|
});
|
|
const mapDispatchToProps = (dispatch) => ({
|
|
toggleModalVisible: () => dispatch(toggleModalVisible("taskUpsert")),
|
|
insertAuditTrail: ({ jobid, billid, operation, type }) =>
|
|
dispatch(insertAuditTrail({ jobid, billid, operation, type }))
|
|
});
|
|
|
|
export function TaskUpsertModalContainer({ bodyshop, currentUser, taskUpsert, toggleModalVisible, insertAuditTrail }) {
|
|
const { t } = useTranslation();
|
|
const history = useNavigate();
|
|
const [insertTask] = useMutation(MUTATION_INSERT_NEW_TASK);
|
|
const [updateTask] = useMutation(MUTATION_UPDATE_TASK);
|
|
const { open, context } = taskUpsert;
|
|
const { jobid, joblineid, billid, partsorderid, taskId, existingTask, query, view } = context;
|
|
const [form] = Form.useForm();
|
|
const [selectedJobId, setSelectedJobId] = useState(null);
|
|
const [selectedJobDetails, setSelectedJobDetails] = useState(null);
|
|
const [jobIdState, setJobIdState] = useState(null);
|
|
const [isTouched, setIsTouched] = useState(false);
|
|
const location = useLocation();
|
|
const notification = useNotification();
|
|
|
|
const { loading, error, data } = useQuery(QUERY_GET_TASKS_JOB_DETAILS_BY_ID, {
|
|
variables: { id: jobIdState },
|
|
skip: !jobIdState
|
|
});
|
|
|
|
const {
|
|
loading: taskLoading,
|
|
error: taskError,
|
|
data: taskData
|
|
} = useQuery(QUERY_GET_TASK_BY_ID, {
|
|
variables: { id: taskId },
|
|
skip: !taskId
|
|
});
|
|
// Use Effect to hydrate existing task if only a taskid is provided
|
|
useEffect(() => {
|
|
if (!taskLoading && !taskError && taskData && taskData?.tasks_by_pk) {
|
|
form.setFieldsValue(taskData.tasks_by_pk);
|
|
setSelectedJobId(taskData.tasks_by_pk.jobid);
|
|
}
|
|
}, [taskLoading, taskError, taskData, form]);
|
|
|
|
// Use Effect to hydrate selected job details
|
|
useEffect(() => {
|
|
if (!loading && !error && data) {
|
|
setSelectedJobDetails(data.jobs_by_pk);
|
|
}
|
|
}, [loading, error, data]);
|
|
|
|
// Use Effect to toggle to set jobid state
|
|
useEffect(() => {
|
|
if (selectedJobId) {
|
|
setJobIdState(selectedJobId);
|
|
}
|
|
}, [selectedJobId]);
|
|
|
|
// Use Effect to hydrate form fields
|
|
useEffect(() => {
|
|
if (jobid || existingTask?.id) {
|
|
setSelectedJobId(jobid || existingTask.jobid);
|
|
}
|
|
if (existingTask && open) {
|
|
form.setFieldsValue(existingTask);
|
|
} else if (!existingTask && open) {
|
|
form.resetFields();
|
|
if (joblineid) form.setFieldsValue({ joblineid });
|
|
if (billid) form.setFieldsValue({ billid });
|
|
if (partsorderid) form.setFieldsValue({ partsorderid });
|
|
}
|
|
return () => {
|
|
setSelectedJobId(null);
|
|
setIsTouched(false);
|
|
};
|
|
}, [jobid, existingTask, form, open, joblineid, billid, partsorderid]);
|
|
|
|
/**
|
|
* Remove the taskid from the URL
|
|
*/
|
|
const removeTaskIdFromUrl = () => {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
if (!urlParams.has("taskid")) return;
|
|
urlParams.delete("taskid");
|
|
history(`${window.location.pathname}?${urlParams}`);
|
|
};
|
|
|
|
/**
|
|
* Generate refetch queries
|
|
* @param jobId
|
|
* @returns {*[]}
|
|
*/
|
|
const generateRefetchQueries = (jobId) => {
|
|
const refetchQueries = [];
|
|
|
|
if (location.pathname.includes("/manage/jobs") && jobId) {
|
|
refetchQueries.push({
|
|
query: GET_JOB_BY_PK,
|
|
variables: {
|
|
id: jobId
|
|
}
|
|
});
|
|
}
|
|
|
|
// We have a specified query
|
|
if (query && Object.keys(query).length) {
|
|
refetchQueries.push(Object.keys(query)[0]);
|
|
}
|
|
// We don't have a specified query, check the page
|
|
else {
|
|
refetchRouteMappings.forEach((mapping) => {
|
|
if (location.pathname.includes(mapping.route)) {
|
|
refetchQueries.push(mapping.query);
|
|
}
|
|
});
|
|
}
|
|
|
|
return refetchQueries;
|
|
};
|
|
|
|
/**
|
|
* Handle existing task
|
|
* @param id
|
|
* @param jobId
|
|
* @param values
|
|
* @returns {Promise<void>}
|
|
*/
|
|
const handleExistingTask = async (id, jobId, values) => {
|
|
const task = replaceUndefinedWithNull(values);
|
|
|
|
// Remind at is dirty so lets clear remind_at_sent
|
|
if (task?.remind_at) {
|
|
task.remind_at_sent = null;
|
|
}
|
|
|
|
const taskObject = {
|
|
variables: {
|
|
taskId: id,
|
|
task
|
|
}
|
|
};
|
|
|
|
taskObject.refetchQueries = generateRefetchQueries(jobId);
|
|
|
|
const taskData = await updateTask(taskObject);
|
|
|
|
if (!taskData.errors) {
|
|
const oldTask = taskData?.data?.update_tasks?.returning[0];
|
|
|
|
insertAuditTrail({
|
|
jobid: oldTask.jobid,
|
|
operation: AuditTrailMapping.tasksUpdated(oldTask.title, currentUser.email),
|
|
type: "tasksUpdated"
|
|
});
|
|
}
|
|
|
|
notification["success"]({
|
|
message: t("tasks.successes.updated")
|
|
});
|
|
|
|
toggleModalVisible();
|
|
};
|
|
|
|
/**
|
|
* Handle new task
|
|
* @param values
|
|
* @returns {Promise<void>}
|
|
*/
|
|
const handleNewTask = async (values) => {
|
|
const taskObject = {
|
|
variables: {
|
|
taskInput: [
|
|
{
|
|
...values,
|
|
created_by: currentUser.email,
|
|
bodyshopid: bodyshop.id
|
|
}
|
|
]
|
|
}
|
|
};
|
|
|
|
taskObject.refetchQueries = generateRefetchQueries(values.jobid);
|
|
|
|
const newTaskData = await insertTask(taskObject);
|
|
const newTask = newTaskData?.data?.insert_tasks?.returning[0];
|
|
|
|
if (!newTaskData.errors) {
|
|
insertAuditTrail({
|
|
jobid: newTask.jobid,
|
|
operation: AuditTrailMapping.tasksCreated(newTask.title, currentUser.email),
|
|
type: "tasksCreated"
|
|
});
|
|
}
|
|
|
|
form.resetFields();
|
|
toggleModalVisible();
|
|
|
|
notification["success"]({
|
|
message: t("tasks.successes.created")
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Handle the form submit
|
|
* @param formValues
|
|
* @returns {Promise<[{jobid, bodyshopid, created_by},...*]>}
|
|
*/
|
|
const handleFinish = async (formValues) => {
|
|
if (existingTask || taskData?.tasks_by_pk) {
|
|
const taskSource = existingTask || taskData?.tasks_by_pk;
|
|
const dirtyValues = Object.keys(formValues).reduce((acc, key) => {
|
|
if (!isEqual(formValues[key], taskSource[key])) {
|
|
acc[key] = formValues[key];
|
|
}
|
|
return acc;
|
|
}, {});
|
|
try {
|
|
await handleExistingTask(taskSource.id, taskSource.jobid, dirtyValues);
|
|
} catch (e) {
|
|
notification["error"]({
|
|
message: t("tasks.failures.updated")
|
|
});
|
|
}
|
|
} else {
|
|
try {
|
|
await handleNewTask(formValues);
|
|
} catch (e) {
|
|
notification["error"]({
|
|
message: t("tasks.failures.created")
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
return (
|
|
<Modal
|
|
title={<span id="task-upsert-modal-title">{view ? t("tasks.actions.view") : existingTask ? t("tasks.actions.edit") : t("tasks.actions.new")}</span>}
|
|
open={open}
|
|
okText={t("general.actions.save")}
|
|
width="50%"
|
|
cancelText={!isTouched ? t("general.actions.ok") : t("general.actions.cancel")}
|
|
onOk={() => {
|
|
removeTaskIdFromUrl();
|
|
form.submit();
|
|
}}
|
|
onCancel={() => {
|
|
removeTaskIdFromUrl();
|
|
toggleModalVisible();
|
|
}}
|
|
okButtonProps={{ disabled: !isTouched }}
|
|
destroyOnClose
|
|
>
|
|
<Form
|
|
form={form}
|
|
onFinish={handleFinish}
|
|
layout="vertical"
|
|
onFieldsChange={() => {
|
|
setIsTouched(true);
|
|
}}
|
|
>
|
|
<TaskUpsertModalComponent
|
|
form={form}
|
|
loading={loading || (taskId && taskLoading)}
|
|
error={error}
|
|
data={data}
|
|
view={view}
|
|
existingTask={existingTask || taskData?.tasks_by_pk}
|
|
selectedJobId={selectedJobId}
|
|
setSelectedJobId={setSelectedJobId}
|
|
selectedJobDetails={selectedJobDetails}
|
|
/>
|
|
</Form>
|
|
</Modal>
|
|
);
|
|
}
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(TaskUpsertModalContainer);
|