diff --git a/package.json b/package.json index 1131dec..c556498 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "drag-drop-playground", + "name": "simple-kanban-board", "version": "0.1.0", "private": true, "dependencies": { diff --git a/src/App.js b/src/App.js deleted file mode 100644 index 69335e2..0000000 --- a/src/App.js +++ /dev/null @@ -1,117 +0,0 @@ -import * as Quote from 'inspirational-quotes'; -import { useState } from 'react'; -import { useDrag, useDrop } from 'react-dnd'; -import { v4 as uuidv4 } from 'uuid'; - -import './App.css'; - - -function getContent(n) { - const contents = [] - for (let i = 0; i < n; i++) { - contents.push({ - text: Quote.getRandomQuote(), - rowId: uuidv4() - }); - } - return contents -} - -const CardType = { TEXT: 'text', 'TEST': 'test' } - -function KanbanRow({ text, position, rowId, handleDrop }) { - const [{ opacity }, drag] = useDrag(() => ({ - type: CardType.TEXT, - item: { rowId }, - collect: monitor => ({ - opacity: monitor.isDragging() ? .5 : .9 - }), - end(item, monitor) { - const dropResult = monitor.getDropResult(); - if (dropResult !== null) { - handleDrop(item.rowId, dropResult.colId) - } - } - }), [rowId]); - - return ( -
-

{text}

-
- ) -} - -function KanbanColumn(props) { - const { colName, position, color, colId } = props; - const [{ canDrop, isOver }, drop] = useDrop(() => ({ - accept: CardType.TEXT, - drop: () => ({ colName, colId }), - collect: (monitor) => ({ - isOver: monitor.isOver(), - canDrop: monitor.canDrop(), - }), - }), [colName, colId]); - - const isActive = canDrop && isOver; - const droppingBox = isActive ? 'dropping-box' : ''; - return ( -
-
{colName}
- {props.children} -
- ) -} - -function NewKanbanRowPlaceHolder(position) { - return ( -
-
- ) -} - -const initialKanbanColumns = [ - { colName: 'QuoteList1', color: 'purple', colId: uuidv4(), data: getContent(7) }, - { colName: 'QuoteList2', color: 'orange', colId: uuidv4(), data: getContent(3) }, - { colName: 'QuoteList3', color: 'green', colId: uuidv4(), data: getContent(2) }, - { colName: 'QuoteList4', color: 'blue', colId: uuidv4(), data: getContent(5) }, -] - -function moveQuotes(kanbanColumns, destColId, rowId) { - const srcColumn = kanbanColumns.find(column => column.data.map(data => data.rowId).includes(rowId)); - const destColumn = kanbanColumns.find(column => column.colId === destColId); - const rowIndexPosInSrcColumn = srcColumn.data.findIndex(row => row.rowId === rowId); - destColumn.data.push(srcColumn.data[rowIndexPosInSrcColumn]); - srcColumn.data.splice(rowIndexPosInSrcColumn, 1); - return [...kanbanColumns]; -} - -function App() { - const [kanbanColumns, setKanbanColumns] = useState(initialKanbanColumns); - - const handleDrop = (rowId, colId) => { - setKanbanColumns(prevKanbanColumns => moveQuotes(prevKanbanColumns, colId, rowId)); - } - - return ( -
- { - kanbanColumns && kanbanColumns.map((column, idx) => ( - - {column.data.map( - ({ text, rowId }, idx) => ) - } - ) - ) - } -
- ); -} - -export default App; diff --git a/src/Kanban.js b/src/Kanban.js new file mode 100644 index 0000000..db37829 --- /dev/null +++ b/src/Kanban.js @@ -0,0 +1,100 @@ +import { useState } from 'react'; +import { useDrag, useDrop } from 'react-dnd'; +import './App.css'; + +const CardType = { TEXT: 'text', TEST: 'test' }; + +function KanbanCard({ text }) { + return (

{text}

); +} + +function KanbanRow({ + text, rowId, handleDrop, +}) { + const [{ opacity }, drag] = useDrag(() => ({ + type: CardType.TEXT, + item: { rowId }, + collect: (monitor) => ({ + opacity: monitor.isDragging() ? 0.5 : 0.9, + }), + end(item, monitor) { + const dropResult = monitor.getDropResult(); + if (dropResult !== null) { + handleDrop(item.rowId, dropResult.colId); + } + }, + }), [rowId]); + + return ( +
+ +
+ ); +} + +function KanbanColumn(props) { + const { + colName, color, colId, + } = props; + const [{ canDrop, isOver }, drop] = useDrop(() => ({ + accept: CardType.TEXT, + drop: () => ({ colName, colId }), + collect: (monitor) => ({ + isOver: monitor.isOver(), + canDrop: monitor.canDrop(), + }), + }), [colName, colId]); + + const isActive = canDrop && isOver; + const droppingBox = isActive ? 'dropping-box' : ''; + return ( +
+
{colName}
+ {props.children} +
+ ); +} + +function moveCards(kanbanColumns, destColId, rowId) { + const srcColumn = kanbanColumns + .find((column) => column.data.map((data) => data.rowId).includes(rowId)); + const destColumn = kanbanColumns.find((column) => column.colId === destColId); + const rowIndexPosInSrcColumn = srcColumn.data.findIndex((row) => row.rowId === rowId); + destColumn.data.push(srcColumn.data[rowIndexPosInSrcColumn]); + srcColumn.data.splice(rowIndexPosInSrcColumn, 1); + return [...kanbanColumns]; +} + +function SimpleKanban({ initialKanbanColumns }) { + const [kanbanColumns, setKanbanColumns] = useState(initialKanbanColumns); + + const handleDrop = (rowId, colId) => { + setKanbanColumns((prevKanbanColumns) => moveCards(prevKanbanColumns, colId, rowId)); + }; + + return ( +
+ { + kanbanColumns && kanbanColumns.map((column) => ( + + {column.data.map( + ({ text, rowId }) => , + ) + } + )) + } +
+ ); +} + +export default SimpleKanban; diff --git a/src/index.js b/src/index.js index da863aa..8fd8876 100644 --- a/src/index.js +++ b/src/index.js @@ -1,17 +1,45 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; +import { v4 as uuidv4 } from 'uuid'; +import * as Quote from 'inspirational-quotes'; +import SimpleKanban from './Kanban'; +import reportWebVitals from './reportWebVitals'; + +function getContent(n) { + const contents = []; + for (let i = 0; i < n; i += 1) { + contents.push({ + text: Quote.getRandomQuote(), + rowId: uuidv4(), + }); + } + return contents; +} + +const initialKanbanColumns = [ + { + colName: 'QuoteList1', color: 'purple', colId: uuidv4(), data: getContent(7), + }, + { + colName: 'QuoteList2', color: 'orange', colId: uuidv4(), data: getContent(3), + }, + { + colName: 'QuoteList3', color: 'green', colId: uuidv4(), data: getContent(2), + }, + { + colName: 'QuoteList4', color: 'blue', colId: uuidv4(), data: getContent(5), + }, +]; ReactDOM.render( - + , - document.getElementById('root') + document.getElementById('root'), ); // If you want to start measuring performance in your app, pass a function diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js index 5253d3a..bb47dbb 100644 --- a/src/reportWebVitals.js +++ b/src/reportWebVitals.js @@ -1,6 +1,8 @@ -const reportWebVitals = onPerfEntry => { +const reportWebVitals = (onPerfEntry) => { if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + import('web-vitals').then(({ + getCLS, getFID, getFCP, getLCP, getTTFB, + }) => { getCLS(onPerfEntry); getFID(onPerfEntry); getFCP(onPerfEntry);