Added sublets tracking to production board. BOD-415

This commit is contained in:
Patrick Fic
2020-09-29 10:15:06 -07:00
parent 6b6d052e74
commit fef95be5a3
26 changed files with 688 additions and 131 deletions

View File

@@ -6,7 +6,6 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter";

View File

@@ -7,6 +7,7 @@ import { Link } from "react-router-dom";
import "./production-board-card.styles.scss";
import ProductionRemoveButton from "../production-remove-button/production-remove-button.component";
import { useTranslation } from "react-i18next";
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
export default function ProductionBoardCard(card) {
const { t } = useTranslation();
@@ -77,8 +78,9 @@ export default function ProductionBoardCard(card) {
</Row>
<div className="imex-flex-row imex-flex-row__flex-space-around">
<ProductionAlert record={card} key="alert" />
<ProductionSubletsManageComponent subletJobLines={card.subletLines} />
<Link to={`/manage/jobs/${card.id}`}>
<EyeFilled key="setting" />
<EyeFilled />
</Link>
</div>
</Card>

View File

@@ -5,12 +5,13 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter";
import PhoneFormatter from "../../utils/PhoneFormatter";
import { alphaSort } from "../../utils/sorters";
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
import ProductionListColumnAlert from "./production-list-columns.alert.component";
import ProductionListColumnBodyPriority from "./production-list-columns.bodypriority.component";
import ProductionListColumnPaintPriority from "./production-list-columns.paintpriority.component";
import ProductionListColumnStatus from "./production-list-columns.status.component";
import ProductionListColumnNote from "./production-list-columns.productionnote.component";
import ProductionListColumnStatus from "./production-list-columns.status.component";
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
export default [
{
@@ -19,7 +20,9 @@ export default [
key: "viewdetail",
ellipsis: true,
render: (text, record) => (
<Link to={{search:`?selected=${record.id}`}} >{i18n.t("general.labels.view")}</Link>
<Link to={{ search: `?selected=${record.id}` }}>
{i18n.t("general.labels.view")}
</Link>
),
},
{
@@ -179,16 +182,8 @@ export default [
title: i18n.t("production.labels.cycletime"),
dataIndex: "ct",
key: "ct",
render: (text, record) => {
let ct = 0;
if (!!record.actual_in) {
const totalHrs = record.larhrs + record.labhrs;
const Difference_In_Time = new Date() - new Date(record.actual_in);
const Difference_In_Days = Difference_In_Time / (1000 * 3600 * 24);
ct = (totalHrs / Difference_In_Days).toFixed(2);
}
return <span>{ct || 0}</span>;
return <ProductionlistColumnTouchTime job={record} />;
},
},
{
@@ -215,4 +210,12 @@ export default [
<ProductionListColumnPaintPriority record={record} />
),
},
{
title: i18n.t("production.labels.sublets"),
dataIndex: "sublets",
key: "sublets",
render: (text, record) => (
<ProductionSubletsManageComponent subletJobLines={record.subletLines} />
),
},
];

View File

@@ -0,0 +1,22 @@
import moment from "moment";
import React, { useMemo } from "react";
export default function ProductionlistColumnTouchTime({ job }) {
let ct = useMemo(() => {
if (!!job.actual_in) {
const totalHrs =
(job.larhrs.aggregate.sum.mod_lb_hrs || 0) +
(job.labhrs.aggregate.sum.mod_lb_hrs || 0);
const Difference_In_Days = moment().diff(
moment(job.actual_in),
"days",
true
);
return (totalHrs / Difference_In_Days).toFixed(2);
}
return 0;
}, [job]);
return <span>{ct}</span>;
}

View File

@@ -1,13 +1,12 @@
import React from "react";
import { Descriptions, Drawer } from "antd";
import queryString from "query-string";
import React from "react";
import { useTranslation } from "react-i18next";
import { useHistory, useLocation } from "react-router-dom";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter";
import PartsStatusPie from "../parts-status-pie/parts-status-pie.component";
import Barcode from "react-barcode";
import ProductionRemoveButton from "../production-remove-button/production-remove-button.component";
import queryString from "query-string";
import { useHistory, useLocation } from "react-router-dom";
export default function ProductionListDetail({ jobs }) {
const search = queryString.parse(useLocation().search);
@@ -31,13 +30,6 @@ export default function ProductionListDetail({ jobs }) {
visible={!!selected}
>
<div>
<Barcode
value={theJob.id || ""}
background="transparent"
displayValue={false}
width={1}
height={15}
/>
<Descriptions bordered size="small" column={1}>
<Descriptions.Item label={t("jobs.fields.ro_number")}>
{theJob.ro_number || ""}

View File

@@ -0,0 +1,97 @@
import { CheckCircleFilled, EyeInvisibleFilled } from "@ant-design/icons";
import { Button, List, notification, Popover } from "antd";
import React, { useMemo, useState } from "react";
import { useMutation } from "react-apollo";
import { useTranslation } from "react-i18next";
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
export default function ProductionSubletsManageComponent({ subletJobLines }) {
const { t } = useTranslation();
const [updateJobLine] = useMutation(UPDATE_JOB_LINE);
const [loading, setLoading] = useState(false);
const subletCount = useMemo(() => {
return {
total: subletJobLines.filter((s) => !s.sublet_ignored).length,
outstanding: subletJobLines.filter(
(s) => !s.sublet_ignored && !s.sublet_completed
).length,
};
}, [subletJobLines]);
const handleSubletMark = async (sublet, action) => {
setLoading(true);
const result = await updateJobLine({
variables: {
lineId: sublet.id,
line: {
sublet_completed:
action === "complete" ? !sublet.sublet_completed : false,
sublet_ignored: action === "ignore" ? !sublet.sublet_ignored : false,
},
},
});
if (!!result.errors) {
notification["error"]({
message: t("joblines.errors.updating", {
message: JSON.stringify(result.errors),
}),
});
} else {
notification["success"]({
message: t("joblines.successes.updated"),
});
}
setLoading(false);
};
const popContent = (
<div style={{ minWidth: "20rem" }}>
<List
size="small"
onClick={(e) => e.stopPropagation()}
dataSource={subletJobLines}
renderItem={(s) => (
<List.Item
actions={[
<Button
key="complete"
loading={loading}
onClick={() => handleSubletMark(s, "complete")}
type={s.sublet_completed ? "primary" : "ghost"}
>
<CheckCircleFilled
color={s.sublet_completed ? "green" : null}
/>
</Button>,
<Button
key="sublet"
loading={loading}
onClick={() => handleSubletMark(s, "ignore")}
type={s.sublet_ignored ? "primary" : "ghost"}
>
<EyeInvisibleFilled
color={s.sublet_ignored ? "tomato" : null}
/>
</Button>,
]}
>
<List.Item.Meta title={s.line_desc} />
</List.Item>
)}
/>
</div>
);
return (
<Popover
trigger={["click"]}
content={popContent}
style={{ cursor: "pointer" }}
placement="bottom"
title={t("production.labels.sublets")}
>
<span>{`${subletCount.outstanding} / ${subletCount.total} rem.`}</span>
</Popover>
);
}

View File

@@ -173,6 +173,17 @@ export const SUBSCRIPTION_JOBS_IN_PRODUCTION = gql`
}
}
}
subletLines: joblines(
where: {
_and: { part_type: { _in: ["PAS", "PASL"] }, removed: { _eq: false } }
}
order_by: { line_no: asc }
) {
id
line_desc
sublet_ignored
sublet_completed
}
}
}
`;

View File

@@ -1345,7 +1345,8 @@
"jobdetail": "Job Details",
"note": "Production Note",
"paintpriority": "P/P",
"refinishhours": "R"
"refinishhours": "R",
"sublets": "Sublets"
},
"successes": {
"removed": "Job removed from production."

View File

@@ -1345,7 +1345,8 @@
"jobdetail": "",
"note": "",
"paintpriority": "",
"refinishhours": ""
"refinishhours": "",
"sublets": ""
},
"successes": {
"removed": ""

View File

@@ -1345,7 +1345,8 @@
"jobdetail": "",
"note": "",
"paintpriority": "",
"refinishhours": ""
"refinishhours": "",
"sublets": ""
},
"successes": {
"removed": ""