import { useParams, Link } from 'react-router-dom'; import { useBoard } from '../hooks/useBoard'; import { useCardMutations } from '../hooks/useCardMutations'; import { useListMutations } from '../hooks/useListMutations'; import { SortableKanbanColumn } from '../components/kanban/SortableKanbanColumn'; import { CreateListModal } from '../components/kanban/CreateListModal'; import { CardPreviewModal } from '../components/CardPreviewModal'; import { useModal } from '../context/modals/useModal'; import { DndContext, DragEndEvent, DragOverlay, DragStartEvent, DragOverEvent, PointerSensor, useSensor, useSensors, closestCenter, } from '@dnd-kit/core'; import { SortableContext, horizontalListSortingStrategy } from '@dnd-kit/sortable'; import { Card as CardType, ListWithCards } from '../types/kanban'; import { useState } from 'react'; export function BoardDetail() { const { id } = useParams<{ id: string }>(); const { board, fetchBoard } = useBoard(parseInt(id || '0')); const { createCard, moveCard } = useCardMutations(parseInt(id || '0'), fetchBoard); const { createList, updateList, deleteList } = useListMutations(parseInt(id || '0'), fetchBoard); const { openModal } = useModal(); const [activeCard, setActiveCard] = useState(null); const [activeList, setActiveList] = useState(null); const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 8, }, }) ); const handleDragStart = (event: DragStartEvent) => { const { active } = event; const [activeType, activeIdStr] = (active.id as string).split('_'); if (activeType === 'COLUMN') { // Dragging a column const listId = parseInt(activeIdStr); const list = board?.lists.find((l) => l.id === listId); if (list) { setActiveList(list); } } else if (activeType === 'CARD') { // Dragging a card const cardId = parseInt(activeIdStr); if (board) { const card = board.lists.flatMap((list) => list.cards).find((c) => c.id === cardId); if (card) { setActiveCard(card); } } } }; const handleDragOver = (event: DragOverEvent) => { const { active, over } = event; // console.log('---handleDragOver', event); if (!over) return; // const activeId = parseInt(active.id as string); // const overId = parseInt(over.id as string); const overIdStr = (over.id as string).split('_')[1]; const overId = parseInt(overIdStr, 10); const activeIdStr = (active.id as string).split('_')[1]; const activeId = parseInt(activeIdStr, 10); if (activeId === overId) return; // Find active card and its current list if (!board) return; const activeList = board.lists.find((list) => list.cards.some((card) => card.id === activeId)); // If we're hovering over a card in same list, do nothing if (activeList) { const overCard = activeList.cards.find((card) => card.id === overId); if (overCard) return; } }; const handleDragEnd = async (event: DragEndEvent) => { const { active, over } = event; setActiveCard(null); setActiveList(null); if (!over || !board) return; const [activeType, activeIdStr] = (active.id as string).split('_'); const [overType, overIdStr] = (over.id as string).split('_'); const activeId = parseInt(activeIdStr, 10); const overId = parseInt(overIdStr, 10); if (active.id === over.id) return; // Handle column reordering if (activeType === 'COLUMN') { // todo find over column id, let overListIndex = -1; const activeList = board.lists.find((l) => l.id === activeId); if (overType === 'CARD') { overListIndex = board.lists.findIndex((l) => { const foundIndex = l.cards.findIndex((card) => card.id === overId); return foundIndex >= 0; }); } else if (overType === 'LIST') { overListIndex = board.lists.findIndex((l) => l.id === overId); } // console.log('-------active.id', active.id) // console.log('-------overType.id', overType) // console.log('-------overListIndex', overListIndex) const activeListIndex = board.lists.findIndex((l) => l.id === activeId); // overListIndex = board.lists.findIndex((l) => l.id === overId); if (activeListIndex === -1 || overListIndex === -1 || !activeList) return; // Calculate new positions for all lists const reorderedLists = [...board.lists]; const [movedList] = reorderedLists.splice(activeListIndex, 1); reorderedLists.splice(overListIndex, 0, movedList); await updateList(activeList.id, { name: activeList.name, pos: overListIndex }); // // Update all list positions // for (let i = 0; i < reorderedLists.length; i++) { // const list = reorderedLists[i]; // if (list.pos !== i) { // await updateList(list.id, { name: list.name, pos: i }); // } // } return; } // Handle card reordering (existing logic) // Find active card let activeCard: CardType | undefined; let activeList: (typeof board.lists)[0] | undefined; for (const list of board.lists) { const card = list.cards.find((c) => c.id === activeId); if (card) { activeCard = card; activeList = list; break; } } if (!activeCard || !activeList) return; // Check if we're dropping on a list or a card if (overType.toLowerCase() === 'list') { const overList = board.lists.find((list) => list.id === overId); // Dropping on a list - append to end if (!overList || overList.id === activeList.id) return; // Same list, do nothing await moveCard(activeCard, activeList.id, overList.id, overList.cards.length); return; } // Dropping on a card - find which list it belongs to let overCard: CardType | undefined; let overListContainingCard: (typeof board.lists)[0] | undefined; for (const list of board.lists) { const card = list.cards.find((c) => c.id === overId); if (card) { overCard = card; overListContainingCard = list; break; } } if (!overCard || !overListContainingCard) return; // Calculate new position const overCardIndex = overListContainingCard.cards.findIndex((c) => c.id === overId); await moveCard(activeCard, activeList.id, overListContainingCard.id, overCardIndex); }; const handleOpenCardModal = (card: CardType) => { openModal((props) => ); }; const handleAddList = () => { openModal((props) => ( { await createList(name, board ? board.lists.length : 0); fetchBoard(); // Refresh board data }} /> )); }; const handleEditList = async (listId: number, name: string) => { const list = board?.lists.find((l) => l.id === listId); if (list) { await updateList(listId, { name, pos: list.pos }); } }; const handleDeleteList = async (listId: number) => { await deleteList(listId); }; const handleAddCard = (listId: number) => async (data: { name: string; description?: string }) => { await createCard(listId, { name: data.name, description: data.description, pos: board ? board.lists.find((list) => list.id === listId)?.cards.length || 0 : 0, }); fetchBoard(); // Refresh board data }; if (!board) { return
Loading...
; } return (
← Back to Boards

{board.name}

{board.description &&

{board.description}

}
Edit Board
`COLUMN_${list.id}`)} strategy={horizontalListSortingStrategy} >
{board.lists.map((list) => ( handleEditList(list.id, name)} onListDelete={() => handleDeleteList(list.id)} /> ))}
{activeCard ? (

{activeCard.name}

) : activeList ? (

{activeList.name}

{activeList.cards.length} cards
) : null}
); }