Board Container and Lane, the last remaining class components are now functional components utilizing up to date react stuff, defaultProps deprecation fixed (rolled into function decleration)

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-05-21 17:12:48 -04:00
parent 55d729339f
commit 19dfec2a34
2 changed files with 220 additions and 185 deletions

View File

@@ -9,42 +9,42 @@ import Lane from "./Lane";
import { PopoverWrapper } from "react-popopo";
import * as actions from "../../../redux/trello/trello.actions.js";
const BoardContainer = (props) => {
const BoardContainer = ({
id,
components,
data,
draggable = false,
laneDraggable = true,
laneDragClass = "react_trello_dragLaneClass",
laneDropClass = "react_trello_dragLaneDropClass",
style,
onDataChange = () => {},
onCardAdd = () => {},
onCardUpdate = () => {},
onCardClick = () => {},
onBeforeCardDelete = () => {},
onCardDelete = () => {},
onLaneScroll = () => {},
onLaneClick = () => {},
onLaneAdd = () => {},
onLaneDelete = () => {},
onLaneUpdate = () => {},
editable = false,
canAddLanes = false,
laneStyle,
onCardMoveAcrossLanes = () => {},
orientation = "horizontal",
eventBusHandle,
handleLaneDragStart = () => {},
handleLaneDragEnd = () => {},
reducerData,
cardStyle,
...otherProps
}) => {
const [addLaneMode, setAddLaneMode] = useState(false);
const {
id,
components,
data,
draggable,
laneDraggable,
laneDragClass,
laneDropClass,
style,
onDataChange,
onCardAdd,
onCardUpdate,
onCardClick,
onBeforeCardDelete,
onCardDelete,
onLaneScroll,
onLaneClick,
onLaneAdd,
onLaneDelete,
onLaneUpdate,
editable,
canAddLanes,
laneStyle,
onCardMoveAcrossLanes,
orientation,
eventBusHandle,
handleLaneDragStart,
handleLaneDragEnd,
...otherProps
} = props;
const dispatch = useDispatch();
const reducerData = useSelector((state) => (state.trello.lanes ? state.trello : {}));
const currentReducerData = useSelector((state) => (state.trello.lanes ? state.trello : {}));
const groupName = `TrelloBoard${id}`;
@@ -91,10 +91,10 @@ const BoardContainer = (props) => {
}, [data, eventBusHandle, dispatch, wireEventBus]);
useEffect(() => {
if (!isEqual(reducerData, props.reducerData)) {
onDataChange(reducerData);
if (!isEqual(currentReducerData, reducerData)) {
onDataChange(currentReducerData);
}
}, [reducerData, props.reducerData, onDataChange]);
}, [currentReducerData, reducerData, onDataChange]);
const onDragStart = useCallback(
({ payload }) => {
@@ -115,16 +115,16 @@ const BoardContainer = (props) => {
const getCardDetails = useCallback(
(laneId, cardIndex) => {
return reducerData.lanes.find((lane) => lane.id === laneId).cards[cardIndex];
return currentReducerData.lanes.find((lane) => lane.id === laneId).cards[cardIndex];
},
[reducerData]
[currentReducerData]
);
const getLaneDetails = useCallback(
(index) => {
return reducerData.lanes[index];
return currentReducerData.lanes[index];
},
[reducerData]
[currentReducerData]
);
const hideEditableLane = () => {
@@ -141,31 +141,65 @@ const BoardContainer = (props) => {
onLaneAdd(params);
};
const passThroughProps = pick(props, [
"onCardMoveAcrossLanes",
"onLaneScroll",
"onLaneDelete",
"onLaneUpdate",
"onCardClick",
"onBeforeCardDelete",
"onCardDelete",
"onCardAdd",
"onCardUpdate",
"onLaneClick",
"laneSortFunction",
"draggable",
"laneDraggable",
"cardDraggable",
"collapsibleLanes",
"canAddLanes",
"hideCardDeleteIcon",
"tagStyle",
"handleDragStart",
"handleDragEnd",
"cardDragClass",
"editLaneTitle",
"orientation"
]);
const passThroughProps = pick(
{
id,
components,
data,
draggable,
laneDraggable,
laneDragClass,
laneDropClass,
style,
onDataChange,
onCardAdd,
onCardUpdate,
onCardClick,
onBeforeCardDelete,
onCardDelete,
onLaneScroll,
onLaneClick,
onLaneAdd,
onLaneDelete,
onLaneUpdate,
editable,
canAddLanes,
laneStyle,
onCardMoveAcrossLanes,
orientation,
eventBusHandle,
handleLaneDragStart,
handleLaneDragEnd,
reducerData,
cardStyle,
...otherProps
},
[
"onCardMoveAcrossLanes",
"onLaneScroll",
"onLaneDelete",
"onLaneUpdate",
"onCardClick",
"onBeforeCardDelete",
"onCardDelete",
"onCardAdd",
"onCardUpdate",
"onLaneClick",
"laneSortFunction",
"draggable",
"laneDraggable",
"cardDraggable",
"collapsibleLanes",
"canAddLanes",
"hideCardDeleteIcon",
"tagStyle",
"handleDragStart",
"handleDragEnd",
"cardDragClass",
"editLaneTitle",
"orientation"
]
);
return (
<components.BoardWrapper style={style} orientation={orientation} draggable={false}>
@@ -180,8 +214,8 @@ const BoardContainer = (props) => {
getChildPayload={(index) => getLaneDetails(index)}
groupName={groupName}
>
{reducerData.lanes.map((lane, index) => {
const { id, droppable, ...otherProps } = lane;
{currentReducerData.lanes.map((lane, index) => {
const { id, droppable, ...laneOtherProps } = lane;
const laneToRender = (
<Lane
key={id}
@@ -193,9 +227,9 @@ const BoardContainer = (props) => {
droppable={droppable === undefined ? true : droppable}
style={laneStyle || lane.style || {}}
labelStyle={lane.labelStyle || {}}
cardStyle={props.cardStyle || lane.cardStyle}
cardStyle={cardStyle || lane.cardStyle}
editable={editable && !lane.disallowAddingCard}
{...otherProps}
{...laneOtherProps}
{...passThroughProps}
/>
);
@@ -251,32 +285,9 @@ BoardContainer.propTypes = {
cardDragClass: PropTypes.string,
laneDragClass: PropTypes.string,
laneDropClass: PropTypes.string,
onCardMoveAcrossLanes: PropTypes.func.isRequired,
orientation: PropTypes.string
};
BoardContainer.defaultProps = {
onDataChange: () => {},
handleDragStart: () => {},
handleDragEnd: () => {},
handleLaneDragStart: () => {},
handleLaneDragEnd: () => {},
onCardUpdate: () => {},
onLaneAdd: () => {},
onLaneDelete: () => {},
onCardMoveAcrossLanes: () => {},
onLaneUpdate: () => {},
editable: false,
canAddLanes: false,
hideCardDeleteIcon: false,
draggable: false,
collapsibleLanes: false,
laneDraggable: true,
cardDraggable: true,
cardDragClass: "react_trello_dragClass",
laneDragClass: "react_trello_dragLaneClass",
laneDropClass: "react_trello_dragLaneDropClass",
orientation: "horizontal"
onCardMoveAcrossLanes: PropTypes.func,
orientation: PropTypes.string,
cardStyle: PropTypes.object
};
export default BoardContainer;

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef, useCallback, useMemo } from "react";
import React, { useCallback, useEffect, useRef, useState } from "react";
import classNames from "classnames";
import PropTypes from "prop-types";
import { bindActionCreators } from "redux";
@@ -12,39 +12,51 @@ import Draggable from "../dnd/Draggable.jsx";
import * as actions from "../../../redux/trello/trello.actions.js";
const defaultProps = {
style: {},
titleStyle: {},
labelStyle: {},
label: undefined,
editable: false,
onLaneUpdate: () => {},
onCardAdd: () => {},
onCardUpdate: () => {},
onCardDelete: () => {},
onBeforeCardDelete: () => {},
onLaneDelete: () => {},
onLaneClick: () => {},
onLaneScroll: () => {},
onCardClick: () => {},
onCardMoveAcrossLanes: () => {},
draggable: false,
laneDraggable: false,
cardDraggable: true,
collapsibleLanes: false,
droppable: true,
canAddLanes: false,
hideCardDeleteIcon: false,
components: {},
handleDragStart: () => {},
handleDragEnd: () => {},
orientation: "vertical"
};
const Lane = (internalProps) => {
const props = useMemo(() => ({ ...defaultProps, ...internalProps }), [internalProps]);
function Lane({
actions,
id,
boardId,
title,
index,
laneSortFunction,
style = {},
cardStyle = {},
tagStyle = {},
titleStyle = {},
labelStyle = {},
cards,
label,
draggable = false,
collapsibleLanes = false,
droppable = true,
onCardMoveAcrossLanes = () => {},
onCardClick = () => {},
onBeforeCardDelete = () => {},
onCardDelete = () => {},
onCardAdd = () => {},
onCardUpdate = () => {},
onLaneDelete = () => {},
onLaneUpdate = () => {},
onLaneClick = () => {},
onLaneScroll = () => {},
editable = false,
laneDraggable = false,
cardDraggable = true,
cardDragClass,
cardDropClass,
canAddLanes = false,
hideCardDeleteIcon = false,
components = {},
getCardDetails,
handleDragStart = () => {},
handleDragEnd = () => {},
orientation = "vertical",
className,
currentPage,
...otherProps
}) {
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(props.currentPage);
const [currentPageFinal, setCurrentPageFinal] = useState(currentPage);
const [addCardMode, setAddCardMode] = useState(false);
const [collapsed, setCollapsed] = useState(false);
const [isDraggingOver, setIsDraggingOver] = useState(false);
@@ -52,23 +64,22 @@ const Lane = (internalProps) => {
const laneRef = useRef(null);
useEffect(() => {
if (!isEqual(props.cards, currentPage)) {
setCurrentPage(props.currentPage);
if (!isEqual(cards, currentPageFinal)) {
setCurrentPageFinal(currentPage);
}
}, [props.cards, props.currentPage, currentPage]);
}, [cards, currentPage, currentPageFinal]);
const handleScroll = useCallback(
(evt) => {
const node = evt.target;
const elemScrollPosition = node.scrollHeight - node.scrollTop - node.clientHeight;
const { onLaneScroll } = props;
if (elemScrollPosition < 1 && onLaneScroll && !loading) {
const nextPage = currentPage + 1;
const nextPage = currentPageFinal + 1;
setLoading(true);
onLaneScroll(nextPage, props.id).then((moreCards) => {
onLaneScroll(nextPage, id).then((moreCards) => {
if ((moreCards || []).length > 0) {
props.actions.paginateLane({
laneId: props.id,
actions.paginateLane({
laneId: id,
newCards: moreCards,
nextPage: nextPage
});
@@ -77,7 +88,7 @@ const Lane = (internalProps) => {
});
}
},
[currentPage, loading, props]
[currentPageFinal, loading, onLaneScroll, id, actions]
);
useEffect(() => {
@@ -99,19 +110,18 @@ const Lane = (internalProps) => {
};
const removeCard = (cardId) => {
if (props.onBeforeCardDelete && typeof props.onBeforeCardDelete === "function") {
props.onBeforeCardDelete(() => {
props.onCardDelete && props.onCardDelete(cardId, props.id);
props.actions.removeCard({ laneId: props.id, cardId: cardId });
if (onBeforeCardDelete && typeof onBeforeCardDelete === "function") {
onBeforeCardDelete(() => {
onCardDelete && onCardDelete(cardId, id);
actions.removeCard({ laneId: id, cardId: cardId });
});
} else {
props.onCardDelete && props.onCardDelete(cardId, props.id);
props.actions.removeCard({ laneId: props.id, cardId: cardId });
onCardDelete && onCardDelete(cardId, id);
actions.removeCard({ laneId: id, cardId: cardId });
}
};
const handleCardClick = (e, card) => {
const { onCardClick } = props;
onCardClick && onCardClick(card.id, card.metadata, card.laneId);
e.stopPropagation();
};
@@ -125,25 +135,23 @@ const Lane = (internalProps) => {
};
const addNewCard = (params) => {
const laneId = props.id;
const id = v1();
const laneId = id;
const newCardId = v1();
hideEditableCard();
let card = { id, ...params };
props.actions.addCard({ laneId, card });
props.onCardAdd(card, laneId);
let card = { id: newCardId, ...params };
actions.addCard({ laneId, card });
onCardAdd(card, laneId);
};
const onDragStart = ({ payload }) => {
const { handleDragStart } = props;
handleDragStart && handleDragStart(payload.id, payload.laneId);
};
const shouldAcceptDrop = (sourceContainerOptions) => {
return props.droppable && sourceContainerOptions.groupName === groupName;
return droppable && sourceContainerOptions.groupName === groupName;
};
const onDragEnd = (laneId, result) => {
const { handleDragEnd } = props;
const { addedIndex, payload } = result;
if (isDraggingOver) {
@@ -154,56 +162,40 @@ const Lane = (internalProps) => {
const newCard = { ...cloneDeep(payload), laneId };
const response = handleDragEnd ? handleDragEnd(payload.id, payload.laneId, laneId, addedIndex, newCard) : true;
if (response === undefined || !!response) {
props.actions.moveCardAcrossLanes({
actions.moveCardAcrossLanes({
fromLaneId: payload.laneId,
toLaneId: laneId,
cardId: payload.id,
index: addedIndex
});
props.onCardMoveAcrossLanes(payload.laneId, laneId, payload.id, addedIndex);
onCardMoveAcrossLanes(payload.laneId, laneId, payload.id, addedIndex);
}
return response;
}
};
const updateCard = (updatedCard) => {
props.actions.updateCard({ laneId: props.id, card: updatedCard });
props.onCardUpdate(props.id, updatedCard);
actions.updateCard({ laneId: id, card: updatedCard });
onCardUpdate(id, updatedCard);
};
const removeLane = () => {
const { id } = props;
props.actions.removeLane({ laneId: id });
props.onLaneDelete(id);
actions.removeLane({ laneId: id });
onLaneDelete(id);
};
const updateTitle = (value) => {
props.actions.updateLane({ id: props.id, title: value });
props.onLaneUpdate(props.id, { title: value });
actions.updateLane({ id, title: value });
onLaneUpdate(id, { title: value });
};
const toggleLaneCollapsed = () => {
props.collapsibleLanes && setCollapsed(!collapsed);
collapsibleLanes && setCollapsed(!collapsed);
};
const groupName = `TrelloBoard${props.boardId}Lane`;
const groupName = `TrelloBoard${boardId}Lane`;
const renderDragContainer = (isDraggingOver) => {
const {
id,
cards,
laneSortFunction,
editable,
hideCardDeleteIcon,
cardDraggable,
cardDragClass,
cardDropClass,
tagStyle,
cardStyle,
components,
orientation
} = props;
const stableCards = collapsed ? [] : cards;
const cardList = sortCards(stableCards, laneSortFunction).map((card, idx) => {
@@ -243,7 +235,7 @@ const Lane = (internalProps) => {
onDragEnter={() => setIsDraggingOver(true)}
onDragLeave={() => setIsDraggingOver(false)}
shouldAcceptDrop={shouldAcceptDrop}
getChildPayload={(index) => props.getCardDetails(id, index)}
getChildPayload={(index) => getCardDetails(id, index)}
>
{cardList}
</Container>
@@ -254,7 +246,6 @@ const Lane = (internalProps) => {
};
const renderHeader = (pickedProps) => {
const { components } = props;
return (
<components.LaneHeader
{...pickedProps}
@@ -265,11 +256,43 @@ const Lane = (internalProps) => {
);
};
const { id, cards, collapsibleLanes, components, onLaneClick, orientation, ...otherProps } = props;
const allClassNames = classNames("react-trello-lane", collapsed ? "lane-collapsed" : "", props.className || "");
const allClassNames = classNames("react-trello-lane", collapsed ? "lane-collapsed" : "", className || "");
const showFooter = collapsibleLanes && cards.length > 0;
// Removed the ...otherProps spread from the components.Section
const passedProps = {
actions,
id,
boardId,
title,
index,
laneSortFunction,
style,
cardStyle,
tagStyle,
titleStyle,
labelStyle,
cards,
label,
draggable,
collapsibleLanes,
droppable,
editable,
laneDraggable,
cardDraggable,
cardDragClass,
cardDropClass,
canAddLanes,
hideCardDeleteIcon,
components,
getCardDetails,
handleDragStart,
handleDragEnd,
orientation,
className,
currentPage,
...otherProps
};
return (
<components.Section
key={id}
@@ -277,14 +300,15 @@ const Lane = (internalProps) => {
draggable={false}
className={allClassNames}
orientation={orientation}
{...passedProps}
>
{renderHeader({ id, cards, ...otherProps })}
{renderHeader({ id, cards, ...passedProps })}
{renderDragContainer(isDraggingOver)}
{loading && <components.Loader />}
{showFooter && <components.LaneFooter onClick={toggleLaneCollapsed} collapsed={collapsed} />}
</components.Section>
);
};
}
Lane.propTypes = {
actions: PropTypes.object,