import { SyncOutlined } from "@ant-design/icons"; import { useApolloClient } from "@apollo/client"; import Board from "./trello-board/index"; import { Button, notification, Skeleton, Space, Statistic } from "antd"; import { PageHeader } from "@ant-design/pro-layout"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { logImEXEvent } from "../../firebase/firebase.utils"; import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries"; import { insertAuditTrail } from "../../redux/application/application.actions"; import { selectBodyshop } from "../../redux/user/user.selectors"; 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 "./production-board-kanban.styles.scss"; import { createBoardData } from "./production-board-kanban.utils.js"; import ProductionBoardKanbanSettings from "./production-board-kanban.settings.component.jsx"; import cloneDeep from "lodash/cloneDeep"; import isEqual from "lodash/isEqual"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop }); const mapDispatchToProps = (dispatch) => ({ insertAuditTrail: ({ jobid, operation, type }) => dispatch( insertAuditTrail({ jobid, operation, type }) ) }); export function ProductionBoardKanbanComponent({ data, bodyshop, refetch, insertAuditTrail, associationSettings }) { const [boardLanes, setBoardLanes] = useState({ lanes: [] }); const [filter, setFilter] = useState({ search: "", employeeId: null }); const [loading, setLoading] = useState(true); const [isMoving, setIsMoving] = useState(false); const [orientation, setOrientation] = useState("vertical"); const { t } = useTranslation(); useEffect(() => { if (associationSettings) { setLoading(false); setOrientation(associationSettings?.kanban_settings?.orientation ? "vertical" : "horizontal"); } }, [associationSettings]); useEffect(() => { const newBoardData = createBoardData( [...bodyshop.md_ro_statuses.production_statuses, ...(bodyshop.md_ro_statuses.additional_board_statuses || [])], data, filter ); newBoardData.lanes = newBoardData.lanes.map((lane) => ({ ...lane, title: `${lane.title} (${lane.cards.length})` })); setBoardLanes((prevBoardLanes) => { const deepClonedData = cloneDeep(newBoardData); if (!isEqual(prevBoardLanes, deepClonedData)) { return deepClonedData; } return prevBoardLanes; }); setIsMoving(false); }, [data, bodyshop.md_ro_statuses, filter]); const client = useApolloClient(); const getCardByID = useCallback((data, cardId) => { for (const lane of data.lanes) { for (const card of lane.cards) { if (card.id === cardId) { return card; } } } return null; }, []); const onDragEnd = useCallback( async ({ type, source, destination, draggableId }) => { logImEXEvent("kanban_drag_end"); if (!type || type !== "lane" || !source || !destination || isMoving) return; setIsMoving(true); const targetLane = boardLanes.lanes.find((lane) => lane.id === destination.droppableId); const sourceLane = boardLanes.lanes.find((lane) => lane.id === source.droppableId); const sameColumnTransfer = source.droppableId === destination.droppableId; const sourceCard = getCardByID(boardLanes, draggableId); const movedCardWillBeFirst = destination.index === 0; const movedCardWillBeLast = destination.index > targetLane.cards.length - 1; const lastCardInTargetLane = targetLane.cards[targetLane.cards.length - 1]; const oldChildCard = sourceLane.cards[destination.index + 1]; const newChildCard = movedCardWillBeLast ? null : targetLane.cards[ sameColumnTransfer ? destination.index - destination.index > 0 ? destination.index : destination.index + 1 : destination.index ]; const oldChildCardNewParent = oldChildCard ? sourceCard.metadata.kanbanparent : null; let movedCardNewKanbanParent; if (movedCardWillBeFirst) { movedCardNewKanbanParent = "-1"; } else if (movedCardWillBeLast) { movedCardNewKanbanParent = lastCardInTargetLane.id; } else if (!!newChildCard) { movedCardNewKanbanParent = newChildCard.metadata.kanbanparent; } else { console.log("==> !!!!!!Couldn't find a parent.!!!! <=="); } const newChildCardNewParent = newChildCard ? draggableId : null; try { const update = await client.mutate({ mutation: generate_UPDATE_JOB_KANBAN( oldChildCard ? oldChildCard.id : null, oldChildCardNewParent, draggableId, movedCardNewKanbanParent, targetLane.id, newChildCard ? newChildCard.id : null, newChildCardNewParent ) }); insertAuditTrail({ jobid: draggableId, operation: AuditTrailMapping.jobstatuschange(targetLane.id), type: "jobstatuschange" }); if (update.errors) { notification["error"]({ message: t("production.errors.boardupdate", { message: JSON.stringify(update.errors) }) }); } } catch (error) { notification["error"]({ message: t("production.errors.boardupdate", { message: error.message }) }); } finally { setIsMoving(false); } }, [boardLanes, client, getCardByID, insertAuditTrail, isMoving, t] ); const totalHrs = useMemo( () => data .reduce( (acc, val) => acc + (val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0) + (val.larhrs?.aggregate?.sum?.mod_lb_hrs || 0), 0 ) .toFixed(1), [data] ); const totalLAB = useMemo( () => data.reduce((acc, val) => acc + (val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0), 0).toFixed(1), [data] ); const totalLAR = useMemo( () => data.reduce((acc, val) => acc + (val.larhrs?.aggregate?.sum?.mod_lb_hrs || 0), 0).toFixed(1), [data] ); const cardSettings = useMemo( () => associationSettings?.kanban_settings && Object.keys(associationSettings.kanban_settings).length > 0 ? associationSettings.kanban_settings : { ats: true, clm_no: true, compact: false, ownr_nm: true, sublets: true, ins_co_nm: true, production_note: true, employeeassignments: true, scheduled_completion: true, cardcolor: false, orientation: false }, [associationSettings] ); const handleSettingsChange = (newSettings) => { setOrientation(newSettings.orientation ? "vertical" : "horizontal"); }; if (loading) { return ; } return (
} extra={ } /> {cardSettings.cardcolor && }
); } export default connect(mapStateToProps, mapDispatchToProps)(ProductionBoardKanbanComponent);