From 5d1f61753b2ecc12d39eef8294ac11c9ce9e715e Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 7 Aug 2024 10:36:00 -0400 Subject: [PATCH] - Add Tasks to production board (and required refactors) Signed-off-by: Dave Richer --- ...ard-kanban-card-color-legend.component.jsx | 0 ...production-board-kanban-card.component.jsx | 20 +++++- .../production-board-kanban.component.jsx | 15 ++--- .../production-board-kanban.statistics.jsx | 62 ++++++++----------- .../settings/InformationSettings.jsx | 3 +- .../settings/defaultKanbanSettings.js | 25 +++++++- ...uction-board-kanban.settings.component.jsx | 29 +++++---- .../trello-board/controllers/Lane.jsx | 2 +- client/src/graphql/jobs.queries.js | 5 ++ client/src/translations/en_us/common.json | 8 ++- client/src/translations/es/common.json | 8 ++- client/src/translations/fr/common.json | 8 ++- 12 files changed, 121 insertions(+), 64 deletions(-) rename client/src/components/{production-board-kanban-card => production-board-kanban}/production-board-kanban-card-color-legend.component.jsx (100%) rename client/src/components/{production-board-kanban-card => production-board-kanban}/production-board-kanban-card.component.jsx (96%) diff --git a/client/src/components/production-board-kanban-card/production-board-kanban-card-color-legend.component.jsx b/client/src/components/production-board-kanban/production-board-kanban-card-color-legend.component.jsx similarity index 100% rename from client/src/components/production-board-kanban-card/production-board-kanban-card-color-legend.component.jsx rename to client/src/components/production-board-kanban/production-board-kanban-card-color-legend.component.jsx diff --git a/client/src/components/production-board-kanban-card/production-board-kanban-card.component.jsx b/client/src/components/production-board-kanban/production-board-kanban-card.component.jsx similarity index 96% rename from client/src/components/production-board-kanban-card/production-board-kanban-card.component.jsx rename to client/src/components/production-board-kanban/production-board-kanban-card.component.jsx index 4febb86c0..e3fe39ff8 100644 --- a/client/src/components/production-board-kanban-card/production-board-kanban-card.component.jsx +++ b/client/src/components/production-board-kanban/production-board-kanban-card.component.jsx @@ -290,6 +290,22 @@ const PartsStatusComponent = ({ metadata, cardSettings }) => ); +const TasksToolTip = ({ metadata, cardSettings, t }) => + cardSettings?.tasks && ( + + + {metadata.tasks_aggregate?.aggregate?.count ? ( + `T: ${metadata.tasks_aggregate.aggregate.count}` + ) : ( + T: 0 + )} + + + ); + export default function ProductionBoardCard({ technician, card, bodyshop, cardSettings, clone }) { const { t } = useTranslation(); const { metadata } = card; @@ -336,7 +352,8 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe cardSettings?.production_note || cardSettings?.partsstatus || cardSettings?.estimator || - cardSettings?.subtotal + cardSettings?.subtotal || + cardSettings?.tasks ); }, [cardSettings]); @@ -393,6 +410,7 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe employee_csr={employee_csr} /> + diff --git a/client/src/components/production-board-kanban/production-board-kanban.component.jsx b/client/src/components/production-board-kanban/production-board-kanban.component.jsx index afd0e94e1..62917e9bd 100644 --- a/client/src/components/production-board-kanban/production-board-kanban.component.jsx +++ b/client/src/components/production-board-kanban/production-board-kanban.component.jsx @@ -15,13 +15,13 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings"; import IndefiniteLoading from "../indefinite-loading/indefinite-loading.component"; import ProductionBoardFilters from "../production-board-filters/production-board-filters.component"; import ProductionListDetailComponent from "../production-list-detail/production-list-detail.component"; -import CardColorLegend from "../production-board-kanban-card/production-board-kanban-card-color-legend.component"; +import CardColorLegend from "./production-board-kanban-card-color-legend.component.jsx"; import "./production-board-kanban.styles.scss"; import { createBoardData } from "./production-board-kanban.utils.js"; import ProductionBoardKanbanSettings from "./settings/production-board-kanban.settings.component.jsx"; import cloneDeep from "lodash/cloneDeep"; import isEqual from "lodash/isEqual"; -import { defaultKanbanSettings } from "./settings/defaultKanbanSettings.js"; +import { mergeWithDefaults } from "./settings/defaultKanbanSettings.js"; import NoteUpsertModal from "../../components/note-upsert-modal/note-upsert-modal.container"; const mapStateToProps = createStructuredSelector({ @@ -182,13 +182,10 @@ function ProductionBoardKanbanComponent({ data, bodyshop, refetch, insertAuditTr [boardLanes, client, getCardByID, isMoving, t, insertAuditTrail] ); - const cardSettings = useMemo( - () => - associationSettings?.kanban_settings && Object.keys(associationSettings.kanban_settings).length > 0 - ? associationSettings.kanban_settings - : defaultKanbanSettings, - [associationSettings] - ); + const cardSettings = useMemo(() => { + const kanbanSettings = associationSettings?.kanban_settings; + return mergeWithDefaults(kanbanSettings); + }, [associationSettings]); const handleSettingsChange = useCallback((newSettings) => { setLoading(true); diff --git a/client/src/components/production-board-kanban/production-board-kanban.statistics.jsx b/client/src/components/production-board-kanban/production-board-kanban.statistics.jsx index 482ddb726..1af5ec59c 100644 --- a/client/src/components/production-board-kanban/production-board-kanban.statistics.jsx +++ b/client/src/components/production-board-kanban/production-board-kanban.statistics.jsx @@ -2,11 +2,13 @@ import React, { useMemo } from "react"; import { Card, Statistic } from "antd"; import { useTranslation } from "react-i18next"; import PropTypes from "prop-types"; -import { statisticsItems, defaultKanbanSettings } from "./settings/defaultKanbanSettings.js"; +import { defaultKanbanSettings, statisticsItems } from "./settings/defaultKanbanSettings.js"; + export const StatisticType = { HOURS: "hours", AMOUNT: "amount", - JOBS: "jobs" + JOBS: "jobs", + TASKS: "tasks" }; const mergeStatistics = (items, values) => { @@ -122,6 +124,20 @@ const ProductionStatistics = ({ data, cardSettings, reducerData }) => { return parseFloat(total.toFixed(2)); }, [reducerData, cardSettings.totalAmountOnBoard]); + const tasksInProduction = useMemo(() => { + if (!data || !cardSettings.tasksInProduction) return null; + return data.reduce((acc, item) => acc + (item.tasks_aggregate?.aggregate?.count || 0), 0); + }, [data, cardSettings.tasksInProduction]); + + const tasksOnBoard = useMemo(() => { + if (!reducerData || !cardSettings.tasksOnBoard) return null; + return reducerData.lanes.reduce((acc, lane) => { + return ( + acc + lane.cards.reduce((laneAcc, card) => laneAcc + (card.metadata.tasks_aggregate?.aggregate?.count || 0), 0) + ); + }, 0); + }, [reducerData, cardSettings.tasksOnBoard]); + const statistics = useMemo( () => mergeStatistics(statisticsItems, [ @@ -134,7 +150,9 @@ const ProductionStatistics = ({ data, cardSettings, reducerData }) => { { id: 6, value: totalAmountOnBoard, type: StatisticType.AMOUNT }, { id: 7, value: totalLABOnBoard, type: StatisticType.HOURS }, { id: 8, value: totalLAROnBoard, type: StatisticType.HOURS }, - { id: 9, value: jobsOnBoard, type: StatisticType.JOBS } + { id: 9, value: jobsOnBoard, type: StatisticType.JOBS }, + { id: 10, value: tasksOnBoard, type: StatisticType.TASKS }, + { id: 11, value: tasksInProduction, type: StatisticType.TASKS } ]), [ totalHrs, @@ -146,7 +164,9 @@ const ProductionStatistics = ({ data, cardSettings, reducerData }) => { totalAmountOnBoard, totalLABOnBoard, totalLAROnBoard, - jobsOnBoard + jobsOnBoard, + tasksOnBoard, + tasksInProduction ] ); @@ -187,37 +207,9 @@ const ProductionStatistics = ({ data, cardSettings, reducerData }) => { }; ProductionStatistics.propTypes = { - data: PropTypes.arrayOf( - PropTypes.shape({ - labhrs: PropTypes.object, - larhrs: PropTypes.object, - job_totals: PropTypes.object - }) - ).isRequired, - cardSettings: PropTypes.shape({ - totalHrs: PropTypes.bool, - totalLAB: PropTypes.bool, - totalLAR: PropTypes.bool, - jobsInProduction: PropTypes.bool, - totalAmountInProduction: PropTypes.bool, - totalHrsOnBoard: PropTypes.bool, - totalLABOnBoard: PropTypes.bool, - totalLAROnBoard: PropTypes.bool, - jobsOnBoard: PropTypes.bool, - totalAmountOnBoard: PropTypes.bool, - statisticsOrder: PropTypes.arrayOf(PropTypes.number) - }).isRequired, - reducerData: PropTypes.shape({ - lanes: PropTypes.arrayOf( - PropTypes.shape({ - cards: PropTypes.arrayOf( - PropTypes.shape({ - metadata: PropTypes.object - }) - ).isRequired - }) - ).isRequired - }) + data: PropTypes.array.isRequired, + cardSettings: PropTypes.object.isRequired, + reducerData: PropTypes.object }; export default ProductionStatistics; diff --git a/client/src/components/production-board-kanban/settings/InformationSettings.jsx b/client/src/components/production-board-kanban/settings/InformationSettings.jsx index c50f61697..3725d1ab8 100644 --- a/client/src/components/production-board-kanban/settings/InformationSettings.jsx +++ b/client/src/components/production-board-kanban/settings/InformationSettings.jsx @@ -18,7 +18,8 @@ const InformationSettings = ({ t }) => ( "sublets", "partsstatus", "estimator", - "subtotal" + "subtotal", + "tasks" ].map((item) => ( diff --git a/client/src/components/production-board-kanban/settings/defaultKanbanSettings.js b/client/src/components/production-board-kanban/settings/defaultKanbanSettings.js index ce0760637..0d10e4e39 100644 --- a/client/src/components/production-board-kanban/settings/defaultKanbanSettings.js +++ b/client/src/components/production-board-kanban/settings/defaultKanbanSettings.js @@ -8,7 +8,9 @@ const statisticsItems = [ { id: 6, name: "totalAmountOnBoard", label: "total_amount_on_board" }, { id: 7, name: "totalLABOnBoard", label: "total_lab_on_board" }, { id: 8, name: "totalLAROnBoard", label: "total_lar_on_board" }, - { id: 9, name: "jobsOnBoard", label: "total_jobs_on_board" } + { id: 9, name: "jobsOnBoard", label: "total_jobs_on_board" }, + { id: 10, name: "tasksOnBoard", label: "tasks_on_board" }, + { id: 11, name: "tasksInProduction", label: "tasks_in_production" } ]; const defaultKanbanSettings = { @@ -23,6 +25,7 @@ const defaultKanbanSettings = { scheduled_completion: true, cardcolor: false, orientation: false, + tasks: false, cardSize: "small", model_info: true, kiosk: false, @@ -35,6 +38,8 @@ const defaultKanbanSettings = { totalLABOnBoard: false, totalLAROnBoard: false, jobsOnBoard: false, + tasksOnBoard: false, + tasksInProduction: false, totalAmountOnBoard: true, estimator: false, subtotal: false, @@ -43,4 +48,20 @@ const defaultKanbanSettings = { selectedEstimators: [] }; -export { defaultKanbanSettings, statisticsItems }; +const mergeWithDefaults = (settings) => { + // Create a new object that starts with the default settings + const mergedSettings = { ...defaultKanbanSettings }; + + // Override with the provided settings, if any + if (settings) { + for (const key in settings) { + if (settings.hasOwnProperty(key)) { + mergedSettings[key] = settings[key]; + } + } + } + + return mergedSettings; +}; + +export { defaultKanbanSettings, statisticsItems, mergeWithDefaults }; diff --git a/client/src/components/production-board-kanban/settings/production-board-kanban.settings.component.jsx b/client/src/components/production-board-kanban/settings/production-board-kanban.settings.component.jsx index 38b0c9350..23da13412 100644 --- a/client/src/components/production-board-kanban/settings/production-board-kanban.settings.component.jsx +++ b/client/src/components/production-board-kanban/settings/production-board-kanban.settings.component.jsx @@ -3,13 +3,14 @@ import { Button, Card, Col, Form, notification, Popover, Row, Tabs } from "antd" import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { UPDATE_KANBAN_SETTINGS } from "../../../graphql/user.queries.js"; -import { defaultKanbanSettings } from "./defaultKanbanSettings.js"; +import { defaultKanbanSettings, mergeWithDefaults } from "./defaultKanbanSettings.js"; import LayoutSettings from "./LayoutSettings.jsx"; import InformationSettings from "./InformationSettings.jsx"; import StatisticsSettings from "./StatisticsSettings.jsx"; import FilterSettings from "./FilterSettings.jsx"; +import PropTypes from "prop-types"; -export default function ProductionBoardKanbanSettings({ associationSettings, parentLoading, bodyshop, data }) { +function ProductionBoardKanbanSettings({ associationSettings, parentLoading, bodyshop, data }) { const [form] = Form.useForm(); const [open, setOpen] = useState(false); const [loading, setLoading] = useState(false); @@ -23,16 +24,11 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par useEffect(() => { if (associationSettings?.kanban_settings) { - form.setFieldsValue(associationSettings.kanban_settings); - if (associationSettings.kanban_settings.statisticsOrder) { - setStatisticsOrder(associationSettings.kanban_settings.statisticsOrder); - } - if (associationSettings.kanban_settings.selectedMdInsCos) { - setSelectedMdInsCos(associationSettings.kanban_settings.selectedMdInsCos); - } - if (associationSettings.kanban_settings.selectedEstimators) { - setSelectedEstimators(associationSettings.kanban_settings.selectedEstimators); - } + const finalSettings = mergeWithDefaults(associationSettings.kanban_settings); + form.setFieldsValue(finalSettings); + setStatisticsOrder(finalSettings.statisticsOrder); + setSelectedMdInsCos(finalSettings.selectedMdInsCos); + setSelectedEstimators(finalSettings.selectedEstimators); } }, [form, associationSettings]); @@ -155,3 +151,12 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par ); } + +ProductionBoardKanbanSettings.propTypes = { + associationSettings: PropTypes.object, + parentLoading: PropTypes.func.isRequired, + bodyshop: PropTypes.object.isRequired, + data: PropTypes.array +}; + +export default ProductionBoardKanbanSettings; diff --git a/client/src/components/production-board-kanban/trello-board/controllers/Lane.jsx b/client/src/components/production-board-kanban/trello-board/controllers/Lane.jsx index 493812840..cd30952fb 100644 --- a/client/src/components/production-board-kanban/trello-board/controllers/Lane.jsx +++ b/client/src/components/production-board-kanban/trello-board/controllers/Lane.jsx @@ -12,7 +12,7 @@ import { EyeInvisibleOutlined, EyeOutlined } from "@ant-design/icons"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../../../redux/user/user.selectors.js"; import { selectTechnician } from "../../../../redux/tech/tech.selectors.js"; -import ProductionBoardCard from "../../../production-board-kanban-card/production-board-kanban-card.component.jsx"; +import ProductionBoardCard from "../../production-board-kanban-card.component.jsx"; import HeightMemoryWrapper from "../components/HeightMemoryWrapper.jsx"; import SizeMemoryWrapper from "../components/SizeMemoryWrapper.jsx"; import ListComponent from "../components/ListComponent.jsx"; diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index 51ff6927c..569936b7c 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -2465,6 +2465,11 @@ export const SUBSCRIPTION_JOBS_IN_PRODUCTION = gql` export const QUERY_JOBS_IN_PRODUCTION = gql` query QUERY_JOBS_IN_PRODUCTION { jobs(where: { inproduction: { _eq: true } }) { + tasks_aggregate(where: { completed: { _eq: false }, deleted: { _eq: false } }) { + aggregate { + count + } + } id updated_at comment diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index f3a95722e..f35baa1d8 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -2757,7 +2757,9 @@ "total_lab_on_board": "Body Hours on Board", "total_lar_on_board": "Refinish Hours on Board", "total_amount_on_board": "Dollars on Board", - "total_jobs_on_board": "Jobs on Board" + "total_jobs_on_board": "Jobs on Board", + "tasks_in_production": "Tasks in Production", + "tasks_on_board": "Tasks on Board" } }, "actions": { @@ -2792,6 +2794,7 @@ "model_info": "Vehicle Info", "actual_in": "Actual In", "alert": "Alert", + "tasks": "Tasks", "alertoff": "Remove alert from Job", "alerton": "Add alert to Job", "ats": "Alternative Transportation", @@ -2845,6 +2848,9 @@ "total_lar_on_board": "Refinish Hours on Board", "total_amount_on_board": "Dollars on Board", "total_jobs_on_board": "Jobs on Board", + "tasks_in_production": "Tasks in Production", + "tasks_on_board": "Tasks on Board", + "tasks": "Tasks", "hours": "Hours", "currency_symbol": "$", "jobs": "Jobs" diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 30cac520b..1d89e15ea 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -2757,7 +2757,9 @@ "total_lab_on_board": "", "total_lar_on_board": "", "total_amount_on_board": "", - "total_jobs_on_board": "" + "total_jobs_on_board": "", + "tasks_in_production": "", + "tasks_on_board": "" } }, "actions": { @@ -2792,6 +2794,7 @@ "model_info": "", "actual_in": "", "alert": "", + "tasks": "", "alertoff": "", "alerton": "", "ats": "", @@ -2845,6 +2848,9 @@ "total_lar_on_board": "", "total_amount_on_board": "", "total_jobs_on_board": "", + "tasks_in_production": "", + "tasks_on_board": "", + "tasks": "", "hours": "", "currency_symbol": "", "jobs": "" diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 967aa9003..4806de18c 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -2757,7 +2757,9 @@ "total_lab_on_board": "", "total_lar_on_board": "", "total_amount_on_board": "", - "total_jobs_on_board": "" + "total_jobs_on_board": "", + "tasks_in_production": "", + "tasks_on_board": "" } }, "actions": { @@ -2792,6 +2794,7 @@ "model_info": "", "actual_in": "", "alert": "", + "tasks": "", "alertoff": "", "alerton": "", "ats": "", @@ -2845,6 +2848,9 @@ "total_lar_on_board": "", "total_amount_on_board": "", "total_jobs_on_board": "", + "tasks_in_production": "", + "tasks_on_board": "", + "tasks": "", "hours": "", "currency_symbol": "", "jobs": ""