diff --git a/client/src/components/schedule-calendar-wrapper/schedule-calendar-header-graph.component.js b/client/src/components/schedule-calendar-wrapper/schedule-calendar-header-graph.component.js
new file mode 100644
index 000000000..63332437d
--- /dev/null
+++ b/client/src/components/schedule-calendar-wrapper/schedule-calendar-header-graph.component.js
@@ -0,0 +1,68 @@
+import { Popover } from "antd";
+import React from "react";
+import { connect } from "react-redux";
+import {
+ PolarAngleAxis,
+ PolarGrid,
+ PolarRadiusAxis,
+ Radar,
+ RadarChart,
+} from "recharts";
+import { createStructuredSelector } from "reselect";
+import { selectBodyshop } from "../../redux/user/user.selectors";
+
+const mapStateToProps = createStructuredSelector({
+ bodyshop: selectBodyshop,
+});
+const mapDispatchToProps = (dispatch) => ({
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
+});
+
+export function ScheduleCalendarHeaderGraph({ bodyshop, loadData }) {
+ const { ssbuckets } = bodyshop;
+
+ const data = Object.keys(loadData.expectedLoad).map((key) => {
+ const metadataBucket = ssbuckets.filter((b) => b.id === key)[0];
+
+ return {
+ bucket: loadData.expectedLoad[key].label,
+ current: loadData.expectedLoad[key].count,
+ target: metadataBucket && metadataBucket.target,
+ };
+ });
+
+//d console.log("data", data);
+ const popContent = (
+
+ );
+
+ return (
+
+ G
+
+ );
+}
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(ScheduleCalendarHeaderGraph);
diff --git a/client/src/components/schedule-calendar-wrapper/schedule-calendar-header.component.js b/client/src/components/schedule-calendar-wrapper/schedule-calendar-header.component.js
index f2929c3b7..20dbeb33b 100644
--- a/client/src/components/schedule-calendar-wrapper/schedule-calendar-header.component.js
+++ b/client/src/components/schedule-calendar-wrapper/schedule-calendar-header.component.js
@@ -1,5 +1,5 @@
import Icon from "@ant-design/icons";
-import { Popover, Statistic } from "antd";
+import { Popover } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { MdFileDownload, MdFileUpload } from "react-icons/md";
@@ -8,23 +8,21 @@ import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import {
selectScheduleLoad,
- selectScheduleLoadCalculating,
+ selectScheduleLoadCalculating
} from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
+import ScheduleCalendarHeaderGraph from "./schedule-calendar-header-graph.component";
const mapStateToProps = createStructuredSelector({
- //currentUser: selectCurrentUser
bodyshop: selectBodyshop,
load: selectScheduleLoad,
calculating: selectScheduleLoadCalculating,
});
-const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
-});
+const mapDispatchToProps = (dispatch) => ({});
export function ScheduleCalendarHeaderComponent({
bodyshop,
@@ -122,23 +120,7 @@ export function ScheduleCalendarHeaderComponent({
{(loadData.hoursOut || 0) && loadData.hoursOut.toFixed(2)}
-
+
) : null;
diff --git a/client/src/components/shop-info/shop-info.scheduling.component.jsx b/client/src/components/shop-info/shop-info.scheduling.component.jsx
index 57f0b14d6..e6f81504d 100644
--- a/client/src/components/shop-info/shop-info.scheduling.component.jsx
+++ b/client/src/components/shop-info/shop-info.scheduling.component.jsx
@@ -102,7 +102,7 @@ export default function ShopInfoSchedulingComponent({ form }) {
key={field.key}
style={{ padding: 0, margin: 2 }}
>
-
+
- {
- remove(field.name);
- }}
- />
-
-
+
+ {
+ remove(field.name);
+ }}
+ />
+
+
+
))}
diff --git a/client/src/debug.log b/client/src/debug.log
new file mode 100644
index 000000000..a56efb4ec
--- /dev/null
+++ b/client/src/debug.log
@@ -0,0 +1,4 @@
+[1008/110112.528:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
+[1008/114603.993:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
+[1008/121110.259:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
+[1008/122424.146:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
diff --git a/client/src/graphql/appointments.queries.js b/client/src/graphql/appointments.queries.js
index e61b90ebe..e7e0551f2 100644
--- a/client/src/graphql/appointments.queries.js
+++ b/client/src/graphql/appointments.queries.js
@@ -166,32 +166,23 @@ export const QUERY_APPOINTMENTS_BY_JOBID = gql`
`;
export const QUERY_SCHEDULE_LOAD_DATA = gql`
query QUERY_SCHEDULE_LOAD_DATA($start: timestamptz!, $end: timestamptz!) {
- labhrs: joblines_aggregate(
- where: {
- mod_lbr_ty: { _eq: "LAB" }
- job: { inproduction: { _eq: true } }
+ prodJobs: jobs(where: { inproduction: { _eq: true } }) {
+ id
+ labhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAB" } }) {
+ aggregate {
+ sum {
+ mod_lb_hrs
+ }
+ }
}
- ) {
- aggregate {
- sum {
- mod_lb_hrs
+ larhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAR" } }) {
+ aggregate {
+ sum {
+ mod_lb_hrs
+ }
}
}
}
-
- larhrs: joblines_aggregate(
- where: {
- mod_lbr_ty: { _eq: "LAR" }
- job: { inproduction: { _eq: true } }
- }
- ) {
- aggregate {
- sum {
- mod_lb_hrs
- }
- }
- }
-
compJobs: jobs(
where: { scheduled_completion: { _gte: $start, _lte: $end } }
) {
diff --git a/client/src/redux/application/application.sagas.js b/client/src/redux/application/application.sagas.js
index 69bd72263..5b2864002 100644
--- a/client/src/redux/application/application.sagas.js
+++ b/client/src/redux/application/application.sagas.js
@@ -1,12 +1,13 @@
-import { all, takeLatest, call, put } from "redux-saga/effects";
-import ApplicationActionTypes from "./application.types";
-import client from "../../utils/GraphQLClient";
+import moment from "moment";
+import { all, call, put, select, takeLatest } from "redux-saga/effects";
import { QUERY_SCHEDULE_LOAD_DATA } from "../../graphql/appointments.queries";
+import client from "../../utils/GraphQLClient";
+import { CalculateLoad, CheckJobBucket } from "../../utils/SSSUtils";
import {
scheduleLoadFailure,
scheduleLoadSuccess,
} from "./application.actions";
-import moment from "moment";
+import ApplicationActionTypes from "./application.types";
export function* onCalculateScheduleLoad() {
yield takeLatest(
@@ -17,6 +18,9 @@ export function* onCalculateScheduleLoad() {
export function* calculateScheduleLoad({ payload: end }) {
//REMINDER: Moment.js is not immutable. Today WILL change when adjusted.
const today = moment(new Date()).startOf("day");
+ const state = yield select();
+ const buckets = state.user.bodyshop.ssbuckets;
+
try {
const result = yield client.query({
query: QUERY_SCHEDULE_LOAD_DATA,
@@ -26,14 +30,26 @@ export function* calculateScheduleLoad({ payload: end }) {
},
fetchPolicy: "network-only",
});
+ const { prodJobs, arrJobs, compJobs } = result.data;
- let load = {
- productionHoursTotal:
- result.data.larhrs.aggregate.sum.mod_lb_hrs +
- result.data.labhrs.aggregate.sum.mod_lb_hrs,
+ const load = {
+ productionTotal: {},
};
- const { arrJobs, compJobs } = result.data;
+ //Set the current load.
+ buckets.forEach((bucket) => {
+ load.productionTotal[bucket.id] = { count: 0, label: bucket.label };
+ });
+
+ prodJobs.forEach((item) => {
+ const bucketId = CheckJobBucket(buckets, item);
+ if (bucketId) {
+ load.productionTotal[bucketId].count =
+ load.productionTotal[bucketId].count + 1;
+ } else {
+ console.log("Uh oh, this job doesn't fit in a bucket!", item);
+ }
+ });
arrJobs.forEach((item) => {
const itemDate = moment(item.scheduled_in).format("yyyy-MM-DD");
@@ -84,17 +100,23 @@ export function* calculateScheduleLoad({ payload: end }) {
}
if (day === 0) {
//Starting on day 1. The load is current.
- load[current].expectedLoad =
- load.productionHoursTotal +
- (load[current].hoursIn || 0) -
- (load[current].hoursOut || 0);
+ load[current].expectedLoad = CalculateLoad(
+ load.productionTotal,
+ buckets,
+ load[current].jobsIn || [],
+ load[current].jobsOut || []
+ );
} else {
- load[current].expectedLoad =
- load[prev].expectedLoad +
- (load[current].hoursIn || 0) -
- (load[current].hoursOut || 0);
+ load[current].expectedLoad = CalculateLoad(
+ load[prev].expectedLoad,
+ buckets,
+ load[current].jobsIn || [],
+ load[current].jobsOut || []
+ );
}
+ console.log(load);
}
+
yield put(scheduleLoadSuccess(load));
} catch (error) {
//console.log("Error in sendEmailFailure saga.", error.message);
diff --git a/client/src/utils/SSSUtils.js b/client/src/utils/SSSUtils.js
new file mode 100644
index 000000000..f64777fcc
--- /dev/null
+++ b/client/src/utils/SSSUtils.js
@@ -0,0 +1,42 @@
+export const CheckJobBucket = (buckets, job) => {
+ const jobHours =
+ job.labhrs.aggregate.sum.mod_lb_hrs + job.larhrs.aggregate.sum.mod_lb_hrs;
+
+ const matchingBucket = buckets.filter(
+ (b) => b.gte <= jobHours && b.lt > jobHours
+ );
+
+ return matchingBucket[0] && matchingBucket[0].id;
+};
+
+export const CalculateLoad = (currentLoad, buckets, jobsIn, jobsOut) => {
+ //Add the jobs coming
+ const newLoad = { ...currentLoad };
+ jobsIn.forEach((job) => {
+ const bucketId = CheckJobBucket(buckets, job);
+ if (bucketId) {
+ newLoad[bucketId].count = newLoad[bucketId].count + 1;
+ } else {
+ console.log(
+ "[Util Arr Job]Uh oh, this job doesn't fit in a bucket!",
+ job
+ );
+ }
+ });
+
+ jobsOut.forEach((job) => {
+ const bucketId = CheckJobBucket(buckets, job);
+ if (bucketId) {
+ newLoad[bucketId].count = newLoad[bucketId].count - 1;
+ } else {
+ console.log(
+ "[Util Arr Job]Uh oh, this job doesn't fit in a bucket!",
+ job
+ );
+ }
+ });
+
+ console.log("newLoad", newLoad);
+
+ return newLoad;
+};