diff --git a/apps/web/src/components/CheckboxDropdown.tsx b/apps/web/src/components/CheckboxDropdown.tsx index 41516232..743e9d89 100644 --- a/apps/web/src/components/CheckboxDropdown.tsx +++ b/apps/web/src/components/CheckboxDropdown.tsx @@ -1,5 +1,6 @@ import { Menu, Transition } from "@headlessui/react"; import { Fragment, useState } from "react"; +import { HiEllipsisHorizontal, HiMiniPlus } from "react-icons/hi2"; import { twMerge } from "tailwind-merge"; interface Item { @@ -20,9 +21,12 @@ interface CheckboxDropdownProps { children: React.ReactNode; items?: Item[]; groups?: Group[]; + createNewItemLabel?: string; menuSpacing?: "sm" | "md" | "lg"; position?: "left" | "right"; handleSelect: (groupKey: string | null, item: { key: string }) => void; + handleEdit?: (key: string) => void; + handleCreate?: () => void; asChild?: boolean; } @@ -30,9 +34,12 @@ export default function CheckboxDropdown({ children, items, groups, + createNewItemLabel = "Create new", menuSpacing = "sm", position = "left", handleSelect, + handleEdit, + handleCreate, asChild = true, }: CheckboxDropdownProps) { const [selectedGroup, setSelectedGroup] = useState(null); @@ -43,6 +50,61 @@ export default function CheckboxDropdown({ lg: "top-[38px]", }; + const renderMenuItems = (items: Item[], groupKey: string | null) => ( + <> + {items.map((item) => ( + +
{ + e.preventDefault(); + handleSelect(groupKey, { key: item.key }); + }} + > + event.stopPropagation()} + onChange={() => handleSelect(groupKey, { key: item.key })} + checked={item.selected} + /> + {item.leftIcon && ( + {item.leftIcon} + )} + + {handleEdit && ( + + )} +
+
+ ))} + {handleCreate && ( + + )} + + ); + return ( {!selectedGroup ? ( <> - {items?.map((item) => ( - -
{ - e.preventDefault(); - handleSelect(null, { key: item.key }); - }} - > - event.stopPropagation()} - onChange={() => handleSelect(null, { key: item.key })} - checked={item.selected} - /> - {item.leftIcon && ( - - {item.leftIcon} - - )} - -
-
- ))} + {items && renderMenuItems(items, null)} + {groups?.map((group) => (
) : ( <> - {groups - ?.find((g) => g.key === selectedGroup) - ?.items.map((item) => ( - -
{ - e.preventDefault(); - handleSelect(selectedGroup, { key: item.key }); - }} - > - event.stopPropagation()} - onChange={() => - handleSelect(selectedGroup, { key: item.key }) - } - checked={item.selected} - /> - {item.leftIcon && ( - - {item.leftIcon} - - )} - -
-
- ))} + {groups?.find((g) => g.key === selectedGroup)?.items && + renderMenuItems( + groups.find((g) => g.key === selectedGroup)?.items || [], + selectedGroup, + )} )}
diff --git a/apps/web/src/views/card/components/LabelSelector.tsx b/apps/web/src/views/card/components/LabelSelector.tsx index 50f89ea7..6fd486a2 100644 --- a/apps/web/src/views/card/components/LabelSelector.tsx +++ b/apps/web/src/views/card/components/LabelSelector.tsx @@ -1,20 +1,18 @@ -import { Menu, Transition } from "@headlessui/react"; -import { Fragment } from "react"; -import { useForm } from "react-hook-form"; -import { HiEllipsisHorizontal, HiMiniPlus } from "react-icons/hi2"; +import { Menu } from "@headlessui/react"; +import { HiMiniPlus } from "react-icons/hi2"; import Badge from "~/components/Badge"; -import LabelIcon from "~/components/LabelIcon"; +import CheckboxDropdown from "~/components/CheckboxDropdown"; import { useModal } from "~/providers/modal"; import { api } from "~/utils/api"; interface LabelSelectorProps { cardPublicId: string; labels: { - publicId: string; - name: string; + key: string; + value: string; selected: boolean; - colourCode: string; + leftIcon: React.ReactNode; }[]; isLoading: boolean; } @@ -35,16 +33,6 @@ export default function LabelSelector({ }, }); - const { register, handleSubmit, setValue, watch } = useForm({ - values: Object.fromEntries( - labels.map((label) => [label.publicId, label.selected]) ?? [], - ), - }); - - const onSubmit = (values: Record) => { - console.log({ values }); - }; - const selectedLabels = labels.filter((label) => label.selected); return ( @@ -54,18 +42,21 @@ export default function LabelSelector({
) : ( - + addOrRemoveLabel.mutate({ cardPublicId, labelPublicId: label.key }) + } + handleEdit={(labelPublicId) => openModal("EDIT_LABEL", labelPublicId)} + handleCreate={() => openModal("NEW_LABEL")} + createNewItemLabel="Create new label" + asChild > {selectedLabels.length ? (
{selectedLabels.map((label) => ( - - } - /> + + ))} @@ -78,84 +69,7 @@ export default function LabelSelector({ Add label )} - - - -
-
- {labels.map((label) => ( - - {() => ( -
{ - const newValue = !watch(label.publicId); - setValue(label.publicId, newValue); - - addOrRemoveLabel.mutate({ - cardPublicId, - labelPublicId: label.publicId, - }); - - handleSubmit(onSubmit); - }} - > - event.stopPropagation()} - {...register(label.publicId)} - checked={watch(label.publicId)} - /> -
-
- - - - -
- - -
-
- )} -
- ))} - -
-
-
-
-
+ )} ); diff --git a/apps/web/src/views/card/index.tsx b/apps/web/src/views/card/index.tsx index 9bfe9fb8..477e7a13 100644 --- a/apps/web/src/views/card/index.tsx +++ b/apps/web/src/views/card/index.tsx @@ -4,6 +4,7 @@ import ContentEditable from "react-contenteditable"; import { useForm } from "react-hook-form"; import { IoChevronForwardSharp } from "react-icons/io5"; +import LabelIcon from "~/components/LabelIcon"; import Modal from "~/components/modal"; import { NewWorkspaceForm } from "~/components/NewWorkspaceForm"; import { PageHead } from "~/components/PageHead"; @@ -55,9 +56,10 @@ export default function CardPage() { ); return { - ...label, + key: label.publicId, + value: label.name, selected: isSelected ?? false, - colourCode: label.colourCode ?? "", + leftIcon: , }; }) ?? [];