From b7c88e844b49714221d43a7977381575858dd28e Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 20 Nov 2024 18:18:57 +0000 Subject: [PATCH] feat: rollback card/list if duplicate index --- src/server/api/routers/board.ts | 4 +- src/server/api/routers/list.ts | 7 ++- .../components/DeleteListConfirmation.tsx | 15 ++++- supabase/seed.sql | 58 ++++++++++++++----- 4 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/server/api/routers/board.ts b/src/server/api/routers/board.ts index a057d84b..d68ff6d6 100644 --- a/src/server/api/routers/board.ts +++ b/src/server/api/routers/board.ts @@ -210,7 +210,7 @@ export const boardRouter = createTRPCRouter({ deletedBy: userId, }); - if (!deletedLists?.length) { + if (!Array.isArray(deletedLists)) { throw new TRPCError({ message: `Failed to delete lists`, code: "INTERNAL_SERVER_ERROR", @@ -223,7 +223,7 @@ export const boardRouter = createTRPCRouter({ deletedBy: userId, }); - if (!deletedCards?.length) { + if (!Array.isArray(deletedCards)) { throw new TRPCError({ message: `Failed to delete cards`, code: "INTERNAL_SERVER_ERROR", diff --git a/src/server/api/routers/list.ts b/src/server/api/routers/list.ts index 2383e83a..c460fda5 100644 --- a/src/server/api/routers/list.ts +++ b/src/server/api/routers/list.ts @@ -53,7 +53,8 @@ export const listRouter = createTRPCRouter({ name: input.name, createdBy: userId, boardId: board.id, - index: latestListIndex ? latestListIndex + 1 : 0, + index: + latestListIndex || latestListIndex === 0 ? latestListIndex + 1 : 0, }); if (!result) @@ -161,7 +162,7 @@ export const listRouter = createTRPCRouter({ deletedBy: userId, }); - if (!deletedCards?.length) + if (!Array.isArray(deletedCards)) throw new TRPCError({ message: `Failed to delete cards`, code: "INTERNAL_SERVER_ERROR", @@ -177,7 +178,7 @@ export const listRouter = createTRPCRouter({ await listRepo.shiftIndex(ctx.db, { boardId: list.boardId, - listIndex: list.id, + listIndex: list.index, }); return { success: true }; diff --git a/src/views/board/components/DeleteListConfirmation.tsx b/src/views/board/components/DeleteListConfirmation.tsx index 17d3237e..2601cf5e 100644 --- a/src/views/board/components/DeleteListConfirmation.tsx +++ b/src/views/board/components/DeleteListConfirmation.tsx @@ -1,6 +1,7 @@ import { api } from "~/utils/api"; import { useBoard } from "~/providers/board"; import { useModal } from "~/providers/modal"; +import { usePopup } from "~/providers/popup"; import Button from "~/components/Button"; @@ -14,6 +15,7 @@ export function DeleteListConfirmation({ const utils = api.useUtils(); const { boardData } = useBoard(); const { closeModal } = useModal(); + const { showPopup } = usePopup(); const refetchBoard = async () => { if (boardData?.publicId) { @@ -30,6 +32,14 @@ export function DeleteListConfirmation({ closeModal(); return refetchBoard(); }, + onError: async () => { + closeModal(); + await refetchBoard(); + showPopup({ + header: "Unable to delete list", + message: "Please try again later, or contact customer support.", + }); + }, }); return ( @@ -46,7 +56,10 @@ export function DeleteListConfirmation({ - diff --git a/supabase/seed.sql b/supabase/seed.sql index f41c1da5..676ff13d 100644 --- a/supabase/seed.sql +++ b/supabase/seed.sql @@ -1,20 +1,36 @@ CREATE OR REPLACE FUNCTION reorder_lists(board_id BIGINT, list_id BIGINT, current_index INT, new_index INT) -RETURNS VOID -LANGUAGE SQL -AS $$ - UPDATE list - SET index = - CASE - WHEN index = current_index AND id = list_id THEN new_index - WHEN current_index < new_index AND index > current_index AND index <= new_index THEN index - 1 - WHEN current_index > new_index AND index >= new_index AND index < current_index THEN index + 1 - ELSE index - END - WHERE "boardId" = board_id; +RETURNS BOOLEAN +LANGUAGE PLPGSQL +AS $$ +BEGIN + UPDATE list + SET index = + CASE + WHEN index = current_index AND id = list_id THEN new_index + WHEN current_index < new_index AND index > current_index AND index <= new_index THEN index - 1 + WHEN current_index > new_index AND index >= new_index AND index < current_index THEN index + 1 + ELSE index + END + WHERE "boardId" = board_id; + + -- Check for duplicate indices after the update + IF EXISTS ( + SELECT index, COUNT(*) + FROM list + WHERE "boardId" = board_id + AND "deletedAt" IS NULL + GROUP BY index + HAVING COUNT(*) > 1 + ) THEN + RAISE EXCEPTION 'Duplicate indices found after reordering in board %', board_id; + END IF; + + RETURN TRUE; +END; $$; CREATE OR REPLACE FUNCTION reorder_cards(card_id BIGINT, current_list_id BIGINT, new_list_id BIGINT, current_index INT, new_index INT) -RETURNS VOID +RETURNS BOOLEAN LANGUAGE PLPGSQL AS $$ DECLARE @@ -45,8 +61,22 @@ AS $$ SET "listId" = new_list_id, index = new_index WHERE id = card_id AND "deletedAt" IS NULL; END IF; + + -- Check for duplicate indices in both affected lists + IF EXISTS ( + SELECT index, COUNT(*) + FROM card + WHERE "listId" IN (current_list_id, new_list_id) + AND "deletedAt" IS NULL + GROUP BY "listId", index + HAVING COUNT(*) > 1 + ) THEN + RAISE EXCEPTION 'Duplicate indices found after reordering in list % or %', current_list_id, new_list_id; + END IF; + + RETURN TRUE; END; -$$ +$$; CREATE OR REPLACE FUNCTION shift_list_index(board_id BIGINT, list_index INT) RETURNS VOID