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",