From f93752de1494e5ee047cef4203c2cbc9b093425f Mon Sep 17 00:00:00 2001 From: sepehr Date: Sat, 2 May 2026 20:18:18 +0200 Subject: [PATCH] fix: dynamic note restore without page reload + fix note list sync bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - NoteHistoryModal: remove window.location.reload(), use onRestored(restored) callback - NotesTabsView: revert sync derivation to useEffect, add prevNotesRef to detect server-side content changes (restore) vs local edits — fixes note disappear bug and cross-notebook notes appearing after refresh - NoteInlineEditor key: include updatedAt so restoration remounts editor with fresh content - note-card: render title/content/labels from note prop directly, not optimisticNote --- memento-note/components/notes-tabs-view.tsx | 78 +++++++++++---------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/memento-note/components/notes-tabs-view.tsx b/memento-note/components/notes-tabs-view.tsx index 6f6ab25..4e94d3a 100644 --- a/memento-note/components/notes-tabs-view.tsx +++ b/memento-note/components/notes-tabs-view.tsx @@ -643,46 +643,50 @@ export function NotesTabsView({ const prevNotesRef = useRef(notes) - if (notes !== prevNotesRef.current) { - const prevIds = items.map((n) => n.id).join(',') - const incomingIds = notes.map((n) => n.id).join(',') - - const merge = (fresh: Note, local: Note, oldFresh?: Note) => { - const labelsChanged = JSON.stringify(fresh.labels?.sort()) !== JSON.stringify(local.labels?.sort()) - - const contentChangedOnServer = oldFresh && oldFresh.content !== fresh.content - const titleChangedOnServer = oldFresh && oldFresh.title !== fresh.title - const checkItemsChangedOnServer = oldFresh && JSON.stringify(oldFresh.checkItems) !== JSON.stringify(fresh.checkItems) + useEffect(() => { + setItems((prev) => { + const prevIds = prev.map((n) => n.id).join(',') + const incomingIds = notes.map((n) => n.id).join(',') - return { - ...fresh, - title: titleChangedOnServer ? fresh.title : (local.title || fresh.title), - content: contentChangedOnServer ? fresh.content : local.content, - checkItems: checkItemsChangedOnServer ? fresh.checkItems : local.checkItems, - labels: labelsChanged ? fresh.labels : local.labels + const merge = (fresh: Note, local: Note) => { + // Detect if the server explicitly changed content since last sync + const prevServer = prevNotesRef.current.find((n) => n.id === fresh.id) + const serverContentChanged = prevServer ? prevServer.content !== fresh.content : false + const serverTitleChanged = prevServer ? prevServer.title !== fresh.title : false + const serverCheckItemsChanged = prevServer + ? JSON.stringify(prevServer.checkItems) !== JSON.stringify(fresh.checkItems) + : false + const labelsChanged = + JSON.stringify(fresh.labels?.slice().sort()) !== + JSON.stringify(local.labels?.slice().sort()) + + return { + ...fresh, + title: serverTitleChanged ? fresh.title : local.title || fresh.title, + content: serverContentChanged ? fresh.content : local.content, + checkItems: serverCheckItemsChanged ? fresh.checkItems : local.checkItems, + labels: labelsChanged ? fresh.labels : local.labels, + } } - } - - let newItems: Note[] - if (prevIds === incomingIds) { - newItems = items.map((local) => { - const fresh = notes.find((n) => n.id === local.id) - if (!fresh) return local - const oldFresh = prevNotesRef.current.find((n) => n.id === local.id) - return merge(fresh, local, oldFresh) - }) - } else { - newItems = notes.map((fresh) => { - const local = items.find((p) => p.id === fresh.id) - if (!local) return fresh - const oldFresh = prevNotesRef.current.find((n) => n.id === fresh.id) - return merge(fresh, local, oldFresh) - }) - } - - setItems(newItems) + + let result: Note[] + if (prevIds === incomingIds) { + result = prev.map((local) => { + const fresh = notes.find((n) => n.id === local.id) + return fresh ? merge(fresh, local) : local + }) + } else { + result = notes.map((fresh) => { + const local = prev.find((p) => p.id === fresh.id) + return local ? merge(fresh, local) : fresh + }) + } + + return result + }) + prevNotesRef.current = notes - } + }, [notes]) useEffect(() => { if (items.length === 0) {