diff --git a/src/providers/modal.tsx b/src/providers/modal.tsx index ed9f6f24..4104b045 100644 --- a/src/providers/modal.tsx +++ b/src/providers/modal.tsx @@ -2,9 +2,10 @@ import { createContext, useContext, useState } from "react"; type ModalContextType = { isOpen: boolean; - openModal: (contentType: string) => void; + openModal: (contentType: string, entityId?: string) => void; closeModal: () => void; modalContentType: string; + entityId: string; }; interface Props { @@ -15,11 +16,13 @@ const ModalContext = createContext(undefined); export const ModalProvider: React.FC = ({ children }) => { const [isOpen, setIsOpen] = useState(false); + const [entityId, setEntityId] = useState(""); const [modalContentType, setModalContentType] = useState(""); - const openModal = (contentType: string) => { + const openModal = (contentType: string, entityId?: string) => { setIsOpen(true); setModalContentType(contentType); + if (entityId) setEntityId(entityId); }; const closeModal = () => { @@ -28,7 +31,7 @@ export const ModalProvider: React.FC = ({ children }) => { return ( {children} diff --git a/src/server/api/routers/label.ts b/src/server/api/routers/label.ts index 86584ab6..148d5b0a 100644 --- a/src/server/api/routers/label.ts +++ b/src/server/api/routers/label.ts @@ -7,6 +7,19 @@ import * as cardRepo from "~/server/db/repository/card.repo"; import * as labelRepo from "~/server/db/repository/label.repo"; export const labelRouter = createTRPCRouter({ + byPublicId: protectedProcedure + .input(z.object({ publicId: z.string().min(12) })) + .query(async ({ ctx, input }) => { + const label = await labelRepo.getByPublicId(ctx.db, input.publicId); + + if (!label) + throw new TRPCError({ + message: `Label with public ID ${input.publicId} not found`, + code: "NOT_FOUND", + }); + + return label; + }), create: protectedProcedure .input( z.object({ @@ -42,6 +55,19 @@ export const labelRouter = createTRPCRouter({ boardId: card.list.boardId, }); + return result; + }), + update: protectedProcedure + .input( + z.object({ + publicId: z.string().min(12), + name: z.string().min(1).max(36), + colourCode: z.string().length(7), + }), + ) + .mutation(async ({ ctx, input }) => { + const result = await labelRepo.update(ctx.db, input); + return result; }), }); diff --git a/src/server/db/repository/label.repo.ts b/src/server/db/repository/label.repo.ts index 6328103c..01c91160 100644 --- a/src/server/db/repository/label.repo.ts +++ b/src/server/db/repository/label.repo.ts @@ -52,10 +52,29 @@ export const getByPublicId = async ( ) => { const { data } = await db .from("label") - .select(`id`) + .select(`id, publicId, name, colourCode`) .eq("publicId", labelPublicId) .limit(1) .single(); return data; }; + +export const update = async ( + db: SupabaseClient, + labelInput: { + publicId: string; + name: string; + colourCode: string; + }, +) => { + const { data } = await db + .from("label") + .update({ + name: labelInput.name, + colourCode: labelInput.colourCode, + }) + .eq("publicId", labelInput.publicId); + + return data; +}; diff --git a/src/views/card/components/NewLabelForm.tsx b/src/views/card/components/LabelForm.tsx similarity index 77% rename from src/views/card/components/NewLabelForm.tsx rename to src/views/card/components/LabelForm.tsx index 37cca753..4ae1701b 100644 --- a/src/views/card/components/NewLabelForm.tsx +++ b/src/views/card/components/LabelForm.tsx @@ -10,11 +10,10 @@ import Button from "~/components/Button"; import Input from "~/components/Input"; import Toggle from "~/components/Toggle"; -import { type NewLabelInput } from "~/types/router.types"; - -type NewLabelFormInput = NewLabelInput & { +type LabelFormInput = { + name: string; colour: Colour; - isCreateAnotherEnabled: boolean; + isCreateAnotherEnabled?: boolean; }; type Colour = { @@ -33,19 +32,38 @@ const colours = [ { name: "Pink", code: "#db2777" }, ]; -export function NewLabelForm({ cardPublicId }: { cardPublicId: string }) { +export function LabelForm({ + cardPublicId, + isEdit, +}: { + cardPublicId: string; + isEdit?: boolean; +}) { const utils = api.useUtils(); - const { closeModal } = useModal(); + const { closeModal, entityId } = useModal(); + + const label = api.label.byPublicId.useQuery( + { + publicId: entityId, + }, + { + enabled: isEdit && !!entityId, + }, + ); const { control, register, reset, handleSubmit, setValue, watch } = - useForm({ - defaultValues: { - name: "", - colour: colours[0], + useForm({ + values: { + name: isEdit && label.data?.name ? label.data.name : "", + colour: (isEdit && label.data?.colourCode + ? colours.find((c) => c.code === label.data.colourCode) + : colours[0]) as Colour, isCreateAnotherEnabled: false, }, }); + console.log({ entityId }); + const refetchCard = () => utils.card.byId.refetch({ id: cardPublicId }); const isCreateAnotherEnabled = watch("isCreateAnotherEnabled"); @@ -69,21 +87,42 @@ export function NewLabelForm({ cardPublicId }: { cardPublicId: string }) { }, }); - const onSubmit = (values: NewLabelFormInput) => { + const updateLabel = api.label.update.useMutation({ + onSuccess: async () => { + await refetchCard(); + closeModal(); + reset({ + name: "", + colour: colours[0], + }); + }, + }); + + const onSubmit = (values: LabelFormInput) => { if (!values.colour?.code) return; - createLabel.mutate({ - name: values.name, - cardPublicId, - colourCode: values.colour.code, - }); + if (isEdit) { + updateLabel.mutate({ + publicId: label.data?.publicId || "", + name: values.name, + colourCode: values.colour.code, + }); + } else { + createLabel.mutate({ + name: values.name, + cardPublicId, + colourCode: values.colour.code, + }); + } }; return (
-

New label

+

+ {isEdit ? "Edit label" : "New label"} +

- - setValue("isCreateAnotherEnabled", !isCreateAnotherEnabled) - } - /> + {!isEdit && ( + + setValue("isCreateAnotherEnabled", !isCreateAnotherEnabled) + } + /> + )}
- +
diff --git a/src/views/card/components/LabelSelector.tsx b/src/views/card/components/LabelSelector.tsx index c559db40..3a8b6707 100644 --- a/src/views/card/components/LabelSelector.tsx +++ b/src/views/card/components/LabelSelector.tsx @@ -6,6 +6,8 @@ import { useForm } from "react-hook-form"; import { useModal } from "~/providers/modal"; +import { HiEllipsisHorizontal } from "react-icons/hi2"; + interface LabelSelectorProps { cardPublicId: string; labels: { @@ -103,7 +105,7 @@ export default function LabelSelector({ {() => (
{ const newValue = !watch(label.publicId); setValue(label.publicId, newValue); @@ -124,12 +126,23 @@ export default function LabelSelector({ {...register(label.publicId)} checked={watch(label.publicId)} /> - +
+ + +
)} diff --git a/src/views/card/index.tsx b/src/views/card/index.tsx index 89517b5d..0b3edfd5 100644 --- a/src/views/card/index.tsx +++ b/src/views/card/index.tsx @@ -9,7 +9,7 @@ import { DeleteCardConfirmation } from "./components/DeleteCardConfirmation"; import LabelSelector from "./components/LabelSelector"; import ListSelector from "./components/ListSelector"; import MemberSelector from "./components/MemberSelector"; -import { NewLabelForm } from "./components/NewLabelForm"; +import { LabelForm } from "./components/LabelForm"; import { NewWorkspaceForm } from "~/components/NewWorkspaceForm"; import Modal from "~/components/modal"; @@ -177,7 +177,10 @@ export default function CardPage() { {modalContentType === "NEW_LABEL" && ( - + + )} + {modalContentType === "EDIT_LABEL" && ( + )} {modalContentType === "DELETE_CARD" && (