44 - Kanban board for managing tasks with drag-and-drop

Description

Develop a React component that visualizes tasks in a Kanban board format with drag-and-drop functionality, enabling task organization and visual workflow management.

  • Displays multiple columns representing different stages of a workflow (e.g., To Do, In Progress, Done).

  • Renders tasks as draggable cards within each column.

  • Allows users to move cards between columns using drag-and-drop to update their status.

  • Optionally supports features like:

    • Task editing and creation

    • Deadlines and priority indicators

    • Filtering and sorting

Algorithm

  1. Component Structure:

    • Define a functional component named KanbanBoard.

    • Accept props for:

      • columns: Array of column objects defining each stage (name, tasks).

      • onTaskMove: Function to handle task status updates when moved.

    • Maintain internal state for:

      • draggedTask: Task being dragged, if any.

      • dragSourceColumn: Column from which the task was dragged.

      • dragTargetColumn: Column over which the task is currently hovering.

  2. Column Rendering:

    • Iterate through the columns array and render each column as a container.

    • Within each column, map over its tasks array and create draggable card elements.

  3. Drag Handling:

    • Attach onDragStart, onDragOver, onDragEnd event listeners to cards and columns:

      • onDragStart: Sets the draggedTask and dragSourceColumn state.

      • onDragOver: Updates dragTargetColumn state based on hover position.

      • onDragEnd: Conditionally moves the task to the new column and calls onTaskMove prop function.

Code

import React, { useState } from 'react';

const KanbanBoard = ({ columns, onTaskMove }) => {
  const [draggedTask, setDraggedTask] = useState(null);
  const [dragSourceColumn, setDragSourceColumn] = useState(null);
  const [dragTargetColumn, setDragTargetColumn] = useState(null);

  const handleDragStart = (task, column) => {
    setDraggedTask(task);
    setDragSourceColumn(column);
  };

  const handleDragOver = (column) => {
    setDragTargetColumn(column);
  };

  const handleDragEnd = () => {
    if (dragTargetColumn && dragTargetColumn !== dragSourceColumn) {
      const updatedColumns = columns.map((column) => {
        if (column === dragSourceColumn) {
          return { ...column, tasks: column.tasks.filter((task) => task !== draggedTask) };
        } else if (column === dragTargetColumn) {
          return { ...column, tasks: [...column.tasks, draggedTask] };
        }
        return column;
      });
      setDraggedTask(null);
      setDragSourceColumn(null);
      setDragTargetColumn(null);
      if (onTaskMove) onTaskMove(draggedTask, dragSourceColumn, dragTargetColumn);
    }
  };

  const renderColumn = (column, columnIndex) => (
    <div key={column.id} className="kanban-column">
      <h3>{column.name}</h3>
      {column.tasks.map((task, taskIndex) => (
        <div
          key={task.id}
          className={draggedTask === task ? 'kanban-card dragging' : 'kanban-card'}
          draggable
          onDragStart={() => handleDragStart(task, column)}
          onDragOver={handleDragOver.bind(null, column)}
        >
          {task.content}
        </div>
      ))}
    </div>
  );

  return (
    <div className="kanban-board">
      {columns.map(renderColumn)}
    </div>
  );
};

export default KanbanBoard;

Explanation

  • State management: Tracks the dragged task, source column, and target column using useState.

  • Drag interaction:

    • onDragStart: Sets the dragged task and source column state.

    • onDragOver: Updates the target column state based on hover position.

    • onDragEnd: Moves the task to the new column and calls the onTaskMove prop function if applicable.

  • Column and task rendering:

    • renderColumn iterates through columns and tasks, creating draggable card elements for each task.

    • Cards receive drag event listeners and conditional styling based on the dragged state.

Additional Notes

  • This is a basic example and can be further customized with styling, animations, and visual indicators.

  • Integrate the onTaskMove prop function with your logic for updating task data based on column changes.

Last updated