Merged in feature/IO-3296-Scheduled-Delivery-Dashboard (pull request #2402)
Feature/IO-3296 Scheduled Delivery Dashboard Approved-by: Dave Richer
This commit is contained in:
@@ -25,6 +25,7 @@ import BillFormContainer from "../bill-form/bill-form.container";
|
|||||||
import { CalculateBillTotal } from "../bill-form/bill-form.totals.utility";
|
import { CalculateBillTotal } from "../bill-form/bill-form.totals.utility";
|
||||||
import { handleUpload as handleLocalUpload } from "../documents-local-upload/documents-local-upload.utility";
|
import { handleUpload as handleLocalUpload } from "../documents-local-upload/documents-local-upload.utility";
|
||||||
import { handleUpload } from "../documents-upload/documents-upload.utility";
|
import { handleUpload } from "../documents-upload/documents-upload.utility";
|
||||||
|
import { handleUpload as handleUploadToImageProxy } from "../documents-upload-imgproxy/documents-upload-imgproxy.utility";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
billEnterModal: selectBillEnterModal,
|
billEnterModal: selectBillEnterModal,
|
||||||
@@ -53,10 +54,10 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
|||||||
const notification = useNotification();
|
const notification = useNotification();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
treatments: { Enhanced_Payroll }
|
treatments: { Enhanced_Payroll, Imgproxy }
|
||||||
} = useSplitTreatments({
|
} = useSplitTreatments({
|
||||||
attributes: {},
|
attributes: {},
|
||||||
names: ["Enhanced_Payroll"],
|
names: ["Enhanced_Payroll", "Imgproxy"],
|
||||||
splitKey: bodyshop.imexshopid
|
splitKey: bodyshop.imexshopid
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -298,20 +299,39 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
upload.forEach((u) => {
|
//Check if using Imgproxy or cloudinary
|
||||||
handleUpload(
|
|
||||||
{ file: u.originFileObj },
|
if (Imgproxy.treatment === "on") {
|
||||||
{
|
upload.forEach((u) => {
|
||||||
bodyshop: bodyshop,
|
handleUploadToImageProxy(
|
||||||
uploaded_by: currentUser.email,
|
{ file: u.originFileObj },
|
||||||
jobId: values.jobid,
|
{
|
||||||
billId: billId,
|
bodyshop: bodyshop,
|
||||||
tagsArray: null,
|
uploaded_by: currentUser.email,
|
||||||
callback: null
|
jobId: values.jobid,
|
||||||
},
|
billId: billId,
|
||||||
notification
|
tagsArray: null,
|
||||||
);
|
callback: null
|
||||||
});
|
},
|
||||||
|
notification
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
upload.forEach((u) => {
|
||||||
|
handleUpload(
|
||||||
|
{ file: u.originFileObj },
|
||||||
|
{
|
||||||
|
bodyshop: bodyshop,
|
||||||
|
uploaded_by: currentUser.email,
|
||||||
|
jobId: values.jobid,
|
||||||
|
billId: billId,
|
||||||
|
tagsArray: null,
|
||||||
|
callback: null
|
||||||
|
},
|
||||||
|
notification
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
|
|||||||
@@ -0,0 +1,411 @@
|
|||||||
|
import { BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined } from "@ant-design/icons";
|
||||||
|
import { Card, Space, Switch, Table, Tooltip, Typography } from "antd";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import { TimeFormatter } from "../../../utils/DateFormatter";
|
||||||
|
import { onlyUnique } from "../../../utils/arrayHelper";
|
||||||
|
import dayjs from "../../../utils/day";
|
||||||
|
import { alphaSort, dateSort } from "../../../utils/sorters";
|
||||||
|
import useLocalStorage from "../../../utils/useLocalStorage";
|
||||||
|
import ChatOpenButton from "../../chat-open-button/chat-open-button.component";
|
||||||
|
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../../owner-name-display/owner-name-display.component";
|
||||||
|
import DashboardRefreshRequired from "../refresh-required.component";
|
||||||
|
|
||||||
|
export default function DashboardScheduledDeliveryToday({ data, ...cardProps }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [state, setState] = useState({
|
||||||
|
sortedInfo: {},
|
||||||
|
filteredInfo: {}
|
||||||
|
});
|
||||||
|
const [isTvModeScheduledDelivery, setIsTvModeScheduledDelivery] = useLocalStorage("isTvModeScheduledDelivery", false);
|
||||||
|
if (!data) return null;
|
||||||
|
if (!data.scheduled_delivery_today) return <DashboardRefreshRequired {...cardProps} />;
|
||||||
|
|
||||||
|
const scheduledDeliveryToday = data.scheduled_delivery_today.map((item) => {
|
||||||
|
const joblines_body = item.joblines
|
||||||
|
? item.joblines.filter((l) => l.mod_lbr_ty !== "LAR").reduce((acc, val) => acc + val.mod_lb_hrs, 0)
|
||||||
|
: 0;
|
||||||
|
const joblines_ref = item.joblines
|
||||||
|
? item.joblines.filter((l) => l.mod_lbr_ty === "LAR").reduce((acc, val) => acc + val.mod_lb_hrs, 0)
|
||||||
|
: 0;
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
joblines_body,
|
||||||
|
joblines_ref
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const tvFontSize = 18;
|
||||||
|
const tvFontWeight = "bold";
|
||||||
|
|
||||||
|
const tvColumns = [
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.scheduled_delivery"),
|
||||||
|
dataIndex: "scheduled_delivery",
|
||||||
|
key: "scheduled_delivery",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => dateSort(a.scheduled_delivery, b.scheduled_delivery),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "scheduled_delivery" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
<TimeFormatter>{record.scheduled_delivery}</TimeFormatter>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ro_number"),
|
||||||
|
dataIndex: "ro_number",
|
||||||
|
key: "ro_number",
|
||||||
|
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<Link to={"/manage/jobs/" + record.jobid} onClick={(e) => e.stopPropagation()}>
|
||||||
|
<Space>
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
{record.ro_number || t("general.labels.na")}
|
||||||
|
{record.production_vars && record.production_vars.alert ? (
|
||||||
|
<ExclamationCircleFilled className="production-alert" />
|
||||||
|
) : null}
|
||||||
|
{record.suspended && <PauseCircleOutlined style={{ color: "orangered" }} />}
|
||||||
|
{record.iouparent && (
|
||||||
|
<Tooltip title={t("jobs.labels.iou")}>
|
||||||
|
<BranchesOutlined style={{ color: "orangered" }} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</Space>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.owner"),
|
||||||
|
dataIndex: "owner",
|
||||||
|
key: "owner",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.ownerid ? (
|
||||||
|
<Link to={"/manage/owners/" + record.ownerid} onClick={(e) => e.stopPropagation()}>
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.vehicle"),
|
||||||
|
dataIndex: "vehicle",
|
||||||
|
key: "vehicle",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) =>
|
||||||
|
alphaSort(
|
||||||
|
`${a.v_model_yr || ""} ${a.v_make_desc || ""} ${a.v_model_desc || ""}`,
|
||||||
|
`${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}`
|
||||||
|
),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.vehicleid ? (
|
||||||
|
<Link to={"/manage/vehicles/" + record.vehicleid} onClick={(e) => e.stopPropagation()}>
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`}
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>{`${
|
||||||
|
record.v_model_yr || ""
|
||||||
|
} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`}</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("appointments.fields.alt_transport"),
|
||||||
|
dataIndex: "alt_transport",
|
||||||
|
key: "alt_transport",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => alphaSort(a.alt_transport, b.alt_transport),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "alt_transport" && state.sortedInfo.order,
|
||||||
|
filters:
|
||||||
|
(scheduledDeliveryToday &&
|
||||||
|
scheduledDeliveryToday
|
||||||
|
.map((j) => j.alt_transport)
|
||||||
|
.filter(onlyUnique)
|
||||||
|
.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || t("dashboard.errors.atp"),
|
||||||
|
value: [s]
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => alphaSort(a.text, b.text))) ||
|
||||||
|
[],
|
||||||
|
onFilter: (value, record) => value.includes(record.alt_transport),
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>{record.alt_transport}</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.status"),
|
||||||
|
dataIndex: "status",
|
||||||
|
key: "status",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => alphaSort(a.status, b.status),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||||
|
filters:
|
||||||
|
(scheduledDeliveryToday &&
|
||||||
|
scheduledDeliveryToday
|
||||||
|
.map((j) => j.status)
|
||||||
|
.filter(onlyUnique)
|
||||||
|
.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || t("dashboard.errors.status"),
|
||||||
|
value: [s]
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => alphaSort(a.text, b.text))) ||
|
||||||
|
[],
|
||||||
|
onFilter: (value, record) => value.includes(record.status),
|
||||||
|
render: (text, record) => <span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>{record.status}</span>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.lab"),
|
||||||
|
dataIndex: "joblines_body",
|
||||||
|
key: "joblines_body",
|
||||||
|
sorter: (a, b) => a.joblines_body - b.joblines_body,
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "joblines_body" && state.sortedInfo.order,
|
||||||
|
align: "right",
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>{record.joblines_body.toFixed(1)}</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.lar"),
|
||||||
|
dataIndex: "joblines_ref",
|
||||||
|
key: "joblines_ref",
|
||||||
|
sorter: (a, b) => a.joblines_ref - b.joblines_ref,
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "joblines_ref" && state.sortedInfo.order,
|
||||||
|
align: "right",
|
||||||
|
render: (text, record) => (
|
||||||
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>{record.joblines_ref.toFixed(1)}</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.scheduled_delivery"),
|
||||||
|
dataIndex: "scheduled_delivery",
|
||||||
|
key: "scheduled_delivery",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => dateSort(a.scheduled_delivery, b.scheduled_delivery),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "scheduled_delivery" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => <TimeFormatter>{record.scheduled_delivery}</TimeFormatter>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ro_number"),
|
||||||
|
dataIndex: "ro_number",
|
||||||
|
key: "ro_number",
|
||||||
|
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<Link to={"/manage/jobs/" + record.jobid} onClick={(e) => e.stopPropagation()}>
|
||||||
|
<Space>
|
||||||
|
{record.ro_number || t("general.labels.na")}
|
||||||
|
{record.production_vars && record.production_vars.alert ? (
|
||||||
|
<ExclamationCircleFilled className="production-alert" />
|
||||||
|
) : null}
|
||||||
|
{record.suspended && <PauseCircleOutlined style={{ color: "orangered" }} />}
|
||||||
|
{record.iouparent && (
|
||||||
|
<Tooltip title={t("jobs.labels.iou")}>
|
||||||
|
<BranchesOutlined style={{ color: "orangered" }} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.owner"),
|
||||||
|
dataIndex: "owner",
|
||||||
|
key: "owner",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.ownerid ? (
|
||||||
|
<Link to={"/manage/owners/" + record.ownerid} onClick={(e) => e.stopPropagation()}>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("dashboard.labels.phone"),
|
||||||
|
dataIndex: "ownr_ph",
|
||||||
|
key: "ownr_ph",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => (
|
||||||
|
<Space size="small" wrap>
|
||||||
|
<ChatOpenButton phone={record.ownr_ph1} jobid={record.jobid} />
|
||||||
|
|
||||||
|
<ChatOpenButton phone={record.ownr_ph2} jobid={record.jobid} />
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ownr_ea"),
|
||||||
|
dataIndex: "ownr_ea",
|
||||||
|
key: "ownr_ea",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => <a href={`mailto:${record.ownr_ea}`}>{record.ownr_ea}</a>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.vehicle"),
|
||||||
|
dataIndex: "vehicle",
|
||||||
|
key: "vehicle",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) =>
|
||||||
|
alphaSort(
|
||||||
|
`${a.v_model_yr || ""} ${a.v_make_desc || ""} ${a.v_model_desc || ""}`,
|
||||||
|
`${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}`
|
||||||
|
),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.vehicleid ? (
|
||||||
|
<Link to={"/manage/vehicles/" + record.vehicleid} onClick={(e) => e.stopPropagation()}>
|
||||||
|
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`}</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ins_co_nm"),
|
||||||
|
dataIndex: "ins_co_nm",
|
||||||
|
key: "ins_co_nm",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
sorter: (a, b) => alphaSort(a.ins_co_nm, b.ins_co_nm),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "ins_co_nm" && state.sortedInfo.order,
|
||||||
|
filters:
|
||||||
|
(scheduledDeliveryToday &&
|
||||||
|
scheduledDeliveryToday
|
||||||
|
.map((j) => j.ins_co_nm)
|
||||||
|
.filter(onlyUnique)
|
||||||
|
.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || t("dashboard.errors.insco"),
|
||||||
|
value: [s]
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => alphaSort(a.text, b.text))) ||
|
||||||
|
[],
|
||||||
|
onFilter: (value, record) => value.includes(record.ins_co_nm)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("appointments.fields.alt_transport"),
|
||||||
|
dataIndex: "alt_transport",
|
||||||
|
key: "alt_transport",
|
||||||
|
ellipsis: true,
|
||||||
|
sorter: (a, b) => alphaSort(a.alt_transport, b.alt_transport),
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "alt_transport" && state.sortedInfo.order,
|
||||||
|
filters:
|
||||||
|
(scheduledDeliveryToday &&
|
||||||
|
scheduledDeliveryToday
|
||||||
|
.map((j) => j.alt_transport)
|
||||||
|
.filter(onlyUnique)
|
||||||
|
.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || t("dashboard.errors.atp"),
|
||||||
|
value: [s]
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => alphaSort(a.text, b.text))) ||
|
||||||
|
[],
|
||||||
|
onFilter: (value, record) => value.includes(record.alt_transport)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
title={t("dashboard.titles.scheduleddeliverydate", {
|
||||||
|
date: dayjs().startOf("day").format("MM/DD/YYYY")
|
||||||
|
})}
|
||||||
|
extra={
|
||||||
|
<Space>
|
||||||
|
<Typography.Text>{t("general.labels.tvmode")}</Typography.Text>
|
||||||
|
<Switch
|
||||||
|
onClick={() => setIsTvModeScheduledDelivery(!isTvModeScheduledDelivery)}
|
||||||
|
defaultChecked={isTvModeScheduledDelivery}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
{...cardProps}
|
||||||
|
>
|
||||||
|
<div style={{ height: "100%" }}>
|
||||||
|
<Table
|
||||||
|
onChange={handleTableChange}
|
||||||
|
pagination={false}
|
||||||
|
columns={isTvModeScheduledDelivery ? tvColumns : columns}
|
||||||
|
scroll={{ x: true, y: "calc(100% - 2em)" }}
|
||||||
|
rowKey="id"
|
||||||
|
style={{ height: "85%" }}
|
||||||
|
dataSource={scheduledDeliveryToday}
|
||||||
|
size={isTvModeScheduledDelivery ? "small" : "middle"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DashboardScheduledDeliveryTodayGql = `
|
||||||
|
scheduled_delivery_today: jobs(where: {
|
||||||
|
date_invoiced: {_is_null: true},
|
||||||
|
ro_number: {_is_null: false},
|
||||||
|
voided: {_eq: false},
|
||||||
|
scheduled_delivery: {_gte: "${dayjs().startOf("day").toISOString()}",
|
||||||
|
_lte: "${dayjs().endOf("day").toISOString()}"}}) {
|
||||||
|
alt_transport
|
||||||
|
clm_no
|
||||||
|
jobid: id
|
||||||
|
joblines(where: {removed: {_eq: false}}) {
|
||||||
|
mod_lb_hrs
|
||||||
|
mod_lbr_ty
|
||||||
|
}
|
||||||
|
ins_co_nm
|
||||||
|
iouparent
|
||||||
|
ownerid
|
||||||
|
ownr_co_nm
|
||||||
|
ownr_ea
|
||||||
|
ownr_fn
|
||||||
|
ownr_ln
|
||||||
|
ownr_ph1
|
||||||
|
ownr_ph2
|
||||||
|
production_vars
|
||||||
|
ro_number
|
||||||
|
scheduled_delivery
|
||||||
|
status
|
||||||
|
suspended
|
||||||
|
v_make_desc
|
||||||
|
v_model_desc
|
||||||
|
v_model_yr
|
||||||
|
v_vin
|
||||||
|
vehicleid
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined } from "@ant-design/icons";
|
import { BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined } from "@ant-design/icons";
|
||||||
import { Card, Space, Switch, Table, Tooltip, Typography } from "antd";
|
import { Card, Space, Switch, Table, Tooltip, Typography } from "antd";
|
||||||
import dayjs from "../../../utils/day";
|
import { useState } from "react";
|
||||||
import React, { useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { TimeFormatter } from "../../../utils/DateFormatter";
|
import { TimeFormatter } from "../../../utils/DateFormatter";
|
||||||
import { onlyUnique } from "../../../utils/arrayHelper";
|
import { onlyUnique } from "../../../utils/arrayHelper";
|
||||||
|
import dayjs from "../../../utils/day";
|
||||||
import { alphaSort, dateSort } from "../../../utils/sorters";
|
import { alphaSort, dateSort } from "../../../utils/sorters";
|
||||||
import useLocalStorage from "../../../utils/useLocalStorage";
|
import useLocalStorage from "../../../utils/useLocalStorage";
|
||||||
import ChatOpenButton from "../../chat-open-button/chat-open-button.component";
|
import ChatOpenButton from "../../chat-open-button/chat-open-button.component";
|
||||||
@@ -169,7 +169,7 @@ export default function DashboardScheduledInToday({ data, ...cardProps }) {
|
|||||||
.filter(onlyUnique)
|
.filter(onlyUnique)
|
||||||
.map((s) => {
|
.map((s) => {
|
||||||
return {
|
return {
|
||||||
text: s || "No Alt. Transport",
|
text: s || t("dashboard.errors.atp"),
|
||||||
value: [s]
|
value: [s]
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -313,7 +313,7 @@ export default function DashboardScheduledInToday({ data, ...cardProps }) {
|
|||||||
.filter(onlyUnique)
|
.filter(onlyUnique)
|
||||||
.map((s) => {
|
.map((s) => {
|
||||||
return {
|
return {
|
||||||
text: s || "No Ins. Co.*",
|
text: s || t("dashboard.errors.insco"),
|
||||||
value: [s]
|
value: [s]
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -335,7 +335,7 @@ export default function DashboardScheduledInToday({ data, ...cardProps }) {
|
|||||||
.filter(onlyUnique)
|
.filter(onlyUnique)
|
||||||
.map((s) => {
|
.map((s) => {
|
||||||
return {
|
return {
|
||||||
text: s || "No Alt. Transport",
|
text: s || t("dashboard.errors.atp"),
|
||||||
value: [s]
|
value: [s]
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined } from "@ant-design/icons";
|
import { BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined } from "@ant-design/icons";
|
||||||
import { Card, Space, Switch, Table, Tooltip, Typography } from "antd";
|
import { Card, Space, Switch, Table, Tooltip, Typography } from "antd";
|
||||||
import dayjs from "../../../utils/day";
|
import { useState } from "react";
|
||||||
import React, { useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { TimeFormatter } from "../../../utils/DateFormatter";
|
import { TimeFormatter } from "../../../utils/DateFormatter";
|
||||||
import { onlyUnique } from "../../../utils/arrayHelper";
|
import { onlyUnique } from "../../../utils/arrayHelper";
|
||||||
|
import dayjs from "../../../utils/day";
|
||||||
import { alphaSort, dateSort } from "../../../utils/sorters";
|
import { alphaSort, dateSort } from "../../../utils/sorters";
|
||||||
import useLocalStorage from "../../../utils/useLocalStorage";
|
import useLocalStorage from "../../../utils/useLocalStorage";
|
||||||
import ChatOpenButton from "../../chat-open-button/chat-open-button.component";
|
import ChatOpenButton from "../../chat-open-button/chat-open-button.component";
|
||||||
@@ -138,7 +138,7 @@ export default function DashboardScheduledOutToday({ data, ...cardProps }) {
|
|||||||
.filter(onlyUnique)
|
.filter(onlyUnique)
|
||||||
.map((s) => {
|
.map((s) => {
|
||||||
return {
|
return {
|
||||||
text: s || "No Alt. Transport*",
|
text: s || t("dashboard.errors.atp"),
|
||||||
value: [s]
|
value: [s]
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -154,7 +154,7 @@ export default function DashboardScheduledOutToday({ data, ...cardProps }) {
|
|||||||
dataIndex: "status",
|
dataIndex: "status",
|
||||||
key: "status",
|
key: "status",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
sorter: (a, b) => alphaSort(a.alt_transport, b.alt_transport),
|
sorter: (a, b) => alphaSort(a.status, b.status),
|
||||||
sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||||
filters:
|
filters:
|
||||||
(scheduledOutToday &&
|
(scheduledOutToday &&
|
||||||
@@ -163,7 +163,7 @@ export default function DashboardScheduledOutToday({ data, ...cardProps }) {
|
|||||||
.filter(onlyUnique)
|
.filter(onlyUnique)
|
||||||
.map((s) => {
|
.map((s) => {
|
||||||
return {
|
return {
|
||||||
text: s || "No Status*",
|
text: s || t("dashboard.errors.status"),
|
||||||
value: [s]
|
value: [s]
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -306,7 +306,7 @@ export default function DashboardScheduledOutToday({ data, ...cardProps }) {
|
|||||||
.filter(onlyUnique)
|
.filter(onlyUnique)
|
||||||
.map((s) => {
|
.map((s) => {
|
||||||
return {
|
return {
|
||||||
text: s || "No Ins. Co.*",
|
text: s || t("dashboard.errors.insco"),
|
||||||
value: [s]
|
value: [s]
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -328,7 +328,7 @@ export default function DashboardScheduledOutToday({ data, ...cardProps }) {
|
|||||||
.filter(onlyUnique)
|
.filter(onlyUnique)
|
||||||
.map((s) => {
|
.map((s) => {
|
||||||
return {
|
return {
|
||||||
text: s || "No Alt. Transport*",
|
text: s || t("dashboard.errors.atp"),
|
||||||
value: [s]
|
value: [s]
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,30 +1,33 @@
|
|||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import DashboardTotalProductionDollars from "../dashboard-components/total-production-dollars/total-production-dollars.component.jsx";
|
import JobLifecycleDashboardComponent, {
|
||||||
import {
|
JobLifecycleDashboardGQL
|
||||||
DashboardTotalProductionHours,
|
} from "../dashboard-components/job-lifecycle/job-lifecycle-dashboard.component.jsx";
|
||||||
DashboardTotalProductionHoursGql
|
|
||||||
} from "../dashboard-components/total-production-hours/total-production-hours.component.jsx";
|
|
||||||
import DashboardProjectedMonthlySales, {
|
|
||||||
DashboardProjectedMonthlySalesGql
|
|
||||||
} from "../dashboard-components/pojected-monthly-sales/projected-monthly-sales.component.jsx";
|
|
||||||
import DashboardMonthlyRevenueGraph, {
|
|
||||||
DashboardMonthlyRevenueGraphGql
|
|
||||||
} from "../dashboard-components/monthly-revenue-graph/monthly-revenue-graph.component.jsx";
|
|
||||||
import DashboardMonthlyJobCosting from "../dashboard-components/monthly-job-costing/monthly-job-costing.component.jsx";
|
|
||||||
import DashboardMonthlyPartsSales from "../dashboard-components/monthly-parts-sales/monthly-parts-sales.component.jsx";
|
|
||||||
import DashboardMonthlyLaborSales from "../dashboard-components/monthly-labor-sales/monthly-labor-sales.component.jsx";
|
|
||||||
import DashboardMonthlyEmployeeEfficiency, {
|
import DashboardMonthlyEmployeeEfficiency, {
|
||||||
DashboardMonthlyEmployeeEfficiencyGql
|
DashboardMonthlyEmployeeEfficiencyGql
|
||||||
} from "../dashboard-components/monthly-employee-efficiency/monthly-employee-efficiency.component.jsx";
|
} from "../dashboard-components/monthly-employee-efficiency/monthly-employee-efficiency.component.jsx";
|
||||||
|
import DashboardMonthlyJobCosting from "../dashboard-components/monthly-job-costing/monthly-job-costing.component.jsx";
|
||||||
|
import DashboardMonthlyLaborSales from "../dashboard-components/monthly-labor-sales/monthly-labor-sales.component.jsx";
|
||||||
|
import DashboardMonthlyPartsSales from "../dashboard-components/monthly-parts-sales/monthly-parts-sales.component.jsx";
|
||||||
|
import DashboardMonthlyRevenueGraph, {
|
||||||
|
DashboardMonthlyRevenueGraphGql
|
||||||
|
} from "../dashboard-components/monthly-revenue-graph/monthly-revenue-graph.component.jsx";
|
||||||
|
import DashboardProjectedMonthlySales, {
|
||||||
|
DashboardProjectedMonthlySalesGql
|
||||||
|
} from "../dashboard-components/pojected-monthly-sales/projected-monthly-sales.component.jsx";
|
||||||
|
import DashboardScheduledDeliveryToday, {
|
||||||
|
DashboardScheduledDeliveryTodayGql
|
||||||
|
} from "../dashboard-components/scheduled-delivery-today/scheduled-delivery-today.component.jsx";
|
||||||
import DashboardScheduledInToday, {
|
import DashboardScheduledInToday, {
|
||||||
DashboardScheduledInTodayGql
|
DashboardScheduledInTodayGql
|
||||||
} from "../dashboard-components/scheduled-in-today/scheduled-in-today.component.jsx";
|
} from "../dashboard-components/scheduled-in-today/scheduled-in-today.component.jsx";
|
||||||
import DashboardScheduledOutToday, {
|
import DashboardScheduledOutToday, {
|
||||||
DashboardScheduledOutTodayGql
|
DashboardScheduledOutTodayGql
|
||||||
} from "../dashboard-components/scheduled-out-today/scheduled-out-today.component.jsx";
|
} from "../dashboard-components/scheduled-out-today/scheduled-out-today.component.jsx";
|
||||||
import JobLifecycleDashboardComponent, {
|
import DashboardTotalProductionDollars from "../dashboard-components/total-production-dollars/total-production-dollars.component.jsx";
|
||||||
JobLifecycleDashboardGQL
|
import {
|
||||||
} from "../dashboard-components/job-lifecycle/job-lifecycle-dashboard.component.jsx";
|
DashboardTotalProductionHours,
|
||||||
|
DashboardTotalProductionHoursGql
|
||||||
|
} from "../dashboard-components/total-production-hours/total-production-hours.component.jsx";
|
||||||
|
|
||||||
const componentList = {
|
const componentList = {
|
||||||
ProductionDollars: {
|
ProductionDollars: {
|
||||||
@@ -118,6 +121,15 @@ const componentList = {
|
|||||||
w: 10,
|
w: 10,
|
||||||
h: 3
|
h: 3
|
||||||
},
|
},
|
||||||
|
ScheduleDeliveryToday: {
|
||||||
|
label: i18next.t("dashboard.titles.scheduleddeliverytoday"),
|
||||||
|
component: DashboardScheduledDeliveryToday,
|
||||||
|
gqlFragment: DashboardScheduledDeliveryTodayGql,
|
||||||
|
minW: 6,
|
||||||
|
minH: 2,
|
||||||
|
w: 10,
|
||||||
|
h: 3
|
||||||
|
},
|
||||||
JobLifecycle: {
|
JobLifecycle: {
|
||||||
label: i18next.t("dashboard.titles.joblifecycle"),
|
label: i18next.t("dashboard.titles.joblifecycle"),
|
||||||
component: JobLifecycleDashboardComponent,
|
component: JobLifecycleDashboardComponent,
|
||||||
|
|||||||
@@ -975,7 +975,10 @@
|
|||||||
"addcomponent": "Add Component"
|
"addcomponent": "Add Component"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
|
"atp": "No Alt. Transport*",
|
||||||
|
"insco": "No Ins. Co.*",
|
||||||
"refreshrequired": "You must refresh the dashboard data to see this component.",
|
"refreshrequired": "You must refresh the dashboard data to see this component.",
|
||||||
|
"status": "No Status*",
|
||||||
"updatinglayout": "Error saving updated layout {{message}}"
|
"updatinglayout": "Error saving updated layout {{message}}"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
@@ -998,6 +1001,8 @@
|
|||||||
"productiondollars": "Total Dollars in Production",
|
"productiondollars": "Total Dollars in Production",
|
||||||
"productionhours": "Total Hours in Production",
|
"productionhours": "Total Hours in Production",
|
||||||
"projectedmonthlysales": "Projected Monthly Sales",
|
"projectedmonthlysales": "Projected Monthly Sales",
|
||||||
|
"scheduleddeliverydate": "Scheduled Delivery Date: {{date}}",
|
||||||
|
"scheduleddeliverytoday": "Scheduled Delivery Today",
|
||||||
"scheduledindate": "Scheduled In Today: {{date}}",
|
"scheduledindate": "Scheduled In Today: {{date}}",
|
||||||
"scheduledintoday": "Scheduled In Today",
|
"scheduledintoday": "Scheduled In Today",
|
||||||
"scheduledoutdate": "Scheduled Out Today: {{date}}",
|
"scheduledoutdate": "Scheduled Out Today: {{date}}",
|
||||||
|
|||||||
@@ -975,7 +975,10 @@
|
|||||||
"addcomponent": ""
|
"addcomponent": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
|
"atp": "",
|
||||||
|
"insco": "",
|
||||||
"refreshrequired": "",
|
"refreshrequired": "",
|
||||||
|
"status": "",
|
||||||
"updatinglayout": ""
|
"updatinglayout": ""
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
@@ -998,6 +1001,8 @@
|
|||||||
"productiondollars": "",
|
"productiondollars": "",
|
||||||
"productionhours": "",
|
"productionhours": "",
|
||||||
"projectedmonthlysales": "",
|
"projectedmonthlysales": "",
|
||||||
|
"scheduleddeliverydate": "",
|
||||||
|
"scheduleddeliverytoday": "",
|
||||||
"scheduledindate": "",
|
"scheduledindate": "",
|
||||||
"scheduledintoday": "",
|
"scheduledintoday": "",
|
||||||
"scheduledoutdate": "",
|
"scheduledoutdate": "",
|
||||||
|
|||||||
@@ -975,7 +975,10 @@
|
|||||||
"addcomponent": ""
|
"addcomponent": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
|
"atp": "",
|
||||||
|
"insco": "",
|
||||||
"refreshrequired": "",
|
"refreshrequired": "",
|
||||||
|
"status": "",
|
||||||
"updatinglayout": ""
|
"updatinglayout": ""
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
@@ -998,6 +1001,8 @@
|
|||||||
"productiondollars": "",
|
"productiondollars": "",
|
||||||
"productionhours": "",
|
"productionhours": "",
|
||||||
"projectedmonthlysales": "",
|
"projectedmonthlysales": "",
|
||||||
|
"scheduleddeliverydate": "",
|
||||||
|
"scheduleddeliverytoday": "",
|
||||||
"scheduledindate": "",
|
"scheduledindate": "",
|
||||||
"scheduledintoday": "",
|
"scheduledintoday": "",
|
||||||
"scheduledoutdate": "",
|
"scheduledoutdate": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user