diff --git a/next.config.mjs b/next.config.mjs index 65764c2d..27f10c6c 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -6,6 +6,7 @@ await import("./src/env.mjs"); /** @type {import("next").NextConfig} */ const config = { + reactStrictMode: false, images: { remotePatterns: [ { diff --git a/src/app/boards/[...id]/page.tsx b/src/app/boards/[...id]/page.tsx index 116335d8..c559d6da 100644 --- a/src/app/boards/[...id]/page.tsx +++ b/src/app/boards/[...id]/page.tsx @@ -44,22 +44,44 @@ export default function BoardPage() { }, }); + const updateList = api.list.update.useMutation({ + onSuccess: async () => { + try { + await refetchBoard(); + } catch (e) { + console.log(e); + } + }, + }); + const onDragEnd = ({ source, destination, draggableId, + type, }: DropResult): void => { if (!destination) { return; } - updateCard.mutate({ - cardId: draggableId, - currentListId: source.droppableId, - newListId: destination.droppableId, - currentIndex: source.index, - newIndex: destination.index, - }); + if (type === "LIST") { + updateList.mutate({ + boardId, + listId: draggableId, + currentIndex: source.index, + newIndex: destination.index, + }); + } + + if (type === "CARD") { + updateCard.mutate({ + cardId: draggableId, + currentListId: source.droppableId, + newListId: destination.droppableId, + currentIndex: source.index, + newIndex: destination.index, + }); + } }; return ( @@ -83,44 +105,70 @@ export default function BoardPage() { -
- {data?.lists.map((list: List) => ( - - {(provided) => ( -
+ {(provided) => ( +
+ {data?.lists.map((list: List, index) => ( + -

- {list.name} -

- - {list.cards?.map((card, index) => ( - ( +
- {(provided) => ( -
-

{card.title}

-
- )} - - ))} -
- )} - - ))} -
+ + {(provided) => ( +
+

+ {list.name} +

+ + {list.cards?.map((card, index) => ( + + {(provided) => ( +
+

+ {card.title} +

+
+ )} +
+ ))} + {provided.placeholder} +
+ )} +
+
+ )} + + ))} + {provided.placeholder} +
+ )} +
); diff --git a/src/server/api/root.ts b/src/server/api/root.ts index 896e14cc..74f5d66b 100644 --- a/src/server/api/root.ts +++ b/src/server/api/root.ts @@ -1,5 +1,6 @@ import { boardRouter } from "~/server/api/routers/board"; import { cardRouter } from "~/server/api/routers/card"; +import { listRouter } from "~/server/api/routers/list"; import { createTRPCRouter } from "~/server/api/trpc"; /** @@ -9,7 +10,8 @@ import { createTRPCRouter } from "~/server/api/trpc"; */ export const appRouter = createTRPCRouter({ board: boardRouter, - card: cardRouter + card: cardRouter, + list: listRouter, }); // export type definition of API diff --git a/src/server/api/routers/card.ts b/src/server/api/routers/card.ts index b0d6d725..f52ec692 100644 --- a/src/server/api/routers/card.ts +++ b/src/server/api/routers/card.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { and, eq, gte, or} from "drizzle-orm"; +import { eq, sql } from "drizzle-orm"; import { cards, lists } from "~/server/db/schema"; @@ -24,20 +24,33 @@ export const cardRouter = createTRPCRouter({ if (!userId) return; return ctx.db.transaction(async (tx) => { - const [currentList, newList] = await tx.select({ id: lists.id }).from(lists).where(or(eq(lists.publicId, input.currentListId), eq(lists.publicId, input.newListId))) - + const [currentList] = await tx.select({ id: lists.id }).from(lists).where(eq(lists.publicId, input.currentListId)) + const [newList] = await tx.select({ id: lists.id }).from(lists).where(eq(lists.publicId, input.newListId)) if (!currentList?.id || !newList?.id) return; - - await tx - .update(cards) - .set({ index: input.newIndex + 1 }) - .where(and(eq(cards.listId, newList.id), gte(cards.index, input.newIndex))) - await tx - .update(cards) - .set({ listId: newList.id, index: input.newIndex }) - .where(eq(cards.publicId, input.cardId)) + if (currentList.id === newList.id) { + await tx.execute(sql` + UPDATE ${cards} + SET ${cards.index} = + CASE + WHEN ${cards.index} = ${input.currentIndex} THEN ${input.newIndex} + WHEN ${input.currentIndex} < ${input.newIndex} AND ${cards.index} > ${input.currentIndex} AND ${cards.index} <= ${input.newIndex} THEN ${cards.index} - 1 + WHEN ${input.currentIndex} > ${input.newIndex} AND ${cards.index} >= ${input.newIndex} AND ${cards.index} < ${input.currentIndex} THEN ${cards.index} + 1 + ELSE ${cards.index} + END + WHERE ${cards.listId} = ${currentList.id}; + `); + } else { + await tx.execute(sql`UPDATE ${cards} SET ${cards.index} = ${cards.index} + 1 WHERE ${cards.listId} = ${newList.id} AND ${cards.index} >= ${input.newIndex};`) + + await tx.execute(sql`UPDATE ${cards} SET ${cards.index} = ${cards.index} - 1 WHERE ${cards.listId} = ${currentList.id} AND ${cards.index} >= ${input.currentIndex};`) + + await tx + .update(cards) + .set({ listId: newList.id, index: input.newIndex }) + .where(eq(cards.publicId, input.cardId)); + } }) - }), + }) }); \ No newline at end of file diff --git a/src/server/api/routers/list.ts b/src/server/api/routers/list.ts new file mode 100644 index 00000000..0a90e6c6 --- /dev/null +++ b/src/server/api/routers/list.ts @@ -0,0 +1,45 @@ +import { z } from "zod"; +import { eq, sql } from "drizzle-orm"; + +import { lists } from "~/server/db/schema"; + +import { + createTRPCRouter, + publicProcedure, +} from "~/server/api/trpc"; + +export const listRouter = createTRPCRouter({ + update: publicProcedure + .input( + z.object({ + boardId: z.string().min(12), + listId: z.string().min(12), + currentIndex: z.number(), + newIndex: z.number(), + })) + .mutation(({ ctx, input }) => { + const userId = ctx.session?.user.id; + + if (!userId) return; + + return ctx.db.transaction(async (tx) => { + const [list] = await tx.select({ id: lists.id, boardId: lists.boardId }).from(lists).where(eq(lists.publicId, input.listId)) + + if (!list) return; + + await tx.execute(sql` + UPDATE ${lists} + SET ${lists.index} = + CASE + WHEN ${lists.index} = ${input.currentIndex} AND ${lists.id} = ${list.id} THEN ${input.newIndex} + WHEN ${input.currentIndex} < ${input.newIndex} AND ${lists.index} > ${input.currentIndex} AND ${lists.index} <= ${input.newIndex} THEN ${lists.index} - 1 + WHEN ${input.currentIndex} > ${input.newIndex} AND ${lists.index} >= ${input.newIndex} AND ${lists.index} < ${input.currentIndex} THEN ${lists.index} + 1 + ELSE ${lists.index} + END + WHERE ${lists.boardId} = ${list.boardId}; + `); + }) + + + }) +}); \ No newline at end of file