"use client"; import { closestCorners, DndContext, type DragEndEvent, type DragOverEvent, DragOverlay, type DragStartEvent, KeyboardSensor, PointerSensor, useSensor, useSensors, } from "@dnd-kit/core"; import { arrayMove, horizontalListSortingStrategy, SortableContext, sortableKeyboardCoordinates, } from "@dnd-kit/sortable"; import { cn } from "@mdxui/primitives/lib/utils"; import * as React from "react"; import { KanbanCardComponent } from "./kanban-card"; import { KanbanColumnComponent } from "./kanban-column"; import type { KanbanBoardProps, KanbanCard, KanbanColumn } from "./types"; export function KanbanBoard({ columns: initialColumns, onCardMove, onCardClick, onAddCard, onColumnReorder, draggable = true, showAddButton = true, className, }: KanbanBoardProps) { const [columns, setColumns] = React.useState(initialColumns); const [activeCard, setActiveCard] = React.useState<{ card: KanbanCard; columnId: string; } | null>(null); const [activeColumn, setActiveColumn] = React.useState( null, ); React.useEffect(() => { setColumns(initialColumns); }, [initialColumns]); const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 8, }, }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates, }), ); const handleDragStart = (event: DragStartEvent) => { const { active } = event; const activeData = active.data.current; if (activeData?.type === "card") { setActiveCard({ card: activeData.card, columnId: activeData.columnId, }); } else if (activeData?.type === "column") { setActiveColumn(activeData.column); } }; const handleDragOver = (event: DragOverEvent) => { const { active, over } = event; if (!over) return; const activeData = active.data.current; const overData = over.data.current; if (activeData?.type !== "card" || !overData) return; const activeColumnId = activeData.columnId; const overColumnId = overData.type === "column" ? overData.column.id : overData.columnId; if (activeColumnId === overColumnId) return; setColumns((prevColumns) => { const activeColumnIndex = prevColumns.findIndex( (col) => col.id === activeColumnId, ); const overColumnIndex = prevColumns.findIndex( (col) => col.id === overColumnId, ); if (activeColumnIndex === -1 || overColumnIndex === -1) return prevColumns; const activeColumn = prevColumns[activeColumnIndex]; const overColumn = prevColumns[overColumnIndex]; const activeCardIndex = activeColumn.cards.findIndex( (card) => card.id === active.id, ); if (activeCardIndex === -1) return prevColumns; const newColumns = [...prevColumns]; const [movedCard] = newColumns[activeColumnIndex].cards.splice( activeCardIndex, 1, ); const overCardIndex = overData.type === "card" ? overData.index : overColumn.cards.length; newColumns[overColumnIndex].cards.splice(overCardIndex, 0, movedCard); return newColumns; }); }; const handleDragEnd = (event: DragEndEvent) => { const { active, over } = event; setActiveCard(null); setActiveColumn(null); if (!over) return; const activeData = active.data.current; const overData = over.data.current; if (activeData?.type === "column" && overData?.type === "column") { const activeIndex = columns.findIndex((col) => col.id === active.id); const overIndex = columns.findIndex((col) => col.id === over.id); if (activeIndex !== overIndex) { const newColumns = arrayMove(columns, activeIndex, overIndex); setColumns(newColumns); onColumnReorder?.(newColumns); } } else if (activeData?.type === "card") { const activeColumnId = activeData.columnId; const overColumnId = overData?.type === "column" ? overData.column.id : overData?.columnId; if (!overColumnId) return; const activeColumnIndex = columns.findIndex( (col) => col.id === activeColumnId, ); const overColumnIndex = columns.findIndex( (col) => col.id === overColumnId, ); if (activeColumnIndex === -1 || overColumnIndex === -1) return; const activeColumn = columns[activeColumnIndex]; const activeCardIndex = activeColumn.cards.findIndex( (card) => card.id === active.id, ); if (activeCardIndex === -1) return; const overColumn = columns[overColumnIndex]; const overCardIndex = overData?.type === "card" ? overData.index : overColumn.cards.length; if (activeColumnId === overColumnId) { if (activeCardIndex !== overCardIndex) { setColumns((prevColumns) => { const newColumns = [...prevColumns]; newColumns[activeColumnIndex].cards = arrayMove( newColumns[activeColumnIndex].cards, activeCardIndex, overCardIndex, ); return newColumns; }); } } else { onCardMove?.( active.id as string, activeColumnId, overColumnId, overCardIndex, ); } } }; const columnIds = columns.map((col) => col.id); return (
{columns.map((column) => ( ))}
{activeCard && ( )} {activeColumn && (

{activeColumn.title}

)}
); }