@@ -84,10 +84,13 @@ function TaskListComponent({
|
|||||||
loading,
|
loading,
|
||||||
tasks,
|
tasks,
|
||||||
total,
|
total,
|
||||||
|
titleTranslation,
|
||||||
refetch,
|
refetch,
|
||||||
toggleCompletedStatus,
|
toggleCompletedStatus,
|
||||||
setTaskUpsertContext,
|
setTaskUpsertContext,
|
||||||
toggleDeletedStatus
|
toggleDeletedStatus,
|
||||||
|
relationshipType,
|
||||||
|
relationshipId
|
||||||
}) {
|
}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
|
|
||||||
@@ -186,7 +189,9 @@ function TaskListComponent({
|
|||||||
const handleCreateTask = () => {
|
const handleCreateTask = () => {
|
||||||
setTaskUpsertContext({
|
setTaskUpsertContext({
|
||||||
actions: {},
|
actions: {},
|
||||||
context: {},
|
context: {
|
||||||
|
[relationshipType]: relationshipId,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -241,7 +246,7 @@ function TaskListComponent({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={t("menus.header.my_tasks")}
|
title={titleTranslation}
|
||||||
extra={tasksExtra()}
|
extra={tasksExtra()}
|
||||||
>
|
>
|
||||||
<Table
|
<Table
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {useMutation, useQuery} from "@apollo/client";
|
|||||||
import {
|
import {
|
||||||
MUTATION_TOGGLE_TASK_COMPLETED,
|
MUTATION_TOGGLE_TASK_COMPLETED,
|
||||||
MUTATION_TOGGLE_TASK_DELETED,
|
MUTATION_TOGGLE_TASK_DELETED,
|
||||||
QUERY_MY_TASKS_PAGINATED
|
|
||||||
} from "../../graphql/tasks.queries.js";
|
} from "../../graphql/tasks.queries.js";
|
||||||
import {pageLimit} from "../../utils/config.js";
|
import {pageLimit} from "../../utils/config.js";
|
||||||
import AlertComponent from "../alert/alert.component.jsx";
|
import AlertComponent from "../alert/alert.component.jsx";
|
||||||
@@ -13,18 +12,18 @@ import TaskListComponent from "./task-list.component.jsx";
|
|||||||
import {notification} from "antd";
|
import {notification} from "antd";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
|
|
||||||
export default function TaskListContainer({bodyshop, currentUser}) {
|
export default function TaskListContainer({bodyshop, titleTranslation ,query, relationshipType, relationshipId}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const searchParams = queryString.parse(useLocation().search);
|
const searchParams = queryString.parse(useLocation().search);
|
||||||
const {page, sortcolumn, sortorder, deleted, completed} = searchParams;
|
const {page, sortcolumn, sortorder, deleted, completed} = searchParams;
|
||||||
const {loading, error, data, refetch} = useQuery(
|
const {loading, error, data, refetch} = useQuery(
|
||||||
QUERY_MY_TASKS_PAGINATED,
|
query,
|
||||||
{
|
{
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
nextFetchPolicy: "network-only",
|
nextFetchPolicy: "network-only",
|
||||||
variables: {
|
variables: {
|
||||||
bodyshop: bodyshop.id,
|
bodyshop: bodyshop.id,
|
||||||
user: currentUser.email,
|
[relationshipType]: relationshipId,
|
||||||
deleted: deleted === 'true',
|
deleted: deleted === 'true',
|
||||||
completed: completed === "true",
|
completed: completed === "true",
|
||||||
offset: page ? (page - 1) * pageLimit : 0,
|
offset: page ? (page - 1) * pageLimit : 0,
|
||||||
@@ -129,9 +128,12 @@ export default function TaskListContainer({bodyshop, currentUser}) {
|
|||||||
loading={loading}
|
loading={loading}
|
||||||
tasks={data ? data.tasks : null}
|
tasks={data ? data.tasks : null}
|
||||||
total={data ? data.tasks_aggregate.aggregate.count : 0}
|
total={data ? data.tasks_aggregate.aggregate.count : 0}
|
||||||
|
titleTranslation={t(titleTranslation || "tasks.title")}
|
||||||
refetch={refetch}
|
refetch={refetch}
|
||||||
toggleCompletedStatus={toggleCompletedStatus}
|
toggleCompletedStatus={toggleCompletedStatus}
|
||||||
toggleDeletedStatus={toggleDeletedStatus}
|
toggleDeletedStatus={toggleDeletedStatus}
|
||||||
|
relationshipType={relationshipType}
|
||||||
|
relationshipId={relationshipId}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export function TaskUpsertModalComponent({
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if (!data || loading || error) return <LoadingSkeleton active/>;
|
if (loading || error) return <LoadingSkeleton active/>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -115,7 +115,7 @@ export function TaskUpsertModalComponent({
|
|||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="jobid"
|
name="jobid"
|
||||||
// initialValue={selectedJobId}
|
initialValue={selectedJobId}
|
||||||
label={t("tasks.fields.jobid")}
|
label={t("tasks.fields.jobid")}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export function TaskUpsertModalContainer({
|
|||||||
const [updateTask] = useMutation(MUTATION_UPDATE_TASK);
|
const [updateTask] = useMutation(MUTATION_UPDATE_TASK);
|
||||||
|
|
||||||
const {open, context, actions} = taskUpsert;
|
const {open, context, actions} = taskUpsert;
|
||||||
const {jobId, existingTask} = context;
|
const {jobid, existingTask, joblineid, billid, partsorderid} = context;
|
||||||
const {refetch} = actions;
|
const {refetch} = actions;
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [selectedJobId, setSelectedJobId] = useState(null);
|
const [selectedJobId, setSelectedJobId] = useState(null);
|
||||||
@@ -52,10 +52,10 @@ export function TaskUpsertModalContainer({
|
|||||||
* 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
|
* 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(() => {
|
useEffect(() => {
|
||||||
if (jobId || existingTask?.id) {
|
if (jobid || existingTask?.id) {
|
||||||
setSelectedJobId(jobId || existingTask.jobid);
|
setSelectedJobId(jobid || existingTask.jobid);
|
||||||
}
|
}
|
||||||
}, [jobId, existingTask]);
|
}, [jobid, existingTask]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the form values when the modal is opened and an existing task is passed as a prop
|
* Set the form values when the modal is opened and an existing task is passed as a prop
|
||||||
@@ -65,9 +65,11 @@ export function TaskUpsertModalContainer({
|
|||||||
form.setFieldsValue(existingTask);
|
form.setFieldsValue(existingTask);
|
||||||
} else if (!existingTask && open) {
|
} else if (!existingTask && open) {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
|
if (joblineid) form.setFieldsValue({joblineid});
|
||||||
|
if (billid) form.setFieldsValue({billid});
|
||||||
|
if (partsorderid) form.setFieldsValue({partsorderid});
|
||||||
}
|
}
|
||||||
}, [existingTask, form, open]);
|
}, [existingTask, form, open, joblineid, billid, partsorderid]);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the job id state when the selected job id changes
|
* Set the job id state when the selected job id changes
|
||||||
@@ -128,7 +130,7 @@ export function TaskUpsertModalContainer({
|
|||||||
...values,
|
...values,
|
||||||
created_by: currentUser.email,
|
created_by: currentUser.email,
|
||||||
bodyshopid: bodyshop.id
|
bodyshopid: bodyshop.id
|
||||||
}, ...existingTasks]
|
}, ...existingTasks]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -42,12 +42,214 @@ export const QUERY_ALL_TASKS_PAGINATED = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
/**
|
const PARTIAL_TASK_FIELDS = gql`
|
||||||
* My tasks paginated query
|
fragment TaskFields on tasks {
|
||||||
* @type {DocumentNode}
|
id
|
||||||
*/
|
created_at
|
||||||
|
updated_at
|
||||||
|
title
|
||||||
|
description
|
||||||
|
deleted
|
||||||
|
deleted_at
|
||||||
|
due_date
|
||||||
|
created_by
|
||||||
|
assigned_to
|
||||||
|
completed
|
||||||
|
completed_at
|
||||||
|
remind_at
|
||||||
|
priority
|
||||||
|
job {
|
||||||
|
id
|
||||||
|
ro_number
|
||||||
|
joblines {
|
||||||
|
id
|
||||||
|
line_desc
|
||||||
|
}
|
||||||
|
bills {
|
||||||
|
id
|
||||||
|
vendor {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
invoice_number
|
||||||
|
}
|
||||||
|
parts_orders {
|
||||||
|
id
|
||||||
|
vendor {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
order_number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jobid
|
||||||
|
joblineid
|
||||||
|
partsorderid
|
||||||
|
billid
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Query for joblineid
|
||||||
|
export const QUERY_JOBLINE_TASKS_PAGINATED = gql`
|
||||||
|
${PARTIAL_TASK_FIELDS}
|
||||||
|
query QUERY_JOBLINE_TASKS_PAGINATED(
|
||||||
|
$offset: Int
|
||||||
|
$limit: Int
|
||||||
|
$joblineid: uuid!
|
||||||
|
$bodyshop: uuid!
|
||||||
|
$deleted: Boolean
|
||||||
|
$completed: Boolean
|
||||||
|
$order: [tasks_order_by!]!
|
||||||
|
) {
|
||||||
|
tasks(
|
||||||
|
offset: $offset
|
||||||
|
limit: $limit
|
||||||
|
order_by: $order
|
||||||
|
where: {
|
||||||
|
joblineid: {_eq: $joblineid},
|
||||||
|
bodyshopid: {_eq: $bodyshop},
|
||||||
|
deleted: {_eq: $deleted},
|
||||||
|
completed: {_eq: $completed}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
...TaskFields
|
||||||
|
}
|
||||||
|
tasks_aggregate(
|
||||||
|
where: {
|
||||||
|
joblineid: {_eq: $joblineid},
|
||||||
|
bodyshopid: {_eq: $bodyshop},
|
||||||
|
deleted: {_eq: $deleted},
|
||||||
|
completed: {_eq: $completed}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
aggregate {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Query for partsorderid
|
||||||
|
export const QUERY_PARTSORDER_TASKS_PAGINATED = gql`
|
||||||
|
${PARTIAL_TASK_FIELDS}
|
||||||
|
query QUERY_PARTSORDER_TASKS_PAGINATED(
|
||||||
|
$offset: Int
|
||||||
|
$limit: Int
|
||||||
|
$partsorderid: uuid!
|
||||||
|
$bodyshop: uuid!
|
||||||
|
$deleted: Boolean
|
||||||
|
$completed: Boolean
|
||||||
|
$order: [tasks_order_by!]!
|
||||||
|
) {
|
||||||
|
tasks(
|
||||||
|
offset: $offset
|
||||||
|
limit: $limit
|
||||||
|
order_by: $order
|
||||||
|
where: {
|
||||||
|
partsorderid: {_eq: $partsorderid},
|
||||||
|
bodyshopid: {_eq: $bodyshop},
|
||||||
|
deleted: {_eq: $deleted},
|
||||||
|
completed: {_eq: $completed}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
...TaskFields
|
||||||
|
}
|
||||||
|
tasks_aggregate(
|
||||||
|
where: {
|
||||||
|
partsorderid: {_eq: $partsorderid},
|
||||||
|
bodyshopid: {_eq: $bodyshop},
|
||||||
|
deleted: {_eq: $deleted},
|
||||||
|
completed: {_eq: $completed}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
aggregate {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Query for billid
|
||||||
|
export const QUERY_BILL_TASKS_PAGINATED = gql`
|
||||||
|
${PARTIAL_TASK_FIELDS}
|
||||||
|
query QUERY_BILL_TASKS_PAGINATED(
|
||||||
|
$offset: Int
|
||||||
|
$limit: Int
|
||||||
|
$billid: uuid!
|
||||||
|
$bodyshop: uuid!
|
||||||
|
$deleted: Boolean
|
||||||
|
$completed: Boolean
|
||||||
|
$order: [tasks_order_by!]!
|
||||||
|
) {
|
||||||
|
tasks(
|
||||||
|
offset: $offset
|
||||||
|
limit: $limit
|
||||||
|
order_by: $order
|
||||||
|
where: {
|
||||||
|
billid: {_eq: $billid},
|
||||||
|
bodyshopid: {_eq: $bodyshop},
|
||||||
|
deleted: {_eq: $deleted},
|
||||||
|
completed: {_eq: $completed}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
...TaskFields
|
||||||
|
}
|
||||||
|
tasks_aggregate(
|
||||||
|
where: {
|
||||||
|
billid: {_eq: $billid},
|
||||||
|
bodyshopid: {_eq: $bodyshop},
|
||||||
|
deleted: {_eq: $deleted},
|
||||||
|
completed: {_eq: $completed}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
aggregate {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Use the fragment in your queries
|
||||||
|
export const QUERY_JOB_TASKS_PAGINATED = gql`
|
||||||
|
${PARTIAL_TASK_FIELDS}
|
||||||
|
query QUERY_JOB_TASKS_PAGINATED(
|
||||||
|
$offset: Int
|
||||||
|
$limit: Int
|
||||||
|
$jobid: uuid!
|
||||||
|
$bodyshop: uuid!
|
||||||
|
$deleted: Boolean
|
||||||
|
$completed: Boolean
|
||||||
|
$order: [tasks_order_by!]!
|
||||||
|
) {
|
||||||
|
tasks(
|
||||||
|
offset: $offset
|
||||||
|
limit: $limit
|
||||||
|
order_by: $order
|
||||||
|
where: {
|
||||||
|
jobid: {_eq: $jobid},
|
||||||
|
bodyshopid: {_eq: $bodyshop},
|
||||||
|
deleted: {_eq: $deleted},
|
||||||
|
completed: {_eq: $completed}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
...TaskFields
|
||||||
|
}
|
||||||
|
tasks_aggregate(
|
||||||
|
where: {
|
||||||
|
jobid: {_eq: $jobid},
|
||||||
|
bodyshopid: {_eq: $bodyshop},
|
||||||
|
deleted: {_eq: $deleted},
|
||||||
|
completed: {_eq: $completed}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
aggregate {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const QUERY_MY_TASKS_PAGINATED = gql`
|
export const QUERY_MY_TASKS_PAGINATED = gql`
|
||||||
query QUERY_TASKS_PAGINATED(
|
${PARTIAL_TASK_FIELDS}
|
||||||
|
query QUERY_MY_TASKS_PAGINATED(
|
||||||
$offset: Int
|
$offset: Int
|
||||||
$limit: Int
|
$limit: Int
|
||||||
$user: String!
|
$user: String!
|
||||||
@@ -67,46 +269,7 @@ export const QUERY_MY_TASKS_PAGINATED = gql`
|
|||||||
completed: {_eq: $completed}
|
completed: {_eq: $completed}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
id
|
...TaskFields
|
||||||
created_at
|
|
||||||
updated_at
|
|
||||||
title
|
|
||||||
description
|
|
||||||
deleted
|
|
||||||
deleted_at
|
|
||||||
due_date
|
|
||||||
created_by
|
|
||||||
assigned_to
|
|
||||||
completed
|
|
||||||
completed_at
|
|
||||||
remind_at
|
|
||||||
priority
|
|
||||||
job {
|
|
||||||
id
|
|
||||||
ro_number
|
|
||||||
joblines {
|
|
||||||
id
|
|
||||||
line_desc
|
|
||||||
}
|
|
||||||
bills {
|
|
||||||
id
|
|
||||||
vendor {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
invoice_number
|
|
||||||
}
|
|
||||||
parts_orders {
|
|
||||||
id
|
|
||||||
vendor {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
order_number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jobid
|
|
||||||
joblineid
|
|
||||||
partsorderid
|
|
||||||
billid
|
|
||||||
}
|
}
|
||||||
tasks_aggregate(
|
tasks_aggregate(
|
||||||
where: {
|
where: {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import dayjs from "../../utils/day";
|
|||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, {useEffect, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {FaHardHat, FaRegStickyNote, FaShieldAlt} from "react-icons/fa";
|
import {FaHardHat, FaRegStickyNote, FaShieldAlt, FaTasks} from "react-icons/fa";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {useLocation, useNavigate} from "react-router-dom";
|
import {useLocation, useNavigate} from "react-router-dom";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
@@ -54,6 +54,8 @@ import JobProfileDataWarning from "../../components/job-profile-data-warning/job
|
|||||||
import {DateTimeFormat} from "../../utils/DateFormatter";
|
import {DateTimeFormat} from "../../utils/DateFormatter";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component";
|
import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component";
|
||||||
|
import TaskListContainer from "../../components/task-list/task-list.container.jsx";
|
||||||
|
import {QUERY_JOB_TASKS_PAGINATED} from "../../graphql/tasks.queries.js";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -376,6 +378,12 @@ export function JobsDetailPage({
|
|||||||
label: t("jobs.labels.audit"),
|
label: t("jobs.labels.audit"),
|
||||||
children: <JobAuditTrail jobId={job.id}/>,
|
children: <JobAuditTrail jobId={job.id}/>,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'tasks',
|
||||||
|
icon: <FaTasks/>,
|
||||||
|
label: t("menus.jobsdetail.tasks"),
|
||||||
|
children: <TaskListContainer bodyshop={bodyshop} relationshipType={'jobid'} relationshipId={job.id} query={QUERY_JOB_TASKS_PAGINATED} titleTranslation='tasks.titles.job_tasks'/>
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import TaskListContainer from "../../components/task-list/task-list.container.jsx";
|
import TaskListContainer from "../../components/task-list/task-list.container.jsx";
|
||||||
|
import {QUERY_MY_TASKS_PAGINATED} from "../../graphql/tasks.queries.js";
|
||||||
|
|
||||||
export default function TasksPageComponent({bodyshop, currentUser}) {
|
export default function TasksPageComponent({bodyshop, currentUser}) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<TaskListContainer bodyshop={bodyshop} currentUser={currentUser} />
|
<TaskListContainer relationshipId={currentUser.email} relationshipType={'user'} query={QUERY_MY_TASKS_PAGINATED} bodyshop={bodyshop} titleTranslation={'tasks.titles.my_tasks'}
|
||||||
|
currentUser={currentUser}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2120,6 +2120,8 @@
|
|||||||
"edit": "Edit Task"
|
"edit": "Edit Task"
|
||||||
},
|
},
|
||||||
"titles": {
|
"titles": {
|
||||||
|
"job_tasks": "Job Tasks",
|
||||||
|
"my_tasks": "My Tasks",
|
||||||
"completed": "Completed Tasks",
|
"completed": "Completed Tasks",
|
||||||
"deleted": "Deleted Tasks"
|
"deleted": "Deleted Tasks"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user