@eureca/eureca-ui
Version:
UI component library of Eureca's user and admin apps
212 lines (186 loc) • 5.25 kB
JavaScript
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { DragDropContext } from 'react-beautiful-dnd';
import { Flex } from '../Flex';
import { Column } from './column';
import { AddColumn } from './add-column';
function Board({
values,
onChange,
cardsOptions,
onAddCard,
onClickCard,
columnMenu,
onClickColumnMenu,
phaseOptions,
onClickCardAction,
}) {
const [boardData, setBoardData] = useState(() => values);
function onDragEnd(result) {
const { destination, source, draggableId } = result;
// dropped outside board
if (!destination) {
return;
}
// dropped in the same position
if (destination.droppableId === source.droppableId && destination.index === source.index) {
return;
}
const start = boardData.columns[source.droppableId];
const finish = boardData.columns[destination.droppableId];
// same column drag
if (start === finish) {
const newTaskIds = [...start.taskIds];
newTaskIds.splice(source.index, 1);
newTaskIds.splice(destination.index, 0, draggableId);
const newColumn = {
...start,
taskIds: newTaskIds,
};
const newBoardData = {
...boardData,
columns: {
...boardData.columns,
[newColumn.id]: newColumn,
},
};
setBoardData(newBoardData);
return;
}
// diff column drag
const startTaskIds = [...start.taskIds];
startTaskIds.splice(source.index, 1);
const newStart = {
...start,
taskIds: startTaskIds,
};
const finishTaskIds = [...finish.taskIds];
finishTaskIds.splice(destination.index, 0, draggableId);
const newFinish = {
...finish,
taskIds: finishTaskIds,
};
const newBoardData = {
...boardData,
columns: {
...boardData.columns,
[newStart.id]: newStart,
[newFinish.id]: newFinish,
},
};
setBoardData(newBoardData);
}
function insert(arr, index, newItem) {
return [...arr.slice(0, index), newItem, ...arr.slice(index)];
}
function handleAdd(value) {
const size = Object.keys(boardData.columns).length;
const newColumn = {
id: `${size}`,
title: value,
points: '',
taskIds: [],
};
const newBoardData = {
...boardData,
columns: {
...boardData.columns,
[size]: newColumn,
},
columnOrder: insert(boardData.columnOrder, size - 1, newColumn.id),
};
setBoardData(newBoardData);
}
useEffect(() => {
setBoardData(values);
}, [values]);
useEffect(() => {
onChange(boardData);
}, [onChange, boardData]);
return (
<DragDropContext onDragEnd={onDragEnd}>
<Flex directionRow style={{ overflowX: 'scroll' }}>
{boardData.columnOrder.map((columnId, index, arr) => {
const column = boardData.columns[columnId];
const tasks = column.taskIds.map(taskId =>
boardData.tasks.find(task => task.id === taskId)
);
if (index === arr.length - 1) {
return (
<React.Fragment key={columnId}>
<AddColumn add={handleAdd} phaseOptions={phaseOptions} />
<Column
column={column}
tasks={tasks}
cardsOptions={cardsOptions}
onAddCard={onAddCard}
onClickCard={onClickCard}
columnMenu={columnMenu}
onClickColumnMenu={onClickColumnMenu}
onClickCardAction={onClickCardAction}
/>
</React.Fragment>
);
}
return (
<Column
column={column}
tasks={tasks}
key={columnId}
cardsOptions={cardsOptions}
onAddCard={onAddCard}
onClickCard={onClickCard}
columnMenu={columnMenu}
onClickColumnMenu={onClickColumnMenu}
onClickCardAction={onClickCardAction}
/>
);
})}
</Flex>
</DragDropContext>
);
}
Board.defaultProps = {
values: {
tasks: [],
columns: {},
columnOrder: [],
},
cardsOptions: [],
columnMenu: [],
onChange: () => {},
onAddCard: () => {},
onClickCard: () => {},
onClickColumnMenu: () => {},
pathOptions: [
{
id: 0,
value: '',
label: '',
icon: null,
},
],
};
Board.propTypes = {
values: PropTypes.shape({
tasks: PropTypes.array.isRequired,
columns: PropTypes.object.isRequired,
columnOrder: PropTypes.array.isRequired,
}).isRequired,
cardsOptions: PropTypes.array,
columnMenu: PropTypes.array,
onChange: PropTypes.func,
onAddCard: PropTypes.func,
onClickCard: PropTypes.func,
onClickColumnMenu: PropTypes.func,
phaseOptions: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
label: PropTypes.string,
icon: PropTypes.oneOfType([PropTypes.node, PropTypes.element]),
})
),
onClickCardAction: PropTypes.func,
};
export { Board };