BOD-84 Added base calculations for schedule load
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
export function getRange(dateParam, viewParam) {
|
||||||
|
let start, end;
|
||||||
|
let date = dateParam || new Date();
|
||||||
|
let view = viewParam || "week";
|
||||||
|
// if view is day: from moment(date).startOf('day') to moment(date).endOf('day');
|
||||||
|
if (view === "day") {
|
||||||
|
start = moment(date).startOf("day");
|
||||||
|
end = moment(date).endOf("day");
|
||||||
|
}
|
||||||
|
// if view is week: from moment(date).startOf('isoWeek') to moment(date).endOf('isoWeek');
|
||||||
|
else if (view === "week") {
|
||||||
|
start = moment(date).startOf("week");
|
||||||
|
end = moment(date).endOf("week");
|
||||||
|
}
|
||||||
|
//if view is month: from moment(date).startOf('month').subtract(7, 'days') to moment(date).endOf('month').add(7, 'days'); i do additional 7 days math because you can see adjacent weeks on month view (that is the way how i generate my recurrent events for the Big Calendar, but if you need only start-end of month - just remove that math);
|
||||||
|
else if (view === "month") {
|
||||||
|
start = moment(date).startOf("month").subtract(7, "days");
|
||||||
|
end = moment(date).endOf("month").add(7, "days");
|
||||||
|
}
|
||||||
|
// if view is agenda: from moment(date).startOf('day') to moment(date).endOf('day').add(1, 'month');
|
||||||
|
else if (view === "agenda") {
|
||||||
|
start = moment(date).startOf("day");
|
||||||
|
end = moment(date).endOf("day").add(1, "month");
|
||||||
|
}
|
||||||
|
|
||||||
|
return { start, end };
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { Progress } from "antd";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Calendar, momentLocalizer } from "react-big-calendar";
|
import { Calendar, momentLocalizer } from "react-big-calendar";
|
||||||
import { useHistory, useLocation } from "react-router-dom";
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
import DateCellWrapper from "../schedule-datecellwrapper/schedule-datecellwrapper.component";
|
|
||||||
import Event from "../schedule-event/schedule-event.container";
|
import Event from "../schedule-event/schedule-event.container";
|
||||||
//import "react-big-calendar/lib/css/react-big-calendar.css";
|
//import "react-big-calendar/lib/css/react-big-calendar.css";
|
||||||
import "./schedule-calendar.styles.scss";
|
import "./schedule-calendar.styles.scss";
|
||||||
@@ -14,6 +14,7 @@ export default function ScheduleCalendarWrapperComponent({
|
|||||||
data,
|
data,
|
||||||
refetch,
|
refetch,
|
||||||
defaultView,
|
defaultView,
|
||||||
|
setDateRangeCallback,
|
||||||
...otherProps
|
...otherProps
|
||||||
}) {
|
}) {
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
@@ -22,12 +23,19 @@ export default function ScheduleCalendarWrapperComponent({
|
|||||||
return (
|
return (
|
||||||
<Calendar
|
<Calendar
|
||||||
events={data}
|
events={data}
|
||||||
defaultView={defaultView}
|
defaultView={search.view || defaultView || "week"}
|
||||||
date={new Date(search.date || Date.now())}
|
date={new Date(search.date || Date.now())}
|
||||||
onNavigate={(date, view, action) => {
|
onNavigate={(date, view, action) => {
|
||||||
search.date = date.toISOString().substr(0, 10);
|
search.date = date.toISOString().substr(0, 10);
|
||||||
history.push({ search: queryString.stringify(search) });
|
history.push({ search: queryString.stringify(search) });
|
||||||
}}
|
}}
|
||||||
|
onRangeChange={(start, end) => {
|
||||||
|
if (setDateRangeCallback) setDateRangeCallback({ start, end });
|
||||||
|
}}
|
||||||
|
onView={(view) => {
|
||||||
|
search.view = view;
|
||||||
|
history.push({ search: queryString.stringify(search) });
|
||||||
|
}}
|
||||||
step={30}
|
step={30}
|
||||||
showMultiDayTimes
|
showMultiDayTimes
|
||||||
localizer={localizer}
|
localizer={localizer}
|
||||||
@@ -35,7 +43,15 @@ export default function ScheduleCalendarWrapperComponent({
|
|||||||
max={new Date("2020-01-01T20:00:00")}
|
max={new Date("2020-01-01T20:00:00")}
|
||||||
components={{
|
components={{
|
||||||
event: (e) => Event({ event: e.event, refetch: refetch }),
|
event: (e) => Event({ event: e.event, refetch: refetch }),
|
||||||
dateCellWrapper: DateCellWrapper,
|
header: (props) => {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
<div>{props.label}</div>
|
||||||
|
<Progress style={{ flex: "1" }} percent={77} showInfo={false} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
//dateCellWrapper: DateCellWrapper,
|
||||||
}}
|
}}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -8,16 +8,15 @@ import { setModalContext } from "../../redux/modals/modals.actions";
|
|||||||
import ScheduleCalendarWrapperComponent from "../schedule-calendar-wrapper/scheduler-calendar-wrapper.component";
|
import ScheduleCalendarWrapperComponent from "../schedule-calendar-wrapper/scheduler-calendar-wrapper.component";
|
||||||
import ScheduleModal from "../schedule-job-modal/schedule-job-modal.container";
|
import ScheduleModal from "../schedule-job-modal/schedule-job-modal.container";
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
const mapDispatchToProps = dispatch => ({
|
setScheduleContext: (context) =>
|
||||||
setScheduleContext: context =>
|
dispatch(setModalContext({ context: context, modal: "schedule" })),
|
||||||
dispatch(setModalContext({ context: context, modal: "schedule" }))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export function ScheduleCalendarComponent({
|
export function ScheduleCalendarComponent({
|
||||||
data,
|
data,
|
||||||
refetch,
|
refetch,
|
||||||
setScheduleContext
|
setScheduleContext,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -36,8 +35,8 @@ export function ScheduleCalendarComponent({
|
|||||||
setScheduleContext({
|
setScheduleContext({
|
||||||
actions: { refetch: refetch },
|
actions: { refetch: refetch },
|
||||||
context: {
|
context: {
|
||||||
jobId: null
|
jobId: null,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -46,11 +45,7 @@ export function ScheduleCalendarComponent({
|
|||||||
|
|
||||||
<ScheduleModal />
|
<ScheduleModal />
|
||||||
|
|
||||||
<ScheduleCalendarWrapperComponent
|
<ScheduleCalendarWrapperComponent data={data} refetch={refetch} />
|
||||||
data={data}
|
|
||||||
defaultView="week"
|
|
||||||
refetch={refetch}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,33 @@
|
|||||||
import { useQuery } from "@apollo/react-hooks";
|
import { useQuery } from "@apollo/react-hooks";
|
||||||
|
import queryString from "query-string";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { useLocation } from "react-router-dom";
|
||||||
import { QUERY_ALL_ACTIVE_APPOINTMENTS } from "../../graphql/appointments.queries";
|
import { QUERY_ALL_ACTIVE_APPOINTMENTS } from "../../graphql/appointments.queries";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||||
|
import { getRange } from "../schedule-calendar-wrapper/schedule-calendar-util";
|
||||||
import ScheduleCalendarComponent from "./schedule-calendar.component";
|
import ScheduleCalendarComponent from "./schedule-calendar.component";
|
||||||
|
import { calculateScheduleLoad } from "../../redux/application/application.actions";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
//currentUser: selectCurrentUser
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
calculateScheduleLoad: (endDate) => dispatch(calculateScheduleLoad(endDate)),
|
||||||
|
});
|
||||||
|
|
||||||
export default function ScheduleCalendarContainer() {
|
export function ScheduleCalendarContainer({ calculateScheduleLoad }) {
|
||||||
|
const search = queryString.parse(useLocation().search);
|
||||||
|
|
||||||
|
const { date, view } = search;
|
||||||
|
const range = getRange(date, view);
|
||||||
const { loading, error, data, refetch } = useQuery(
|
const { loading, error, data, refetch } = useQuery(
|
||||||
QUERY_ALL_ACTIVE_APPOINTMENTS
|
QUERY_ALL_ACTIVE_APPOINTMENTS,
|
||||||
|
{
|
||||||
|
variables: { start: range.start.toDate(), end: range.end.toDate() },
|
||||||
|
skip: !!!range.start || !!!range.end,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (loading) return <LoadingSpinner />;
|
if (loading) return <LoadingSpinner />;
|
||||||
@@ -22,10 +42,32 @@ export default function ScheduleCalendarContainer() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log("ScheduleCalendarContainer -> normalizedData", normalizedData);
|
||||||
|
normalizedData.push({
|
||||||
|
id: 1,
|
||||||
|
title: "All day event",
|
||||||
|
allDay: true,
|
||||||
|
isintake: false,
|
||||||
|
start: new Date(),
|
||||||
|
end: new Date(),
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<ScheduleCalendarComponent
|
<span>
|
||||||
refetch={refetch}
|
<button
|
||||||
data={data ? normalizedData : null}
|
onClick={() => {
|
||||||
/>
|
calculateScheduleLoad(range.end);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Calc Load
|
||||||
|
</button>
|
||||||
|
<ScheduleCalendarComponent
|
||||||
|
refetch={refetch}
|
||||||
|
data={data ? normalizedData : null}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(ScheduleCalendarContainer);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export default function ScheduleDateCellWrapper(dateCellWrapperProps) {
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
borderLeft: "1px solid #DDD",
|
borderLeft: "1px solid #DDD",
|
||||||
backgroundColor: "#fff"
|
backgroundColor: "#fff",
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div style={style}>
|
<div style={style}>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Popover, Button } from "antd";
|
import { Popover, Button, Progress } from "antd";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
@@ -13,30 +13,30 @@ export default function ScheduleEventComponent({ event, handleCancel }) {
|
|||||||
<strong>{event.title}</strong>
|
<strong>{event.title}</strong>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<strong>{`${(event.job && event.job.ownr_fn) || ""} ${(event.job &&
|
<strong>{`${(event.job && event.job.ownr_fn) || ""} ${
|
||||||
event.job.ownr_ln) ||
|
(event.job && event.job.ownr_ln) || ""
|
||||||
""}`}</strong>
|
}`}</strong>
|
||||||
<span style={{ margin: 4 }}>
|
<span style={{ margin: 4 }}>
|
||||||
{`${(event.job && event.job.v_model_yr) ||
|
{`${(event.job && event.job.v_model_yr) || ""} ${
|
||||||
""} ${(event.job && event.job.v_make_desc) ||
|
(event.job && event.job.v_make_desc) || ""
|
||||||
""} ${(event.job && event.job.v_model_desc) || ""}`}
|
} ${(event.job && event.job.v_model_desc) || ""}`}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{event.job ? (
|
{event.job ? (
|
||||||
<div>
|
<div>
|
||||||
<div>{`${t("jobs.fields.ro_number")}: ${(event.job &&
|
<div>{`${t("jobs.fields.ro_number")}: ${
|
||||||
event.job.ro_number) ||
|
(event.job && event.job.ro_number) || ""
|
||||||
""}`}</div>
|
}`}</div>
|
||||||
<div>
|
<div>
|
||||||
{t("jobs.fields.clm_total")}:
|
{t("jobs.fields.clm_total")}:
|
||||||
<CurrencyFormatter>
|
<CurrencyFormatter>
|
||||||
{(event.job && event.job.clm_total) || ""}
|
{(event.job && event.job.clm_total) || ""}
|
||||||
</CurrencyFormatter>
|
</CurrencyFormatter>
|
||||||
</div>
|
</div>
|
||||||
<div>{`${t("jobs.fields.clm_no")}: ${(event.job &&
|
<div>{`${t("jobs.fields.clm_no")}: ${
|
||||||
event.job.clm_no) ||
|
(event.job && event.job.clm_no) || ""
|
||||||
""}`}</div>
|
}`}</div>
|
||||||
<div>
|
<div>
|
||||||
{t("jobs.fields.ownr_ea")}:{(event.job && event.job.ownr_ea) || ""}
|
{t("jobs.fields.ownr_ea")}:{(event.job && event.job.ownr_ea) || ""}
|
||||||
</div>
|
</div>
|
||||||
@@ -76,26 +76,31 @@ export default function ScheduleEventComponent({ event, handleCancel }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const RegularEvent = event.isintake ? (
|
||||||
|
<div>
|
||||||
|
<strong>{`${(event.job && event.job.ownr_fn) || ""} ${
|
||||||
|
(event.job && event.job.ownr_ln) || ""
|
||||||
|
}`}</strong>
|
||||||
|
<span style={{ margin: 4 }}>
|
||||||
|
{`${(event.job && event.job.v_model_yr) || ""} ${
|
||||||
|
(event.job && event.job.v_make_desc) || ""
|
||||||
|
} ${(event.job && event.job.v_model_desc) || ""}`}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<strong>{`${event.title || ""}`}</strong>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const Load = (
|
||||||
|
<div className="load">
|
||||||
|
<Progress percent={77} showInfo={false} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<Popover content={popoverContent}>
|
<Popover content={popoverContent}>
|
||||||
<div>
|
<div>{event.allDay ? Load : RegularEvent}</div>
|
||||||
{event.isintake ? (
|
|
||||||
<div>
|
|
||||||
<strong>{`${(event.job && event.job.ownr_fn) || ""} ${(event.job &&
|
|
||||||
event.job.ownr_ln) ||
|
|
||||||
""}`}</strong>
|
|
||||||
<span style={{ margin: 4 }}>
|
|
||||||
{`${(event.job && event.job.v_model_yr) ||
|
|
||||||
""} ${(event.job && event.job.v_make_desc) ||
|
|
||||||
""} ${(event.job && event.job.v_model_desc) || ""}`}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>
|
|
||||||
<strong>{`${event.title || ""}`}</strong>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||||
|
|
||||||
export default function ScheduleExistingAppointmentsList({
|
export default function ScheduleExistingAppointmentsList({
|
||||||
existingAppointments
|
existingAppointments,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
if (existingAppointments.loading) return <LoadingSpinner />;
|
if (existingAppointments.loading) return <LoadingSpinner />;
|
||||||
@@ -22,22 +22,26 @@ export default function ScheduleExistingAppointmentsList({
|
|||||||
<div>
|
<div>
|
||||||
{t("appointments.labels.priorappointments")}
|
{t("appointments.labels.priorappointments")}
|
||||||
<Timeline>
|
<Timeline>
|
||||||
{existingAppointments.data.appointments.map(item => {
|
{existingAppointments.data
|
||||||
return (
|
? existingAppointments.data.appointments.map((item) => {
|
||||||
<Timeline.Item
|
return (
|
||||||
key={item.id}
|
<Timeline.Item
|
||||||
color={item.canceled ? "red" : item.arrived ? "green" : "blue"}
|
key={item.id}
|
||||||
>
|
color={
|
||||||
{item.canceled
|
item.canceled ? "red" : item.arrived ? "green" : "blue"
|
||||||
? t("appointments.labels.cancelledappointment")
|
}
|
||||||
: item.arrived
|
>
|
||||||
? t("appointments.labels.arrivedon")
|
{item.canceled
|
||||||
: t("appointments.labels.scheduledfor")}
|
? t("appointments.labels.cancelledappointment")
|
||||||
|
: item.arrived
|
||||||
|
? t("appointments.labels.arrivedon")
|
||||||
|
: t("appointments.labels.scheduledfor")}
|
||||||
|
|
||||||
<DateTimeFormatter>{item.start}</DateTimeFormatter>
|
<DateTimeFormatter>{item.start}</DateTimeFormatter>
|
||||||
</Timeline.Item>
|
</Timeline.Item>
|
||||||
);
|
);
|
||||||
})}
|
})
|
||||||
|
: null}
|
||||||
</Timeline>
|
</Timeline>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export function ScheduleJobModalContainer({
|
|||||||
const existingAppointments = useQuery(QUERY_APPOINTMENTS_BY_JOBID, {
|
const existingAppointments = useQuery(QUERY_APPOINTMENTS_BY_JOBID, {
|
||||||
variables: { jobid: jobId },
|
variables: { jobid: jobId },
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
skip: !visible,
|
skip: !visible || !!!jobId,
|
||||||
});
|
});
|
||||||
|
|
||||||
//TODO Customize the amount of minutes it will add.
|
//TODO Customize the amount of minutes it will add.
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
|
|
||||||
export const QUERY_ALL_ACTIVE_APPOINTMENTS = gql`
|
export const QUERY_ALL_ACTIVE_APPOINTMENTS = gql`
|
||||||
query QUERY_ALL_ACTIVE_APPOINTMENTS {
|
query QUERY_ALL_ACTIVE_APPOINTMENTS(
|
||||||
appointments(where: { canceled: { _eq: false } }) {
|
$start: timestamptz!
|
||||||
|
$end: timestamptz!
|
||||||
|
) {
|
||||||
|
appointments(
|
||||||
|
where: {
|
||||||
|
canceled: { _eq: false }
|
||||||
|
end: { _lte: $end }
|
||||||
|
start: { _gte: $start }
|
||||||
|
}
|
||||||
|
) {
|
||||||
start
|
start
|
||||||
id
|
id
|
||||||
end
|
end
|
||||||
@@ -11,18 +20,16 @@ export const QUERY_ALL_ACTIVE_APPOINTMENTS = gql`
|
|||||||
job {
|
job {
|
||||||
ro_number
|
ro_number
|
||||||
ownr_ln
|
ownr_ln
|
||||||
|
ownr_co_nm
|
||||||
ownr_fn
|
ownr_fn
|
||||||
ownr_ph1
|
ownr_ph1
|
||||||
ownr_ea
|
ownr_ea
|
||||||
clm_total
|
clm_total
|
||||||
id
|
id
|
||||||
clm_no
|
clm_no
|
||||||
vehicle {
|
v_model_yr
|
||||||
id
|
v_make_desc
|
||||||
v_model_yr
|
v_model_desc
|
||||||
v_make_desc
|
|
||||||
v_model_desc
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,3 +101,53 @@ export const QUERY_APPOINTMENTS_BY_JOBID = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
export const QUERY_SCHEDULE_LOAD_DATA = gql`
|
||||||
|
query QUERY_SCHEDULE_LOAD_DATA($start: timestamptz!, $end: timestamptz!) {
|
||||||
|
productionview_aggregate {
|
||||||
|
aggregate {
|
||||||
|
sum {
|
||||||
|
larhrs
|
||||||
|
labhrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compJobs: jobs(
|
||||||
|
where: { scheduled_completion: { _gte: $start, _lte: $end } }
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
scheduled_completion
|
||||||
|
labhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAB" } }) {
|
||||||
|
aggregate {
|
||||||
|
sum {
|
||||||
|
mod_lb_hrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
larhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAR" } }) {
|
||||||
|
aggregate {
|
||||||
|
sum {
|
||||||
|
mod_lb_hrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arrJobs: jobs(where: { scheduled_in: { _gte: $start, _lte: $end } }) {
|
||||||
|
id
|
||||||
|
scheduled_in
|
||||||
|
labhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAB" } }) {
|
||||||
|
aggregate {
|
||||||
|
sum {
|
||||||
|
mod_lb_hrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
larhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAR" } }) {
|
||||||
|
aggregate {
|
||||||
|
sum {
|
||||||
|
mod_lb_hrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -13,3 +13,8 @@ export const setBreadcrumbs = (breadcrumbs) => ({
|
|||||||
type: ApplicationActionTypes.SET_BREAD_CRUMBS,
|
type: ApplicationActionTypes.SET_BREAD_CRUMBS,
|
||||||
payload: breadcrumbs,
|
payload: breadcrumbs,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const calculateScheduleLoad = (rangeEnd) => ({
|
||||||
|
type: ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD,
|
||||||
|
payload: rangeEnd,
|
||||||
|
});
|
||||||
|
|||||||
@@ -3,10 +3,43 @@ import ApplicationActionTypes from "./application.types";
|
|||||||
const INITIAL_STATE = {
|
const INITIAL_STATE = {
|
||||||
loading: false,
|
loading: false,
|
||||||
breadcrumbs: [],
|
breadcrumbs: [],
|
||||||
|
scheduleLoad: {
|
||||||
|
load: [],
|
||||||
|
calculating: false,
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const applicationReducer = (state = INITIAL_STATE, action) => {
|
const applicationReducer = (state = INITIAL_STATE, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case ApplicationActionTypes.SET_BREAD_CRUMBS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
breadcrumbs: action.payload,
|
||||||
|
};
|
||||||
|
case ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
scheduleLoad: { ...state.scheduleLoad, calculating: true, error: null },
|
||||||
|
};
|
||||||
|
case ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
scheduleLoad: {
|
||||||
|
...state.scheduleLoad,
|
||||||
|
load: action.payload,
|
||||||
|
calculating: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD_FAILURE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
scheduleLoad: {
|
||||||
|
...state.scheduleLoad,
|
||||||
|
calculating: false,
|
||||||
|
error: action.payload,
|
||||||
|
},
|
||||||
|
};
|
||||||
case ApplicationActionTypes.START_LOADING:
|
case ApplicationActionTypes.START_LOADING:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@@ -17,11 +50,7 @@ const applicationReducer = (state = INITIAL_STATE, action) => {
|
|||||||
...state,
|
...state,
|
||||||
loading: false,
|
loading: false,
|
||||||
};
|
};
|
||||||
case ApplicationActionTypes.SET_BREAD_CRUMBS:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
breadcrumbs: action.payload,
|
|
||||||
};
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,87 @@
|
|||||||
import { all } from "redux-saga/effects";
|
import { all, takeLatest, call } from "redux-saga/effects";
|
||||||
|
import ApplicationActionTypes from "./application.types";
|
||||||
|
import { client } from "../../App/App.container";
|
||||||
|
import { QUERY_SCHEDULE_LOAD_DATA } from "../../graphql/appointments.queries";
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
// export function* onSendEmail() {
|
export function* onCalculateScheduleLoad() {
|
||||||
// yield takeLatest(EmailActionTypes.SEND_EMAIL, sendEmail);
|
yield takeLatest(
|
||||||
// }
|
ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD,
|
||||||
// export function* sendEmail(payload) {
|
calculateScheduleLoad
|
||||||
// try {
|
);
|
||||||
// console.log("Sending thta email", payload);
|
}
|
||||||
// axios.post("/sendemail", payload).then(response => {
|
export function* calculateScheduleLoad({ payload: end }) {
|
||||||
// console.log(JSON.stringify(response));
|
const today = moment(new Date()).startOf("day");
|
||||||
// put(sendEmailSuccess());
|
try {
|
||||||
// });
|
const result = yield client.query({
|
||||||
// } catch (error) {
|
query: QUERY_SCHEDULE_LOAD_DATA,
|
||||||
// console.log("Error in sendEmail saga.");
|
variables: {
|
||||||
// yield put(sendEmailFailure(error.message));
|
start: today,
|
||||||
// }
|
end: end,
|
||||||
// }
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// export function* onSendEmailSuccess() {
|
const productionHoursTotal =
|
||||||
// yield takeLatest(EmailActionTypes.SEND_EMAIL_SUCCESS, sendEmailSuccessSaga);
|
result.data.productionview_aggregate.aggregate.sum.larhrs +
|
||||||
// }
|
result.data.productionview_aggregate.aggregate.sum.labhrs;
|
||||||
// export function* sendEmailSuccessSaga() {
|
|
||||||
// try {
|
|
||||||
// console.log("Send email success.");
|
|
||||||
// } catch (error) {
|
|
||||||
// console.log("Error in sendEmailSuccess saga.");
|
|
||||||
// yield put(sendEmailFailure(error.message));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export function* onRenderTemplate() {
|
const range = Math.round(moment.duration(end.diff(today)).asDays());
|
||||||
// yield takeLatest(ApplicationActionTypes.RENDER_TEMPLATE, renderTemplate);
|
let load = {};
|
||||||
// }
|
|
||||||
// export function* renderTemplate({ payload: template }) {
|
//Start from today and go until the range.
|
||||||
// try {
|
// for (var day = 0; day < range; day++) {
|
||||||
// yield console.log("Render Template Saga => template", template);
|
// let workingDate = today.add(day, "days");
|
||||||
// } catch (error) {
|
// console.log(
|
||||||
// console.log("Error in sendEmailFailure saga.", error.message);
|
// "function*calculateScheduleLoad -> workingDate",
|
||||||
// }
|
// workingDate.toLocaleString()
|
||||||
// }
|
// );
|
||||||
|
// }
|
||||||
|
const { arrJobs, compJobs } = result.data;
|
||||||
|
|
||||||
|
arrJobs.forEach((item) => {
|
||||||
|
const itemDate = moment(item.scheduled_in).toISOString().substr(0, 10);
|
||||||
|
if (!!load[itemDate]) {
|
||||||
|
load[itemDate].hoursIn =
|
||||||
|
(load[itemDate].hoursIn || 0) +
|
||||||
|
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||||
|
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||||
|
} else {
|
||||||
|
load[itemDate] = {
|
||||||
|
hoursIn:
|
||||||
|
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||||
|
item.larhrs.aggregate.sum.mod_lb_hrs,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
compJobs.forEach((item) => {
|
||||||
|
const itemDate = moment(item.scheduled_completion)
|
||||||
|
.toISOString()
|
||||||
|
.substr(0, 10);
|
||||||
|
if (!!load[itemDate]) {
|
||||||
|
load[itemDate].hoursOut =
|
||||||
|
(load[itemDate].hoursOut || 0) +
|
||||||
|
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||||
|
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||||
|
} else {
|
||||||
|
load[itemDate] = {
|
||||||
|
hoursOut:
|
||||||
|
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||||
|
item.larhrs.aggregate.sum.mod_lb_hrs,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("load", load);
|
||||||
|
} catch (error) {
|
||||||
|
//console.log("Error in sendEmailFailure saga.", error.message);
|
||||||
|
console.log("error", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function* applicationSagas() {
|
export function* applicationSagas() {
|
||||||
yield all([
|
yield all([
|
||||||
// call(onSendEmail),
|
call(onCalculateScheduleLoad),
|
||||||
// call(onSendEmailFailure),
|
// call(onSendEmailFailure),
|
||||||
// call(onSendEmailSuccess)
|
// call(onSendEmailSuccess)
|
||||||
//call(onRenderTemplate),
|
//call(onRenderTemplate),
|
||||||
|
|||||||
@@ -11,3 +11,13 @@ export const selectBreadcrumbs = createSelector(
|
|||||||
[selectApplication],
|
[selectApplication],
|
||||||
(application) => application.breadcrumbs
|
(application) => application.breadcrumbs
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectScheduleLoad = createSelector(
|
||||||
|
[selectApplication],
|
||||||
|
(application) => application.scheduleLoad.load
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectScheduleLoadCalculating = createSelector(
|
||||||
|
[selectApplication],
|
||||||
|
(application) => application.scheduleLoad.calculating
|
||||||
|
);
|
||||||
|
|||||||
@@ -2,5 +2,8 @@ const ApplicationActionTypes = {
|
|||||||
START_LOADING: "START_LOADING",
|
START_LOADING: "START_LOADING",
|
||||||
END_LOADING: "END_LOADING",
|
END_LOADING: "END_LOADING",
|
||||||
SET_BREAD_CRUMBS: "SET_BREAD_CRUMBS",
|
SET_BREAD_CRUMBS: "SET_BREAD_CRUMBS",
|
||||||
|
CALCULATE_SCHEDULE_LOAD: "CALCULATE_SCHEDULE_LOAD",
|
||||||
|
CALCULATE_SCHEDULE_LOAD_SUCCESS: "CALCULATE_SCHEDULE_LOAD_SUCCESS",
|
||||||
|
CALCULATE_SCHEDULE_LOAD_FAILURE: "CALCULATE_SCHEDULE_LOAD_FAILURE",
|
||||||
};
|
};
|
||||||
export default ApplicationActionTypes;
|
export default ApplicationActionTypes;
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
- args:
|
||||||
|
role: user
|
||||||
|
table:
|
||||||
|
name: productionview
|
||||||
|
schema: public
|
||||||
|
type: drop_select_permission
|
||||||
|
- args:
|
||||||
|
permission:
|
||||||
|
allow_aggregations: false
|
||||||
|
columns:
|
||||||
|
- id
|
||||||
|
- status
|
||||||
|
- ro_number
|
||||||
|
- est_number
|
||||||
|
- ownr_fn
|
||||||
|
- ownr_ln
|
||||||
|
- v_model_yr
|
||||||
|
- v_model_desc
|
||||||
|
- clm_no
|
||||||
|
- v_make_desc
|
||||||
|
- v_color
|
||||||
|
- plate_no
|
||||||
|
- actual_in
|
||||||
|
- scheduled_completion
|
||||||
|
- scheduled_delivery
|
||||||
|
- ins_co_nm
|
||||||
|
- clm_total
|
||||||
|
- ownr_ph1
|
||||||
|
- special_coverage_policy
|
||||||
|
- production_vars
|
||||||
|
- labhrs
|
||||||
|
- larhrs
|
||||||
|
- shopid
|
||||||
|
- partcount
|
||||||
|
computed_fields: []
|
||||||
|
filter:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
role: user
|
||||||
|
table:
|
||||||
|
name: productionview
|
||||||
|
schema: public
|
||||||
|
type: create_select_permission
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
- args:
|
||||||
|
role: user
|
||||||
|
table:
|
||||||
|
name: productionview
|
||||||
|
schema: public
|
||||||
|
type: drop_select_permission
|
||||||
|
- args:
|
||||||
|
permission:
|
||||||
|
allow_aggregations: true
|
||||||
|
columns:
|
||||||
|
- id
|
||||||
|
- status
|
||||||
|
- ro_number
|
||||||
|
- est_number
|
||||||
|
- ownr_fn
|
||||||
|
- ownr_ln
|
||||||
|
- v_model_yr
|
||||||
|
- v_model_desc
|
||||||
|
- clm_no
|
||||||
|
- v_make_desc
|
||||||
|
- v_color
|
||||||
|
- plate_no
|
||||||
|
- actual_in
|
||||||
|
- scheduled_completion
|
||||||
|
- scheduled_delivery
|
||||||
|
- ins_co_nm
|
||||||
|
- clm_total
|
||||||
|
- ownr_ph1
|
||||||
|
- special_coverage_policy
|
||||||
|
- production_vars
|
||||||
|
- labhrs
|
||||||
|
- larhrs
|
||||||
|
- shopid
|
||||||
|
- partcount
|
||||||
|
computed_fields: []
|
||||||
|
filter:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
role: user
|
||||||
|
table:
|
||||||
|
name: productionview
|
||||||
|
schema: public
|
||||||
|
type: create_select_permission
|
||||||
@@ -2978,6 +2978,7 @@ tables:
|
|||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
- active:
|
- active:
|
||||||
_eq: true
|
_eq: true
|
||||||
|
allow_aggregations: true
|
||||||
- table:
|
- table:
|
||||||
schema: public
|
schema: public
|
||||||
name: templates
|
name: templates
|
||||||
|
|||||||
Reference in New Issue
Block a user