Progress Commit

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-05-17 16:29:46 -04:00
parent c3108a17f4
commit 55d729339f
9 changed files with 440 additions and 511 deletions

View File

@@ -1,6 +1,5 @@
import React, { Component } from "react";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import React, { useState, useEffect, useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import Container from "../dnd/Container";
import Draggable from "../dnd/Draggable";
import PropTypes from "prop-types";
@@ -8,220 +7,214 @@ import pick from "lodash/pick";
import isEqual from "lodash/isEqual";
import Lane from "./Lane";
import { PopoverWrapper } from "react-popopo";
import * as actions from "../../../redux/trello/trello.actions.js";
class BoardContainer extends Component {
state = {
addLaneMode: false
};
const BoardContainer = (props) => {
const [addLaneMode, setAddLaneMode] = useState(false);
get groupName() {
const { id } = this.props;
return `TrelloBoard${id}`;
}
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;
componentDidMount() {
const { actions, eventBusHandle } = this.props;
actions.loadBoard(this.props.data);
if (eventBusHandle) {
this.wireEventBus();
}
}
const dispatch = useDispatch();
const reducerData = useSelector((state) => (state.trello.lanes ? state.trello : {}));
componentDidUpdate(prevProps) {
const { data, reducerData, onDataChange, actions } = this.props;
const groupName = `TrelloBoard${id}`;
if (this.props.reducerData && !isEqual(reducerData, prevProps.reducerData)) {
onDataChange(this.props.reducerData);
}
if (data && !isEqual(data, prevProps.data)) {
actions.loadBoard(data);
onDataChange(data);
}
}
onDragStart = ({ payload }) => {
const { handleLaneDragStart } = this.props;
handleLaneDragStart(payload.id);
};
onLaneDrop = ({ removedIndex, addedIndex, payload }) => {
const { actions, handleLaneDragEnd } = this.props;
if (removedIndex !== addedIndex) {
actions.moveLane({ oldIndex: removedIndex, newIndex: addedIndex });
handleLaneDragEnd(removedIndex, addedIndex, payload);
}
};
getCardDetails = (laneId, cardIndex) => {
return this.props.reducerData.lanes.find((lane) => lane.id === laneId).cards[cardIndex];
};
getLaneDetails = (index) => {
return this.props.reducerData.lanes[index];
};
wireEventBus = () => {
const { actions, eventBusHandle } = this.props;
let eventBus = {
const wireEventBus = useCallback(() => {
const eventBus = {
publish: (event) => {
switch (event.type) {
case "ADD_CARD":
return actions.addCard({ laneId: event.laneId, card: event.card });
// Note: Removed because there was a duplicate entry
// case "UPDATE_CARD":
// return actions.updateCard({ laneId: event.laneId, card: event.card });
return dispatch(actions.addCard({ laneId: event.laneId, card: event.card }));
case "REMOVE_CARD":
return actions.removeCard({ laneId: event.laneId, cardId: event.cardId });
return dispatch(actions.removeCard({ laneId: event.laneId, cardId: event.cardId }));
case "REFRESH_BOARD":
return actions.loadBoard(event.data);
return dispatch(actions.loadBoard(event.data));
case "MOVE_CARD":
return actions.moveCardAcrossLanes({
fromLaneId: event.fromLaneId,
toLaneId: event.toLaneId,
cardId: event.cardId,
index: event.index
});
return dispatch(
actions.moveCardAcrossLanes({
fromLaneId: event.fromLaneId,
toLaneId: event.toLaneId,
cardId: event.cardId,
index: event.index
})
);
case "UPDATE_CARDS":
return actions.updateCards({ laneId: event.laneId, cards: event.cards });
return dispatch(actions.updateCards({ laneId: event.laneId, cards: event.cards }));
case "UPDATE_CARD":
return actions.updateCard({ laneId: event.laneId, updatedCard: event.card });
return dispatch(actions.updateCard({ laneId: event.laneId, updatedCard: event.card }));
case "UPDATE_LANES":
return actions.updateLanes(event.lanes);
return dispatch(actions.updateLanes(event.lanes));
case "UPDATE_LANE":
return actions.updateLane(event.lane);
return dispatch(actions.updateLane(event.lane));
default:
return;
}
}
};
eventBusHandle(eventBus);
}, [dispatch, eventBusHandle]);
useEffect(() => {
dispatch(actions.loadBoard(data));
if (eventBusHandle) {
wireEventBus();
}
}, [data, eventBusHandle, dispatch, wireEventBus]);
useEffect(() => {
if (!isEqual(reducerData, props.reducerData)) {
onDataChange(reducerData);
}
}, [reducerData, props.reducerData, onDataChange]);
const onDragStart = useCallback(
({ payload }) => {
handleLaneDragStart(payload.id);
},
[handleLaneDragStart]
);
const onLaneDrop = useCallback(
({ removedIndex, addedIndex, payload }) => {
if (removedIndex !== addedIndex) {
dispatch(actions.moveLane({ oldIndex: removedIndex, newIndex: addedIndex }));
handleLaneDragEnd(removedIndex, addedIndex, payload);
}
},
[dispatch, handleLaneDragEnd]
);
const getCardDetails = useCallback(
(laneId, cardIndex) => {
return reducerData.lanes.find((lane) => lane.id === laneId).cards[cardIndex];
},
[reducerData]
);
const getLaneDetails = useCallback(
(index) => {
return reducerData.lanes[index];
},
[reducerData]
);
const hideEditableLane = () => {
setAddLaneMode(false);
};
// + add
hideEditableLane = () => {
this.setState({ addLaneMode: false });
const showEditableLane = () => {
setAddLaneMode(true);
};
showEditableLane = () => {
this.setState({ addLaneMode: true });
const addNewLane = (params) => {
hideEditableLane();
dispatch(actions.addLane(params));
onLaneAdd(params);
};
addNewLane = (params) => {
this.hideEditableLane();
this.props.actions.addLane(params);
this.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"
]);
render() {
const {
id,
components,
reducerData,
draggable,
laneDraggable,
laneDragClass,
laneDropClass,
style,
onDataChange,
onCardAdd,
onCardUpdate,
onCardClick,
onBeforeCardDelete,
onCardDelete,
onLaneScroll,
onLaneClick,
onLaneAdd,
onLaneDelete,
onLaneUpdate,
editable,
canAddLanes,
laneStyle,
onCardMoveAcrossLanes,
t,
orientation,
...otherProps
} = this.props;
const { addLaneMode } = this.state;
// Stick to whitelisting attributes to segregate board and lane props
const passThroughProps = pick(this.props, [
"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} {...otherProps} draggable={false}>
<PopoverWrapper>
<Container
orientation={orientation === "vertical" ? "vertical" : "horizontal"}
onDragStart={this.onDragStart}
dragClass={laneDragClass}
dropClass={laneDropClass}
onDrop={this.onLaneDrop}
lockAxis={orientation === "vertical" ? "y" : "x"}
getChildPayload={(index) => this.getLaneDetails(index)}
groupName={this.groupName}
>
{reducerData.lanes.map((lane, index) => {
const { id, droppable, ...otherProps } = lane;
const laneToRender = (
<Lane
key={id}
boardId={this.groupName}
components={components}
id={id}
getCardDetails={this.getCardDetails}
index={index}
droppable={droppable === undefined ? true : droppable}
style={laneStyle || lane.style || {}}
labelStyle={lane.labelStyle || {}}
cardStyle={this.props.cardStyle || lane.cardStyle}
editable={editable && !lane.disallowAddingCard}
{...otherProps}
{...passThroughProps}
/>
);
return draggable && laneDraggable ? <Draggable key={lane.id}>{laneToRender}</Draggable> : laneToRender;
})}
</Container>
</PopoverWrapper>
{canAddLanes && (
<Container orientation={orientation === "vertical" ? "vertical" : "horizontal"}>
{editable && !addLaneMode ? (
<components.NewLaneSection onClick={this.showEditableLane} />
) : (
addLaneMode && <components.NewLaneForm onCancel={this.hideEditableLane} onAdd={this.addNewLane} t={t} />
)}
</Container>
)}
</components.BoardWrapper>
);
}
}
return (
<components.BoardWrapper style={style} orientation={orientation} draggable={false}>
<PopoverWrapper>
<Container
orientation={orientation === "vertical" ? "vertical" : "horizontal"}
onDragStart={onDragStart}
dragClass={laneDragClass}
dropClass={laneDropClass}
onDrop={onLaneDrop}
lockAxis={orientation === "vertical" ? "y" : "x"}
getChildPayload={(index) => getLaneDetails(index)}
groupName={groupName}
>
{reducerData.lanes.map((lane, index) => {
const { id, droppable, ...otherProps } = lane;
const laneToRender = (
<Lane
key={id}
boardId={groupName}
components={components}
id={id}
getCardDetails={getCardDetails}
index={index}
droppable={droppable === undefined ? true : droppable}
style={laneStyle || lane.style || {}}
labelStyle={lane.labelStyle || {}}
cardStyle={props.cardStyle || lane.cardStyle}
editable={editable && !lane.disallowAddingCard}
{...otherProps}
{...passThroughProps}
/>
);
return draggable && laneDraggable ? <Draggable key={lane.id}>{laneToRender}</Draggable> : laneToRender;
})}
</Container>
</PopoverWrapper>
{canAddLanes && (
<Container orientation={orientation === "vertical" ? "vertical" : "horizontal"}>
{editable && !addLaneMode ? (
<components.NewLaneSection onClick={showEditableLane} />
) : (
addLaneMode && <components.NewLaneForm onCancel={hideEditableLane} onAdd={addNewLane} />
)}
</Container>
)}
</components.BoardWrapper>
);
};
BoardContainer.propTypes = {
id: PropTypes.string,
@@ -259,12 +252,10 @@ BoardContainer.propTypes = {
laneDragClass: PropTypes.string,
laneDropClass: PropTypes.string,
onCardMoveAcrossLanes: PropTypes.func.isRequired,
t: PropTypes.func,
orientation: PropTypes.string
};
BoardContainer.defaultProps = {
t: (v) => v,
onDataChange: () => {},
handleDragStart: () => {},
handleDragEnd: () => {},
@@ -284,16 +275,8 @@ BoardContainer.defaultProps = {
cardDraggable: true,
cardDragClass: "react_trello_dragClass",
laneDragClass: "react_trello_dragLaneClass",
laneDropClass: "",
laneDropClass: "react_trello_dragLaneDropClass",
orientation: "horizontal"
};
const mapStateToProps = (state) => {
return state.trello.lanes ? { reducerData: state.trello } : {};
};
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators({ ...actions }, dispatch)
});
export default connect(mapStateToProps, mapDispatchToProps)(BoardContainer);
export default BoardContainer;