import { SyncOutlined } from "@ant-design/icons"; import { useApolloClient } from "@apollo/client"; import Board, { moveCard } from "@asseinfo/react-kanban"; import { Button, Grid, notification, PageHeader, Space, Statistic } from "antd"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { Sticky, StickyContainer } from "react-sticky"; import { createStructuredSelector } from "reselect"; import styled from "styled-components"; import { logImEXEvent } from "../../firebase/firebase.utils"; import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries"; import { insertAuditTrail } from "../../redux/application/application.actions"; import { selectTechnician } from "../../redux/tech/tech.selectors"; 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 ProductionBoardCard from "../production-board-kanban-card/production-board-kanban-card.component"; import ProductionListDetailComponent from "../production-list-detail/production-list-detail.component"; import ProductionBoardKanbanCardSettings from "./production-board-kanban.card-settings.component"; //import "@asseinfo/react-kanban/dist/styles.css"; import "./production-board-kanban.styles.scss"; import { createBoardData } from "./production-board-kanban.utils.js"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, technician: selectTechnician, }); const mapDispatchToProps = (dispatch) => ({ insertAuditTrail: ({ jobid, operation }) => dispatch(insertAuditTrail({ jobid, operation })), }); export function ProductionBoardKanbanComponent({ data, bodyshop, refetch, technician, insertAuditTrail, associationSettings, }) { const [boardLanes, setBoardLanes] = useState({ columns: [{ id: "Loading...", title: "Loading...", cards: [] }], }); const [filter, setFilter] = useState({ search: "", employeeId: null }); const [isMoving, setIsMoving] = useState(false); const { t } = useTranslation(); useEffect(() => { const boardData = createBoardData( bodyshop.md_ro_statuses.production_statuses, data, filter ); boardData.columns = boardData.columns.map((d) => { return { ...d, title: `${d.title} (${d.cards.length})` }; }); setBoardLanes(boardData); setIsMoving(false); }, [ data, setBoardLanes, setIsMoving, bodyshop.md_ro_statuses.production_statuses, filter, ]); const client = useApolloClient(); const handleDragEnd = async (card, source, destination) => { logImEXEvent("kanban_drag_end"); setIsMoving(true); setBoardLanes(moveCard(boardLanes, source, destination)); const sameColumnTransfer = source.fromColumnId === destination.toColumnId; const sourceColumn = boardLanes.columns.find( (x) => x.id === source.fromColumnId ); const destinationColumn = boardLanes.columns.find( (x) => x.id === destination.toColumnId ); const movedCardWillBeFirst = destination.toPosition === 0; const movedCardWillBeLast = destinationColumn.cards.length - destination.toPosition < 1; const lastCardInDestinationColumn = destinationColumn.cards[destinationColumn.cards.length - 1]; const oldChildCard = sourceColumn.cards[source.fromPosition + 1]; const newChildCard = movedCardWillBeLast ? null : destinationColumn.cards[ sameColumnTransfer ? source.fromPosition - destination.toPosition > 0 ? destination.toPosition : destination.toPosition + 1 : destination.toPosition ]; const oldChildCardNewParent = oldChildCard ? card.kanbanparent : null; let movedCardNewKanbanParent; if (movedCardWillBeFirst) { //console.log("==> New Card is first."); movedCardNewKanbanParent = "-1"; } else if (movedCardWillBeLast) { // console.log("==> New Card is last."); movedCardNewKanbanParent = lastCardInDestinationColumn.id; } else if (!!newChildCard) { // console.log("==> New Card is somewhere in the middle"); movedCardNewKanbanParent = newChildCard.kanbanparent; } else { throw new Error("==> !!!!!!Couldn't find a parent.!!!! <=="); } const newChildCardNewParent = newChildCard ? card.id : null; const update = await client.mutate({ mutation: generate_UPDATE_JOB_KANBAN( oldChildCard ? oldChildCard.id : null, oldChildCardNewParent, card.id, movedCardNewKanbanParent, destination.toColumnId, newChildCard ? newChildCard.id : null, newChildCardNewParent ), // TODO: optimisticResponse }); insertAuditTrail({ jobid: card.id, operation: AuditTrailMapping.jobstatuschange(destination.toColumnId), }); if (update.errors) { notification["error"]({ message: t("production.errors.boardupdate", { message: JSON.stringify(update.errors), }), }); } }; const totalHrs = data .reduce( (acc, val) => acc + (val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0) + (val.larhrs?.aggregate?.sum?.mod_lb_hrs || 0), 0 ) .toFixed(1); const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) .filter((screen) => !!screen[1]) .slice(-1)[0]; const standardSizes = { xs: "250", sm: "250", md: "250", lg: "250", xl: "250", xxl: "250", }; const compactSizes = { xs: "150", sm: "150", md: "150", lg: "150", xl: "155", xxl: "155", }; const width = selectedBreakpoint ? associationSettings && associationSettings.kanban_settings && associationSettings.kanban_settings.compact ? compactSizes[selectedBreakpoint[0]] : standardSizes[selectedBreakpoint[0]] : "250"; const stickyHeader = { renderColumnHeader: ({ title }) => ( {({ style, // the following are also available but unused in this example isSticky, wasSticky, distanceFromTop, distanceFromBottom, calculatedHeight, }) => (
{title}
)}
), }; const cardSettings = associationSettings && 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, stickyheader: false, }; return ( } extra={ } /> ProductionBoardCard(technician, card, bodyshop, cardSettings) } onCardDragEnd={handleDragEnd} /> ); } export default connect( mapStateToProps, mapDispatchToProps )(ProductionBoardKanbanComponent); const Container = styled.div` .react-kanban-card-skeleton, .react-kanban-card, .react-kanban-card-adder-form { box-sizing: border-box; max-width: ${(props) => props.width}px; min-width: ${(props) => props.width}px; } `;