payload-kanban-board
Version:
A kanban board plugin for Payload CMS
93 lines (90 loc) • 5.55 kB
JSX
'use client';
import { Button, DefaultListView, Gutter, ListControls, ListHeader, RenderCustomComponent, SelectionProvider, TableColumnsProvider, useAuth, useConfig, useListQuery, useTranslation, useWindowInfo, ViewDescription, } from '@payloadcms/ui';
import { usePathname } from 'next/navigation.js';
import React, { Fragment, useCallback, useMemo, useState } from 'react';
import { Board } from '../../exports/client.js';
import './styles.scss';
const baseClass = 'scrumboard';
const WorkflowView = ({ config, fieldConfig, collectionSlug, hasCreatePermission = false, newDocumentURL, listMenuItems, renderedFilters, resolvedFilterOptions, columnState, Description, ...props }) => {
const authData = useAuth();
const { data: listData, handleSearchChange, handleSortChange, handleWhereChange, } = useListQuery();
const { user } = useAuth();
const docs = useMemo(() => {
return listData.docs;
}, [listData.docs]);
const { permissions } = authData || {};
const pathname = usePathname();
const isFromSamePage = pathname.includes(collectionSlug);
const dragEnabled = permissions?.collections[collectionSlug]?.update || false;
const hasReadAccess = permissions?.collections[collectionSlug]?.read || false;
const { i18n, t } = useTranslation();
const fulldata = useConfig();
const { getEntityConfig } = useConfig();
const { routes, serverURL } = fulldata || {};
const collection = getEntityConfig({ collectionSlug });
const collectionConfig = getEntityConfig({ collectionSlug });
const hideNoStatusColumn = collectionConfig.admin?.custom?.hideNoStatusColumn;
const { fields: collectionFields, labels: { plural: pluralLabel }, } = collection || { fields: [], labels: { plural: '' } };
const { api } = routes || {};
const [showingWorkflow, setShowingWorkflow] = useState(true);
const statusDefinition = collectionFields.find((field) => field?.name === 'kanbanStatus');
const handleDocumentKanbanStatusChange = async (documentId, kanbanStatus, kanbanOrderRank) => {
const url = `/api/${collectionSlug}/${documentId}`;
try {
const response = await fetch(url, {
method: 'PATCH',
body: JSON.stringify({
kanbanStatus: kanbanStatus === 'null' ? null : kanbanStatus,
kanbanOrderRank,
}),
headers: {
'Content-Type': 'application/json',
'Accept-Language': i18n.language,
},
});
// Return the status code from the response
return response;
}
catch (error) {
console.error('Error updating kanban status:', error);
// Return a non-200 status code to indicate failure
return 500;
}
};
const { breakpoints: { s: smallBreak }, } = useWindowInfo();
// Empty callback that could be implemented later
const openBulkUpload = useCallback(() => { }, []);
const toggleView = () => setShowingWorkflow(!showingWorkflow);
// View toggle button component
const ViewToggleButton = (<Button buttonStyle="secondary" onClick={toggleView}>
{showingWorkflow ? 'Switch to table view' : 'Switch to kanban view'}
</Button>);
// If no read access or not on the same page, return default view
if (!hasReadAccess || !isFromSamePage)
return (<DefaultListView collectionSlug={''} columnState={[]} hasCreatePermission={true} newDocumentURL={''} Table={undefined} {...props}/>);
// If showing table view
if (!showingWorkflow) {
return (<div className={`${baseClass}_wrapper`}>
<DefaultListView collectionSlug={''} columnState={[]} hasCreatePermission={true} newDocumentURL={''} Table={undefined} Description={<div style={{ marginLeft: 'auto' }}>{ViewToggleButton}</div>} {...props}/>
</div>);
}
// If showing kanban view
return (<Fragment>
<TableColumnsProvider docs={docs} preferenceKey={`${collectionSlug}`} collectionSlug={collectionSlug} columnState={columnState} setTable={() => { }}>
<div className={`collection-list collection-list--${collectionSlug}`}>
<SelectionProvider docs={docs} totalDocs={listData.totalDocs} user={user}>
<Gutter className="collection-list__wrap">
{collectionConfig && (<ListHeader collectionConfig={collectionConfig} className={`${baseClass}_header`} Description={<div style={{ marginLeft: 'auto' }}>
<RenderCustomComponent CustomComponent={ViewToggleButton} Fallback={<ViewDescription description={collectionConfig?.admin?.description}/>}/>
</div>} hasCreatePermission={hasCreatePermission} i18n={i18n} isBulkUploadEnabled={false} newDocumentURL={newDocumentURL} openBulkUpload={openBulkUpload} smallBreak={smallBreak} t={function (key, options) {
throw new Error('Function not implemented.');
}}/>)}
<ListControls collectionConfig={collectionConfig} collectionSlug={collectionSlug} renderedFilters={renderedFilters}/>
<Board collection={collection} documents={listData.docs} hideNoStatusColumn={hideNoStatusColumn} statusDefinition={statusDefinition} onDocumentkanbanStatusChange={handleDocumentKanbanStatusChange} dragEnabled={dragEnabled} collectionSlug={collectionSlug}/>
</Gutter>
</SelectionProvider>
</div>
</TableColumnsProvider>
</Fragment>);
};
export default WorkflowView;