import Icon, { BarsOutlined, CalendarFilled, DollarCircleOutlined, FileImageFilled, PrinterFilled, ToolFilled, HistoryOutlined, SyncOutlined, } from "@ant-design/icons"; import { Button, Divider, Form, notification, PageHeader, Space, Tabs, } from "antd"; import Axios from "axios"; import moment from "moment"; import queryString from "query-string"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { FaHardHat, FaRegStickyNote, FaShieldAlt } from "react-icons/fa"; import { connect } from "react-redux"; import { useHistory, useLocation } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component"; import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container"; import JobLineUpsertModalContainer from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container"; import JobReconciliationModal from "../../components/job-reconciliation-modal/job-reconciliation.modal.container"; import JobSyncButton from "../../components/job-sync-button/job-sync-button.component"; import JobsChangeStatus from "../../components/jobs-change-status/jobs-change-status.component"; import JobsConvertButton from "../../components/jobs-convert-button/jobs-convert-button.component"; import JobsDetailDatesComponent from "../../components/jobs-detail-dates/jobs-detail-dates.component"; import JobsDetailGeneral from "../../components/jobs-detail-general/jobs-detail-general.component"; import JobsDetailHeaderActions from "../../components/jobs-detail-header-actions/jobs-detail-header-actions.component"; import JobsDetailHeader from "../../components/jobs-detail-header/jobs-detail-header.component"; import JobsDetailLaborContainer from "../../components/jobs-detail-labor/jobs-detail-labor.container"; import JobsDetailPliContainer from "../../components/jobs-detail-pli/jobs-detail-pli.container"; import JobsDetailRates from "../../components/jobs-detail-rates/jobs-detail-rates.component"; import JobsDetailTotals from "../../components/jobs-detail-totals/jobs-detail-totals.component"; import JobsDocumentsGalleryContainer from "../../components/jobs-documents-gallery/jobs-documents-gallery.container"; import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container"; import ScheduleJobModalContainer from "../../components/schedule-job-modal/schedule-job-modal.container"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { setModalContext } from "../../redux/modals/modals.actions"; import { selectBodyshop } from "../../redux/user/user.selectors"; import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component"; import AuditTrailMapping from "../../utils/AuditTrailMappings"; import { insertAuditTrail } from "../../redux/application/application.actions"; import JobsDocumentsLocalGallery from "../../components/jobs-documents-local-gallery/jobs-documents-local-gallery.container"; import UndefinedToNull from "../../utils/undefinedtonull"; import NoteUpsertModalComponent from "../../components/note-upsert-modal/note-upsert-modal.container"; import _ from "lodash"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, jobRO: selectJobReadOnly, }); const mapDispatchToProps = (dispatch) => ({ setPrintCenterContext: (context) => dispatch(setModalContext({ context: context, modal: "printCenter" })), insertAuditTrail: ({ jobid, operation }) => dispatch(insertAuditTrail({ jobid, operation })), }); export function JobsDetailPage({ bodyshop, setPrintCenterContext, jobRO, job, mutationUpdateJob, handleSubmit, insertAuditTrail, refetch, }) { const { t } = useTranslation(); const [form] = Form.useForm(); const history = useHistory(); const [loading, setLoading] = useState(false); const search = queryString.parse(useLocation().search); const formItemLayout = { layout: "vertical", }; useEffect(() => { //form.setFieldsValue(transormJobToForm(job)); form.resetFields(); }, [form, job]); //useKeyboardSaveShortcut(form.submit); const handleFinish = async (values) => { setLoading(true); const result = await mutationUpdateJob({ variables: { jobId: job.id, job: { ...UndefinedToNull(values, [ "alt_transport", "category", "referral_source", ]), // The union and spread is required to keep values coming in from the estimating system that aren't displayed. parts_tax_rates: _.union( Object.keys(job.parts_tax_rates), Object.keys(values.parts_tax_rates) ).reduce((acc, val) => { acc[val] = { ...job.parts_tax_rates[val], ...values.parts_tax_rates[val], }; return acc; }, {}), materials: _.union( Object.keys(job.materials), Object.keys(values.materials) ).reduce((acc, val) => { acc[val] = { ...job.materials[val], ...values.materials[val], }; return acc; }, {}), cieca_pfl: _.union( Object.keys(job.cieca_pfl), Object.keys(values.cieca_pfl) ).reduce((acc, val) => { acc[val] = { ...job.cieca_pfl[val], ...values.cieca_pfl[val], }; return acc; }, {}), cieca_pfo: { ...job.cieca_pfo, ...values.cieca_pfo }, }, }, }); try { const newTotals = await Axios.post("/job/totalsssu", { id: job.id, }); if (newTotals.status !== 200 || result.errors) { notification["error"]({ message: t("jobs.errors.totalscalc"), }); } else { notification["success"]({ message: t("jobs.successes.savetitle"), }); const changedAuditFields = form.getFieldsValue( [ "scheduled_in", "actual_in", "scheduled_completion", "actual_completion", "scheduled_delivery", "actual_delivery", "date_invoiced", "ins_co_nm", "ded_amt", "ded_status", "date_exported", "special_coverage_policy", "ca_gst_registrant", "ca_bc_pvrt", "scheduled_in", "rate_la1", "rate_la2", "rate_la3", "rate_la4", "rate_laa", "rate_lab", "rate_lad", "rate_lae", "rate_laf", "rate_lag", "rate_lam", "rate_lar", "rate_las", "rate_lau", "rate_ma2s", "rate_ma2t", "rate_ma3s", "rate_mabl", "rate_macs", "rate_mapa", "rate_mahw", "rate_mash", "rate_matd", ], (meta) => meta && meta.touched ); Object.keys(changedAuditFields).forEach((key) => { insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.jobfieldchange( key, changedAuditFields[key] instanceof moment ? moment(changedAuditFields[key]).format("MM/DD/YYYY hh:mm a") : changedAuditFields[key] ), }); }); await refetch(); form.setFieldsValue(transormJobToForm(job)); form.resetFields(); } } catch (error) { notification["error"]({ message: t("jobs.errors.totalscalc"), }); } finally { setLoading(false); } }; const menuExtra = ( ); return (
window.history.back()} title={job.ro_number || t("general.labels.na")} extra={menuExtra} /> history.push({ search: `?tab=${key}` })} tabBarStyle={{ fontWeight: "bold", borderBottom: "10px" }} > {t("menus.jobsdetail.general")} } key="general" > {t("menus.jobsdetail.repairdata")} } key="repairdata" > {t("menus.jobsdetail.rates")} } key="rates" > {t("menus.jobsdetail.totals")} } key="totals" > {t("menus.jobsdetail.partssublet")} } key="partssublet" > {t("menus.jobsdetail.labor")} } key="labor" > {t("menus.jobsdetail.dates")} } key="dates" > {t("jobs.labels.documents")} } key="documents" > {bodyshop.uselocalmediaserver ? ( ) : ( )} {t("jobs.labels.notes")} } key="notes" > {t("jobs.labels.audit")} } key="audit" >
); } export default connect(mapStateToProps, mapDispatchToProps)(JobsDetailPage); const transormJobToForm = (job) => { Object.keys(job.parts_tax_rates).forEach((parttype) => { Object.keys(job.parts_tax_rates[parttype]).forEach((key) => { if (key.includes("tx_in")) { if ( job.parts_tax_rates[parttype][key] === "Y" || job.parts_tax_rates[parttype][key] === true ) { job.parts_tax_rates[parttype][key] = true; } else { job.parts_tax_rates[parttype][key] = false; } } }); }); return { ...job, loss_date: job.loss_date ? moment(job.loss_date) : null, date_estimated: job.date_estimated ? moment(job.date_estimated) : null, }; };