import React, { forwardRef, useState } from 'react'; import { DragDropContext } from 'react-beautiful-dnd'; import Column from './Column'; import ColumnAdder from './ColumnAdder'; import DefaultCard from './DefaultCard'; import DefaultColumnHeader from './DefaultColumnHeader'; import * as helpers from './helpers'; import { addCard, addColumn, changeColumn, moveCard, moveColumn, removeCard, removeColumn } from './helpers'; import { getCard, getCoordinates, isAColumnMove, isMovingACardToAnotherPosition, isMovingAColumnToAnotherPosition, } from './services'; import { partialRight, when } from './utils'; import withDroppable from './withDroppable'; const Columns = forwardRef((props, ref: any) =>
); const DroppableBoard = withDroppable(Columns); const Board: any = (props) => { return props.initialBoard ? : ; }; Object.keys(helpers).forEach((key) => { Board[key] = helpers[key]; }); function UncontrolledBoard({ initialBoard, onCardDragEnd, onColumnDragEnd, allowAddColumn, cardAdderPosition, renderCardAdder, renderColumnAdder, onNewColumnConfirm, onColumnRemove, renderColumnHeader, allowRemoveColumn, allowRenameColumn, onColumnRename, onCardNew, renderCard, allowRemoveCard, onCardRemove, onColumnNew, disableCardDrag, disableColumnDrag, allowAddCard, onNewCardConfirm, }) { const [board, setBoard] = useState(initialBoard); const handleOnCardDragEnd = partialRight(handleOnDragEnd, { moveCallback: moveCard, notifyCallback: onCardDragEnd }); const handleOnColumnDragEnd = partialRight(handleOnDragEnd, { moveCallback: moveColumn, notifyCallback: onColumnDragEnd, }); function handleOnDragEnd({ source, destination, subject }, { moveCallback, notifyCallback }) { const reorderedBoard = moveCallback(board, source, destination); when(notifyCallback)((callback) => callback(reorderedBoard, subject, source, destination)); setBoard(reorderedBoard); } async function handleColumnAdd(newColumn) { const column = renderColumnAdder ? newColumn : await onNewColumnConfirm(newColumn); const boardWithNewColumn = addColumn(board, column); onColumnNew(boardWithNewColumn, column); setBoard(boardWithNewColumn); } function handleColumnRemove(column) { const filteredBoard = removeColumn(board, column); onColumnRemove(filteredBoard, column); setBoard(filteredBoard); } function handleColumnRename(column, title) { const boardWithRenamedColumn = changeColumn(board, column, { title }); onColumnRename(boardWithRenamedColumn, { ...column, title }); setBoard(boardWithRenamedColumn); } function handleCardAdd(column, card, options = {}) { const boardWithNewCard = addCard(board, column, card, options); onCardNew( boardWithNewCard, boardWithNewCard.columns.find(({ id }) => id === column.id), card, ); setBoard(boardWithNewCard); } async function handleDraftCardAdd(column, card, options = {}) { const newCard = await onNewCardConfirm(card); handleCardAdd(column, newCard, options); } function handleCardRemove(column, card) { const boardWithoutCard = removeCard(board, column, card); onCardRemove( boardWithoutCard, boardWithoutCard.columns.find(({ id }) => id === column.id), card, ); setBoard(boardWithoutCard); } return ( { if (!allowAddColumn) return null; if (renderColumnAdder) return renderColumnAdder({ addColumn: handleColumnAdd }); if (!onNewColumnConfirm) return null; return handleColumnAdd({ title, cards: [] })} />; }} {...(renderColumnHeader && { renderColumnHeader: (column) => renderColumnHeader(column, { removeColumn: handleColumnRemove.bind(null, column), renameColumn: handleColumnRename.bind(null, column), addCard: handleCardAdd.bind(null, column), }), })} renderCard={(column, card, dragging) => { if (renderCard) return renderCard(card, { removeCard: handleCardRemove.bind(null, column, card), dragging }); return ( handleCardRemove(column, card)} > {card} ); }} allowRemoveColumn={allowRemoveColumn} onColumnRemove={handleColumnRemove} allowRenameColumn={allowRenameColumn} onColumnRename={handleColumnRename} disableColumnDrag={disableColumnDrag} disableCardDrag={disableCardDrag} onCardNew={(column, card) => handleDraftCardAdd(column, card, allowAddCard)} allowAddCard={allowAddCard && onNewCardConfirm} > {board} ); } function ControlledBoard({ children: board, onCardDragEnd, onColumnDragEnd, allowAddColumn, renderCardAdder, renderColumnAdder, onNewColumnConfirm, onColumnRemove, renderColumnHeader, allowRemoveColumn, allowRenameColumn, onColumnRename, renderCard, allowAddCard, allowRemoveCard, onCardRemove, disableCardDrag, disableColumnDrag, cardAdderPosition, }) { const handleOnCardDragEnd = partialRight(handleOnDragEnd, { notifyCallback: onCardDragEnd }); const handleOnColumnDragEnd = partialRight(handleOnDragEnd, { notifyCallback: onColumnDragEnd }); function handleOnDragEnd({ source, destination, subject }, { notifyCallback }) { when(notifyCallback)((callback) => callback(subject, source, destination)); } return ( { if (!allowAddColumn) return null; if (renderColumnAdder) return renderColumnAdder(); if (!onNewColumnConfirm) return null; return onNewColumnConfirm({ title, cards: [] })} />; }} {...(renderColumnHeader && { renderColumnHeader: renderColumnHeader })} renderCard={(column, card, dragging) => { if (renderCard) return renderCard(card, { column, dragging }); return ( onCardRemove(card, column)} > {card} ); }} allowAddCard={allowAddCard} allowRemoveColumn={allowRemoveColumn} onColumnRemove={onColumnRemove} allowRenameColumn={allowRenameColumn} onColumnRename={onColumnRename} disableColumnDrag={disableColumnDrag} disableCardDrag={disableCardDrag} > {board} ); } function BoardContainer(props) { const { children: board, renderCard, disableColumnDrag, disableCardDrag, cardAdderPosition, renderCardAdder, renderColumnHeader, renderColumnAdder, allowRemoveColumn, onColumnRemove, allowRenameColumn, onColumnRename, onColumnDragEnd, onCardDragEnd, onCardNew, allowAddCard, } = props; function handleOnDragEnd(event) { const coordinates = getCoordinates(event, board); if (!coordinates.source) return; isAColumnMove(event.type) ? isMovingAColumnToAnotherPosition(coordinates) && onColumnDragEnd({ ...coordinates, subject: board.columns?.[coordinates.source.fromPosition] }) : isMovingACardToAnotherPosition(coordinates) && onCardDragEnd({ ...coordinates, subject: getCard(board, coordinates.source) }); } return (
{board.columns?.map((column, index) => ( renderColumnHeader ? ( renderColumnHeader(column) ) : ( {column} ) } cardAdderPosition={cardAdderPosition} disableColumnDrag={disableColumnDrag} disableCardDrag={disableCardDrag} onCardNew={onCardNew} allowAddCard={allowAddCard} > {column} ))} {renderColumnAdder()}
); } export default Board;