From 914a7e3c7b16e75e89b07070474ea0710189cf51 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Wed, 16 Jun 2021 10:51:53 -0700 Subject: [PATCH] IO-306 Dashboard monthly employee efficiency --- bodyshop_translations.babel | 21 +++ .../monthly-employee-efficiency.component.jsx | 166 ++++++++++++++++++ .../total-production-hours.component.jsx | 12 +- .../dashboard-grid.component.jsx | 27 ++- .../components/header/header.component.jsx | 4 +- .../jobs-create-jobs-info.component.jsx | 22 ++- ...chedule-calendar-header-graph.component.js | 2 +- .../jobs-create/jobs-create.container.jsx | 3 + client/src/translations/en_us/common.json | 7 +- client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + 11 files changed, 250 insertions(+), 16 deletions(-) create mode 100644 client/src/components/dashboard-components/monthly-employee-efficiency/monthly-employee-efficiency.component.jsx diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 042ad7c33..3858948d7 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -10689,6 +10689,27 @@ titles + + monthlyemployeeefficiency + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + monthlyjobcosting false diff --git a/client/src/components/dashboard-components/monthly-employee-efficiency/monthly-employee-efficiency.component.jsx b/client/src/components/dashboard-components/monthly-employee-efficiency/monthly-employee-efficiency.component.jsx new file mode 100644 index 000000000..e90220698 --- /dev/null +++ b/client/src/components/dashboard-components/monthly-employee-efficiency/monthly-employee-efficiency.component.jsx @@ -0,0 +1,166 @@ +import { Card } from "antd"; +import _ from "lodash"; +import moment from "moment"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import { + Bar, + CartesianGrid, + ComposedChart, + Legend, + Line, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from "recharts"; +import * as Utils from "../../scoreboard-targets-table/scoreboard-targets-table.util"; +import DashboardRefreshRequired from "../refresh-required.component"; + +export default function DashboardMonthlyEmployeeEfficiency({ + data, + ...cardProps +}) { + const { t } = useTranslation(); + if (!data) return null; + if (!data.monthly_employee_efficiency) + return ; + + const ticketsByDate = _.groupBy(data.monthly_employee_efficiency, (item) => + moment(item.date).format("YYYY-MM-DD") + ); + + const listOfDays = Utils.ListOfDaysInCurrentMonth(); + + const chartData = listOfDays.reduce((acc, val) => { + //Sum up the current day. + let dailyHrs; + if (!!ticketsByDate[val]) { + dailyHrs = ticketsByDate[val].reduce( + (dayAcc, dayVal) => { + return { + actual: dayAcc.actual + dayVal.actualhrs, + productive: dayAcc.actual + dayVal.productivehrs, + }; + }, + { actual: 0, productive: 0 } + ); + } else { + dailyHrs = { actual: 0, productive: 0 }; + } + + const dailyEfficiency = + ((dailyHrs.productive - dailyHrs.actual) / dailyHrs.productive + 1) * 100; + + const theValue = { + date: moment(val).format("DD"), + ...dailyHrs, + dailyEfficiency: isNaN(dailyEfficiency) ? 0 : dailyEfficiency.toFixed(1), + accActual: + acc.length > 0 + ? acc[acc.length - 1].accActual + dailyHrs.actual + : dailyHrs.actual, + + accProductive: + acc.length > 0 + ? acc[acc.length - 1].accProductive + dailyHrs.productive + : dailyHrs.productive, + accEfficiency: 0, + }; + theValue.accEfficiency = ( + ((theValue.accProductive - theValue.accActual) / + (theValue.accProductive || 1) + + 1) * + 100 + ).toFixed(1); + + return [...acc, theValue]; + }, []); + + return ( + +
+ + + + + + + + + + + + + + +
+
+ ); +} + +export const DashboardMonthlyEmployeeEfficiencyGql = ` + monthly_employee_efficiency: timetickets(where: {_and: [{date: {_gte: "${moment() + .startOf("month") + .format("YYYY-MM-DD")}"}},{date: {_lte: "${moment() + .endOf("month") + .format("YYYY-MM-DD")}"}} ]}) { + actualhrs + productivehrs + employeeid + employee { + first_name + last_name + } + date + } +`; diff --git a/client/src/components/dashboard-components/total-production-hours/total-production-hours.component.jsx b/client/src/components/dashboard-components/total-production-hours/total-production-hours.component.jsx index 81a852400..9cdf7fc68 100644 --- a/client/src/components/dashboard-components/total-production-hours/total-production-hours.component.jsx +++ b/client/src/components/dashboard-components/total-production-hours/total-production-hours.component.jsx @@ -42,11 +42,17 @@ export function DashboardTotalProductionHours({ return ( - - + + diff --git a/client/src/components/dashboard-grid/dashboard-grid.component.jsx b/client/src/components/dashboard-grid/dashboard-grid.component.jsx index b7fa83049..6b87d0d7a 100644 --- a/client/src/components/dashboard-grid/dashboard-grid.component.jsx +++ b/client/src/components/dashboard-grid/dashboard-grid.component.jsx @@ -1,6 +1,7 @@ import Icon, { SyncOutlined } from "@ant-design/icons"; import { gql, useMutation, useQuery } from "@apollo/client"; import { Button, Dropdown, Menu, notification, PageHeader, Space } from "antd"; +import i18next from "i18next"; import _ from "lodash"; import moment from "moment"; import React, { useState } from "react"; @@ -16,6 +17,9 @@ import { selectCurrentUser, } from "../../redux/user/user.selectors"; import AlertComponent from "../alert/alert.component"; +import DashboardMonthlyEmployeeEfficiency, { + DashboardMonthlyEmployeeEfficiencyGql, +} from "../dashboard-components/monthly-employee-efficiency/monthly-employee-efficiency.component"; import DashboardMonthlyJobCosting from "../dashboard-components/monthly-job-costing/monthly-job-costing.component"; import DashboardMonthlyLaborSales from "../dashboard-components/monthly-labor-sales/monthly-labor-sales.component"; import DashboardMonthlyPartsSales from "../dashboard-components/monthly-parts-sales/monthly-parts-sales.component"; @@ -195,7 +199,7 @@ export default connect( const componentList = { ProductionDollars: { - label: "Production Dollars", + label: i18next.t("dashboard.titles.productiondollars"), component: DashboardTotalProductionDollars, gqlFragment: null, w: 1, @@ -204,7 +208,7 @@ const componentList = { minH: 1, }, ProductionHours: { - label: "Production Hours", + label: i18next.t("dashboard.titles.productionhours"), component: DashboardTotalProductionHours, gqlFragment: DashboardTotalProductionHoursGql, w: 3, @@ -213,7 +217,7 @@ const componentList = { minH: 1, }, ProjectedMonthlySales: { - label: "Projected Monthly Sales", + label: i18next.t("dashboard.titles.projectedmonthlysales"), component: DashboardProjectedMonthlySales, gqlFragment: DashboardProjectedMonthlySalesGql, w: 2, @@ -222,7 +226,7 @@ const componentList = { minH: 1, }, MonthlyRevenueGraph: { - label: "Monthly Sales Graph", + label: i18next.t("dashboard.titles.monthlyrevenuegraph"), component: DashboardMonthlyRevenueGraph, gqlFragment: DashboardMonthlyRevenueGraphGql, w: 4, @@ -231,7 +235,7 @@ const componentList = { minH: 2, }, MonthlyJobCosting: { - label: "Monthly Job Costing", + label: i18next.t("dashboard.titles.monthlyjobcosting"), component: DashboardMonthlyJobCosting, gqlFragment: null, minW: 6, @@ -240,7 +244,7 @@ const componentList = { h: 3, }, MonthlyPartsSales: { - label: "Monthly Parts Sales", + label: i18next.t("dashboard.titles.productiondollars"), component: DashboardMonthlyPartsSales, gqlFragment: null, minW: 2, @@ -249,7 +253,7 @@ const componentList = { h: 2, }, MonthlyLaborSales: { - label: "Monthly Parts Sales", + label: i18next.t("dashboard.titles.monthlypartssales"), component: DashboardMonthlyLaborSales, gqlFragment: null, minW: 2, @@ -257,6 +261,15 @@ const componentList = { w: 2, h: 2, }, + MonthlyEmployeeEfficency: { + label: i18next.t("dashboard.titles.monthlyemployeeefficiency"), + component: DashboardMonthlyEmployeeEfficiency, + gqlFragment: DashboardMonthlyEmployeeEfficiencyGql, + minW: 2, + minH: 2, + w: 2, + h: 2, + }, }; const createDashboardQuery = (state) => { diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx index 5069e3df6..f1004f4f4 100644 --- a/client/src/components/header/header.component.jsx +++ b/client/src/components/header/header.component.jsx @@ -317,7 +317,9 @@ function Header({ window.open("https://help.imex.online/", "_blank"); }} icon={} - /> + > + {t("menus.header.help")} + { diff --git a/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx b/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx index 95bad7368..e99a109c4 100644 --- a/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx +++ b/client/src/components/jobs-create-jobs-info/jobs-create-jobs-info.component.jsx @@ -1,4 +1,4 @@ -import { Collapse, Form, Input, Select, Switch } from "antd"; +import { Collapse, Form, Input, InputNumber, Select, Switch } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -240,6 +240,26 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) { + + + + + + + + + + + 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 index f80c0118a..e3a48640c 100644 --- 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 @@ -53,7 +53,7 @@ export function ScheduleCalendarHeaderGraph({ bodyshop, loadData }) { name="Ideal Load" dataKey="target" stroke="darkgreen" - fill="whitr" + fill="white" fillOpacity={0} />