import { Alert, Button, Card, Typography } from "antd"; import ResponsiveTable from "../responsive-table/responsive-table.component"; import { SyncOutlined } from "@ant-design/icons"; import { useCallback, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import Dinero from "dinero.js"; import { DMS_MAP } from "../../utils/dmsUtils"; import { selectBodyshop } from "../../redux/user/user.selectors"; import { pageLimit } from "../../utils/config"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop }); const mapDispatchToProps = () => ({}); export default connect(mapStateToProps, mapDispatchToProps)(DmsAllocationsSummary); /** * DMS Allocations Summary component * @param mode * @param socket * @param bodyshop * @param jobId * @param title * @param onAllocationsChange * @returns {JSX.Element} * @constructor */ export function DmsAllocationsSummary({ mode, socket, bodyshop, jobId, title, onAllocationsChange }) { const { t } = useTranslation(); const [allocationsSummary, setAllocationsSummary] = useState([]); const socketRef = useRef(socket); useEffect(() => { socketRef.current = socket; }, [socket]); // Resolve event name by mode (PBS reuses the CDK event per existing behavior) const allocationsEvent = mode === DMS_MAP.reynolds ? "rr-calculate-allocations" : mode === DMS_MAP.fortellis ? "fortellis-calculate-allocations" : /* "cdk" | "pbs" (legacy) */ "cdk-calculate-allocations"; const fetchAllocations = useCallback(() => { if (!socket || !jobId || !mode) return; try { socket.emit(allocationsEvent, jobId, (ack) => { const list = Array.isArray(ack) ? ack : []; setAllocationsSummary(list); // Preserve side-channel used by the post form for discrepancy checks socketRef.current.allocationsSummary = list; if (onAllocationsChange) onAllocationsChange(list); }); } catch { // Best-effort; leave table empty on error setAllocationsSummary([]); if (socketRef.current) { socketRef.current.allocationsSummary = []; } if (onAllocationsChange) { onAllocationsChange([]); } } }, [socket, jobId, mode, allocationsEvent]); // Initial + whenever mode/socket/jobId changes useEffect(() => { fetchAllocations(); }, [fetchAllocations]); const columns = [ { title: t("jobs.fields.dms.center"), dataIndex: "center", key: "center" }, { title: t("jobs.fields.dms.sale"), dataIndex: "sale", key: "sale", render: (_text, record) => Dinero(record.sale).toFormat() }, { title: t("jobs.fields.dms.cost"), dataIndex: "cost", key: "cost", render: (_text, record) => Dinero(record.cost).toFormat() }, { title: t("jobs.fields.dms.sale_dms_acctnumber"), dataIndex: "sale_dms_acctnumber", key: "sale_dms_acctnumber", render: (_text, record) => record.profitCenter?.dms_acctnumber }, { title: t("jobs.fields.dms.cost_dms_acctnumber"), dataIndex: "cost_dms_acctnumber", key: "cost_dms_acctnumber", render: (_text, record) => record.costCenter?.dms_acctnumber }, { title: t("jobs.fields.dms.dms_wip_acctnumber"), dataIndex: "dms_wip_acctnumber", key: "dms_wip_acctnumber", render: (_text, record) => record.costCenter?.dms_wip_acctnumber } ]; return ( } />} > {bodyshop.pbs_configuration?.disablebillwip && ( )} { const totals = allocationsSummary?.reduce( (acc, val) => ({ totalSale: acc.totalSale.add(Dinero(val.sale)), totalCost: acc.totalCost.add(Dinero(val.cost)) }), { totalSale: Dinero(), totalCost: Dinero() } ) || { totalSale: Dinero(), totalCost: Dinero() }; const hasNonZeroSaleTotal = totals.totalSale.getAmount() !== 0; return ( {t("general.labels.totals")} {hasNonZeroSaleTotal ? totals.totalSale.toFormat() : null} ); }} /> ); }