UNPKG

payload-kanban-board

Version:
178 lines (177 loc) 9.19 kB
'use client'; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { LexoRank } from 'lexorank'; import { useEffect, useState } from 'react'; import { DragDropContext } from 'react-beautiful-dnd'; import { toast } from '@payloadcms/ui'; import BoardColumn from '../BoardColumn/BoardColumn.js'; import { sortAndFilterDocumentsForStatus, sortAndFilterDocumentsWithoutStatus } from '../utils/documents.util.js'; import './styles.scss'; const Board = (props)=>{ const { statusDefinition, documents: initDocuments, hideNoStatusColumn, onDocumentkanbanStatusChange, collection, dragEnabled, collectionSlug } = props; const [documents, setDocuments] = useState(initDocuments ?? []); useEffect(()=>{ setDocuments(initDocuments); }, [ initDocuments ]); const updateDocument = async (documentId, destinationStatus, orderRank, sourceId)=>{ try { // Store the original document state before updating const originalDocuments = [ ...documents ]; const documentIndex = originalDocuments.findIndex((doc)=>doc.id === documentId); const originalDocumentState = documentIndex !== -1 ? { ...originalDocuments[documentIndex] } : null; // Update the UI optimistically setDocuments((prev)=>{ const updatedDocumentIndex = prev.findIndex((_doc)=>_doc.id === documentId); if (updatedDocumentIndex === -1) { return prev; } const newDocuments = [ ...prev ]; newDocuments[updatedDocumentIndex] = { ...newDocuments[updatedDocumentIndex], kanbanStatus: destinationStatus, kanbanOrderRank: orderRank }; return newDocuments; }); // Call the status change function and wait for the status code const response = await onDocumentkanbanStatusChange(documentId, destinationStatus, orderRank); const statusCode = response.status; if (statusCode !== 200) { const res = await response.json(); const errorMessage = res.errors[0].message; // Revert the UI state if the API call fails toast.error(errorMessage ? errorMessage : 'You are not authorised to update document status'); // Restore the original state for this document if (originalDocumentState) { setDocuments((prev)=>{ const revertIndex = prev.findIndex((_doc)=>_doc.id === documentId); if (revertIndex === -1) { return prev; } const revertedDocuments = [ ...prev ]; revertedDocuments[revertIndex] = originalDocumentState; return revertedDocuments; }); } return false; } return true; } catch (error) { console.error('Error updating document:', error); toast.error('Something went wrong'); // Revert to original documents on error setDocuments(initDocuments); return false; } }; const onDragEnd = async (result)=>{ if (!dragEnabled) { toast.error('You are not authorized to perform this action'); return; } if (!result.destination) { return; } const source = result.source; const destination = result.destination; if (source.droppableId === destination.droppableId && source.index === destination.index) { return; } const documentId = result.draggableId; const sourceStatus = source.droppableId; const destinationStatus = destination.droppableId; const destinationIndex = destination.index; try { const destinationStatusGroup = sortAndFilterDocumentsForStatus(documents, destinationStatus); const minOrderRank = documents[0]?.kanbanOrderRank ?? LexoRank.min().toString(); const maxOrderRank = documents[documents.length - 1]?.kanbanOrderRank ?? LexoRank.max().toString(); // First in entire collection when added to empty group if (destinationStatusGroup.length === 0 && documents.findIndex((_doc)=>_doc.id === documentId) === 0) { return updateDocument(documentId, destinationStatus, LexoRank.min().toString(), source.droppableId); } // First in list on empty group if (destinationStatusGroup.length === 0 && destinationIndex === 0) { return updateDocument(documentId, destinationStatus, LexoRank.min().genNext().toString(), source.droppableId); } // First in list if (destinationIndex === 0) { const previousFirstDoc = [ ...destinationStatusGroup ].shift(); // If the value has not been set, set a default value if (!(typeof previousFirstDoc?.kanbanOrderRank === 'string')) { const updatedOrderRank = LexoRank.parse(minOrderRank).between(LexoRank.max()).toString(); return updateDocument(documentId, destinationStatus, updatedOrderRank, source.droppableId); } const updatedOrderRank = LexoRank.parse(previousFirstDoc.kanbanOrderRank).genPrev(); return updateDocument(documentId, destinationStatus, updatedOrderRank.toString(), source.droppableId); } // Last in the list if (sourceStatus === destinationStatus && destinationIndex + 1 === destinationStatusGroup.length || sourceStatus !== destinationStatus && destinationIndex === destinationStatusGroup.length) { const previousLastDoc = [ ...destinationStatusGroup ].pop(); // If the value has not been set, set a default value if (!(typeof previousLastDoc?.kanbanOrderRank === 'string')) { const updatedOrderRank = LexoRank.parse(maxOrderRank).between(LexoRank.min()).toString(); return updateDocument(documentId, destinationStatus, updatedOrderRank, source.droppableId); } const updatedOrderRank = LexoRank.parse(previousLastDoc.kanbanOrderRank).genNext(); return updateDocument(documentId, destinationStatus, updatedOrderRank.toString(), source.droppableId); } // Between 2 documents let documentBefore = destinationStatusGroup[destinationIndex - 1]; let documentAfter = destinationStatusGroup[destinationIndex]; // Within the same list re-ordering to the bottom, switch the document before and after if (sourceStatus === destinationStatus && source.index < destinationIndex) { documentBefore = destinationStatusGroup[destinationIndex]; documentAfter = destinationStatusGroup[destinationIndex + 1]; } const documentBeforeRank = LexoRank.parse(documentBefore.kanbanOrderRank); const documentAfterRank = LexoRank.parse(documentAfter.kanbanOrderRank); // Status change accepted return updateDocument(documentId, destinationStatus, documentBeforeRank.between(documentAfterRank).toString(), source.droppableId); } catch (error) { console.error('Error updating document:', error); toast.error('Something went wrong'); } }; return /*#__PURE__*/ _jsx(DragDropContext, { onDragEnd: (result)=>onDragEnd(result), children: /*#__PURE__*/ _jsx("div", { className: "scrumboard", children: /*#__PURE__*/ _jsxs("div", { className: "scrumboard-body", children: [ hideNoStatusColumn ? /*#__PURE__*/ _jsx(_Fragment, {}) : /*#__PURE__*/ _jsx(BoardColumn, { collection: collection, title: 'No status', identifier: 'null', contents: sortAndFilterDocumentsWithoutStatus(documents), collapsible: true, dragEnabled: dragEnabled }), statusDefinition?.options.map((status)=>/*#__PURE__*/ _jsx(BoardColumn, { collection: collection, title: status.label, identifier: status.value, dragEnabled: dragEnabled, contents: sortAndFilterDocumentsForStatus(documents, status.value) }, status.value)) ] }) }) }); }; export { Board }; //# sourceMappingURL=Board.js.map