From e1970c792f82286e807499a12e1233e8322691fb Mon Sep 17 00:00:00 2001 From: Danny Ward Date: Mon, 26 Oct 2026 08:44:39 -0400 Subject: [PATCH 1/2] fix(ui): flush pending sticky saves on unmount Closes #377 Co-Authored-By: OpenAI Codex (GPT-6) --- .../components/stickies/StickyNoteCard.tsx | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/apps/web/src/components/stickies/StickyNoteCard.tsx b/apps/web/src/components/stickies/StickyNoteCard.tsx index c8985c72..1d9bbabe 100644 --- a/apps/web/src/components/stickies/StickyNoteCard.tsx +++ b/apps/web/src/components/stickies/StickyNoteCard.tsx @@ -196,6 +196,7 @@ export function StickyNoteCard({ const safeSlug = workspaceSlug.trim(); const initialHtml = getInitialStickyHtml(sticky); const debounceRef = useRef | null>(null); + const pendingHtmlRef = useRef(null); const lastSyncedHtmlRef = useRef(initialHtml); const contentRequestIdRef = useRef(0); const colorRequestIdRef = useRef(0); @@ -228,6 +229,11 @@ export function StickyNoteCard({ }, [safeSlug, sticky.id, onUpdate], ); + const persistStickyRef = useRef(persistSticky); + + useEffect(() => { + persistStickyRef.current = persistSticky; + }, [persistSticky]); const editor = useEditor({ extensions: [ @@ -259,15 +265,25 @@ export function StickyNoteCard({ ], content: initialHtml, onUpdate: ({ editor: ed }) => { - const html = ed.getHTML(); + pendingHtmlRef.current = ed.getHTML(); if (debounceRef.current) clearTimeout(debounceRef.current); - debounceRef.current = setTimeout(() => persistSticky(html), 400); + debounceRef.current = setTimeout(() => { + debounceRef.current = null; + const pendingHtml = pendingHtmlRef.current; + pendingHtmlRef.current = null; + if (pendingHtml !== null) persistStickyRef.current(pendingHtml); + }, 400); }, }); useEffect( () => () => { - if (debounceRef.current) clearTimeout(debounceRef.current); + if (!debounceRef.current) return; + clearTimeout(debounceRef.current); + debounceRef.current = null; + const pendingHtml = pendingHtmlRef.current; + pendingHtmlRef.current = null; + if (pendingHtml !== null) persistStickyRef.current(pendingHtml); }, [], ); From 0029f0d1d63993c59d1a020faa0f2683e7da3282 Mon Sep 17 00:00:00 2001 From: Danny Ward Date: Wed, 28 Oct 2026 12:56:11 -0400 Subject: [PATCH 2/2] fix(ui): serialize sticky note updates Co-Authored-By: OpenAI Codex --- .../components/stickies/StickyNoteCard.tsx | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/apps/web/src/components/stickies/StickyNoteCard.tsx b/apps/web/src/components/stickies/StickyNoteCard.tsx index 1d9bbabe..9cfcd790 100644 --- a/apps/web/src/components/stickies/StickyNoteCard.tsx +++ b/apps/web/src/components/stickies/StickyNoteCard.tsx @@ -199,6 +199,7 @@ export function StickyNoteCard({ const pendingHtmlRef = useRef(null); const lastSyncedHtmlRef = useRef(initialHtml); const contentRequestIdRef = useRef(0); + const stickyUpdateChainRef = useRef>(Promise.resolve()); const colorRequestIdRef = useRef(0); const colorListboxId = useId(); const [colorOpen, setColorOpen] = useState(false); @@ -210,11 +211,17 @@ export function StickyNoteCard({ if (!safeSlug) return; const plain = htmlToPlainText(html).slice(0, 255); const requestId = ++contentRequestIdRef.current; - stickiesService - .update(safeSlug, sticky.id, { + const save = stickyUpdateChainRef.current.then(() => + stickiesService.update(safeSlug, sticky.id, { description: html, name: plain || 'Untitled', - }) + }), + ); + stickyUpdateChainRef.current = save.then( + () => undefined, + () => undefined, + ); + save .then((data) => { if (requestId !== contentRequestIdRef.current) return; setContentSaveError(false); @@ -311,8 +318,14 @@ export function StickyNoteCard({ const setStickyColor = (next: string) => { if (!safeSlug) return; const requestId = ++colorRequestIdRef.current; - stickiesService - .update(safeSlug, sticky.id, { color: next }) + const update = stickyUpdateChainRef.current.then(() => + stickiesService.update(safeSlug, sticky.id, { color: next }), + ); + stickyUpdateChainRef.current = update.then( + () => undefined, + () => undefined, + ); + update .then((data) => { if (requestId !== colorRequestIdRef.current) return; onUpdate(data);