From 4cc505c63d15d7fc5dd1e6876231f44184ae0fdf Mon Sep 17 00:00:00 2001 From: Froidefond Julien Date: Wed, 25 Mar 2026 16:46:37 +0100 Subject: [PATCH] fix(gif-mood): prevent SSE refresh from wiping in-progress note edits Track textarea focus state and skip note sync from server while focused. Fixes concurrent edit race condition where router.refresh() triggered by another participant's SSE event would overwrite the current user's draft. Co-Authored-By: Claude Sonnet 4.6 --- src/components/gif-mood/GifMoodCard.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/gif-mood/GifMoodCard.tsx b/src/components/gif-mood/GifMoodCard.tsx index e860721..ca3ead3 100644 --- a/src/components/gif-mood/GifMoodCard.tsx +++ b/src/components/gif-mood/GifMoodCard.tsx @@ -26,6 +26,7 @@ export const GifMoodCard = memo(function GifMoodCard({ const [itemVersion, setItemVersion] = useState(item); const [isPending, startTransition] = useTransition(); const [imgError, setImgError] = useState(false); + const [isFocused, setIsFocused] = useState(false); const textareaRef = useRef(null); useEffect(() => { @@ -35,9 +36,12 @@ export const GifMoodCard = memo(function GifMoodCard({ el.style.height = el.scrollHeight + 'px'; }, [note]); + // Sync from server only when not focused — prevents SSE refresh from wiping in-progress edits if (itemVersion !== item) { setItemVersion(item); - setNote(item.note || ''); + if (!isFocused) { + setNote(item.note || ''); + } } const isOwner = item.userId === currentUserId; @@ -103,7 +107,8 @@ export const GifMoodCard = memo(function GifMoodCard({ ref={textareaRef} value={note} onChange={(e) => setNote(e.target.value)} - onBlur={handleNoteBlur} + onFocus={() => setIsFocused(true)} + onBlur={() => { setIsFocused(false); handleNoteBlur(); }} placeholder="Ajouter une note…" rows={1} className="w-full text-foreground/70 bg-transparent resize-none outline-none placeholder:text-muted/40 leading-snug text-center overflow-hidden"