@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user