Files
bodyshop/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx
2024-01-08 10:37:19 -08:00

282 lines
10 KiB
JavaScript

import {
BranchesOutlined,
ExclamationCircleFilled,
PauseCircleOutlined,
WarningFilled,
} from "@ant-design/icons";
import { Card, Col, Row, Space, Tag, Tooltip } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import DataLabel from "../data-label/data-label.component";
import JobAltTransportChange from "../job-at-change/job-at-change.component";
import JobEmployeeAssignments from "../job-employee-assignments/job-employee-assignments.container";
import JobsRelatedRos from "../jobs-related-ros/jobs-related-ros.component";
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
import "./jobs-detail-header.styles.scss";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
setPrintCenterContext: (context) =>
dispatch(setModalContext({ context: context, modal: "printCenter" })),
});
const colSpan = {
xs: {
span: 24,
},
sm: {
span: 24,
},
md: {
span: 12,
},
lg: {
span: 6,
},
xl: {
span: 6,
},
};
export function JobsDetailHeader({ job, bodyshop, disabled }) {
const { t } = useTranslation();
const [notesClamped, setNotesClamped] = useState(true);
const vehicleTitle = `${job.v_model_yr || ""} ${job.v_color || ""}
${job.v_make_desc || ""}
${job.v_model_desc || ""}`.trim();
const ownerTitle = OwnerNameDisplayFunction(job).trim();
return (
<Row gutter={[16, 16]} style={{ alignItems: "stretch" }}>
<Col {...colSpan}>
<Card title={"Job Status"} style={{ height: "100%" }}>
<div>
<DataLabel label={t("jobs.fields.status")}>
<Space wrap>
{job.status}
{job.inproduction && (
<Tag color="#f50" key="production">
{t("jobs.labels.inproduction")}
</Tag>
)}
{job.suspended && (
<PauseCircleOutlined style={{ color: "orangered" }} />
)}
{job.iouparent && (
<Link to={`/manage/jobs/${job.iouparent}`}>
<Tooltip title={t("jobs.labels.iou")}>
<BranchesOutlined style={{ color: "orangered" }} />
</Tooltip>
</Link>
)}
{job.production_vars && job.production_vars.alert ? (
<ExclamationCircleFilled className="production-alert" />
) : null}
{job.status === bodyshop.md_ro_statuses.default_scheduled &&
job.scheduled_in ? (
<Tag>
<DateTimeFormatter>{job.scheduled_in}</DateTimeFormatter>
</Tag>
) : null}
</Space>
</DataLabel>
<DataLabel
label={t("jobs.fields.comment")}
valueStyle={{ overflow: "hidden", textOverflow: "ellipsis" }}
>
<ProductionListColumnComment record={job} />
</DataLabel>
<DataLabel label={t("jobs.fields.ins_co_nm_short")}>
{job.ins_co_nm}
</DataLabel>
<DataLabel label={t("jobs.fields.clm_no")}>{job.clm_no}</DataLabel>
<DataLabel label={t("jobs.fields.ponumber")} hideIfNull>
{job.po_number}
</DataLabel>
<DataLabel label={t("jobs.fields.repairtotal")}>
<CurrencyFormatter>{job.clm_total}</CurrencyFormatter>
<span style={{ margin: "0rem .5rem" }}>/</span>
<CurrencyFormatter>{job.owner_owing}</CurrencyFormatter>
</DataLabel>
<DataLabel label={t("jobs.fields.alt_transport")}>
{job.alt_transport}
<JobAltTransportChange job={job} />
</DataLabel>
{job.cccontracts.length > 0 && (
<DataLabel label={t("jobs.labels.contracts")}>
{job.cccontracts.map((c) => (
<Link
key={c.id}
to={`/manage/courtesycars/contracts/${c.id}`}
>{`${c.agreementnumber} - ${c.courtesycar.fleetnumber} ${c.courtesycar.year} ${c.courtesycar.make} ${c.courtesycar.model}`}</Link>
))}
</DataLabel>
)}
<DataLabel label={t("jobs.fields.production_vars.note")}>
<ProductionListColumnProductionNote record={job} />
</DataLabel>
<Space>
{job.special_coverage_policy && (
<Tag color="tomato">
<Space>
<WarningFilled />
<span>{t("jobs.labels.specialcoveragepolicy")}</span>
</Space>
</Tag>
)}
{job.ca_gst_registrant && (
<Tag color="geekblue">
<Space>
<WarningFilled />
<span>{t("jobs.fields.ca_gst_registrant")}</span>
</Space>
</Tag>
)}
</Space>
</div>
</Card>
</Col>
<Col {...colSpan}>
<Card
style={{ height: "100%" }}
title={
<Link to={disabled ? "#" : `/manage/owners/${job.owner.id}`}>
{ownerTitle.length > 0
? ownerTitle
: t("owner.labels.noownerinfo")}
</Link>
}
>
<div>
<DataLabel key="2" label={t("jobs.fields.ownr_ph1")}>
<ChatOpenButton phone={job.ownr_ph1} jobid={job.id} />
</DataLabel>
<DataLabel key="22" label={t("jobs.fields.ownr_ph2")}>
<ChatOpenButton phone={job.ownr_ph2} jobid={job.id} />
</DataLabel>
<DataLabel key="3" label={t("owners.fields.address")}>
{`${job.ownr_addr1 || ""} ${job.ownr_addr2 || ""} ${
job.ownr_city || ""
} ${job.ownr_st || ""} ${job.ownr_zip || ""}`}
</DataLabel>
<DataLabel key="4" label={t("owners.fields.ownr_ea")}>
{job.ownr_ea || ""}
</DataLabel>
{job.owner?.tax_number && (
<DataLabel key="5" label={t("owners.fields.tax_number")}>
{job.owner?.tax_number || ""}
</DataLabel>
)}
</div>
</Card>
</Col>
<Col {...colSpan}>
<Card
style={{ height: "100%" }}
title={
job.vehicle ? (
<Link
to={
disabled
? "#"
: job.vehicle && `/manage/vehicles/${job.vehicle.id}`
}
>
{vehicleTitle.length > 0
? vehicleTitle
: t("vehicles.labels.novehinfo")}
</Link>
) : (
<span></span>
)
}
>
<div>
<DataLabel key="2" label={t("vehicles.fields.plate_no")}>
{`${job.plate_no || t("general.labels.na")} (${`${
job.plate_st || t("general.labels.na")
}`})`}
</DataLabel>
<DataLabel key="4" label={t("vehicles.fields.v_vin")}>
<VehicleVinDisplay>
{`${job.v_vin || t("general.labels.na")}`}
</VehicleVinDisplay>
{bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (
job.v_vin?.length !== 17 ? (
<WarningFilled style={{ color: "tomato", marginLeft: ".3rem" }} />
) : null
) : null}
</DataLabel>
<DataLabel label={t("jobs.fields.regie_number")}>
{job.regie_number || t("general.labels.na")}
</DataLabel>
<DataLabel label={t("jobs.labels.relatedros")}>
<JobsRelatedRos jobid={job.id} job={job} />
</DataLabel>
{job.vehicle && job.vehicle.notes && (
<DataLabel
label={t("vehicles.fields.notes")}
valueStyle={{ whiteSpace: "pre-wrap" }}
valueClassName={notesClamped ? "clamp" : ""}
onValueClick={() => setNotesClamped(!notesClamped)}
>
{job.vehicle.notes}
</DataLabel>
)}
{job.vehicle && job.vehicle.v_paint_codes && (
<DataLabel
label={t("vehicles.fields.v_paint_codes", { number: "" })}
>
<span style={{ whiteSpace: "pre" }}>
{Object.keys(job.vehicle.v_paint_codes)
.filter(
(key) =>
job.vehicle.v_paint_codes[key] !== "" &&
job.vehicle.v_paint_codes[key] !== null &&
job.vehicle.v_paint_codes[key] !== undefined
)
.map((key, idx) => (
<Tag key={idx}>{job.vehicle.v_paint_codes[key]}</Tag>
))}
</span>
</DataLabel>
)}
</div>
</Card>
</Col>
<Col {...colSpan}>
<Card
style={{ height: "100%" }}
title={t("jobs.labels.employeeassignments")}
>
<div>
<JobEmployeeAssignments job={job} />
</div>
</Card>
</Col>
</Row>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(JobsDetailHeader);