From 260448447365b28e81de8cda741f4222c14b26a5 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 13 Nov 2023 23:39:29 +0000 Subject: [PATCH] feat: update card on drop --- src/app/boards/[...id]/page.tsx | 38 +++++++++++++++++++++++++++-- src/server/api/root.ts | 2 ++ src/server/api/routers/card.ts | 43 +++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 src/server/api/routers/card.ts diff --git a/src/app/boards/[...id]/page.tsx b/src/app/boards/[...id]/page.tsx index 5610631a..116335d8 100644 --- a/src/app/boards/[...id]/page.tsx +++ b/src/app/boards/[...id]/page.tsx @@ -2,7 +2,12 @@ import { useParams } from "next/navigation"; import { HiOutlinePlusSmall } from "react-icons/hi2"; -import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; +import { + DragDropContext, + Droppable, + type DropResult, + Draggable, +} from "react-beautiful-dnd"; import { api } from "~/trpc/react"; @@ -19,6 +24,7 @@ interface Card { export default function BoardPage() { const params = useParams(); + const utils = api.useUtils(); const boardId = params?.id?.length && params.id[0]; @@ -26,7 +32,35 @@ export default function BoardPage() { const { data } = api.board.byId.useQuery({ id: boardId }); - const onDragEnd = () => null; + const refetchBoard = () => utils.board.byId.refetch({ id: boardId }); + + const updateCard = api.card.update.useMutation({ + onSuccess: async () => { + try { + await refetchBoard(); + } catch (e) { + console.log(e); + } + }, + }); + + const onDragEnd = ({ + source, + destination, + draggableId, + }: DropResult): void => { + if (!destination) { + return; + } + + updateCard.mutate({ + cardId: draggableId, + currentListId: source.droppableId, + newListId: destination.droppableId, + currentIndex: source.index, + newIndex: destination.index, + }); + }; return (
diff --git a/src/server/api/root.ts b/src/server/api/root.ts index 976ea23f..896e14cc 100644 --- a/src/server/api/root.ts +++ b/src/server/api/root.ts @@ -1,4 +1,5 @@ import { boardRouter } from "~/server/api/routers/board"; +import { cardRouter } from "~/server/api/routers/card"; import { createTRPCRouter } from "~/server/api/trpc"; /** @@ -8,6 +9,7 @@ import { createTRPCRouter } from "~/server/api/trpc"; */ export const appRouter = createTRPCRouter({ board: boardRouter, + card: cardRouter }); // export type definition of API diff --git a/src/server/api/routers/card.ts b/src/server/api/routers/card.ts new file mode 100644 index 00000000..b0d6d725 --- /dev/null +++ b/src/server/api/routers/card.ts @@ -0,0 +1,43 @@ +import { z } from "zod"; +import { and, eq, gte, or} from "drizzle-orm"; + +import { cards, lists } from "~/server/db/schema"; + +import { + createTRPCRouter, + publicProcedure, +} from "~/server/api/trpc"; + +export const cardRouter = createTRPCRouter({ + update: publicProcedure + .input( + z.object({ + cardId: z.string().min(12), + currentListId: z.string().min(12), + newListId: 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 [currentList, newList] = await tx.select({ id: lists.id }).from(lists).where(or(eq(lists.publicId, input.currentListId), 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)) + }) + }), +}); \ No newline at end of file