import type { DraggableProvided } from "react-beautiful-dnd"; import { t } from "@lingui/core/macro"; import { useState } from "react"; import { HiXMark } from "react-icons/hi2"; import { RiDraggable } from "react-icons/ri"; import { twMerge } from "tailwind-merge"; import PlainTextEditor from "~/components/PlainTextEditor"; import { usePopup } from "~/providers/popup"; import { api } from "~/utils/api"; import { invalidateCard } from "~/utils/cardInvalidation"; interface ChecklistItemRowProps { item: { publicId: string; title: string; completed: boolean; }; cardPublicId: string; onCreateNewItem?: () => void; viewOnly?: boolean; dragHandleProps?: DraggableProvided["dragHandleProps"]; isDragging?: boolean; } export default function ChecklistItemRow({ item, cardPublicId, onCreateNewItem, viewOnly = false, dragHandleProps, isDragging = false, }: ChecklistItemRowProps) { const utils = api.useUtils(); const { showPopup } = usePopup(); const [completed, setCompleted] = useState(item.completed); const updateItem = api.checklist.updateItem.useMutation({ onMutate: async (vars) => { await utils.card.byId.cancel({ cardPublicId }); const previous = utils.card.byId.getData({ cardPublicId }); utils.card.byId.setData({ cardPublicId }, (old) => { if (!old) return old as any; const updatedChecklists = old.checklists.map((cl) => ({ ...cl, items: cl.items.map((ci) => ci.publicId === item.publicId ? { ...ci, ...(vars.title !== undefined ? { title: vars.title } : {}), ...(vars.completed !== undefined ? { completed: vars.completed } : {}), } : ci, ), })); return { ...old, checklists: updatedChecklists } as typeof old; }); return { previous }; }, onError: (_err, _vars, ctx) => { if (ctx?.previous) utils.card.byId.setData({ cardPublicId }, ctx.previous); showPopup({ header: t`Unable to update checklist item`, message: t`Please try again later, or contact customer support.`, icon: "error", }); }, onSettled: async () => { await invalidateCard(utils, cardPublicId); }, }); const deleteItem = api.checklist.deleteItem.useMutation({ onMutate: async () => { await utils.card.byId.cancel({ cardPublicId }); const previous = utils.card.byId.getData({ cardPublicId }); utils.card.byId.setData({ cardPublicId }, (old) => { if (!old) return old as any; const updatedChecklists = old.checklists.map((cl) => ({ ...cl, items: cl.items.filter((ci) => ci.publicId !== item.publicId), })); return { ...old, checklists: updatedChecklists } as typeof old; }); return { previous }; }, onError: (_err, _vars, ctx) => { if (ctx?.previous) utils.card.byId.setData({ cardPublicId }, ctx.previous); showPopup({ header: t`Unable to delete checklist item`, message: t`Please try again later, or contact customer support.`, icon: "error", }); }, onSettled: async () => { await invalidateCard(utils, cardPublicId); }, }); const handleToggleCompleted = () => { if (viewOnly) return; setCompleted((prev) => !prev); updateItem.mutate({ checklistItemPublicId: item.publicId, completed: !completed, }); }; const commitTitle = (plain: string) => { if (!plain || plain === item.title) return; updateItem.mutate({ checklistItemPublicId: item.publicId, title: plain, }); }; const handleDelete = () => { if (viewOnly) return; deleteItem.mutate({ checklistItemPublicId: item.publicId }); }; return (
{!viewOnly && (
)} {viewOnly &&
}
{ commitTitle(plain); onCreateNewItem?.(); }} onEscape={() => undefined} className={twMerge( "m-0 min-h-[20px] w-full p-0 text-sm leading-[20px] text-light-950 dark:text-dark-950", viewOnly && "cursor-default", )} />
{!viewOnly && ( )}
); }