From f1a314c60d090fe16afcc8f7a740bf6982caa2d9 Mon Sep 17 00:00:00 2001 From: Hammer Date: Thu, 29 Jan 2026 01:49:31 +0000 Subject: [PATCH] feat: save/cancel buttons for task editing (HQ-19) - EditableText now updates draft state instead of saving immediately - Panel tracks dirty state across title, description, priority, source - Save/Cancel bar slides up when any field is modified - Cancel reverts all changes, Save commits them in one API call - Slide-up animation for the save/cancel bar --- frontend/src/components/TaskDetailPanel.tsx | 113 ++++++++++++++++---- frontend/src/index.css | 15 +++ 2 files changed, 105 insertions(+), 23 deletions(-) diff --git a/frontend/src/components/TaskDetailPanel.tsx b/frontend/src/components/TaskDetailPanel.tsx index 98d8b6e..4a0c8cf 100644 --- a/frontend/src/components/TaskDetailPanel.tsx +++ b/frontend/src/components/TaskDetailPanel.tsx @@ -124,27 +124,24 @@ function ElapsedTimer({ since }: { since: string }) { function EditableText({ value, - onSave, + onChange, multiline = false, className = "", placeholder = "Click to edit...", }: { value: string; - onSave: (val: string) => void; + onChange: (val: string) => void; multiline?: boolean; className?: string; placeholder?: string; }) { const [editing, setEditing] = useState(false); - const [draft, setDraft] = useState(value); const ref = useRef(null); - useEffect(() => { setDraft(value); }, [value]); useEffect(() => { if (editing) ref.current?.focus(); }, [editing]); - const save = () => { + const stopEditing = () => { setEditing(false); - if (draft.trim() !== value) onSave(draft.trim()); }; if (!editing) { @@ -164,10 +161,10 @@ function EditableText({ return (