256 lines
10 KiB
JavaScript
256 lines
10 KiB
JavaScript
import {
|
|
BranchesOutlined,
|
|
CalendarOutlined,
|
|
DownloadOutlined,
|
|
EyeFilled,
|
|
PauseCircleOutlined
|
|
} from "@ant-design/icons";
|
|
import { Card, Col, Row, Space, Tooltip } from "antd";
|
|
import React, { useMemo } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Link } from "react-router-dom";
|
|
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
|
|
|
import ProductionAlert from "../production-list-columns/production-list-columns.alert.component";
|
|
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
|
|
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
|
|
|
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";
|
|
|
|
const cardColor = (ssbuckets, totalHrs) => {
|
|
const bucket = ssbuckets.find((bucket) => bucket.gte <= totalHrs && (!bucket.lt || bucket.lt > totalHrs));
|
|
return bucket && bucket.color ? bucket.color.rgb || bucket.color : { r: 255, g: 255, b: 255 };
|
|
};
|
|
|
|
const getContrastYIQ = (bgColor) =>
|
|
(bgColor.r * 299 + bgColor.g * 587 + bgColor.b * 114) / 1000 >= 128 ? "black" : "white";
|
|
|
|
const findEmployeeById = (employees, id) => employees.find((e) => e.id === id);
|
|
|
|
const EllipsesToolTip = React.memo(({ title, children }) => (
|
|
<Tooltip title={title}>
|
|
<div className="ellipses">{children}</div>
|
|
</Tooltip>
|
|
));
|
|
|
|
export default function ProductionBoardCard({ technician, card, bodyshop, cardSettings, clone }) {
|
|
const { t } = useTranslation();
|
|
const { metadata } = card;
|
|
|
|
const employees = useMemo(() => bodyshop.employees, [bodyshop.employees]);
|
|
|
|
const { employee_body, employee_prep, employee_refinish, employee_csr } = useMemo(() => {
|
|
return {
|
|
employee_body: metadata?.employee_body && findEmployeeById(employees, metadata.employee_body),
|
|
employee_prep: metadata?.employee_prep && findEmployeeById(employees, metadata.employee_prep),
|
|
employee_refinish: metadata?.employee_refinish && findEmployeeById(employees, metadata.employee_refinish),
|
|
employee_csr: metadata?.employee_csr && findEmployeeById(employees, metadata.employee_csr)
|
|
};
|
|
}, [metadata, employees]);
|
|
|
|
const pastDueAlert = useMemo(() => {
|
|
if (!metadata?.scheduled_completion) return null;
|
|
const completionDate = dayjs(metadata.scheduled_completion);
|
|
if (dayjs().isSameOrAfter(completionDate, "day")) return "production-completion-past";
|
|
if (dayjs().add(1, "day").isSame(completionDate, "day")) return "production-completion-soon";
|
|
return null;
|
|
}, [metadata?.scheduled_completion]);
|
|
|
|
const totalHrs = useMemo(() => {
|
|
return metadata?.labhrs && metadata?.larhrs
|
|
? metadata.labhrs.aggregate.sum.mod_lb_hrs + metadata.larhrs.aggregate.sum.mod_lb_hrs
|
|
: 0;
|
|
}, [metadata?.labhrs, metadata?.larhrs]);
|
|
|
|
const bgColor = useMemo(() => cardColor(bodyshop.ssbuckets, totalHrs), [bodyshop.ssbuckets, totalHrs]);
|
|
const contrastYIQ = useMemo(() => getContrastYIQ(bgColor), [bgColor]);
|
|
|
|
const isBodyEmpty = useMemo(() => {
|
|
return !(
|
|
cardSettings?.ownr_nm ||
|
|
cardSettings?.model_info ||
|
|
(cardSettings?.ins_co_nm && metadata.ins_co_nm) ||
|
|
(cardSettings?.clm_no && metadata.clm_no) ||
|
|
cardSettings?.employeeassignments ||
|
|
(cardSettings?.actual_in && metadata.actual_in) ||
|
|
(cardSettings?.scheduled_completion && metadata.scheduled_completion) ||
|
|
(cardSettings?.ats && metadata.alt_transport) ||
|
|
cardSettings?.sublets ||
|
|
cardSettings?.production_note ||
|
|
cardSettings?.partsstatus
|
|
);
|
|
}, [cardSettings, metadata]);
|
|
|
|
const headerContent = (
|
|
<div className="header-content-container">
|
|
<div className="inner-container">
|
|
<ProductionAlert
|
|
record={{
|
|
id: card.id,
|
|
production_vars: card?.metadata.production_vars,
|
|
refetch: card?.refetch
|
|
}}
|
|
key="alert"
|
|
/>
|
|
{metadata?.suspended && <PauseCircleOutlined className="circle-outline" key="suspended" />}
|
|
{metadata?.iouparent && (
|
|
<EllipsesToolTip title={t("jobs.labels.iou")} key="iouparent" className="iouparent">
|
|
<BranchesOutlined className="branches-outlined" />
|
|
</EllipsesToolTip>
|
|
)}
|
|
</div>
|
|
<span className="tech-container">
|
|
<Link to={technician ? `/tech/joblookup?selected=${card.id}` : `/manage/jobs/${card.id}`}>
|
|
{metadata?.ro_number || t("general.labels.na")}
|
|
</Link>
|
|
</span>
|
|
{isBodyEmpty && (
|
|
<div className="body-empty-container">
|
|
<Link to={{ search: `?selected=${card.id}` }}>
|
|
<EyeFilled />
|
|
</Link>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
|
|
const bodyContent = (
|
|
<Row>
|
|
{cardSettings?.ownr_nm && (
|
|
<Col span={24}>
|
|
<EllipsesToolTip title={<OwnerNameDisplay ownerObject={metadata} />}>
|
|
{cardSettings.compact ? (
|
|
`${metadata.ownr_ln || ""} ${metadata.ownr_co_nm || ""}`
|
|
) : (
|
|
<OwnerNameDisplay ownerObject={metadata} />
|
|
)}
|
|
</EllipsesToolTip>
|
|
</Col>
|
|
)}
|
|
{cardSettings?.model_info && (
|
|
<Col span={24}>
|
|
<EllipsesToolTip
|
|
title={`${metadata.v_model_yr || ""} ${metadata.v_make_desc || ""} ${metadata.v_model_desc || ""}`}
|
|
>
|
|
{`${metadata.v_model_yr || ""} ${metadata.v_make_desc || ""} ${metadata.v_model_desc || ""}`}
|
|
</EllipsesToolTip>
|
|
</Col>
|
|
)}
|
|
{cardSettings?.ins_co_nm && metadata.ins_co_nm && (
|
|
<Col span={cardSettings.compact ? 24 : 12}>
|
|
<EllipsesToolTip title={metadata.ins_co_nm || ""}>{metadata.ins_co_nm || ""}</EllipsesToolTip>
|
|
</Col>
|
|
)}
|
|
{cardSettings?.clm_no && metadata.clm_no && (
|
|
<Col span={cardSettings.compact ? 24 : 12}>
|
|
<EllipsesToolTip title={metadata.clm_no || ""}>{metadata.clm_no || ""}</EllipsesToolTip>
|
|
</Col>
|
|
)}
|
|
{cardSettings?.employeeassignments && (
|
|
<Col span={24}>
|
|
<Row>
|
|
<Col span={cardSettings.compact ? 24 : 12}>
|
|
<EllipsesToolTip
|
|
title={`B: ${employee_body ? `${employee_body.first_name.substring(0, 3)} ${employee_body.last_name.charAt(0)}` : ""} ${metadata.labhrs.aggregate.sum.mod_lb_hrs || "?"}h`}
|
|
>
|
|
{`B: ${employee_body ? `${employee_body.first_name.substring(0, 3)} ${employee_body.last_name.charAt(0)}` : ""} ${metadata.labhrs.aggregate.sum.mod_lb_hrs || "?"}h`}
|
|
</EllipsesToolTip>
|
|
</Col>
|
|
<Col span={cardSettings.compact ? 24 : 12}>
|
|
<EllipsesToolTip
|
|
title={`P: ${employee_prep ? `${employee_prep.first_name.substring(0, 3)} ${employee_prep.last_name.charAt(0)}` : ""}`}
|
|
>
|
|
{`P: ${employee_prep ? `${employee_prep.first_name.substring(0, 3)} ${employee_prep.last_name.charAt(0)}` : ""}`}
|
|
</EllipsesToolTip>
|
|
</Col>
|
|
<Col span={cardSettings.compact ? 24 : 12}>
|
|
<EllipsesToolTip
|
|
title={`R: ${employee_refinish ? `${employee_refinish.first_name.substring(0, 3)} ${employee_refinish.last_name.charAt(0)}` : ""} ${metadata.larhrs.aggregate.sum.mod_lb_hrs || "?"}h`}
|
|
>
|
|
{`R: ${employee_refinish ? `${employee_refinish.first_name.substring(0, 3)} ${employee_refinish.last_name.charAt(0)}` : ""} ${metadata.larhrs.aggregate.sum.mod_lb_hrs || "?"}h`}
|
|
</EllipsesToolTip>
|
|
</Col>
|
|
<Col span={cardSettings.compact ? 24 : 12}>
|
|
<EllipsesToolTip
|
|
title={`C: ${employee_csr ? `${employee_csr.first_name} ${employee_csr.last_name}` : ""}`}
|
|
>
|
|
{`C: ${employee_csr ? `${employee_csr.first_name} ${employee_csr.last_name}` : ""}`}
|
|
</EllipsesToolTip>
|
|
</Col>
|
|
</Row>
|
|
</Col>
|
|
)}
|
|
{cardSettings?.actual_in && metadata.actual_in && (
|
|
<Col span={cardSettings.compact ? 24 : 12}>
|
|
<EllipsesToolTip title={metadata.actual_in}>
|
|
<Space>
|
|
<DownloadOutlined />
|
|
<DateTimeFormatter format="MM/DD">{metadata.actual_in}</DateTimeFormatter>
|
|
</Space>
|
|
</EllipsesToolTip>
|
|
</Col>
|
|
)}
|
|
{cardSettings?.scheduled_completion && metadata.scheduled_completion && (
|
|
<Col span={cardSettings.compact ? 24 : 12}>
|
|
<EllipsesToolTip title={metadata.scheduled_completion}>
|
|
<Space className={pastDueAlert}>
|
|
<CalendarOutlined />
|
|
<DateTimeFormatter format="MM/DD">{metadata.scheduled_completion}</DateTimeFormatter>
|
|
</Space>
|
|
</EllipsesToolTip>
|
|
</Col>
|
|
)}
|
|
{cardSettings?.ats && metadata.alt_transport && (
|
|
<Col span={12}>
|
|
<EllipsesToolTip title={metadata.alt_transport}>{metadata.alt_transport || ""}</EllipsesToolTip>
|
|
</Col>
|
|
)}
|
|
{cardSettings?.sublets && (
|
|
<Col span={12}>
|
|
<ProductionSubletsManageComponent subletJobLines={metadata.subletLines} />
|
|
</Col>
|
|
)}
|
|
{cardSettings?.production_note && (
|
|
<Col span={24}>
|
|
<ProductionListColumnProductionNote
|
|
record={{
|
|
production_vars: metadata?.production_vars,
|
|
id: card?.id,
|
|
refetch: card?.refetch
|
|
}}
|
|
/>
|
|
</Col>
|
|
)}
|
|
{cardSettings?.partsstatus && (
|
|
<Col span={24}>
|
|
<JobPartsQueueCount parts={metadata.joblines_status} />
|
|
</Col>
|
|
)}
|
|
</Row>
|
|
);
|
|
|
|
return (
|
|
<Card
|
|
className="react-trello-card"
|
|
size="small"
|
|
style={{
|
|
backgroundColor: cardSettings?.cardcolor && `rgba(${bgColor.r},${bgColor.g},${bgColor.b},${bgColor.a})`,
|
|
color: cardSettings?.cardcolor && contrastYIQ
|
|
}}
|
|
title={!isBodyEmpty ? headerContent : null}
|
|
extra={
|
|
!isBodyEmpty && (
|
|
<Link to={{ search: `?selected=${card.id}` }}>
|
|
<EyeFilled />
|
|
</Link>
|
|
)
|
|
}
|
|
>
|
|
{isBodyEmpty ? headerContent : bodyContent}
|
|
</Card>
|
|
);
|
|
}
|