Files
bodyshop/client/src/components/task-upsert-modal/task-upsert-modal.container.jsx
Dave Richer 69ac2f0a6c - Progress Commit
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-04-02 17:33:54 -04:00

220 lines
6.8 KiB
JavaScript

import {useMutation, useQuery} from "@apollo/client";
import {Form, Modal, notification} from "antd";
import React, {useEffect, 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 {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 {useNavigate} from "react-router-dom";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
bodyshop: selectBodyshop,
taskUpsert: selectTaskUpsert,
});
const mapDispatchToProps = (dispatch) => ({
toggleModalVisible: () => dispatch(toggleModalVisible("taskUpsert")),
});
export function TaskUpsertModalContainer({
bodyshop,
currentUser,
taskUpsert,
toggleModalVisible,
}) {
const {t} = useTranslation();
const history = useNavigate();
const [insertTask] = useMutation(MUTATION_INSERT_NEW_TASK);
const [updateTask] = useMutation(MUTATION_UPDATE_TASK);
const {open, context, actions} = taskUpsert;
const {jobid, joblineid, billid, partsorderid, taskId, existingTask} = context;
const {refetch} = actions;
const [form] = Form.useForm();
const [selectedJobId, setSelectedJobId] = useState(null);
const [selectedJobDetails, setSelectedJobDetails] = useState(null);
const [jobIdState, setJobIdState] = useState(null);
const {
loading: loading,
error: error,
data: 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,
});
// This takes care of the ability to deep link a task from the URL (Fills in form fields)
useEffect(() => {
if (!taskLoading && !taskError && taskData && taskData?.tasks_by_pk) {
form.setFieldsValue(taskData.tasks_by_pk);
setSelectedJobId(taskData.tasks_by_pk.jobid);
}
}, [taskLoading, taskError, taskData]);
/**
* Set the selected job id when the modal is opened and jobId is passed as a prop or when an existing task is passed as a prop
*/
useEffect(() => {
if (jobid || existingTask?.id) {
setSelectedJobId(jobid || existingTask.jobid);
}
return () => {
setSelectedJobId(null);
};
}, [jobid, existingTask]);
/**
* Set the form values when the modal is opened and an existing task is passed as a prop
*/
useEffect(() => {
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});
}
}, [existingTask, form, open, joblineid, billid, partsorderid]);
/**
* Set the job id state when the selected job id changes
*/
useEffect(() => {
if (selectedJobId) {
// Update the state variable instead of calling useQuery
setJobIdState(selectedJobId);
}
}, [selectedJobId]);
/**
* Set the selected job details when the job details query is successful
*/
useEffect(() => {
if (!loading && !error && data) {
setSelectedJobDetails(data.jobs_by_pk);
}
}, [loading, error, data]);
const removeTaskIdFromUrl = () => {
const urlParams = new URLSearchParams(window.location.search);
urlParams.delete('taskid');
history(`${window.location.pathname}?${urlParams}`);
}
/**
* Handle the form submit
* @param formValues
* @returns {Promise<[{jobid, bodyshopid, created_by},...*]>}
*/
const handleFinish = async (formValues) => {
const {...values} = formValues;
if (existingTask) {
await updateTask({
variables: {
taskId: existingTask.id,
task: replaceUndefinedWithNull(values)
},
});
window.dispatchEvent(new CustomEvent('taskUpdated', {
detail: {message: 'A task has been created or edited.'},
}));
notification["success"]({
message: t("tasks.successes.updated"),
});
if (refetch) await refetch();
toggleModalVisible();
} else {
await insertTask({
variables: {
taskInput: [
{
...values,
created_by: currentUser.email,
bodyshopid: bodyshop.id
},
],
},
// TODO: Consult Patrick, because this fails on relationship data, and an event emitter is just much easier to use
// update(cache) {
// cache.modify({
// fields: {
// tasks(existingTasks) {
// return [{
// ...values,
// jobid: selectedJobId || values.jobid,
// created_by: currentUser.email,
// bodyshopid: bodyshop.id
// }, ...existingTasks]
// },
// },
// });
// },
});
if (refetch) await refetch();
form.resetFields();
toggleModalVisible();
window.dispatchEvent(new CustomEvent('taskUpdated', {
detail: {message: 'A task has been created or edited.'},
}));
notification["success"]({
message: t("tasks.successes.created"),
});
}
};
return (
<Modal
title={existingTask ? t("tasks.actions.edit") : t("tasks.actions.new")}
open={open}
okText={t("general.actions.save")}
width="50%"
onOk={() => {
removeTaskIdFromUrl();
form.submit();
}}
onCancel={() => {
removeTaskIdFromUrl();
toggleModalVisible();
}}
destroyOnClose
>
<Form form={form} onFinish={handleFinish} layout="vertical">
<TaskUpsertModalComponent form={form} loading={loading || (taskId && taskLoading)} error={error} data={data}
selectedJobId={selectedJobId}
setSelectedJobId={setSelectedJobId}
selectedJobDetails={selectedJobDetails}/>
</Form>
</Modal>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(TaskUpsertModalContainer);