|
|
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
|
|
PauseCircleOutlined
|
|
|
|
|
} from "@ant-design/icons";
|
|
|
|
|
import { Card, Col, Row, Space, Tooltip } from "antd";
|
|
|
|
|
import React from "react";
|
|
|
|
|
import React, { useMemo } from "react";
|
|
|
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
|
import { Link } from "react-router-dom";
|
|
|
|
|
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
|
|
|
|
@@ -18,60 +18,78 @@ import dayjs from "../../utils/day";
|
|
|
|
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
|
|
|
|
import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the color of the card based on the total hours
|
|
|
|
|
* @param ssbuckets
|
|
|
|
|
* @param totalHrs
|
|
|
|
|
* @returns {{r: number, b: number, g: number}}
|
|
|
|
|
*/
|
|
|
|
|
const cardColor = (ssbuckets, totalHrs) => {
|
|
|
|
|
const bucket = ssbuckets.filter((bucket) => bucket.gte <= totalHrs && (!!bucket.lt ? bucket.lt > totalHrs : true))[0];
|
|
|
|
|
const bucket = ssbuckets.find((bucket) => bucket.gte <= totalHrs && (!bucket.lt || bucket.lt > totalHrs));
|
|
|
|
|
|
|
|
|
|
let color = { r: 255, g: 255, b: 255 };
|
|
|
|
|
|
|
|
|
|
if (bucket && bucket.color) {
|
|
|
|
|
color = bucket.color;
|
|
|
|
|
|
|
|
|
|
if (bucket.color.rgb) {
|
|
|
|
|
color = bucket.color.rgb;
|
|
|
|
|
}
|
|
|
|
|
color = bucket.color.rgb || bucket.color;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return color;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function getContrastYIQ(bgColor) {
|
|
|
|
|
const yiq = (bgColor.r * 299 + bgColor.g * 587 + bgColor.b * 114) / 1000;
|
|
|
|
|
|
|
|
|
|
return yiq >= 128 ? "black" : "white";
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Get the contrast color based on the background color
|
|
|
|
|
* @param bgColor
|
|
|
|
|
* @returns {string}
|
|
|
|
|
*/
|
|
|
|
|
const getContrastYIQ = (bgColor) =>
|
|
|
|
|
(bgColor.r * 299 + bgColor.g * 587 + bgColor.b * 114) / 1000 >= 128 ? "black" : "white";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Production Board Card component
|
|
|
|
|
* @param technician
|
|
|
|
|
* @param card
|
|
|
|
|
* @param bodyshop
|
|
|
|
|
* @param cardSettings
|
|
|
|
|
* @returns {Element}
|
|
|
|
|
* @constructor
|
|
|
|
|
*/
|
|
|
|
|
export default function ProductionBoardCard({ technician, card, bodyshop, cardSettings }) {
|
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
|
|
|
|
|
let employee_body, employee_prep, employee_refinish, employee_csr;
|
|
|
|
|
|
|
|
|
|
if (card && card.metadata && card.metadata.employee_body) {
|
|
|
|
|
employee_body = bodyshop.employees.find((e) => e.id === card.metadata.employee_body);
|
|
|
|
|
// Destructure metadata
|
|
|
|
|
const { metadata } = card;
|
|
|
|
|
|
|
|
|
|
if (metadata?.employee_body) {
|
|
|
|
|
employee_body = bodyshop.employees.find((e) => e.id === metadata.employee_body);
|
|
|
|
|
}
|
|
|
|
|
if (card && card.metadata && card.metadata.employee_prep) {
|
|
|
|
|
employee_prep = bodyshop.employees.find((e) => e.id === card.metadata.employee_prep);
|
|
|
|
|
if (metadata?.employee_prep) {
|
|
|
|
|
employee_prep = bodyshop.employees.find((e) => e.id === metadata.employee_prep);
|
|
|
|
|
}
|
|
|
|
|
if (card && card.metadata && card.metadata.employee_refinish) {
|
|
|
|
|
employee_refinish = bodyshop.employees.find((e) => e.id === card.metadata.employee_refinish);
|
|
|
|
|
if (metadata?.employee_refinish) {
|
|
|
|
|
employee_refinish = bodyshop.employees.find((e) => e.id === metadata.employee_refinish);
|
|
|
|
|
}
|
|
|
|
|
if (card && card.metadata && card.metadata.employee_csr) {
|
|
|
|
|
employee_csr = bodyshop.employees.find((e) => e.id === card.metadata.employee_csr);
|
|
|
|
|
if (metadata?.employee_csr) {
|
|
|
|
|
employee_csr = bodyshop.employees.find((e) => e.id === metadata.employee_csr);
|
|
|
|
|
}
|
|
|
|
|
// if (card && card.metadata && card.metadata.employee_csr) {
|
|
|
|
|
// employee_csr = bodyshop.employees.find((e) => e.id === card.metadata.employee_csr);
|
|
|
|
|
// if (metadata.?employee_csr) {
|
|
|
|
|
// employee_csr = bodyshop.employees.find((e) => e.id === metadata.employee_csr);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
const pastDueAlert =
|
|
|
|
|
!!card?.metadata?.scheduled_completion &&
|
|
|
|
|
((dayjs().isSameOrAfter(dayjs(card.metadata.scheduled_completion), "day") && "production-completion-past") ||
|
|
|
|
|
(dayjs().add(1, "day").isSame(dayjs(card.metadata.scheduled_completion), "day") && "production-completion-soon"));
|
|
|
|
|
!!metadata?.scheduled_completion &&
|
|
|
|
|
((dayjs().isSameOrAfter(dayjs(metadata.scheduled_completion), "day") && "production-completion-past") ||
|
|
|
|
|
(dayjs().add(1, "day").isSame(dayjs(metadata.scheduled_completion), "day") && "production-completion-soon"));
|
|
|
|
|
|
|
|
|
|
const totalHrs =
|
|
|
|
|
card && card?.metadata?.labhrs && card?.metadata?.larhrs
|
|
|
|
|
? card.metadata.labhrs.aggregate.sum.mod_lb_hrs + card.metadata.larhrs.aggregate.sum.mod_lb_hrs
|
|
|
|
|
const totalHrs = useMemo(() => {
|
|
|
|
|
return metadata?.labhrs && metadata?.larhrs
|
|
|
|
|
? metadata.labhrs.aggregate.sum.mod_lb_hrs + metadata.larhrs.aggregate.sum.mod_lb_hrs
|
|
|
|
|
: 0;
|
|
|
|
|
}, [metadata]);
|
|
|
|
|
|
|
|
|
|
const bgColor = cardColor(bodyshop.ssbuckets, totalHrs);
|
|
|
|
|
const bgColor = useMemo(() => cardColor(bodyshop.ssbuckets, totalHrs), [bodyshop.ssbuckets, totalHrs]);
|
|
|
|
|
const contrastYIQ = useMemo(() => getContrastYIQ(bgColor), [bgColor]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Card
|
|
|
|
|
@@ -80,22 +98,22 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe
|
|
|
|
|
style={{
|
|
|
|
|
backgroundColor:
|
|
|
|
|
cardSettings && cardSettings.cardcolor && `rgba(${bgColor.r},${bgColor.g},${bgColor.b},${bgColor.a})`,
|
|
|
|
|
color: cardSettings && cardSettings.cardcolor && getContrastYIQ(bgColor),
|
|
|
|
|
color: cardSettings && cardSettings.cardcolor && contrastYIQ,
|
|
|
|
|
maxWidth: "250px",
|
|
|
|
|
margin: "5px"
|
|
|
|
|
}}
|
|
|
|
|
title={
|
|
|
|
|
<Space>
|
|
|
|
|
<ProductionAlert record={card} key="alert" />
|
|
|
|
|
{card.metadata.suspended && <PauseCircleOutlined style={{ color: "orangered" }} />}
|
|
|
|
|
{card.metadata.iouparent && (
|
|
|
|
|
{metadata?.suspended && <PauseCircleOutlined style={{ color: "orangered" }} />}
|
|
|
|
|
{metadata?.iouparent && (
|
|
|
|
|
<Tooltip title={t("jobs.labels.iou")}>
|
|
|
|
|
<BranchesOutlined style={{ color: "orangered" }} />
|
|
|
|
|
</Tooltip>
|
|
|
|
|
)}
|
|
|
|
|
<span style={{ fontWeight: "bolder" }}>
|
|
|
|
|
<Link to={technician ? `/tech/joblookup?selected=${card.id}` : `/manage/jobs/${card.id}`}>
|
|
|
|
|
{card.metadata.ro_number || t("general.labels.na")}
|
|
|
|
|
{metadata?.ro_number || t("general.labels.na")}
|
|
|
|
|
</Link>
|
|
|
|
|
</span>
|
|
|
|
|
</Space>
|
|
|
|
|
@@ -110,7 +128,7 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe
|
|
|
|
|
{cardSettings && cardSettings.ownr_nm && (
|
|
|
|
|
<Col span={24}>
|
|
|
|
|
{cardSettings && cardSettings.compact ? (
|
|
|
|
|
<div className="ellipses">{`${card.metadata.ownr_ln || ""} ${card.metadata.ownr_co_nm || ""}`}</div>
|
|
|
|
|
<div className="ellipses">{`${metadata.ownr_ln || ""} ${metadata.ownr_co_nm || ""}`}</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="ellipses">
|
|
|
|
|
<OwnerNameDisplay ownerObject={card} />
|
|
|
|
|
@@ -119,18 +137,18 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe
|
|
|
|
|
</Col>
|
|
|
|
|
)}
|
|
|
|
|
<Col span={24}>
|
|
|
|
|
<div className="ellipses">{`${card.metadata.v_model_yr || ""} ${
|
|
|
|
|
card.metadata.v_make_desc || ""
|
|
|
|
|
} ${card.metadata.v_model_desc || ""}`}</div>
|
|
|
|
|
<div className="ellipses">{`${metadata.v_model_yr || ""} ${
|
|
|
|
|
metadata.v_make_desc || ""
|
|
|
|
|
} ${metadata.v_model_desc || ""}`}</div>
|
|
|
|
|
</Col>
|
|
|
|
|
{cardSettings && cardSettings.ins_co_nm && card.metadata.ins_co_nm && (
|
|
|
|
|
{cardSettings && cardSettings.ins_co_nm && metadata.ins_co_nm && (
|
|
|
|
|
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
|
|
|
|
|
<div className="ellipses">{card.metadata.ins_co_nm || ""}</div>
|
|
|
|
|
<div className="ellipses">{metadata.ins_co_nm || ""}</div>
|
|
|
|
|
</Col>
|
|
|
|
|
)}
|
|
|
|
|
{cardSettings && cardSettings.clm_no && card.metadata.clm_no && (
|
|
|
|
|
{cardSettings && cardSettings.clm_no && metadata.clm_no && (
|
|
|
|
|
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
|
|
|
|
|
<div className="ellipses">{card.metadata.clm_no || ""}</div>
|
|
|
|
|
<div className="ellipses">{metadata.clm_no || ""}</div>
|
|
|
|
|
</Col>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
@@ -139,7 +157,7 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe
|
|
|
|
|
<Row>
|
|
|
|
|
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`B: ${
|
|
|
|
|
employee_body ? `${employee_body.first_name.substr(0, 3)} ${employee_body.last_name.charAt(0)}` : ""
|
|
|
|
|
} ${card.metadata.labhrs.aggregate.sum.mod_lb_hrs || "?"}h`}</Col>
|
|
|
|
|
} ${metadata.labhrs.aggregate.sum.mod_lb_hrs || "?"}h`}</Col>
|
|
|
|
|
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`P: ${
|
|
|
|
|
employee_prep ? `${employee_prep.first_name.substr(0, 3)} ${employee_prep.last_name.charAt(0)}` : ""
|
|
|
|
|
}`}</Col>
|
|
|
|
|
@@ -147,7 +165,7 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe
|
|
|
|
|
employee_refinish
|
|
|
|
|
? `${employee_refinish.first_name.substr(0, 3)} ${employee_refinish.last_name.charAt(0)}`
|
|
|
|
|
: ""
|
|
|
|
|
} ${card.metadata.larhrs.aggregate.sum.mod_lb_hrs || "?"}h`}</Col>
|
|
|
|
|
} ${metadata.larhrs.aggregate.sum.mod_lb_hrs || "?"}h`}</Col>
|
|
|
|
|
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`C: ${
|
|
|
|
|
employee_csr ? `${employee_csr.first_name} ${employee_csr.last_name}` : ""
|
|
|
|
|
}`}</Col>
|
|
|
|
|
@@ -158,48 +176,56 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe
|
|
|
|
|
<Col span={24}>
|
|
|
|
|
<Row>
|
|
|
|
|
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`B: ${
|
|
|
|
|
card.metadata.labhrs.aggregate.sum.mod_lb_hrs || "?"
|
|
|
|
|
metadata.labhrs.aggregate.sum.mod_lb_hrs || "?"
|
|
|
|
|
} hrs`}</Col>
|
|
|
|
|
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`R: ${
|
|
|
|
|
card.metadata.larhrs.aggregate.sum.mod_lb_hrs || "?"
|
|
|
|
|
metadata.larhrs.aggregate.sum.mod_lb_hrs || "?"
|
|
|
|
|
} hrs`}</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
</Col>
|
|
|
|
|
)} */}
|
|
|
|
|
{cardSettings && cardSettings.actual_in && card.metadata.actual_in && (
|
|
|
|
|
{cardSettings && cardSettings.actual_in && metadata.actual_in && (
|
|
|
|
|
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
|
|
|
|
|
<Space>
|
|
|
|
|
<DownloadOutlined />
|
|
|
|
|
<DateTimeFormatter format="MM/DD">{card.metadata.actual_in}</DateTimeFormatter>
|
|
|
|
|
<DateTimeFormatter format="MM/DD">{metadata.actual_in}</DateTimeFormatter>
|
|
|
|
|
</Space>
|
|
|
|
|
</Col>
|
|
|
|
|
)}
|
|
|
|
|
{cardSettings && cardSettings.scheduled_completion && card.metadata.scheduled_completion && (
|
|
|
|
|
{cardSettings && cardSettings.scheduled_completion && metadata.scheduled_completion && (
|
|
|
|
|
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
|
|
|
|
|
<Space className={pastDueAlert}>
|
|
|
|
|
<CalendarOutlined />
|
|
|
|
|
<DateTimeFormatter format="MM/DD">{card.metadata.scheduled_completion}</DateTimeFormatter>
|
|
|
|
|
<DateTimeFormatter format="MM/DD">{metadata.scheduled_completion}</DateTimeFormatter>
|
|
|
|
|
</Space>
|
|
|
|
|
</Col>
|
|
|
|
|
)}
|
|
|
|
|
{cardSettings && cardSettings.ats && card.metadata.alt_transport && (
|
|
|
|
|
{cardSettings && cardSettings.ats && metadata.alt_transport && (
|
|
|
|
|
<Col span={12}>
|
|
|
|
|
<div>{card.metadata.alt_transport || ""}</div>
|
|
|
|
|
<div>{metadata.alt_transport || ""}</div>
|
|
|
|
|
</Col>
|
|
|
|
|
)}
|
|
|
|
|
{cardSettings && cardSettings.sublets && (
|
|
|
|
|
<Col span={12}>
|
|
|
|
|
<ProductionSubletsManageComponent subletJobLines={card.metadata.subletLines} />
|
|
|
|
|
<ProductionSubletsManageComponent subletJobLines={metadata.subletLines} />
|
|
|
|
|
</Col>
|
|
|
|
|
)}
|
|
|
|
|
{cardSettings && cardSettings.production_note && (
|
|
|
|
|
<Col span={24}>
|
|
|
|
|
{cardSettings && cardSettings.production_note && <ProductionListColumnProductionNote record={card} />}
|
|
|
|
|
{cardSettings && cardSettings.production_note && (
|
|
|
|
|
<ProductionListColumnProductionNote
|
|
|
|
|
record={{
|
|
|
|
|
production_vars: card?.metadata.production_vars,
|
|
|
|
|
id: card?.id,
|
|
|
|
|
refetch: card?.refetch
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Col>
|
|
|
|
|
)}
|
|
|
|
|
{cardSettings && cardSettings.partsstatus && (
|
|
|
|
|
<Col span={24}>
|
|
|
|
|
<JobPartsQueueCount parts={card.metadata.joblines_status} />
|
|
|
|
|
<JobPartsQueueCount parts={metadata.joblines_status} />
|
|
|
|
|
</Col>
|
|
|
|
|
)}
|
|
|
|
|
</Row>
|
|
|
|
|
|