Fixed up scheduling logic using UTC dates instead of local dates. Updated scheduling header. Fixed month view not showing. BOD-179
This commit is contained in:
17
.vscode/launch.json
vendored
17
.vscode/launch.json
vendored
@@ -1,19 +1,20 @@
|
|||||||
{
|
{
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Attach to Chrome",
|
||||||
|
"port": 9222,
|
||||||
|
"request": "attach",
|
||||||
|
"type": "pwa-chrome",
|
||||||
|
"webRoot": "${workspaceFolder}/client/src"
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "Chrome",
|
"name": "Chrome",
|
||||||
"type": "chrome",
|
"type": "chrome",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"url": "http://localhost:3000",
|
"url": "http://localhost:3000",
|
||||||
"webRoot": "${workspaceRoot}/src"
|
"webRoot": "${workspaceRoot}/client/src"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Yarn Dev Server",
|
|
||||||
"type": "node",
|
|
||||||
"request": "launch",
|
|
||||||
"runtimeExecutable": "yarn",
|
|
||||||
"runtimeArgs": ["dev"]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Icon from "@ant-design/icons";
|
import Icon from "@ant-design/icons";
|
||||||
import React, { useEffect, useRef } from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import { FaCheck, FaCheckDouble } from "react-icons/fa";
|
import { MdDone, MdDoneAll } from "react-icons/md";
|
||||||
import {
|
import {
|
||||||
AutoSizer,
|
AutoSizer,
|
||||||
CellMeasurer,
|
CellMeasurer,
|
||||||
@@ -38,8 +38,9 @@ export default function ChatMessageListComponent({ messages }) {
|
|||||||
style={style}
|
style={style}
|
||||||
className={`${
|
className={`${
|
||||||
messages[index].isoutbound ? "mine messages" : "yours messages"
|
messages[index].isoutbound ? "mine messages" : "yours messages"
|
||||||
}`}>
|
}`}
|
||||||
<div className='message msgmargin'>
|
>
|
||||||
|
<div className="message msgmargin">
|
||||||
{MessageRender(messages[index])}
|
{MessageRender(messages[index])}
|
||||||
{StatusRender(messages[index].status)}
|
{StatusRender(messages[index].status)}
|
||||||
</div>
|
</div>
|
||||||
@@ -50,7 +51,7 @@ export default function ChatMessageListComponent({ messages }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='chat'>
|
<div className="chat">
|
||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
{({ height, width }) => (
|
{({ height, width }) => (
|
||||||
<List
|
<List
|
||||||
@@ -73,12 +74,8 @@ export default function ChatMessageListComponent({ messages }) {
|
|||||||
const MessageRender = (message) => {
|
const MessageRender = (message) => {
|
||||||
if (message.image) {
|
if (message.image) {
|
||||||
return (
|
return (
|
||||||
<a href={message.image_path} target='__blank'>
|
<a href={message.image_path} target="__blank">
|
||||||
<img
|
<img alt="Received" className="message-img" src={message.image_path} />
|
||||||
alt='Received'
|
|
||||||
className='message-img'
|
|
||||||
src={message.image_path}
|
|
||||||
/>
|
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -89,9 +86,9 @@ const MessageRender = (message) => {
|
|||||||
const StatusRender = (status) => {
|
const StatusRender = (status) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "sent":
|
case "sent":
|
||||||
return <Icon component={FaCheck} className='message-icon' />;
|
return <Icon component={MdDone} className="message-icon" />;
|
||||||
case "delivered":
|
case "delivered":
|
||||||
return <Icon component={FaCheckDouble} className='message-icon' />;
|
return <Icon component={MdDoneAll} className="message-icon" />;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export default function ProductionBoardCard(card) {
|
|||||||
<div className="imex-flex-row imex-flex-row__flex-space-around">
|
<div className="imex-flex-row imex-flex-row__flex-space-around">
|
||||||
<div className="mex-flex-row__margin">
|
<div className="mex-flex-row__margin">
|
||||||
<div>{`B: ${card.labhrs.aggregate.sum.mod_lb_hrs || "?"}`}</div>
|
<div>{`B: ${card.labhrs.aggregate.sum.mod_lb_hrs || "?"}`}</div>
|
||||||
<div>{`R: ${card.labhrs.aggregate.sum.mod_lb_hrs || "?"}`}</div>
|
<div>{`R: ${card.larhrs.aggregate.sum.mod_lb_hrs || "?"}`}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mex-flex-row__margin">
|
<div className="mex-flex-row__margin">
|
||||||
<div>{`B: ${
|
<div>{`B: ${
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
|
|
||||||
export function ProductionBoardKanbanContainer({ bodyshop }) {
|
export function ProductionBoardKanbanContainer({ bodyshop }) {
|
||||||
const { loading, data } = useSubscription(SUBSCRIPTION_JOBS_IN_PRODUCTION, {
|
const { loading, data } = useSubscription(SUBSCRIPTION_JOBS_IN_PRODUCTION, {
|
||||||
variables: {
|
// variables: {
|
||||||
statusList: bodyshop.md_ro_statuses.production_statuses || [],
|
// statusList: bodyshop.md_ro_statuses.production_statuses || [],
|
||||||
},
|
// },
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ export default connect(mapStateToProps, null)(ProductionListTableContainer);
|
|||||||
|
|
||||||
export function ProductionListTableContainer({ bodyshop }) {
|
export function ProductionListTableContainer({ bodyshop }) {
|
||||||
const { loading, data } = useSubscription(SUBSCRIPTION_JOBS_IN_PRODUCTION, {
|
const { loading, data } = useSubscription(SUBSCRIPTION_JOBS_IN_PRODUCTION, {
|
||||||
variables: {
|
// variables: {
|
||||||
statusList: bodyshop.md_ro_statuses.production_statuses || [],
|
// statusList: bodyshop.md_ro_statuses.production_statuses || [],
|
||||||
},
|
// },
|
||||||
});
|
});
|
||||||
|
|
||||||
const columnState = useState(
|
const columnState = useState(
|
||||||
|
|||||||
@@ -24,10 +24,7 @@ export function ScheduleBlockDay({ date, children, refetch, bodyshop }) {
|
|||||||
const handleMenu = async (e) => {
|
const handleMenu = async (e) => {
|
||||||
e.domEvent.stopPropagation();
|
e.domEvent.stopPropagation();
|
||||||
|
|
||||||
|
|
||||||
if (e.key === "block") {
|
if (e.key === "block") {
|
||||||
|
|
||||||
|
|
||||||
const blockAppt = {
|
const blockAppt = {
|
||||||
title: t("appointments.labels.blocked"),
|
title: t("appointments.labels.blocked"),
|
||||||
block: true,
|
block: true,
|
||||||
@@ -38,7 +35,6 @@ export function ScheduleBlockDay({ date, children, refetch, bodyshop }) {
|
|||||||
};
|
};
|
||||||
logImEXEvent("dashboard_change_layout");
|
logImEXEvent("dashboard_change_layout");
|
||||||
|
|
||||||
|
|
||||||
const result = await insertBlock({
|
const result = await insertBlock({
|
||||||
variables: { app: [blockAppt] },
|
variables: { app: [blockAppt] },
|
||||||
});
|
});
|
||||||
@@ -57,9 +53,7 @@ export function ScheduleBlockDay({ date, children, refetch, bodyshop }) {
|
|||||||
|
|
||||||
const menu = (
|
const menu = (
|
||||||
<Menu onClick={handleMenu}>
|
<Menu onClick={handleMenu}>
|
||||||
<Menu.Item key='block'>{t("appointments.actions.block")}</Menu.Item>
|
<Menu.Item key="block">{t("appointments.actions.block")}</Menu.Item>
|
||||||
<Menu.Item key='2'>2nd menu item</Menu.Item>
|
|
||||||
<Menu.Item key='3'>3rd menu item</Menu.Item>
|
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,13 @@ import {
|
|||||||
selectScheduleLoadCalculating,
|
selectScheduleLoadCalculating,
|
||||||
} from "../../redux/application/application.selectors";
|
} from "../../redux/application/application.selectors";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
import { Progress } from "antd";
|
import { Progress, Statistic } from "antd";
|
||||||
import { MdCallReceived, MdCallMissedOutgoing } from "react-icons/md";
|
import {
|
||||||
|
MdCallReceived,
|
||||||
|
MdCallMissedOutgoing,
|
||||||
|
MdFileDownload,
|
||||||
|
MdFileUpload,
|
||||||
|
} from "react-icons/md";
|
||||||
import Icon from "@ant-design/icons";
|
import Icon from "@ant-design/icons";
|
||||||
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
|
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
|
||||||
|
|
||||||
@@ -34,18 +39,24 @@ export function ScheduleCalendarHeaderComponent({
|
|||||||
const loadData = load[date.toISOString().substr(0, 10)];
|
const loadData = load[date.toISOString().substr(0, 10)];
|
||||||
|
|
||||||
const LoadComponent = loadData ? (
|
const LoadComponent = loadData ? (
|
||||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
<div className="imex-flex-row imex-flex-row__flex-space-around">
|
||||||
<Progress
|
<Icon component={MdFileDownload} style={{ color: "green" }} />
|
||||||
style={{ display: "flex", alignItems: "center" }}
|
{(loadData.hoursIn || 0) && loadData.hoursIn.toFixed(2)}
|
||||||
percent={((loadData.expectedLoad || 0) / ShopTargetHrs) * 100}
|
<Icon component={MdFileUpload} style={{ color: "red" }} />
|
||||||
|
{(loadData.hoursOut || 0) && loadData.hoursOut.toFixed(2)}
|
||||||
|
<Statistic
|
||||||
|
value={((loadData.expectedLoad || 0) / ShopTargetHrs) * 100}
|
||||||
|
suffix={"%"}
|
||||||
|
precision={0}
|
||||||
|
valueStyle={{
|
||||||
|
color:
|
||||||
|
Math.abs(
|
||||||
|
100 - ((loadData.expectedLoad || 0) / ShopTargetHrs) * 100
|
||||||
|
) <= 10
|
||||||
|
? "green"
|
||||||
|
: "red",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="imex-flex-row imex-flex-row__flex-space-around">
|
|
||||||
<Icon component={MdCallReceived} />
|
|
||||||
{(loadData.hoursIn || 0) && loadData.hoursIn.toFixed(2)}
|
|
||||||
<Icon component={MdCallMissedOutgoing} />
|
|
||||||
{(loadData.hoursOut || 0) && loadData.hoursOut.toFixed(2)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
@@ -53,11 +64,7 @@ export function ScheduleCalendarHeaderComponent({
|
|||||||
<ScheduleBlockDay date={date} refetch={refetch}>
|
<ScheduleBlockDay date={date} refetch={refetch}>
|
||||||
<div>
|
<div>
|
||||||
{label}
|
{label}
|
||||||
{calculating || JSON.stringify(load) === "{}" ? (
|
{calculating ? <LoadingSkeleton /> : LoadComponent}
|
||||||
<LoadingSkeleton />
|
|
||||||
) : (
|
|
||||||
LoadComponent
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</ScheduleBlockDay>
|
</ScheduleBlockDay>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,3 +12,11 @@
|
|||||||
.imex-event-block {
|
.imex-event-block {
|
||||||
background-color: rgba(212, 2, 2, 0.6);
|
background-color: rgba(212, 2, 2, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rbc-month-view {
|
||||||
|
height: 125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbc-event.rbc-selected {
|
||||||
|
background-color: slategrey;
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ export function ScoreboardLastDays({ bodyshop, sbEntriesByDate }) {
|
|||||||
|
|
||||||
const ArrayOfDate = [];
|
const ArrayOfDate = [];
|
||||||
for (var i = lastNumberWorkingDays - 1; i >= 0; i--) {
|
for (var i = lastNumberWorkingDays - 1; i >= 0; i--) {
|
||||||
ArrayOfDate.push(
|
ArrayOfDate.push(moment().businessSubtract(i, "day").format("yyyy-MM-DD"));
|
||||||
moment().businessSubtract(i, "day").toISOString().substr(0, 10)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export const QUERY_ALL_ACTIVE_JOBS = gql`
|
|||||||
|
|
||||||
export const SUBSCRIPTION_JOBS_IN_PRODUCTION = gql`
|
export const SUBSCRIPTION_JOBS_IN_PRODUCTION = gql`
|
||||||
subscription SUBSCRIPTION_JOBS_IN_PRODUCTION($statusList: [String!]!) {
|
subscription SUBSCRIPTION_JOBS_IN_PRODUCTION($statusList: [String!]!) {
|
||||||
jobs(where: { status: { _in: $statusList } }) {
|
jobs(where: { inproduction: { _eq: true } }) {
|
||||||
id
|
id
|
||||||
status
|
status
|
||||||
ro_number
|
ro_number
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export function* calculateScheduleLoad({ payload: end }) {
|
|||||||
const { arrJobs, compJobs } = result.data;
|
const { arrJobs, compJobs } = result.data;
|
||||||
|
|
||||||
arrJobs.forEach((item) => {
|
arrJobs.forEach((item) => {
|
||||||
const itemDate = moment(item.scheduled_in).toISOString().substr(0, 10);
|
const itemDate = moment(item.scheduled_in).format("yyyy-MM-DD");
|
||||||
if (!!load[itemDate]) {
|
if (!!load[itemDate]) {
|
||||||
load[itemDate].hoursIn =
|
load[itemDate].hoursIn =
|
||||||
(load[itemDate].hoursIn || 0) +
|
(load[itemDate].hoursIn || 0) +
|
||||||
@@ -44,7 +44,7 @@ export function* calculateScheduleLoad({ payload: end }) {
|
|||||||
load[itemDate].jobsIn.push(item);
|
load[itemDate].jobsIn.push(item);
|
||||||
} else {
|
} else {
|
||||||
load[itemDate] = {
|
load[itemDate] = {
|
||||||
jobsIn: [],
|
jobsIn: [item],
|
||||||
jobsOut: [],
|
jobsOut: [],
|
||||||
hoursIn:
|
hoursIn:
|
||||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||||
@@ -54,9 +54,7 @@ export function* calculateScheduleLoad({ payload: end }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
compJobs.forEach((item) => {
|
compJobs.forEach((item) => {
|
||||||
const itemDate = moment(item.scheduled_completion)
|
const itemDate = moment(item.scheduled_completion).format("yyyy-MM-DD");
|
||||||
.toISOString()
|
|
||||||
.substr(0, 10);
|
|
||||||
if (!!load[itemDate]) {
|
if (!!load[itemDate]) {
|
||||||
load[itemDate].hoursOut =
|
load[itemDate].hoursOut =
|
||||||
(load[itemDate].hoursOut || 0) +
|
(load[itemDate].hoursOut || 0) +
|
||||||
@@ -65,6 +63,7 @@ export function* calculateScheduleLoad({ payload: end }) {
|
|||||||
load[itemDate].jobsOut.push(item);
|
load[itemDate].jobsOut.push(item);
|
||||||
} else {
|
} else {
|
||||||
load[itemDate] = {
|
load[itemDate] = {
|
||||||
|
jobsOut: [item],
|
||||||
hoursOut:
|
hoursOut:
|
||||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||||
item.larhrs.aggregate.sum.mod_lb_hrs,
|
item.larhrs.aggregate.sum.mod_lb_hrs,
|
||||||
@@ -75,20 +74,19 @@ export function* calculateScheduleLoad({ payload: end }) {
|
|||||||
//Propagate the expected load to each day.
|
//Propagate the expected load to each day.
|
||||||
const range = Math.round(moment.duration(end.diff(today)).asDays());
|
const range = Math.round(moment.duration(end.diff(today)).asDays());
|
||||||
for (var day = 0; day < range; day++) {
|
for (var day = 0; day < range; day++) {
|
||||||
const current = moment(today)
|
const current = moment(today).add(day, "days").format("yyyy-MM-DD");
|
||||||
.add(day, "days")
|
|
||||||
.toISOString()
|
|
||||||
.substr(0, 10);
|
|
||||||
const prev = moment(today)
|
const prev = moment(today)
|
||||||
.add(day - 1, "days")
|
.add(day - 1, "days")
|
||||||
.toISOString()
|
.format("yyyy-MM-DD");
|
||||||
.substr(0, 10);
|
|
||||||
if (!!!load[current]) {
|
if (!!!load[current]) {
|
||||||
load[current] = {};
|
load[current] = {};
|
||||||
}
|
}
|
||||||
if (day === 0) {
|
if (day === 0) {
|
||||||
//Starting on day 1. The load is current.
|
//Starting on day 1. The load is current.
|
||||||
load[current].expectedLoad = load.productionHoursTotal;
|
load[current].expectedLoad =
|
||||||
|
load.productionHoursTotal +
|
||||||
|
(load[current].hoursIn || 0) -
|
||||||
|
(load[current].hoursOut || 0);
|
||||||
} else {
|
} else {
|
||||||
load[current].expectedLoad =
|
load[current].expectedLoad =
|
||||||
load[prev].expectedLoad +
|
load[prev].expectedLoad +
|
||||||
@@ -96,7 +94,6 @@ export function* calculateScheduleLoad({ payload: end }) {
|
|||||||
(load[current].hoursOut || 0);
|
(load[current].hoursOut || 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
yield put(scheduleLoadSuccess(load));
|
yield put(scheduleLoadSuccess(load));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
//console.log("Error in sendEmailFailure saga.", error.message);
|
//console.log("Error in sendEmailFailure saga.", error.message);
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ exports.job = async (req, res) => {
|
|||||||
|
|
||||||
//Initialize the bucket matrix
|
//Initialize the bucket matrix
|
||||||
for (i = 0; i < totalMatrixDays; i++) {
|
for (i = 0; i < totalMatrixDays; i++) {
|
||||||
const theDate = moment().add(i, "days").toISOString().substr(0, 10);
|
const theDate = moment().add(i, "days").format("yyyy-MM-DD");
|
||||||
//Only need to create a matrix for jobs of the same bucket.
|
//Only need to create a matrix for jobs of the same bucket.
|
||||||
bucketMatrix[theDate] = { in: 0, out: 0 };
|
bucketMatrix[theDate] = { in: 0, out: 0 };
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ exports.job = async (req, res) => {
|
|||||||
)[0];
|
)[0];
|
||||||
if (appointmentBucket.id === JobBucket.id) {
|
if (appointmentBucket.id === JobBucket.id) {
|
||||||
//Theyre the same classification. Add it to the matrix.
|
//Theyre the same classification. Add it to the matrix.
|
||||||
const appDate = moment(appointment.start).toISOString().substr(0, 10);
|
const appDate = moment(appointment.start).format("yyyy-MM-DD");
|
||||||
bucketMatrix[appDate] = {
|
bucketMatrix[appDate] = {
|
||||||
...bucketMatrix[appDate],
|
...bucketMatrix[appDate],
|
||||||
in: bucketMatrix[appDate].in + 1,
|
in: bucketMatrix[appDate].in + 1,
|
||||||
@@ -85,7 +85,7 @@ exports.job = async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
//Populate the jobs that are leaving today.
|
//Populate the jobs that are leaving today.
|
||||||
const todayIsoString = moment().toISOString().substr(0, 10);
|
const todayIsoString = moment().format("yyyy-MM-DD");
|
||||||
productionview.forEach((pjob) => {
|
productionview.forEach((pjob) => {
|
||||||
const jobHrs = pjob.larhrs + pjob.labhrs;
|
const jobHrs = pjob.larhrs + pjob.labhrs;
|
||||||
//Is the job in the same bucket?
|
//Is the job in the same bucket?
|
||||||
@@ -100,7 +100,7 @@ exports.job = async (req, res) => {
|
|||||||
let dateToUse;
|
let dateToUse;
|
||||||
dateToUse = compDate.isValid()
|
dateToUse = compDate.isValid()
|
||||||
? moment().diff(compDate, "days") <= 0
|
? moment().diff(compDate, "days") <= 0
|
||||||
? compDate.toISOString().substr(0, 10)
|
? compDate.format("yyyy-MM-DD")
|
||||||
: todayIsoString
|
: todayIsoString
|
||||||
: todayIsoString;
|
: todayIsoString;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user