From e9211464d616e7e34b2488a6e0740beabe395bd8 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 17 Apr 2025 14:09:56 +0100 Subject: [PATCH] feat: create label from new card modal --- apps/web/src/components/CheckboxDropdown.tsx | 4 ++-- .../components/DeleteLabelConfirmation.tsx | 9 +++---- .../{views/card => }/components/LabelForm.tsx | 19 +++++++-------- .../views/board/components/NewCardForm.tsx | 7 +++++- apps/web/src/views/board/index.tsx | 24 ++++++++++++++++++- apps/web/src/views/card/index.tsx | 18 ++++++++++---- packages/api/src/routers/label.ts | 13 +++++----- packages/db/src/repository/board.repo.ts | 14 +++++++++++ 8 files changed, 77 insertions(+), 31 deletions(-) rename apps/web/src/{views/card => }/components/DeleteLabelConfirmation.tsx (88%) rename apps/web/src/{views/card => }/components/LabelForm.tsx (96%) diff --git a/apps/web/src/components/CheckboxDropdown.tsx b/apps/web/src/components/CheckboxDropdown.tsx index bcfec462..5a9148f7 100644 --- a/apps/web/src/components/CheckboxDropdown.tsx +++ b/apps/web/src/components/CheckboxDropdown.tsx @@ -135,12 +135,12 @@ export default function CheckboxDropdown({ > -
+
{!selectedGroup ? ( <> {items && renderMenuItems(items, null)} diff --git a/apps/web/src/views/card/components/DeleteLabelConfirmation.tsx b/apps/web/src/components/DeleteLabelConfirmation.tsx similarity index 88% rename from apps/web/src/views/card/components/DeleteLabelConfirmation.tsx rename to apps/web/src/components/DeleteLabelConfirmation.tsx index f821e6c2..e4a7650a 100644 --- a/apps/web/src/views/card/components/DeleteLabelConfirmation.tsx +++ b/apps/web/src/components/DeleteLabelConfirmation.tsx @@ -4,20 +4,17 @@ import { usePopup } from "~/providers/popup"; import { api } from "~/utils/api"; export function DeleteLabelConfirmation({ - cardPublicId, labelPublicId, + refetch, }: { - cardPublicId: string; labelPublicId: string; + refetch: () => void; }) { - const utils = api.useUtils(); const { closeModal } = useModal(); const { showPopup } = usePopup(); - const refetchCard = () => utils.card.byId.refetch({ cardPublicId }); - const deleteLabelMutation = api.label.delete.useMutation({ - onSuccess: () => refetchCard(), + onSuccess: () => refetch(), onError: () => showPopup({ header: "Error deleting label", diff --git a/apps/web/src/views/card/components/LabelForm.tsx b/apps/web/src/components/LabelForm.tsx similarity index 96% rename from apps/web/src/views/card/components/LabelForm.tsx rename to apps/web/src/components/LabelForm.tsx index 81b16778..ef1a5496 100644 --- a/apps/web/src/views/card/components/LabelForm.tsx +++ b/apps/web/src/components/LabelForm.tsx @@ -23,13 +23,14 @@ interface Colour { } export function LabelForm({ - cardPublicId, + boardPublicId, + refetch, isEdit, }: { - cardPublicId: string; + boardPublicId: string; + refetch: () => void; isEdit?: boolean; }) { - const utils = api.useUtils(); const { closeModal, entityId, openModal } = useModal(); const label = api.label.byPublicId.useQuery( @@ -52,17 +53,15 @@ export function LabelForm({ }, }); - const refetchCard = () => utils.card.byId.refetch({ cardPublicId }); - const isCreateAnotherEnabled = watch("isCreateAnotherEnabled"); const createLabel = api.label.create.useMutation({ - onSuccess: async () => { + onSuccess: () => { const currentColourIndex = colours.findIndex( (c) => c.code === watch("colour").code, ); try { - await refetchCard(); + refetch(); if (!isCreateAnotherEnabled) closeModal(); reset({ name: "", @@ -76,8 +75,8 @@ export function LabelForm({ }); const updateLabel = api.label.update.useMutation({ - onSuccess: async () => { - await refetchCard(); + onSuccess: () => { + refetch(); closeModal(); reset({ name: "", @@ -98,8 +97,8 @@ export function LabelForm({ } else { createLabel.mutate({ name: values.name, - cardPublicId, colourCode: values.colour.code, + boardPublicId, }); } }; diff --git a/apps/web/src/views/board/components/NewCardForm.tsx b/apps/web/src/views/board/components/NewCardForm.tsx index 32463cc1..fa6f49c9 100644 --- a/apps/web/src/views/board/components/NewCardForm.tsx +++ b/apps/web/src/views/board/components/NewCardForm.tsx @@ -43,7 +43,7 @@ export function NewCardForm({ queryParams, }: NewCardFormProps) { const { showPopup } = usePopup(); - const { closeModal } = useModal(); + const { closeModal, openModal } = useModal(); const utils = api.useUtils(); @@ -299,6 +299,11 @@ export function NewCardForm({ handleSelectLabels(item.key)} + handleEdit={(labelPublicId) => + openModal("EDIT_LABEL", labelPublicId) + } + handleCreate={() => openModal("NEW_LABEL")} + createNewItemLabel="Create new label" >
{!labelPublicIds.length ? ( diff --git a/apps/web/src/views/board/index.tsx b/apps/web/src/views/board/index.tsx index 204bc041..46f65d37 100644 --- a/apps/web/src/views/board/index.tsx +++ b/apps/web/src/views/board/index.tsx @@ -11,6 +11,8 @@ import { HiOutlinePlusSmall, HiOutlineSquare3Stack3D } from "react-icons/hi2"; import type { UpdateBoardInput } from "@kan/api/types"; import Button from "~/components/Button"; +import { DeleteLabelConfirmation } from "~/components/DeleteLabelConfirmation"; +import { LabelForm } from "~/components/LabelForm"; import Modal from "~/components/modal"; import { NewWorkspaceForm } from "~/components/NewWorkspaceForm"; import { PageHead } from "~/components/PageHead"; @@ -40,7 +42,7 @@ export default function BoardPage() { const utils = api.useUtils(); const { showPopup } = usePopup(); const { workspace } = useWorkspace(); - const { openModal, modalContentType } = useModal(); + const { openModal, modalContentType, entityId } = useModal(); const [selectedPublicListId, setSelectedPublicListId] = useState(""); const [isInitialLoading, setIsInitialLoading] = useState(true); @@ -78,6 +80,10 @@ export default function BoardPage() { placeholderData: keepPreviousData, }); + const refetchBoard = async () => { + if (boardId) await utils.board.byId.refetch({ boardPublicId: boardId }); + }; + useEffect(() => { if (boardId) { setIsInitialLoading(false); @@ -409,6 +415,22 @@ export default function BoardPage() { /> )} {modalContentType === "NEW_WORKSPACE" && } + {modalContentType === "NEW_LABEL" && ( + + )} + {modalContentType === "EDIT_LABEL" && ( + + )} + {modalContentType === "DELETE_LABEL" && ( + + )} {modalContentType === "UPDATE_BOARD_SLUG" && ( { + if (cardId) await utils.card.byId.refetch({ cardPublicId: cardId }); + }; + const board = card?.list?.board; const boardId = board?.publicId; const labels = board?.labels; @@ -246,14 +250,18 @@ export default function CardPage() { {modalContentType === "NEW_LABEL" && ( - + )} {modalContentType === "EDIT_LABEL" && ( - + )} {modalContentType === "DELETE_LABEL" && ( )} diff --git a/packages/api/src/routers/label.ts b/packages/api/src/routers/label.ts index d4f94ba0..ca4b72ec 100644 --- a/packages/api/src/routers/label.ts +++ b/packages/api/src/routers/label.ts @@ -1,6 +1,7 @@ import { TRPCError } from "@trpc/server"; import { z } from "zod"; +import * as boardRepo from "@kan/db/repository/board.repo"; import * as cardRepo from "@kan/db/repository/card.repo"; import * as labelRepo from "@kan/db/repository/label.repo"; @@ -45,7 +46,7 @@ export const labelRouter = createTRPCRouter({ .input( z.object({ name: z.string().min(1).max(36), - cardPublicId: z.string().min(12), + boardPublicId: z.string().min(12), colourCode: z.string().length(7), }), ) @@ -59,14 +60,14 @@ export const labelRouter = createTRPCRouter({ code: "UNAUTHORIZED", }); - const card = await cardRepo.getCardWithListByPublicId( + const board = await boardRepo.getIdByPublicId( ctx.db, - input.cardPublicId, + input.boardPublicId, ); - if (!card?.list) + if (!board) throw new TRPCError({ - message: `Card with public ID ${input.cardPublicId} not found`, + message: `Board with public ID ${input.boardPublicId} not found`, code: "NOT_FOUND", }); @@ -74,7 +75,7 @@ export const labelRouter = createTRPCRouter({ name: input.name, colourCode: input.colourCode, createdBy: userId, - boardId: card.list.boardId, + boardId: board.id, }); if (!result) diff --git a/packages/db/src/repository/board.repo.ts b/packages/db/src/repository/board.repo.ts index bb10982b..1f4c0beb 100644 --- a/packages/db/src/repository/board.repo.ts +++ b/packages/db/src/repository/board.repo.ts @@ -16,6 +16,20 @@ export const getAllByWorkspaceId = async ( return data ?? []; }; +export const getIdByPublicId = async ( + db: SupabaseClient, + boardPublicId: string, +) => { + const { data } = await db + .from("board") + .select("id") + .eq("publicId", boardPublicId) + .limit(1) + .single(); + + return data; +}; + export const getByPublicId = async ( db: SupabaseClient, boardPublicId: string,