Skip to content

Commit dfc9d73

Browse files
authored
Merge pull request #287 from mpJunot/285-fix-fix-drag-and-drop
feat(frontend): sortable listes/cartes, arrayMove, collision listes, …
2 parents 8a8d7f9 + b81fb65 commit dfc9d73

9 files changed

Lines changed: 519 additions & 478 deletions

File tree

frontend/app/boards/[id]/cardEventHandlers.ts

Lines changed: 100 additions & 172 deletions
Large diffs are not rendered by default.

frontend/app/boards/[id]/listEventHandlers.ts

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { QueryClient } from '@tanstack/react-query';
22
import { Dispatch, SetStateAction } from 'react';
3+
import { arrayMove } from '@dnd-kit/sortable';
34
import { createList, updateList, reorderLists, deleteList, archiveList } from '@/lib/actions/lists';
45
import { createCard, moveCard } from '@/lib/actions/cards';
56
import { List, Card } from './types';
@@ -63,36 +64,27 @@ export function createListEventHandlers(
6364
if (!detail) return;
6465
const { listId, newPosition } = detail;
6566

66-
let updatedLists: List[] = [];
67+
let listPositions: { id: string; position: number }[] = [];
6768
let originalLists: List[] = [];
6869

69-
// Optimistic UI update
7070
setLists((prevLists) => {
7171
originalLists = [...prevLists];
7272
const sourceIndex = prevLists.findIndex((l) => l.id === listId);
73-
7473
if (sourceIndex === -1 || sourceIndex === newPosition) return prevLists;
7574

76-
const updated = [...prevLists];
77-
const [moved] = updated.splice(sourceIndex, 1);
78-
updated.splice(newPosition, 0, moved);
79-
updatedLists = updated;
75+
const updated = arrayMove(prevLists, sourceIndex, newPosition);
76+
listPositions = updated.map((l, idx) => ({ id: l.id, position: idx }));
8077
return updated;
8178
});
8279

83-
// Backend sync with rollback
84-
(async () => {
85-
try {
86-
const positions = updatedLists.map((l, idx) => ({ id: l.id, position: idx }));
87-
await reorderLists({ boardId, listPositions: positions });
88-
logAction('✅', 'Lists reordered');
89-
invalidateBoard();
90-
} catch (err) {
91-
handleAsyncError(err, 'reorder lists');
92-
// Rollback on failure
93-
setLists(() => originalLists);
94-
}
95-
})();
80+
try {
81+
await reorderLists({ boardId, listPositions });
82+
logAction('✅', 'Lists reordered');
83+
invalidateBoard();
84+
} catch (err) {
85+
handleAsyncError(err, 'reorder lists');
86+
setLists(() => originalLists);
87+
}
9688
}
9789

9890
async function handleListCopy(e?: DetailEvent<{ sourceListId: string; newListTitle: string }>) {
@@ -123,7 +115,6 @@ export function createListEventHandlers(
123115
return [...prevLists, newList];
124116
});
125117

126-
// If no cards to create, exit early
127118
if (!cardsToCreate) return;
128119

129120
(async () => {
@@ -132,7 +123,6 @@ export function createListEventHandlers(
132123
const newList = await createList({ boardId, title: newListTitle });
133124
if (!newList) throw new Error('Failed to copy list');
134125

135-
// 2. Create all cards in the new list
136126
const createdCards: Card[] = [];
137127
for (let i = 0; i < cardsToCreate.length; i++) {
138128
const sourceCard = cardsToCreate[i];

0 commit comments

Comments
 (0)