release/2024-12-13: Merge in Rome Lite Branch
This commit is contained in:
@@ -6,6 +6,8 @@ import { connect } from "react-redux";
|
||||
import { Legend, PolarAngleAxis, PolarGrid, PolarRadiusAxis, Radar, RadarChart, Tooltip } from "recharts";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||
import { UpsellMaskWrapper, upsellEnum } from "../upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -38,26 +40,34 @@ export function ScheduleCalendarHeaderGraph({ bodyshop, loadData }) {
|
||||
<div>
|
||||
<Space>
|
||||
{t("appointments.labels.expectedprodhrs")}
|
||||
<strong>{loadData?.expectedHours?.toFixed(1)}</strong>
|
||||
<BlurWrapperComponent featureName="smartscheduling">
|
||||
<strong>{loadData?.expectedHours?.toFixed(1)}</strong>
|
||||
</BlurWrapperComponent>
|
||||
{t("appointments.labels.expectedjobs")}
|
||||
<strong>{loadData?.expectedJobCount}</strong>
|
||||
<BlurWrapperComponent featureName="smartscheduling">
|
||||
<strong>{loadData?.expectedJobCount}</strong>
|
||||
</BlurWrapperComponent>
|
||||
</Space>
|
||||
<RadarChart
|
||||
// cx={300}
|
||||
// cy={250}
|
||||
// outerRadius={150}
|
||||
width={800}
|
||||
height={600}
|
||||
data={data}
|
||||
>
|
||||
<PolarGrid />
|
||||
<PolarAngleAxis dataKey="bucket" />
|
||||
<PolarRadiusAxis angle={90} />
|
||||
<Radar name="Ideal Load" dataKey="target" stroke="darkgreen" fill="white" fillOpacity={0} />
|
||||
<Radar name="EOD Load" dataKey="current" stroke="dodgerblue" fill="dodgerblue" fillOpacity={0.6} />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
</RadarChart>
|
||||
<UpsellMaskWrapper upsell={upsellEnum().smartscheduling.general}>
|
||||
<BlurWrapperComponent featureName="smartscheduling">
|
||||
<RadarChart
|
||||
// cx={300}
|
||||
// cy={250}
|
||||
// outerRadius={150}
|
||||
width={800}
|
||||
height={600}
|
||||
data={data}
|
||||
>
|
||||
<PolarGrid />
|
||||
<PolarAngleAxis dataKey="bucket" />
|
||||
<PolarRadiusAxis angle={90} />
|
||||
<Radar name="Ideal Load" dataKey="target" stroke="darkgreen" fill="white" fillOpacity={0} />
|
||||
<Radar name="EOD Load" dataKey="current" stroke="dodgerblue" fill="dodgerblue" fillOpacity={0.6} />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
</RadarChart>
|
||||
</BlurWrapperComponent>
|
||||
</UpsellMaskWrapper>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Icon from "@ant-design/icons";
|
||||
import { Popover, Space } from "antd";
|
||||
import { Card, Popover, Space } from "antd";
|
||||
import _ from "lodash";
|
||||
import dayjs from "../../utils/day";
|
||||
|
||||
@@ -12,11 +12,12 @@ import { createStructuredSelector } from "reselect";
|
||||
import { selectScheduleLoad, selectScheduleLoadCalculating } from "../../redux/application/application.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { default as BlurWrapper, default as BlurWrapperComponent } from "../feature-wrapper/blur-wrapper.component";
|
||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
|
||||
import ScheduleCalendarHeaderGraph from "./schedule-calendar-header-graph.component";
|
||||
import InstanceRenderMgr from "../../utils/instanceRenderMgr";
|
||||
import UpsellComponent, { upsellEnum, UpsellMaskWrapper } from "../upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -58,38 +59,39 @@ export function ScheduleCalendarHeaderComponent({
|
||||
<tbody>
|
||||
{loadData && loadData.allJobsOut ? (
|
||||
loadData.allJobsOut.map((j) => (
|
||||
<tr key={j.id}>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link> (
|
||||
{j.status})
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<OwnerNameDisplay ownerObject={j} />
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
{`(${j.labhrs?.aggregate?.sum?.mod_lb_hrs?.toFixed(1) || 0}/${
|
||||
j.larhrs?.aggregate?.sum?.mod_lb_hrs?.toFixed(1) || 0
|
||||
}/${(
|
||||
j.labhrs.aggregate?.sum?.mod_lb_hrs +
|
||||
j.larhrs.aggregate?.sum?.mod_lb_hrs
|
||||
).toFixed(1)} ${t("general.labels.hours")})`}
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<DateTimeFormatter>
|
||||
{j.scheduled_completion}
|
||||
</DateTimeFormatter>
|
||||
</td>
|
||||
</tr>
|
||||
<BlurWrapperComponent key={j.id} featureName="smartscheduling">
|
||||
<tr>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link> ({j.status})
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<OwnerNameDisplay ownerObject={j} />
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
{`(${j.labhrs?.aggregate?.sum?.mod_lb_hrs?.toFixed(1) || 0}/${
|
||||
j.larhrs?.aggregate?.sum?.mod_lb_hrs?.toFixed(1) || 0
|
||||
}/${(j.labhrs.aggregate?.sum?.mod_lb_hrs + j.larhrs.aggregate?.sum?.mod_lb_hrs).toFixed(
|
||||
1
|
||||
)} ${t("general.labels.hours")})`}
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<DateTimeFormatter>{j.scheduled_completion}</DateTimeFormatter>
|
||||
</td>
|
||||
</tr>
|
||||
</BlurWrapperComponent>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
{t("appointments.labels.nocompletingjobs")}
|
||||
</td>
|
||||
<BlurWrapperComponent featureName="smartscheduling">
|
||||
<td style={{ padding: "2.5px" }}>{t("appointments.labels.nocompletingjobs")}</td>
|
||||
</BlurWrapperComponent>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
<Card style={{ maxWidth: "30rem" }}>
|
||||
<UpsellComponent size="small" upsell={upsellEnum().smartscheduling.hrsdelta} />
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -99,33 +101,37 @@ export function ScheduleCalendarHeaderComponent({
|
||||
<tbody>
|
||||
{loadData && loadData.allJobsIn ? (
|
||||
loadData.allJobsIn.map((j) => (
|
||||
<tr key={j.id}>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link>
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<OwnerNameDisplay ownerObject={j} />
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
{`(${j.labhrs?.aggregate?.sum.mod_lb_hrs?.toFixed(1) || 0}/${
|
||||
j.larhrs?.aggregate?.sum?.mod_lb_hrs?.toFixed(1) || 0
|
||||
}/${(
|
||||
j.labhrs?.aggregate?.sum?.mod_lb_hrs +
|
||||
j.larhrs?.aggregate?.sum?.mod_lb_hrs
|
||||
).toFixed(1)} ${t("general.labels.hours")})`}
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<DateTimeFormatter>{j.scheduled_in}</DateTimeFormatter>
|
||||
</td>
|
||||
</tr>
|
||||
<BlurWrapperComponent key={j.id} featureName="smartscheduling">
|
||||
<tr>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link>
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<OwnerNameDisplay ownerObject={j} />
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
{`(${j.labhrs?.aggregate?.sum.mod_lb_hrs?.toFixed(1) || 0}/${
|
||||
j.larhrs?.aggregate?.sum?.mod_lb_hrs?.toFixed(1) || 0
|
||||
}/${(j.labhrs?.aggregate?.sum?.mod_lb_hrs + j.larhrs?.aggregate?.sum?.mod_lb_hrs).toFixed(
|
||||
1
|
||||
)} ${t("general.labels.hours")})`}
|
||||
</td>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
<DateTimeFormatter>{j.scheduled_in}</DateTimeFormatter>
|
||||
</td>
|
||||
</tr>
|
||||
</BlurWrapperComponent>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td style={{ padding: "2.5px" }}>
|
||||
{t("appointments.labels.noarrivingjobs")}
|
||||
</td>
|
||||
<BlurWrapperComponent featureName="smartscheduling">
|
||||
<td style={{ padding: "2.5px" }}>{t("appointments.labels.noarrivingjobs")}</td>
|
||||
</BlurWrapperComponent>
|
||||
</tr>
|
||||
)}
|
||||
<Card style={{ maxWidth: "30rem" }}>
|
||||
<UpsellComponent size="small" upsell={upsellEnum().smartscheduling.hrsdelta} />
|
||||
</Card>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -133,33 +139,36 @@ export function ScheduleCalendarHeaderComponent({
|
||||
|
||||
const LoadComponent = loadData ? (
|
||||
<div>
|
||||
<Space align="center">
|
||||
<Popover
|
||||
placement={"bottom"}
|
||||
content={jobsInPopup}
|
||||
trigger="hover"
|
||||
title={t("appointments.labels.arrivingjobs")}
|
||||
>
|
||||
<Space align="center">
|
||||
<Popover
|
||||
placement={"bottom"}
|
||||
content={jobsInPopup}
|
||||
trigger="hover"
|
||||
title={t("appointments.labels.arrivingjobs")}
|
||||
>
|
||||
<Space size="small">
|
||||
<Icon component={MdFileDownload} style={{ color: "green" }} />
|
||||
{(loadData.allHoursInBody || 0) &&
|
||||
loadData.allHoursInBody.toFixed(1)}
|
||||
/
|
||||
{(loadData.allHoursInRefinish || 0) &&
|
||||
loadData.allHoursInRefinish.toFixed(1)}
|
||||
/{(loadData.allHoursIn || 0) && loadData.allHoursIn.toFixed(1)}
|
||||
</Popover>
|
||||
<Popover
|
||||
placement={"bottom"}
|
||||
content={jobsOutPopup}
|
||||
trigger="hover"
|
||||
title={t("appointments.labels.completingjobs")}
|
||||
>
|
||||
<BlurWrapper featureName="smartscheduling">
|
||||
<span>{`${(loadData.allHoursInBody || 0) && loadData.allHoursInBody.toFixed(1)}/${(loadData.allHoursInRefinish || 0) && loadData.allHoursInRefinish.toFixed(1)}/${(loadData.allHoursIn || 0) && loadData.allHoursIn.toFixed(1)}`}</span>
|
||||
</BlurWrapper>
|
||||
</Space>
|
||||
</Popover>
|
||||
<Popover
|
||||
placement={"bottom"}
|
||||
content={jobsOutPopup}
|
||||
trigger="hover"
|
||||
title={t("appointments.labels.completingjobs")}
|
||||
>
|
||||
<Space size="small">
|
||||
<Icon component={MdFileUpload} style={{ color: "red" }} />
|
||||
{(loadData.allHoursOut || 0) && loadData.allHoursOut.toFixed(1)}
|
||||
</Popover>
|
||||
<ScheduleCalendarHeaderGraph loadData={loadData} />
|
||||
</Space>
|
||||
|
||||
<BlurWrapper featureName="smartscheduling">
|
||||
<span>{(loadData.allHoursOut || 0) && loadData.allHoursOut.toFixed(1)}</span>
|
||||
</BlurWrapper>
|
||||
</Space>
|
||||
</Popover>
|
||||
<ScheduleCalendarHeaderGraph loadData={loadData} />
|
||||
</Space>
|
||||
|
||||
<div>
|
||||
<ul style={{ listStyleType: "none", columns: "2 auto", padding: 0 }}>
|
||||
{Object.keys(ATSToday).map((key, idx) => (
|
||||
@@ -207,11 +216,7 @@ export function ScheduleCalendarHeaderComponent({
|
||||
<ScheduleBlockDay alreadyBlocked={isDayBlocked.length > 0} date={date} refetch={refetch}>
|
||||
<div style={{ color: isShopOpen(date) ? "" : "tomato" }}>
|
||||
{label}
|
||||
{InstanceRenderMgr({
|
||||
imex: calculating ? <LoadingSkeleton /> : LoadComponent,
|
||||
rome: "USE_IMEX",
|
||||
promanager: <></>
|
||||
})}
|
||||
{calculating ? <LoadingSkeleton /> : LoadComponent}
|
||||
</div>
|
||||
</ScheduleBlockDay>
|
||||
</div>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import dayjs from "../../utils/day";
|
||||
import { Alert, Collapse, Space } from "antd";
|
||||
import queryString from "query-string";
|
||||
import React from "react";
|
||||
import { Calendar } from "react-big-calendar";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectProblemJobs } from "../../redux/application/application.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import dayjs from "../../utils/day";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import Event from "../job-at-change/schedule-event.container";
|
||||
import JobDetailCards from "../job-detail-cards/job-detail-cards.component";
|
||||
import local from "./localizer";
|
||||
import HeaderComponent from "./schedule-calendar-header.component";
|
||||
import "./schedule-calendar.styles.scss";
|
||||
import JobDetailCards from "../job-detail-cards/job-detail-cards.component";
|
||||
import { selectProblemJobs } from "../../redux/application/application.selectors";
|
||||
import { Alert, Collapse, Space } from "antd";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import local from "./localizer";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -54,58 +54,54 @@ export function ScheduleCalendarWrapperComponent({
|
||||
return (
|
||||
<>
|
||||
<JobDetailCards />
|
||||
{InstanceRenderManager({
|
||||
imex:
|
||||
problemJobs && problemJobs.length > 2 ? (
|
||||
<Collapse style={{ marginBottom: "5px" }}>
|
||||
<Collapse.Panel
|
||||
key="1"
|
||||
header={<span style={{ color: "tomato" }}>{t("appointments.labels.severalerrorsfound")}</span>}
|
||||
>
|
||||
<Space direction="vertical" style={{ width: "100%" }}>
|
||||
{problemJobs.map((problem) => (
|
||||
<Alert
|
||||
key={problem.id}
|
||||
type="error"
|
||||
message={
|
||||
<Trans
|
||||
i18nKey="appointments.labels.dataconsistency"
|
||||
components={[<Link to={`/manage/jobs/${problem.id}`} target="_blank" />]}
|
||||
values={{
|
||||
ro_number: problem.ro_number,
|
||||
code: problem.code
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Space>
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
) : (
|
||||
<Space direction="vertical" style={{ width: "100%", marginBottom: "5px" }}>
|
||||
{problemJobs.map((problem) => (
|
||||
<Alert
|
||||
key={problem.id}
|
||||
type="error"
|
||||
message={
|
||||
<Trans
|
||||
i18nKey="appointments.labels.dataconsistency"
|
||||
components={[<Link to={`/manage/jobs/${problem.id}`} target="_blank" />]}
|
||||
values={{
|
||||
ro_number: problem.ro_number,
|
||||
code: problem.code
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Space>
|
||||
),
|
||||
|
||||
rome: "USE_IMEX",
|
||||
promanager: <span />
|
||||
})}
|
||||
{HasFeatureAccess({ featureName: "smartscheduling", bodyshop }) &&
|
||||
problemJobs &&
|
||||
(problemJobs.length > 2 ? (
|
||||
<Collapse style={{ marginBottom: "5px" }}>
|
||||
<Collapse.Panel
|
||||
key="1"
|
||||
header={<span style={{ color: "tomato" }}>{t("appointments.labels.severalerrorsfound")}</span>}
|
||||
>
|
||||
<Space direction="vertical" style={{ width: "100%" }}>
|
||||
{problemJobs.map((problem) => (
|
||||
<Alert
|
||||
key={problem.id}
|
||||
type="error"
|
||||
message={
|
||||
<Trans
|
||||
i18nKey="appointments.labels.dataconsistency"
|
||||
components={[<Link to={`/manage/jobs/${problem.id}`} target="_blank" />]}
|
||||
values={{
|
||||
ro_number: problem.ro_number,
|
||||
code: problem.code
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Space>
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
) : (
|
||||
<Space direction="vertical" style={{ width: "100%", marginBottom: "5px" }}>
|
||||
{problemJobs.map((problem) => (
|
||||
<Alert
|
||||
key={problem.id}
|
||||
type="error"
|
||||
message={
|
||||
<Trans
|
||||
i18nKey="appointments.labels.dataconsistency"
|
||||
components={[<Link to={`/manage/jobs/${problem.id}`} target="_blank" />]}
|
||||
values={{
|
||||
ro_number: problem.ro_number,
|
||||
code: problem.code
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Space>
|
||||
))}
|
||||
|
||||
<Calendar
|
||||
events={data}
|
||||
|
||||
Reference in New Issue
Block a user