"; dropping on
+ // another card gives that card's id and the destination is its column.
+ let destinationColumnId: string;
+ let dropIndex: number;
+
+ if (overId.startsWith("column:")) {
+ destinationColumnId = overId.slice("column:".length);
+ dropIndex = (byColumn.get(destinationColumnId) ?? []).length;
+ } else {
+ const overCard = cards.find((c) => c.id === overId);
+ if (!overCard) return;
+ destinationColumnId = overCard.column;
+ const list = byColumn.get(destinationColumnId) ?? [];
+ dropIndex = list.findIndex((c) => c.id === overCard.id);
+ }
+
+ const destination = byColumn.get(destinationColumnId) ?? [];
+ const sameColumn = card.column === destinationColumnId;
+
+ const position = computeDropPosition(
+ destination,
+ dropIndex,
+ sameColumn ? card.id : null
+ );
+
+ if (sameColumn && position === card.position) return;
+
+ const previous = cards;
+ const optimistic = cards.map((c) =>
+ c.id === card.id ? { ...c, column: destinationColumnId, position } : c
+ );
+ setCards(optimistic);
+
+ // Through the server route, not the browser SDK: the auth token lives in
+ // an httpOnly cookie that JavaScript cannot read, so the browser-side
+ // PocketBase instance has no credentials. See Task 10.
+ const response = await fetch(`/api/owner/cards/${card.id}/move`, {
+ method: "PATCH",
+ headers: { "content-type": "application/json" },
+ body: JSON.stringify({ column: destinationColumnId, position }),
+ });
+
+ if (!response.ok) {
+ console.error("[board] move failed", response.status);
+ setCards(previous);
+ }
+ }
+
+ function onPatched(updated: CardRecord) {
+ setCards((current) =>
+ current.map((c) => (c.id === updated.id ? { ...c, ...updated } : c))
+ );
+ }
+
+ const content = (
+
+ {columns.map((column) => {
+ const list = byColumn.get(column.id) ?? [];
+ return (
+
+ c.id)}
+ strategy={verticalListSortingStrategy}
+ >
+ {list.map((card) => (
+
+ ))}
+
+
+ );
+ })}
+
+ );
+
+ if (role !== "owner") {
+ return {content}
;
+ }
+
+ return (
+
+
+ {content}
+
+ {activeCard && }
+
+
+
+ );
+}
\ No newline at end of file