Skip to content

Lite Note: Core note organization improvements - #9

Open
ark-commits wants to merge 1 commit into
masterfrom
note-organization-basics
Open

Lite Note: Core note organization improvements#9
ark-commits wants to merge 1 commit into
masterfrom
note-organization-basics

Conversation

@ark-commits

@ark-commits ark-commits commented Feb 18, 2026

Copy link
Copy Markdown
Owner

This PR implements core note organization improvements in Lite Note (search, pin/unpin, rename, duplicate, delete, recency sorting, and notes storage v2 migration).

Closes https://linear.app/arkcoderabbit/issue/ARK-5/lite-note-core-note-organization-improvements

Summary by CodeRabbit

  • New Features

    • Search bar now filters by title and content in real time and shows a “no results” message.
    • Note actions: rename, duplicate (resets pin), delete (with fallback/confirmation), toggle pin.
    • Create new blank/default notes and pick emojis for them.
  • Improvements

    • Notes sorted by recent edits when searching; relative “last edited” timestamps shown.
    • Sidebar slightly wider with updated layout and action controls.

@coderabbitai

coderabbitai Bot commented Feb 18, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

App and sidebar changes add dual-key localStorage for notes (v2 preferred, v1 fallback), normalize note shape (id, createdAt, updatedAt, isPinned), introduce search/filter/sort (visibleNotes), and add in-app note mutations (rename, delete, duplicate, toggle-pin) with UI wiring and formatted timestamps.

Changes

Notes Storage, State, Search & UI

Layer / File(s) Summary
Data Shape & Factories
src/App.jsx
Introduce STORAGE_KEYS.notesV1/notesV2; add generateNoteId, createDefaultNote(overrides), createBlankNote with createdAt/updatedAt/isPinned.
Validation / Normalization
src/App.jsx
Add isBaseNote/normalizeNotes pipeline to filter/normalize notes and ensure updatedAt and isPinned defaults.
Storage Read / Migration
src/App.jsx
readStoredNotes now prefers notesV2, falls back to notesV1, otherwise creates a default note.
Derived State: Search & Sorting
src/App.jsx
Add searchQuery and normalizedSearchQuery; compute visibleNotes by filtering title/content and sorting (pinned-first when no query; updatedAt-desc when querying).
Note Mutation Handlers
src/App.jsx
Add handleSearchChange, handleRenameNote, handleDeleteNote (with blank fallback and active-note reassignment), handleDuplicateNote (new id, “Copy”, reset pin), handleTogglePin; update updatedAt on edits; commitDraftToNote sets updatedAt only on change.
Persistence / Wiring
src/App.jsx
Switch storage writes to STORAGE_KEYS.notesV2; createNoteId delegates to generateNoteId; maintain active-note reconciliation on notes changes.
Sidebar UI & Props
src/components/NotesSidebar.jsx, src/App.jsx
NotesSidebar gains searchQuery, onSearchChange, onRenameNote, onDeleteNote, onDuplicateNote, onTogglePin, newNoteTitle/Emoji props; adds formatEditedAt; search bar and action controls (pin, rename, copy, delete); no-results fallback; desktop sidebar width expanded from w-72 to w-80; both desktop and mobile drawers receive visibleNotes and mutation callbacks.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant Sidebar as NotesSidebar
    participant App as App
    participant Storage as localStorage

    User->>Sidebar: types in search / clicks action
    Sidebar->>App: onSearchChange / onRenameNote / onDeleteNote / onDuplicateNote / onTogglePin
    App->>App: update searchQuery or mutate notes (normalize, set updatedAt, toggle isPinned)
    App->>App: recompute visibleNotes (filter + sort)
    App->>Storage: persist notes to notesV2
    App->>Sidebar: render visibleNotes + current searchQuery
    Sidebar->>User: display filtered/sorted notes and updated UI
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • ARK-5: Lite Note: Core note organization improvements — Implements search/filter, per-note actions, pinned-first/updatedAt sorting, timestamp fields, and v1→v2 storage migration matching the issue objectives.

Possibly related PRs

Poem

🐇 I burrowed through bytes, found notes old and new,

I stitched their timestamps, gave each a fresh view.
Pin, rename, duplicate — hops quick as a wink,
Search lights the trail where the secret thoughts sink.
A tiny rabbit cheers: your notes now bloom and grew.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Lite Note: Core note organization improvements' accurately summarizes the main changes: search, pin/unpin, rename, duplicate, delete functionality, and recency sorting with v2 storage migration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch note-organization-basics

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • LINEAR integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Review rate limit: 9/10 reviews remaining, refill in 6 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/App.jsx`:
- Around line 189-209: The visibleNotes useMemo currently sorts by updatedAt
when normalizedSearchQuery is truthy, which ignores isPinned; instead, first
filter notes by normalizedSearchQuery (if present) and then sort the resulting
list so pinned notes always come first and within each group sort by updatedAt.
Update the visibleNotes logic to: compute filteredNotes = normalizedSearchQuery
? notes.filter(...) : notes; then compute sortedNotes =
[...filteredNotes].sort((a,b) => (a.isPinned === b.isPinned) ? (b.updatedAt -
a.updatedAt) : (a.isPinned ? -1 : 1)); and return sortedNotes; ensure you
reference normalizedSearchQuery, visibleNotes, sortedNotes and isPinned in the
change.

Comment thread src/App.jsx
Comment on lines +189 to +209
const normalizedSearchQuery = useMemo(() => searchQuery.trim().toLowerCase(), [searchQuery])

const visibleNotes = useMemo(() => {
const sortedNotes = [...notes].sort((a, b) => {
if (normalizedSearchQuery) {
return b.updatedAt - a.updatedAt
}

if (a.isPinned !== b.isPinned) {
return a.isPinned ? -1 : 1
}

return b.updatedAt - a.updatedAt
})

if (!normalizedSearchQuery) {
return sortedNotes
}

return sortedNotes.filter((note) => note.title.toLowerCase().includes(normalizedSearchQuery))
}, [notes, normalizedSearchQuery])

@coderabbitai coderabbitai Bot Feb 18, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Pinned notes lose priority during search.

When normalizedSearchQuery is set, sorting ignores isPinned, so pinned notes can appear below unpinned ones. This violates the requirement that pinned notes remain on top.

✅ Suggested fix (filter first, then always pin-sort)
-  const visibleNotes = useMemo(() => {
-    const sortedNotes = [...notes].sort((a, b) => {
-      if (normalizedSearchQuery) {
-        return b.updatedAt - a.updatedAt
-      }
-
-      if (a.isPinned !== b.isPinned) {
-        return a.isPinned ? -1 : 1
-      }
-
-      return b.updatedAt - a.updatedAt
-    })
-
-    if (!normalizedSearchQuery) {
-      return sortedNotes
-    }
-
-    return sortedNotes.filter((note) => note.title.toLowerCase().includes(normalizedSearchQuery))
-  }, [notes, normalizedSearchQuery])
+  const visibleNotes = useMemo(() => {
+    const filteredNotes = normalizedSearchQuery
+      ? notes.filter((note) => note.title.toLowerCase().includes(normalizedSearchQuery))
+      : notes
+
+    return [...filteredNotes].sort((a, b) => {
+      if (a.isPinned !== b.isPinned) {
+        return a.isPinned ? -1 : 1
+      }
+      return b.updatedAt - a.updatedAt
+    })
+  }, [notes, normalizedSearchQuery])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const normalizedSearchQuery = useMemo(() => searchQuery.trim().toLowerCase(), [searchQuery])
const visibleNotes = useMemo(() => {
const sortedNotes = [...notes].sort((a, b) => {
if (normalizedSearchQuery) {
return b.updatedAt - a.updatedAt
}
if (a.isPinned !== b.isPinned) {
return a.isPinned ? -1 : 1
}
return b.updatedAt - a.updatedAt
})
if (!normalizedSearchQuery) {
return sortedNotes
}
return sortedNotes.filter((note) => note.title.toLowerCase().includes(normalizedSearchQuery))
}, [notes, normalizedSearchQuery])
const normalizedSearchQuery = useMemo(() => searchQuery.trim().toLowerCase(), [searchQuery])
const visibleNotes = useMemo(() => {
const filteredNotes = normalizedSearchQuery
? notes.filter((note) => note.title.toLowerCase().includes(normalizedSearchQuery))
: notes
return [...filteredNotes].sort((a, b) => {
if (a.isPinned !== b.isPinned) {
return a.isPinned ? -1 : 1
}
return b.updatedAt - a.updatedAt
})
}, [notes, normalizedSearchQuery])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/App.jsx` around lines 189 - 209, The visibleNotes useMemo currently sorts
by updatedAt when normalizedSearchQuery is truthy, which ignores isPinned;
instead, first filter notes by normalizedSearchQuery (if present) and then sort
the resulting list so pinned notes always come first and within each group sort
by updatedAt. Update the visibleNotes logic to: compute filteredNotes =
normalizedSearchQuery ? notes.filter(...) : notes; then compute sortedNotes =
[...filteredNotes].sort((a,b) => (a.isPinned === b.isPinned) ? (b.updatedAt -
a.updatedAt) : (a.isPinned ? -1 : 1)); and return sortedNotes; ensure you
reference normalizedSearchQuery, visibleNotes, sortedNotes and isPinned in the
change.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai create a new issue for this in linear under the ARK team

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
curl -X POST \
-H "Authorization: Bearer $LINEAR_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{
  \"query\": \"mutation { issueCreate(input: { title: \\\"Pinned notes lose priority during search\\\", description: \\\"## Issue\\n\\nWhen a search query is active, the sorting logic in \\\\\`visibleNotes\\\\\` ignores the \\\\\`isPinned\\\\\` property, causing pinned notes to appear below unpinned notes based solely on \\\\\`updatedAt\\\\\`. This violates the requirement that pinned notes should always remain on top.\\n\\n## Location\\n\\nFile: \\\\\`src/App.jsx\\\\\`\\nFunction: \\\\\`visibleNotes\\\\\` useMemo hook\\n\\n## Context\\n\\n- PR: https://github.com/ark-commits/lite-note/pull/9\\n- Comment: https://github.com/ark-commits/lite-note/pull/9#discussion_r2824135699\\n- Reported by: `@ark-commits`\\n\\n## Expected Behavior\\n\\nPinned notes should always appear first in the list, regardless of whether a search filter is active, followed by unpinned notes. Within each group (pinned and unpinned), notes should be sorted by \\\\\`updatedAt\\\\\` descending.\\\", teamId: \\\"ARK\\\" }) { success issue { id identifier url } } }\"
}" \
"https://api.linear.app/graphql"

Length of output: 803


🏁 Script executed:

#!/bin/bash

# Create the description with proper escaping
DESCRIPTION="## Issue\\n\\nWhen a search query is active, the sorting logic in \`visibleNotes\` ignores the \`isPinned\` property, causing pinned notes to appear below unpinned notes based solely on \`updatedAt\`. This violates the requirement that pinned notes should always remain on top.\\n\\n## Location\\n\\nFile: \`src/App.jsx\`\\nFunction: \`visibleNotes\` useMemo hook\\n\\n## Context\\n\\n- PR: https://github.com/ark-commits/lite-note/pull/9\\n- Comment: https://github.com/ark-commits/lite-note/pull/9#discussion_r2824135699\\n- Reported by: `@ark-commits`\\n\\n## Expected Behavior\\n\\nPinned notes should always appear first in the list, regardless of whether a search filter is active, followed by unpinned notes. Within each group (pinned and unpinned), notes should be sorted by \`updatedAt\` descending."

# Create the mutation query
MUTATION="mutation { issueCreate(input: { title: \"Pinned notes lose priority during search\", description: \"$DESCRIPTION\", teamId: \"ARK\" }) { success issue { id identifier url } } }"

# Execute the GraphQL request
curl -X POST \
  -H "Authorization: Bearer $LINEAR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg query "$MUTATION" '{query: $query}')" \
  "https://api.linear.app/graphql"

Length of output: 1639


🏁 Script executed:

#!/bin/bash

# First, get the team UUID for team key "ARK"
TEAM_QUERY='query { teams { nodes { id key name } } }'

TEAM_RESPONSE=$(curl -s -X POST \
  -H "Authorization: Bearer $LINEAR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg query "$TEAM_QUERY" '{query: $query}')" \
  "https://api.linear.app/graphql")

echo "Team response:"
echo "$TEAM_RESPONSE"

# Extract the team ID for ARK team
TEAM_ID=$(echo "$TEAM_RESPONSE" | jq -r '.data.teams.nodes[] | select(.key == "ARK") | .id')

echo ""
echo "Team ID for ARK: $TEAM_ID"

if [ -z "$TEAM_ID" ] || [ "$TEAM_ID" = "null" ]; then
  echo "Error: Could not find team with key ARK"
  exit 1
fi

# Now create the issue with the correct team UUID
DESCRIPTION="## Issue\\n\\nWhen a search query is active, the sorting logic in \`visibleNotes\` ignores the \`isPinned\` property, causing pinned notes to appear below unpinned notes based solely on \`updatedAt\`. This violates the requirement that pinned notes should always remain on top.\\n\\n## Location\\n\\nFile: \`src/App.jsx\`\\nFunction: \`visibleNotes\` useMemo hook\\n\\n## Context\\n\\n- PR: https://github.com/ark-commits/lite-note/pull/9\\n- Comment: https://github.com/ark-commits/lite-note/pull/9#discussion_r2824135699\\n- Reported by: `@ark-commits`\\n\\n## Expected Behavior\\n\\nPinned notes should always appear first in the list, regardless of whether a search filter is active, followed by unpinned notes. Within each group (pinned and unpinned), notes should be sorted by \`updatedAt\` descending."

MUTATION="mutation { issueCreate(input: { title: \"Pinned notes lose priority during search\", description: \"$DESCRIPTION\", teamId: \"$TEAM_ID\" }) { success issue { id identifier url } } }"

echo ""
echo "Creating issue..."
curl -s -X POST \
  -H "Authorization: Bearer $LINEAR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg query "$MUTATION" '{query: $query}')" \
  "https://api.linear.app/graphql" | jq '.'

Length of output: 483


@ark-commits I've successfully created a Linear issue for this problem:

ARK-7: Pinned notes lose priority during search

The issue documents the sorting bug where pinned notes lose their top position when a search query is active, includes the location in the code, and links back to this PR and comment.

Repository owner deleted a comment from coderabbitai Bot Feb 18, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/App.jsx (1)

191-213: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Search results still break pin priority and content matching consistency.

When search is active, sorting ignores isPinned, and content matching uses raw searchQuery (not normalized), so body search can fail for uppercase/mixed-case input.

✅ Suggested fix
 const visibleNotes = useMemo(() => {
-  const sortedNotes = [...notes].sort((a, b) => {
-    if (normalizedSearchQuery) {
-      return b.updatedAt - a.updatedAt
-    }
-
-    if (a.isPinned !== b.isPinned) {
-      return a.isPinned ? -1 : 1
-    }
-
-    return b.updatedAt - a.updatedAt
-  })
-
-  if (!normalizedSearchQuery) {
-    return sortedNotes
-  }
-
-  return sortedNotes.filter(
-    (note) =>
-      note.title.toLowerCase().includes(normalizedSearchQuery) ||
-      note.content.toLowerCase().includes(searchQuery),
-  )
+  const filteredNotes = normalizedSearchQuery
+    ? notes.filter(
+        (note) =>
+          note.title.toLowerCase().includes(normalizedSearchQuery) ||
+          note.content.toLowerCase().includes(normalizedSearchQuery),
+      )
+    : notes
+
+  return [...filteredNotes].sort((a, b) => {
+    if (a.isPinned !== b.isPinned) {
+      return a.isPinned ? -1 : 1
+    }
+    return b.updatedAt - a.updatedAt
+  })
 }, [notes, normalizedSearchQuery])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/App.jsx` around lines 191 - 213, The visibleNotes useMemo is dropping pin
priority when a search is active and is using the raw searchQuery for body
matching; update the sorting and filtering in visibleNotes so sorting always
respects isPinned first then updatedAt (i.e., sort by pinned difference then
updatedAt for all cases inside the sort callback of visibleNotes) and use
normalizedSearchQuery for both title and content comparisons (replace the
content check note.content.toLowerCase().includes(searchQuery) with
note.content.toLowerCase().includes(normalizedSearchQuery)) so case-insensitive
search and pin precedence remain consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/App.jsx`:
- Around line 487-511: handleDuplicateNote can capture stale content because
flushPendingCommit() schedules an update but sourceNote is read from notes
immediately; to fix, after finding sourceNote in handleDuplicateNote (and before
building duplicatedNote) check if sourceNote.id === activeNoteIdRef.current and
if so use the latest draftContent (instead of sourceNote.content) when setting
duplicatedNote.content (keep using createNoteId(), timestamps, isPinned reset,
and update setNotes/setActiveNoteId/activeNoteIdRef.set accordingly). This
ensures the duplicated note uses the most recent draft when duplicating the
currently active note while leaving other notes unchanged.

---

Duplicate comments:
In `@src/App.jsx`:
- Around line 191-213: The visibleNotes useMemo is dropping pin priority when a
search is active and is using the raw searchQuery for body matching; update the
sorting and filtering in visibleNotes so sorting always respects isPinned first
then updatedAt (i.e., sort by pinned difference then updatedAt for all cases
inside the sort callback of visibleNotes) and use normalizedSearchQuery for both
title and content comparisons (replace the content check
note.content.toLowerCase().includes(searchQuery) with
note.content.toLowerCase().includes(normalizedSearchQuery)) so case-insensitive
search and pin precedence remain consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 83026463-561b-4f77-955b-b8a28d311e05

📥 Commits

Reviewing files that changed from the base of the PR and between 56133b0 and e773466.

📒 Files selected for processing (1)
  • src/App.jsx

Comment thread src/App.jsx
Comment on lines +487 to +511
const handleDuplicateNote = (noteId) => {
flushPendingCommit()

const sourceNote = notes.find((note) => note.id === noteId)
if (!sourceNote) {
return
}

const now = Date.now()
const duplicatedNote = {
...sourceNote,
id: createNoteId(),
title: `${sourceNote.title} Copy`,
createdAt: now,
updatedAt: now,
isPinned: false,
}

setNotes((previousNotes) => [...previousNotes, duplicatedNote])
setActiveNoteId(duplicatedNote.id)
activeNoteIdRef.current = duplicatedNote.id
setDraftContent(duplicatedNote.content)
setActiveMobileTab('edit')
setIsMobileNotesOpen(false)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Duplicate can copy stale content right after a pending flush.

flushPendingCommit() schedules a state update, but sourceNote is read from current render state (notes) immediately after. That can duplicate pre-flush content instead of the latest committed draft.

✅ Suggested fix
 const handleDuplicateNote = (noteId) => {
   flushPendingCommit()
-
-  const sourceNote = notes.find((note) => note.id === noteId)
-  if (!sourceNote) {
-    return
-  }
-
-  const now = Date.now()
-  const duplicatedNote = {
-    ...sourceNote,
-    id: createNoteId(),
-    title: `${sourceNote.title} Copy`,
-    createdAt: now,
-    updatedAt: now,
-    isPinned: false,
-  }
-
-  setNotes((previousNotes) => [...previousNotes, duplicatedNote])
-  setActiveNoteId(duplicatedNote.id)
-  activeNoteIdRef.current = duplicatedNote.id
-  setDraftContent(duplicatedNote.content)
-  setActiveMobileTab('edit')
-  setIsMobileNotesOpen(false)
+  setNotes((previousNotes) => {
+    const sourceNote = previousNotes.find((note) => note.id === noteId)
+    if (!sourceNote) {
+      return previousNotes
+    }
+
+    const now = Date.now()
+    const duplicatedNote = {
+      ...sourceNote,
+      id: createNoteId(),
+      title: `${sourceNote.title} Copy`,
+      createdAt: now,
+      updatedAt: now,
+      isPinned: false,
+    }
+
+    setActiveNoteId(duplicatedNote.id)
+    activeNoteIdRef.current = duplicatedNote.id
+    setDraftContent(duplicatedNote.content)
+    setActiveMobileTab('edit')
+    setIsMobileNotesOpen(false)
+
+    return [...previousNotes, duplicatedNote]
+  })
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/App.jsx` around lines 487 - 511, handleDuplicateNote can capture stale
content because flushPendingCommit() schedules an update but sourceNote is read
from notes immediately; to fix, after finding sourceNote in handleDuplicateNote
(and before building duplicatedNote) check if sourceNote.id ===
activeNoteIdRef.current and if so use the latest draftContent (instead of
sourceNote.content) when setting duplicatedNote.content (keep using
createNoteId(), timestamps, isPinned reset, and update
setNotes/setActiveNoteId/activeNoteIdRef.set accordingly). This ensures the
duplicated note uses the most recent draft when duplicating the currently active
note while leaving other notes unchanged.

@ark-commits
ark-commits force-pushed the note-organization-basics branch from e773466 to 56133b0 Compare May 4, 2026 00:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant