From 7524d061261870ed61887df8c7f2fd27cd1ab13f Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Tue, 2 Jul 2024 14:16:25 -0400 Subject: [PATCH] - Checkpoint Signed-off-by: Dave Richer --- .../production-board-card.styles.scss | 11 -- ...production-board-kanban-card.component.jsx | 13 +- .../production-board-kanban.component.jsx | 41 ++--- ...uction-board-kanban.settings.component.jsx | 30 ++-- .../production-board-kanban.utils.js | 2 +- .../controllers/BoardContainer.jsx | 38 +++-- .../trello-board/controllers/Lane.jsx | 141 +++++++++--------- .../trello-board/helpers/LaneHelper.js | 2 - .../components/trello-board/styles/Base.js | 7 + client/src/translations/en_us/common.json | 10 ++ 10 files changed, 151 insertions(+), 144 deletions(-) diff --git a/client/src/components/production-board-kanban-card/production-board-card.styles.scss b/client/src/components/production-board-kanban-card/production-board-card.styles.scss index ce7f5fe49..e69de29bb 100644 --- a/client/src/components/production-board-kanban-card/production-board-card.styles.scss +++ b/client/src/components/production-board-kanban-card/production-board-card.styles.scss @@ -1,11 +0,0 @@ -.imex-kanban-card { - padding: 0px !important; - - .ant-card-body { - padding: 0.8rem; - } - - .ant-card-head { - padding: 0rem 0.8rem; - } -} diff --git a/client/src/components/production-board-kanban-card/production-board-kanban-card.component.jsx b/client/src/components/production-board-kanban-card/production-board-kanban-card.component.jsx index 3cef9bba5..f81a77d25 100644 --- a/client/src/components/production-board-kanban-card/production-board-kanban-card.component.jsx +++ b/client/src/components/production-board-kanban-card/production-board-kanban-card.component.jsx @@ -136,11 +136,14 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe )} )} - -
{`${metadata.v_model_yr || ""} ${ - metadata.v_make_desc || "" - } ${metadata.v_model_desc || ""}`}
- + {cardSettings && cardSettings.model_info && ( + +
{`${metadata.v_model_yr || ""} ${ + metadata.v_make_desc || "" + } ${metadata.v_model_desc || ""}`}
+ + )} + {cardSettings && cardSettings.ins_co_nm && metadata.ins_co_nm && (
{metadata.ins_co_nm || ""}
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 761b646f0..bffcf77f2 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 @@ -19,8 +19,10 @@ import ProductionBoardCard from "../production-board-kanban-card/production-boar 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 { createBoardData, createFakeBoardData } 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, @@ -63,25 +65,27 @@ export function ProductionBoardKanbanComponent({ }, [associationSettings]); useEffect(() => { - const boardData = createBoardData( + const newBoardData = createFakeBoardData( [...bodyshop.md_ro_statuses.production_statuses, ...(bodyshop.md_ro_statuses.additional_board_statuses || [])], data, filter ); // Build Board Lanes Data - boardData.lanes = boardData.lanes.map((lane) => { - return { - ...lane, - title: `${lane.title} (${lane.cards.length})` - }; + 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; }); - - setBoardLanes(boardData); setIsMoving(false); - }, [data, setBoardLanes, setIsMoving, bodyshop.md_ro_statuses, filter]); - - // + }, [data, bodyshop.md_ro_statuses, filter]); const client = useApolloClient(); @@ -102,13 +106,11 @@ export function ProductionBoardKanbanComponent({ return null; }; - // TODO, refine and use action - const onDragEnd = async ({ type, source, destination, draggableId, ...args }) => { - // //cardId, sourceLaneId, targetLaneId, position, cardDetails + const onDragEnd = async ({ type, source, destination, draggableId }) => { logImEXEvent("kanban_drag_end"); - // Early Gate - if (!type || type !== "lane" || !source || !destination) return; + // Early gate, also if the card is already moving bail + if (!type || type !== "lane" || !source || !destination || isMoving) return; setIsMoving(true); @@ -120,13 +122,11 @@ export function ProductionBoardKanbanComponent({ const movedCardWillBeFirst = destination.index === 0; const movedCardWillBeLast = destination.index > targetLane.cards.length - 1; - const movedCardIsFirstNewCard = movedCardWillBeFirst && movedCardWillBeLast; const lastCardInTargetLane = targetLane.cards[targetLane.cards.length - 1]; const oldChildCard = sourceLane.cards[destination.index + 1]; - // const newChildCard = movedCardWillBeLast ? null : targetLane.cards[ @@ -138,7 +138,7 @@ export function ProductionBoardKanbanComponent({ ]; const oldChildCardNewParent = oldChildCard ? sourceCard.metadata.kanbanparent : null; - // + let movedCardNewKanbanParent; if (movedCardWillBeFirst) { movedCardNewKanbanParent = "-1"; @@ -186,6 +186,7 @@ export function ProductionBoardKanbanComponent({ setIsMoving(false); } }; + const totalHrs = useMemo( () => data diff --git a/client/src/components/production-board-kanban/production-board-kanban.settings.component.jsx b/client/src/components/production-board-kanban/production-board-kanban.settings.component.jsx index bc3dfe987..d81304787 100644 --- a/client/src/components/production-board-kanban/production-board-kanban.settings.component.jsx +++ b/client/src/components/production-board-kanban/production-board-kanban.settings.component.jsx @@ -51,7 +51,7 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par const renderCardSettings = () => ( <> - + @@ -65,8 +65,13 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par - + + + + {t("production.labels.model_info")} + + {t("production.labels.ownr_nm")} @@ -119,21 +124,12 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par - - - - - {t("production.labels.stickyheader")} - - - - ); const renderBoardSettings = () => ( <> - + Orientation @@ -167,7 +163,7 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par const renderLaneSettings = () => ( <> - + {/**/} {/* */} @@ -207,13 +203,13 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par
- + {renderCardSettings()} - + {renderBoardSettings()} - + {renderLaneSettings()} @@ -236,7 +232,7 @@ export default function ProductionBoardKanbanSettings({ associationSettings, par return ( ); diff --git a/client/src/components/production-board-kanban/production-board-kanban.utils.js b/client/src/components/production-board-kanban/production-board-kanban.utils.js index 61519d007..a10446928 100644 --- a/client/src/components/production-board-kanban/production-board-kanban.utils.js +++ b/client/src/components/production-board-kanban/production-board-kanban.utils.js @@ -1,5 +1,5 @@ import { groupBy } from "lodash"; -import fakeData from "./testData/board1200.json"; +import fakeData from "./testData/board600.json"; const sortByParentId = (arr) => { // return arr.reduce((accumulator, currentValue) => { diff --git a/client/src/components/trello-board/controllers/BoardContainer.jsx b/client/src/components/trello-board/controllers/BoardContainer.jsx index 7754ae10a..283234361 100644 --- a/client/src/components/trello-board/controllers/BoardContainer.jsx +++ b/client/src/components/trello-board/controllers/BoardContainer.jsx @@ -8,7 +8,6 @@ import isEqual from "lodash/isEqual"; import Lane from "./Lane"; import { PopoverWrapper } from "react-popopo"; import * as actions from "../../../redux/trello/trello.actions.js"; -import { isFunction } from "lodash"; /** * BoardContainer is a React component that represents a Trello-like board. @@ -73,6 +72,8 @@ const BoardContainer = ({ ...otherProps }) => { const [addLaneMode, setAddLaneMode] = useState(false); + const [isDragging, setIsDragging] = useState(false); + const [isProcessing, setIsProcessing] = useState(false); const dispatch = useDispatch(); const currentReducerData = useSelector((state) => (state.trello.lanes ? state.trello : {})); @@ -143,7 +144,12 @@ const BoardContainer = ({ * onDragStart * @type {(function({draggableId: *, type: *, source: *, mode: *}): void)|*} */ - const onDragStart = useCallback(({ draggableId, type, source, mode }) => {}, []); + const onDragStart = useCallback( + ({ draggableId, type, source, mode }) => { + setIsDragging(true); + }, + [setIsDragging] + ); /** * onBeforeDragStart @@ -236,8 +242,13 @@ const BoardContainer = ({ ] ); - const onLaneDrag = ({ draggableId, type, source, reason, mode, destination, combine }) => { + const onLaneDrag = async ({ draggableId, type, source, reason, mode, destination, combine }) => { + setIsDragging(false); + if (!type || type !== "lane" || !source || !destination) return; + + setIsProcessing(true); + dispatch( actions.moveCardAcrossLanes({ fromLaneId: source.droppableId, @@ -246,29 +257,26 @@ const BoardContainer = ({ index: destination.index }) ); - // onCardMoveAcrossLanes(payload.laneId, laneId, payload.id, addedIndex); - }; - const combinedDragEnd = (...params) => { - // Early Gate - if (!params || !params[0]) return; - onLaneDrag(params[0]); - if (isFunction(onDragEnd)) { - onDragEnd(params[0]); - } + onDragEnd({ draggableId, type, source, reason, mode, destination, combine }) + .catch((err) => { + console.error("Error in onLaneDrag", err); + }) + .finally(() => { + setIsProcessing(false); + }); }; return ( getLaneDetails(index)} > {currentReducerData.lanes.map((lane, index) => { const { id, droppable, ...laneOtherProps } = lane; @@ -288,6 +296,8 @@ const BoardContainer = ({ {...laneOtherProps} {...passThroughProps} cards={lane.cards} + isDragging={isDragging} + isProcessing={isProcessing} /> ); })} diff --git a/client/src/components/trello-board/controllers/Lane.jsx b/client/src/components/trello-board/controllers/Lane.jsx index 4c637378d..8725cccb2 100644 --- a/client/src/components/trello-board/controllers/Lane.jsx +++ b/client/src/components/trello-board/controllers/Lane.jsx @@ -11,12 +11,14 @@ import { Draggable, Droppable } from "../dnd/lib"; import { Virtuoso, VirtuosoGrid } from "react-virtuoso"; import HeightPreservingItem from "../components/Lane/HeightPreservingItem.jsx"; -function Lane({ +const Lane = ({ actions, id, boardId, title, index, + isDragging, + isProcessing, laneSortFunction, style = {}, cardStyle = {}, @@ -51,7 +53,7 @@ function Lane({ className, currentPage, ...otherProps -}) { +}) => { const [loading, setLoading] = useState(false); const [currentPageFinal, setCurrentPageFinal] = useState(currentPage); const [addCardMode, setAddCardMode] = useState(false); @@ -99,77 +101,80 @@ function Lane({ }; }, [handleScroll]); - const sortCards = (cards, sortFunction) => { + const sortCards = useCallback((cards, sortFunction) => { if (!cards) return []; if (!sortFunction) return cards; return cards.concat().sort((card1, card2) => sortFunction(card1, card2)); - }; + }, []); - const removeCard = (cardId) => { - if (onBeforeCardDelete && typeof onBeforeCardDelete === "function") { - onBeforeCardDelete(() => { + const removeCard = useCallback( + (cardId) => { + if (onBeforeCardDelete && typeof onBeforeCardDelete === "function") { + onBeforeCardDelete(() => { + onCardDelete && onCardDelete(cardId, id); + actions.removeCard({ laneId: id, cardId: cardId }); + }); + } else { onCardDelete && onCardDelete(cardId, id); actions.removeCard({ laneId: id, cardId: cardId }); - }); - } else { - onCardDelete && onCardDelete(cardId, id); - actions.removeCard({ laneId: id, cardId: cardId }); - } - }; + } + }, + [onBeforeCardDelete, onCardDelete, actions, id] + ); - const handleCardClick = (e, card) => { - onCardClick && onCardClick(card.id, card.metadata, card.laneId); - e.stopPropagation(); - }; + const handleCardClick = useCallback( + (e, card) => { + onCardClick && onCardClick(card.id, card.metadata, card.laneId); + e.stopPropagation(); + }, + [onCardClick] + ); - const showEditableCard = () => { + const showEditableCard = useCallback(() => { setAddCardMode(true); - }; + }, []); - const hideEditableCard = () => { + const hideEditableCard = useCallback(() => { setAddCardMode(false); - }; + }, []); - const addNewCard = (params) => { - const laneId = id; - const newCardId = v1(); - hideEditableCard(); - let card = { id: newCardId, ...params }; - actions.addCard({ laneId, card }); - onCardAdd(card, laneId); - }; + const addNewCard = useCallback( + (params) => { + const laneId = id; + const newCardId = v1(); + hideEditableCard(); + let card = { id: newCardId, ...params }; + actions.addCard({ laneId, card }); + onCardAdd(card, laneId); + }, + [actions, id, onCardAdd, hideEditableCard] + ); - // const onDragStart = ({ payload }) => { - // handleDragStart && handleDragStart(payload.id, payload.laneId); - // }; + const updateCard = useCallback( + (updatedCard) => { + actions.updateCard({ laneId: id, card: updatedCard }); + onCardUpdate(id, updatedCard); + }, + [actions, id, onCardUpdate] + ); - // const shouldAcceptDrop = (sourceContainerOptions) => { - // return droppable && sourceContainerOptions.groupName === groupName; - // }; - - const updateCard = (updatedCard) => { - actions.updateCard({ laneId: id, card: updatedCard }); - onCardUpdate(id, updatedCard); - }; - - const removeLane = () => { + const removeLane = useCallback(() => { actions.removeLane({ laneId: id }); onLaneDelete(id); - }; + }, [actions, id, onLaneDelete]); - const updateTitle = (value) => { - actions.updateLane({ id, title: value }); - onLaneUpdate(id, { title: value }); - }; + const updateTitle = useCallback( + (value) => { + actions.updateLane({ id, title: value }); + onLaneUpdate(id, { title: value }); + }, + [actions, id, onLaneUpdate] + ); - const toggleLaneCollapsed = () => { + const toggleLaneCollapsed = useCallback(() => { collapsibleLanes && setCollapsed(!collapsed); - }; + }, [collapsibleLanes, collapsed]); - /** - * Card component - * @type {React.NamedExoticComponent<{readonly item?: *, readonly provided?: *, readonly isDragging?: *}>} - */ const Card = React.memo(({ provided, item: card, isDragging }) => { const onDeleteCard = () => removeCard(card.id); return ( @@ -210,27 +215,16 @@ function Lane({ ); - /** - * Render the add card link - * @returns {false|React.JSX.Element} - */ - const renderAddCardLink = () => - editable && !addCardMode && ; + const renderAddCardLink = useCallback( + () => editable && !addCardMode && , + [editable, addCardMode, showEditableCard, id] + ); - /** - * Render the new card form - * @returns {false|React.JSX.Element} - */ - const renderNewCardForm = () => - addCardMode && ; + const renderNewCardForm = useCallback( + () => addCardMode && , + [addCardMode, hideEditableCard, addNewCard, id] + ); - /** - * Wrapper for the item in the grid layout - * @param children - * @param props - * @returns {React.JSX.Element} - * @constructor - */ const ItemWrapper = ({ children, ...props }) => (
{renderHeader({ id, cards, ...passedProps })} {renderDragContainer()} - {/*{renderDragContainer(isDraggingOver)}*/} {loading && } {showFooter && } ); -} +}; Lane.propTypes = { actions: PropTypes.object, diff --git a/client/src/components/trello-board/helpers/LaneHelper.js b/client/src/components/trello-board/helpers/LaneHelper.js index 501a09019..69b9edb52 100644 --- a/client/src/components/trello-board/helpers/LaneHelper.js +++ b/client/src/components/trello-board/helpers/LaneHelper.js @@ -100,8 +100,6 @@ const LaneHelper = { // Clone the state to avoid mutation const newLanes = cloneDeep(state.lanes); - console.dir({ fromLaneId, toLaneId, cardId, index }); - // Find the source and destination lanes using the lane IDs const fromLane = newLanes.find((lane) => lane.id === fromLaneId); const toLane = newLanes.find((lane) => lane.id === toLaneId); diff --git a/client/src/components/trello-board/styles/Base.js b/client/src/components/trello-board/styles/Base.js index dd8d9683c..775e9589d 100644 --- a/client/src/components/trello-board/styles/Base.js +++ b/client/src/components/trello-board/styles/Base.js @@ -81,6 +81,9 @@ export const StyleHorizontal = styled.div` .react-trello-lane.lane-collapsed { min-height: 15px; } + .ant-card-body { + padding: 4px; + } `; export const StyleVertical = styled.div` @@ -98,6 +101,7 @@ export const StyleVertical = styled.div` .react-trello-card { flex: 0 1 auto; + min-width: 120px; } .react-trello-board { @@ -109,6 +113,9 @@ export const StyleVertical = styled.div` .grid-item { } + + .ant-card-body { + } `; export const CustomPopoverContainer = styled(PopoverContainer)` diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index b2e9d344d..a60b8c1b5 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -2719,6 +2719,16 @@ } }, "production": { + "settings": { + "layout": "Layout", + "information": "Information", + "board_settings": "Board Settings", + "tabs": { + "card": "Card", + "board": "Board", + "lane": "Lane" + } + }, "actions": { "addcolumns": "Add Columns", "bodypriority-clear": "Clear Body Priority",