import { t } from "@lingui/core/macro"; import { useEffect, useRef, useState } from "react"; import { twMerge } from "tailwind-merge"; import { usePopup } from "~/providers/popup"; import { api } from "~/utils/api"; export default function ChecklistNameInput({ checklistPublicId, initialName, cardPublicId, viewOnly = false, }: { checklistPublicId: string; initialName: string; cardPublicId: string; viewOnly?: boolean; }) { const utils = api.useUtils(); const { showPopup } = usePopup(); const [name, setName] = useState(initialName); const inputRef = useRef(null); useEffect(() => { setName(initialName); }, [initialName, checklistPublicId]); const update = api.checklist.update.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 updated = old.checklists.map((cl) => cl.publicId === checklistPublicId ? { ...cl, name: vars.name } : cl, ); return { ...old, checklists: updated } 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`, message: t`Please try again later, or contact customer support.`, icon: "error", }); }, onSettled: async () => { await utils.card.byId.invalidate({ cardPublicId }); }, }); const commit = () => { if (viewOnly) return; const trimmed = name.trim(); if (!trimmed || trimmed === initialName) return; update.mutate({ checklistPublicId, name: trimmed }); }; return ( setName(e.target.value)} onBlur={commit} onKeyDown={(e) => { if (viewOnly) return; if (e.key === "Enter") { e.preventDefault(); commit(); inputRef.current?.blur(); } if (e.key === "Escape") { e.preventDefault(); setName(initialName); inputRef.current?.blur(); } }} title={name} className={twMerge( "text-md block w-full truncate border-0 bg-transparent p-0 py-0 font-medium text-light-1000 outline-none focus:ring-0 dark:text-dark-1000", viewOnly && "cursor-default", )} /> ); }