From 988c3a9f2245ff914148f7e54374ea9fdb1fec1d Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Mon, 18 Apr 2022 13:53:21 -0700
Subject: [PATCH] IO-1477 Updated parts queue page.
---
bodyshop_translations.babel | 42 +++++++
.../job-parts-queue-count.component.jsx | 76 ++++++++++++
.../job-remove-from-parts-queue.component.jsx | 20 ++--
client/src/graphql/jobs.queries.js | 23 ++--
.../parts-queue.page.component.jsx | 113 ++++++++++--------
client/src/translations/en_us/common.json | 2 +
client/src/translations/es/common.json | 2 +
client/src/translations/fr/common.json | 2 +
8 files changed, 209 insertions(+), 71 deletions(-)
create mode 100644 client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx
diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel
index ce8c30b78..4706a9625 100644
--- a/bodyshop_translations.babel
+++ b/bodyshop_translations.babel
@@ -23189,6 +23189,27 @@
+
+ partsstatus
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
pas
false
@@ -23341,6 +23362,27 @@
+
+ queued_for_parts
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
rate_ats
false
diff --git a/client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx b/client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx
new file mode 100644
index 000000000..deebf46b1
--- /dev/null
+++ b/client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx
@@ -0,0 +1,76 @@
+import React, { useMemo } from "react";
+import { Row, Col, Tag, Tooltip } from "antd";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { selectBodyshop } from "../../redux/user/user.selectors";
+const mapStateToProps = createStructuredSelector({
+ bodyshop: selectBodyshop,
+});
+const mapDispatchToProps = (dispatch) => ({
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
+});
+export default connect(mapStateToProps, mapDispatchToProps)(JobPartsQueueCount);
+
+export function JobPartsQueueCount({ bodyshop, parts }) {
+ console.log(parts);
+ const partsStatus = useMemo(() => {
+ return parts.reduce(
+ (acc, val) => {
+ acc.total = acc.total + val.count;
+ acc[val.status] = acc[val.status] + val.count;
+
+ return acc;
+ },
+ {
+ total: 0,
+ [bodyshop.md_order_statuses.default_bo]: 0,
+ [bodyshop.md_order_statuses.default_ordered]: 0,
+ [bodyshop.md_order_statuses.default_received]: 0,
+ [bodyshop.md_order_statuses.default_returned]: 0,
+ }
+ );
+ }, [bodyshop, parts]);
+
+ console.log(
+ "🚀 ~ file: job-parts-queue-count.component.jsx ~ line 8 ~ partsStatus",
+ partsStatus
+ );
+
+ return (
+
+
+
+ {partsStatus.total}
+
+
+
+
+
+ {partsStatus[bodyshop.md_order_statuses.default_ordered]}
+
+
+
+
+
+
+ {partsStatus[bodyshop.md_order_statuses.default_received]}
+
+
+
+
+
+
+ {partsStatus[bodyshop.md_order_statuses.default_returned]}
+
+
+
+
+
+
+ {partsStatus[bodyshop.md_order_statuses.default_bo]}
+
+
+
+
+ );
+}
diff --git a/client/src/components/job-remove-from-parst-queue/job-remove-from-parts-queue.component.jsx b/client/src/components/job-remove-from-parst-queue/job-remove-from-parts-queue.component.jsx
index 254f2edd7..a0c95fad8 100644
--- a/client/src/components/job-remove-from-parst-queue/job-remove-from-parts-queue.component.jsx
+++ b/client/src/components/job-remove-from-parst-queue/job-remove-from-parts-queue.component.jsx
@@ -1,24 +1,23 @@
-import { Button, notification } from "antd";
-import React, { useState } from "react";
import { useMutation } from "@apollo/client";
-import { UPDATE_JOB } from "../../graphql/jobs.queries";
+import { Checkbox, notification, Space, Spin } from "antd";
+import React, { useState } from "react";
import { useTranslation } from "react-i18next";
+import { UPDATE_JOB } from "../../graphql/jobs.queries";
-export default function JobRemoveFromPartsQueue({ jobId, refetch }) {
+export default function JobRemoveFromPartsQueue({ checked, jobId }) {
const [updateJob] = useMutation(UPDATE_JOB);
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
- const handleClick = async (e) => {
+ const handleChange = async (e) => {
setLoading(true);
const result = await updateJob({
- variables: { jobId: jobId, job: { queued_for_parts: false } },
+ variables: { jobId: jobId, job: { queued_for_parts: e.target.checked } },
});
if (!!!result.errors) {
notification["success"]({ message: t("jobs.successes.save") });
- if (refetch) refetch();
} else {
notification["error"]({
message: t("jobs.errors.saving", {
@@ -30,8 +29,9 @@ export default function JobRemoveFromPartsQueue({ jobId, refetch }) {
};
return (
-
+
+
+ {loading && }
+
);
}
diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js
index 7c288b576..5d4db071f 100644
--- a/client/src/graphql/jobs.queries.js
+++ b/client/src/graphql/jobs.queries.js
@@ -50,25 +50,13 @@ export const QUERY_PARTS_QUEUE = gql`
$limit: Int
$order: [jobs_order_by!]
) {
- jobs_aggregate(
- where: {
- _and: [
- { status: { _in: $statuses } }
- { queued_for_parts: { _eq: true } }
- ]
- }
- ) {
+ jobs_aggregate(where: { _and: [{ status: { _in: $statuses } }] }) {
aggregate {
count(distinct: true)
}
}
jobs(
- where: {
- _and: [
- { status: { _in: $statuses } }
- { queued_for_parts: { _eq: true } }
- ]
- }
+ where: { _and: [{ status: { _in: $statuses } }] }
offset: $offset
limit: $limit
order_by: $order
@@ -99,6 +87,12 @@ export const QUERY_PARTS_QUEUE = gql`
updated_at
vehicleid
ownerid
+ queued_for_parts
+ joblines_status {
+ count
+ part_type
+ status
+ }
}
}
`;
@@ -1050,6 +1044,7 @@ export const UPDATE_JOB = gql`
production_vars
lbr_adjustments
suspended
+ queued_for_parts
}
}
}
diff --git a/client/src/pages/parts-queue/parts-queue.page.component.jsx b/client/src/pages/parts-queue/parts-queue.page.component.jsx
index fcac8eb44..d5a11537a 100644
--- a/client/src/pages/parts-queue/parts-queue.page.component.jsx
+++ b/client/src/pages/parts-queue/parts-queue.page.component.jsx
@@ -1,23 +1,22 @@
import { SyncOutlined } from "@ant-design/icons";
import { useQuery } from "@apollo/client";
import { Button, Card, Input, Space, Table } from "antd";
+import _ from "lodash";
+import queryString from "query-string";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
-import { Link, useHistory } from "react-router-dom";
+import { Link, useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
+import JobPartsQueueCount from "../../components/job-parts-queue-count/job-parts-queue-count.component";
import JobRemoveFromPartsQueue from "../../components/job-remove-from-parst-queue/job-remove-from-parts-queue.component";
+import OwnerNameDisplay from "../../components/owner-name-display/owner-name-display.component";
import { QUERY_PARTS_QUEUE } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { onlyUnique } from "../../utils/arrayHelper";
-import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { TimeAgoFormatter } from "../../utils/DateFormatter";
-import { alphaSort } from "../../utils/sorters";
-import { useLocation } from "react-router-dom";
-import queryString from "query-string";
-import _ from "lodash";
-import OwnerNameDisplay from "../../components/owner-name-display/owner-name-display.component";
+import { alphaSort, dateSort } from "../../utils/sorters";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -25,20 +24,25 @@ const mapStateToProps = createStructuredSelector({
export function PartsQueuePageComponent({ bodyshop }) {
const searchParams = queryString.parse(useLocation().search);
- const { page, sortcolumn, sortorder, statusFilters } = searchParams;
+ const {
+ //page,
+ sortcolumn,
+ sortorder,
+ statusFilters,
+ } = searchParams;
const history = useHistory();
const { loading, error, data, refetch } = useQuery(QUERY_PARTS_QUEUE, {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
variables: {
- offset: page ? (page - 1) * 25 : 0,
- limit: 25,
+ // offset: page ? (page - 1) * 25 : 0,
+ // limit: 25,
statuses: (statusFilters && JSON.parse(statusFilters)) ||
bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"],
order: [
{
- [sortcolumn || "updated_at"]: sortorder
+ [sortcolumn || "ro_number"]: sortorder
? sortorder === "descend"
? "desc"
: "asc"
@@ -85,7 +89,7 @@ export function PartsQueuePageComponent({ bodyshop }) {
: [];
const handleTableChange = (pagination, filters, sorter) => {
- searchParams.page = pagination.current;
+ // searchParams.page = pagination.current;
searchParams.sortcolumn = sorter.columnKey;
searchParams.sortorder = sorter.order;
if (filters.status) {
@@ -114,10 +118,10 @@ export function PartsQueuePageComponent({ bodyshop }) {
},
{
title: t("jobs.fields.owner"),
- dataIndex: "owner",
- key: "owner",
- // sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
- // sortOrder: sortcolumn === "owner" && sortorder,
+ dataIndex: "ownr_ln",
+ key: "ownr_ln",
+ sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
+ sortOrder: sortcolumn === "ownr_ln" && sortorder,
render: (text, record) => {
return record.ownerid ? (
@@ -173,16 +177,16 @@ export function PartsQueuePageComponent({ bodyshop }) {
);
},
},
- {
- title: t("vehicles.fields.plate_no"),
- dataIndex: "plate_no",
- key: "plate_no",
- sorter: (a, b) => alphaSort(a.plate_no, b.plate_no),
- sortOrder: sortcolumn === "plate_no" && sortorder,
- render: (text, record) => {
- return record.plate_no ? record.plate_no : "";
- },
- },
+ // {
+ // title: t("vehicles.fields.plate_no"),
+ // dataIndex: "plate_no",
+ // key: "plate_no",
+ // sorter: (a, b) => alphaSort(a.plate_no, b.plate_no),
+ // sortOrder: sortcolumn === "plate_no" && sortorder,
+ // render: (text, record) => {
+ // return record.plate_no ? record.plate_no : "";
+ // },
+ // },
{
title: t("jobs.fields.clm_no"),
dataIndex: "clm_no",
@@ -198,34 +202,49 @@ export function PartsQueuePageComponent({ bodyshop }) {
);
},
},
- {
- title: t("jobs.fields.clm_total"),
- dataIndex: "clm_total",
- key: "clm_total",
- sorter: (a, b) => a.clm_total - b.clm_total,
- sortOrder: sortcolumn === "clm_total" && sortorder,
- render: (text, record) => {
- return record.clm_total ? (
- {record.clm_total}
- ) : (
- t("general.labels.unknown")
- );
- },
- },
+ // {
+ // title: t("jobs.fields.clm_total"),
+ // dataIndex: "clm_total",
+ // key: "clm_total",
+ // sorter: (a, b) => a.clm_total - b.clm_total,
+ // sortOrder: sortcolumn === "clm_total" && sortorder,
+ // render: (text, record) => {
+ // return record.clm_total ? (
+ // {record.clm_total}
+ // ) : (
+ // t("general.labels.unknown")
+ // );
+ // },
+ // },
{
title: t("jobs.fields.updated_at"),
dataIndex: "updated_at",
key: "updated_at",
+ sorter: (a, b) => dateSort(a.updated_at, b.updated_at),
+ sortOrder: sortcolumn === "updated_at" && sortorder,
render: (text, record) => (
{record.updated_at}
),
},
{
- title: t("general.labels.actions"),
- dataIndex: "actions",
- key: "actions",
+ title: t("jobs.fields.partsstatus"),
+ dataIndex: "partsstatus",
+ key: "partsstatus",
render: (text, record) => (
-
+
+ ),
+ },
+ {
+ title: t("jobs.fields.queued_for_parts"),
+ dataIndex: "queued_for_parts",
+ key: "queued_for_parts",
+ sorter: (a, b) => a.queued_for_parts - b.queued_for_parts,
+ sortOrder: sortcolumn === "queued_for_parts" && sortorder,
+ render: (text, record) => (
+
),
},
];
@@ -253,9 +272,9 @@ export function PartsQueuePageComponent({ bodyshop }) {
loading={loading}
pagination={{
position: "top",
- pageSize: 25,
- current: parseInt(page || 1),
- total: data && data.jobs_aggregate.aggregate.count,
+ pageSize: 50,
+ // current: parseInt(page || 1),
+ // total: data && data.jobs_aggregate.aggregate.count,
}}
columns={columns}
rowKey="id"
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index b258ec8a7..f398759a5 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -1387,6 +1387,7 @@
"prt_tax_rt": "Part Tax Rate",
"prt_type": "Part Type"
},
+ "partsstatus": "Parts Status",
"pas": "Sublet",
"pay_date": "Pay Date",
"phoneshort": "PH",
@@ -1396,6 +1397,7 @@
"production_vars": {
"note": "Production Note"
},
+ "queued_for_parts": "Queued for Parts",
"rate_ats": "ATS Rate",
"rate_la1": "LA1",
"rate_la2": "LA2",
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index 7edccfb60..5c93bb36e 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -1387,6 +1387,7 @@
"prt_tax_rt": "",
"prt_type": ""
},
+ "partsstatus": "",
"pas": "",
"pay_date": "Fecha de Pay",
"phoneshort": "PH",
@@ -1396,6 +1397,7 @@
"production_vars": {
"note": ""
},
+ "queued_for_parts": "",
"rate_ats": "",
"rate_la1": "Tarifa LA1",
"rate_la2": "Tarifa LA2",
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index f7e49304c..ebab12b16 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -1387,6 +1387,7 @@
"prt_tax_rt": "",
"prt_type": ""
},
+ "partsstatus": "",
"pas": "",
"pay_date": "Date d'Pay",
"phoneshort": "PH",
@@ -1396,6 +1397,7 @@
"production_vars": {
"note": ""
},
+ "queued_for_parts": "",
"rate_ats": "",
"rate_la1": "Taux LA1",
"rate_la2": "Taux LA2",