Skip to content

feat: add search & filter + tags system for notes - #147

Closed
AnjanaLakshan777 wants to merge 1 commit into
niharika-mente:mainfrom
AnjanaLakshan777:feature/anjanalakshan777-search_and_filter
Closed

feat: add search & filter + tags system for notes#147
AnjanaLakshan777 wants to merge 1 commit into
niharika-mente:mainfrom
AnjanaLakshan777:feature/anjanalakshan777-search_and_filter

Conversation

@AnjanaLakshan777

@AnjanaLakshan777 AnjanaLakshan777 commented Jul 14, 2026

Copy link
Copy Markdown

Summary

Adds a search bar and tags system for organizing and filtering notes in ThinkBoard.

Changes

Backend

  • Added tags field to Note model
  • Backend now supports ?search= (searches title & content) and ?tag= (filter by tag) query params
  • New GET /notes/tags endpoint returns all unique tags with counts

Frontend

  • SearchBar — Debounced search input on homepage with clear button
  • TagBadge — Colorful tag pills with auto-colored backgrounds
  • TagFilter — Clickable tag cloud to filter notes
  • CreatePage — Tag input with Enter/comma key support when creating notes
  • NoteDetailPage — Add/remove tags when editing notes
  • NoteCard — Shows tags on each note card
  • NotesNotFound — Shows contextual message when filters return no results

Files Changed

  • 3 new files, 8 modified files
  • 497 lines added, 26 lines removed

Build Status

✅ Vite build passes with zero errors

Testing

  • Search is debounced (300ms) to avoid excessive API calls
  • Tags are normalized to lowercase to prevent duplicates
  • Maximum 10 tags per note

Summary by CodeRabbit

  • New Features
    • Added tags to notes, including creation, editing, display, and removal.
    • Added note search with case-insensitive title and content matching.
    • Added tag-based filtering and a list of available tags with usage counts.
    • Added a search bar, tag filters, colored tag badges, and filter-clearing controls.
    • Added distinct empty states for no notes versus no matching results.
    • Limited notes to 10 tags and automatically normalized tag formatting.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Notes now support normalized tags across storage, CRUD APIs, creation, editing, display, search, and filtering. The frontend adds reusable tag badges, tag selection, debounced search, filtered empty states, and an authenticated endpoint for aggregated user tag counts.

Changes

Notes tagging and filtering

Layer / File(s) Summary
Backend tag contracts and query APIs
backend/src/controllers/notesController.js, backend/src/models/Note.js, backend/src/routes/notesRoutes.js
Notes persist normalized tags, filtered note queries accept search and tag parameters, and GET /tags returns aggregated user tag counts.
Tag display and filter components
frontend/src/components/TagBadge.jsx, frontend/src/components/TagFilter.jsx, frontend/src/components/SearchBar.jsx, frontend/src/components/NoteCard.jsx, frontend/src/components/NotesNotFound.jsx
Reusable tag badges, search and tag controls, note-card tag rendering, and filtered empty-state messaging are added.
Create and edit tag workflows
frontend/src/pages/CreatePage.jsx, frontend/src/pages/NoteDetailPage.jsx
Create and detail pages add, remove, normalize, limit, display, and persist note tags.
Home search and tag filtering
frontend/src/pages/HomePage.jsx
HomePage debounces search, sends search/tag query parameters, supports clearing filters, and distinguishes filtered empty results.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant HomePage
  participant SearchBar
  participant TagFilter
  participant notesController
  participant NoteModel
  User->>SearchBar: Enter search text
  SearchBar->>HomePage: Update searchQuery
  User->>TagFilter: Select a tag
  TagFilter->>HomePage: Update selectedTag
  HomePage->>notesController: Request filtered notes
  notesController->>NoteModel: Query user-scoped notes
  NoteModel-->>notesController: Return matching notes
  notesController-->>HomePage: Return filtered notes
Loading

Possibly related PRs

Suggested reviewers: niharika-mente, pratyush-panda-2006

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main changes: note search/filtering plus tag support across backend and frontend.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/pages/HomePage.jsx (1)

52-84: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Prevent race conditions in search results.

When typing quickly, network responses may arrive out of order, causing older search queries to overwrite newer ones. Pass an AbortSignal to fetchNotes to cancel stale requests and prevent data tearing.

🛡️ Proposed fix
-  const fetchNotes = useCallback(async () => {
+  const fetchNotes = useCallback(async (signal) => {
     try {
       const params = {};
       if (debouncedSearch.trim()) {
         params.search = debouncedSearch.trim();
       }
       if (selectedTag) {
         params.tag = selectedTag;
       }
-      const res = await api.get("/notes", { params });
+      const res = await api.get("/notes", { params, signal });
       setNotes(res.data);
       setIsRateLimited(false);
     } catch (error) {
+      if (signal?.aborted) return;
       console.log("Error fetching notes", error.response);
       if (error.response?.status === 429) {
         setIsRateLimited(true);
       } else {
         toast.error("Failed to load notes");
       }
     } finally {
-      setLoading(false);
+      if (!signal?.aborted) {
+        setLoading(false);
+      }
     }
   }, [debouncedSearch, selectedTag]);
 
   useEffect(() => {
     if (!authLoading && !user) {
       navigate("/login");
       return;
     }
+    const controller = new AbortController();
     if (user) {
-      fetchNotes();
+      fetchNotes(controller.signal);
     }
+    return () => controller.abort();
   }, [user, authLoading, navigate, fetchNotes]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/HomePage.jsx` around lines 52 - 84, Update fetchNotes to
accept an AbortSignal and pass it through the api.get("/notes") request, then
have the useEffect create an AbortController for each fetch and abort it during
cleanup before starting or leaving a newer request. Ignore cancellation errors
while preserving existing error handling for genuine failures, preventing stale
responses from updating notes or related state.
🧹 Nitpick comments (3)
backend/src/controllers/notesController.js (1)

23-28: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Normalize query tags to lowercase to match persistence logic.

Tags are lowercased when saved to the database (in createNote and updateNote). However, the query tags here are only trimmed. If a user manually passes mixed-case tags in the query string, they will fail to match. Ensure query tags are also lowercased.

♻️ Proposed fix
         if (tag && typeof tag === "string" && tag.trim()) {
-            const tags = tag.split(",").map((t) => t.trim()).filter(Boolean);
+            const tags = tag.split(",").map((t) => t.trim().toLowerCase()).filter(Boolean);
             if (tags.length > 0) {
                 filter.tags = { $in: tags };
             }
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/controllers/notesController.js` around lines 23 - 28, Normalize
each query tag to lowercase in the tags transformation within the tag-filter
block before assigning filter.tags, matching the persistence behavior used by
createNote and updateNote while preserving trimming and empty-tag removal.
frontend/src/components/TagBadge.jsx (1)

34-37: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Improve accessibility for interactive tags.

When onClick is provided, this <span> acts as an interactive element. To make it accessible to keyboard and screen-reader users, consider rendering a <button> when it's clickable, or add appropriate ARIA roles and keyboard event handlers.

♻️ Proposed refactor
   return (
-    <span
+    <button
+      type="button"
       className={`inline-flex items-center gap-1 rounded-full font-medium ${sizeClasses} ${getTagColor(tag)} ${activeClasses} ${onClick ? "cursor-pointer hover:opacity-80 transition-opacity" : ""}`}
       onClick={onClick ? (e) => { e.stopPropagation(); onClick(tag); } : undefined}
+      disabled={!onClick && !onRemove}
     >
       #{tag}

Note: Depending on how TagBadge is used, you may prefer to conditionally render a <button> vs <span> to avoid nesting buttons if onRemove is also present.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/TagBadge.jsx` around lines 34 - 37, Update the
interactive rendering in TagBadge so a tag with onClick is keyboard- and
screen-reader-accessible, preferably by rendering a button while retaining span
for non-interactive tags. Account for onRemove usage to avoid nested buttons,
and preserve the existing stopPropagation and onClick(tag) behavior.
frontend/src/pages/HomePage.jsx (1)

24-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Simplify debounce logic.

The useRef approach to managing the debounce timer is unnecessarily complex. A standard useEffect cleanup function inherently clears the timeout from the previous render.

♻️ Proposed refactor
   const [searchQuery, setSearchQuery] = useState("");
   const [selectedTag, setSelectedTag] = useState(null);
   const [debouncedSearch, setDebouncedSearch] = useState("");
-  const debounceTimer = useRef(null);
 
   // Drag & drop state
   const [activeDragId, setActiveDragId] = useState(null);
 
   // Group creation modal state
   const [showNamingModal, setShowNamingModal] = useState(false);
   const [modalSourceId, setModalSourceId] = useState(null);
   const [modalTargetId, setModalTargetId] = useState(null);
   const [groupTitle, setGroupTitle] = useState("");
 
   // Debounce search input
-  useEffect(() => {
-    if (debounceTimer.current) {
-      clearTimeout(debounceTimer.current);
-    }
-    debounceTimer.current = setTimeout(() => {
-      setDebouncedSearch(searchQuery);
-    }, 300);
-    return () => {
-      if (debounceTimer.current) clearTimeout(debounceTimer.current);
-    };
-  }, [searchQuery]);
+  useEffect(() => {
+    const timer = setTimeout(() => {
+      setDebouncedSearch(searchQuery);
+    }, 300);
+    return () => clearTimeout(timer);
+  }, [searchQuery]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/HomePage.jsx` around lines 24 - 47, In the HomePage
debounce useEffect, remove the debounceTimer useRef and its manual clearTimeout
checks. Create the timeout directly within the effect, update debouncedSearch
after 300ms, and return cleanup that clears that effect’s timeout; keep
searchQuery as the dependency.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/src/controllers/notesController.js`:
- Around line 89-98: Update the tag parsing in createNote at
backend/src/controllers/notesController.js lines 89-98 to normalize tags, remove
duplicates, and reject requests with more than 10 tags using a 400 response;
apply the same uniqueness and maximum-length validation in updateNote at lines
147-155, preserving the existing array and string validation behavior.
- Around line 14-20: Escape the trimmed user input before constructing the
RegExp in the search filter block of notesController. Add or reuse a
regex-escaping helper, then pass the escaped value to new RegExp while
preserving case-insensitive title and content matching.

In `@frontend/src/pages/CreatePage.jsx`:
- Around line 32-40: Update handleTagKeyDown in
frontend/src/pages/CreatePage.jsx at lines 32-40 and the corresponding handler
in frontend/src/pages/NoteDetailPage.jsx at lines 84-89 so Tab only calls
preventDefault and handleAddTag when tagInput contains text; otherwise allow
normal focus navigation. Preserve the existing Enter and comma behavior.

In `@frontend/src/pages/HomePage.jsx`:
- Around line 196-206: Update the “Clear all filters” handler in HomePage to
immediately reset debouncedSearch alongside searchQuery and selectedTag before
triggering loading, preventing fetchNotes from using the stale search value
during the debounce window.

---

Outside diff comments:
In `@frontend/src/pages/HomePage.jsx`:
- Around line 52-84: Update fetchNotes to accept an AbortSignal and pass it
through the api.get("/notes") request, then have the useEffect create an
AbortController for each fetch and abort it during cleanup before starting or
leaving a newer request. Ignore cancellation errors while preserving existing
error handling for genuine failures, preventing stale responses from updating
notes or related state.

---

Nitpick comments:
In `@backend/src/controllers/notesController.js`:
- Around line 23-28: Normalize each query tag to lowercase in the tags
transformation within the tag-filter block before assigning filter.tags,
matching the persistence behavior used by createNote and updateNote while
preserving trimming and empty-tag removal.

In `@frontend/src/components/TagBadge.jsx`:
- Around line 34-37: Update the interactive rendering in TagBadge so a tag with
onClick is keyboard- and screen-reader-accessible, preferably by rendering a
button while retaining span for non-interactive tags. Account for onRemove usage
to avoid nested buttons, and preserve the existing stopPropagation and
onClick(tag) behavior.

In `@frontend/src/pages/HomePage.jsx`:
- Around line 24-47: In the HomePage debounce useEffect, remove the
debounceTimer useRef and its manual clearTimeout checks. Create the timeout
directly within the effect, update debouncedSearch after 300ms, and return
cleanup that clears that effect’s timeout; keep searchQuery as the dependency.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: aea44da6-1c52-465a-86bc-cc14a61ee528

📥 Commits

Reviewing files that changed from the base of the PR and between b4a4936 and 934fe32.

📒 Files selected for processing (11)
  • backend/src/controllers/notesController.js
  • backend/src/models/Note.js
  • backend/src/routes/notesRoutes.js
  • frontend/src/components/NoteCard.jsx
  • frontend/src/components/NotesNotFound.jsx
  • frontend/src/components/SearchBar.jsx
  • frontend/src/components/TagBadge.jsx
  • frontend/src/components/TagFilter.jsx
  • frontend/src/pages/CreatePage.jsx
  • frontend/src/pages/HomePage.jsx
  • frontend/src/pages/NoteDetailPage.jsx

Comment on lines +14 to +20
if (search && typeof search === "string" && search.trim()) {
const regex = new RegExp(search.trim(), "i");
filter.$or = [
{ title: regex },
{ content: regex },
];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Escape special characters in the search string to prevent ReDoS and application errors.

Passing user input directly to new RegExp without escaping special characters can lead to Regular Expression Denial of Service (ReDoS) or cause 500 errors if the user searches for characters like [, *, or ?.

Please escape the search string before using it in the regular expression.

🛡️ Proposed fix to escape regex characters
         if (search && typeof search === "string" && search.trim()) {
-            const regex = new RegExp(search.trim(), "i");
+            const escapedSearch = search.trim().replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+            const regex = new RegExp(escapedSearch, "i");
             filter.$or = [
                 { title: regex },
                 { content: regex },
             ];
         }
📝 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
if (search && typeof search === "string" && search.trim()) {
const regex = new RegExp(search.trim(), "i");
filter.$or = [
{ title: regex },
{ content: regex },
];
}
if (search && typeof search === "string" && search.trim()) {
const escapedSearch = search.trim().replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(escapedSearch, "i");
filter.$or = [
{ title: regex },
{ content: regex },
];
}
🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 14-14: Detects non-literal values in regular expressions
Context: new RegExp(search.trim(), "i")
Note: [CWE-1333] Inefficient Regular Expression Complexity (ReDoS via non-literal RegExp).

(detect-non-literal-regexp)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/controllers/notesController.js` around lines 14 - 20, Escape the
trimmed user input before constructing the RegExp in the search filter block of
notesController. Add or reuse a regex-escaping helper, then pass the escaped
value to new RegExp while preserving case-insensitive title and content
matching.

Source: Linters/SAST tools

Comment on lines +89 to +98
// Validate tags if provided
let parsedTags = [];
if (tags !== undefined) {
if (!Array.isArray(tags)) {
return res.status(400).json({ message: "Tags must be an array of strings" });
}
parsedTags = tags
.map((t) => (typeof t === "string" ? t.trim().toLowerCase() : ""))
.filter((t) => t.length > 0);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Enforce tag limits and uniqueness on the backend.

Although the frontend limits users to 10 tags and prevents duplicates, this validation should also be enforced in the backend controllers to maintain data integrity and prevent malformed API requests from bypassing frontend constraints.

  • backend/src/controllers/notesController.js#L89-L98: Update the createNote tag parsing logic to remove duplicates and reject requests exceeding 10 tags.
  • backend/src/controllers/notesController.js#L147-L155: Apply the same uniqueness and length constraints to the updateNote logic.
📍 Affects 1 file
  • backend/src/controllers/notesController.js#L89-L98 (this comment)
  • backend/src/controllers/notesController.js#L147-L155
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/controllers/notesController.js` around lines 89 - 98, Update the
tag parsing in createNote at backend/src/controllers/notesController.js lines
89-98 to normalize tags, remove duplicates, and reject requests with more than
10 tags using a 400 response; apply the same uniqueness and maximum-length
validation in updateNote at lines 147-155, preserving the existing array and
string validation behavior.

Comment on lines +32 to +40
const handleTagKeyDown = (e) => {
if (e.key === "Enter") {
e.preventDefault();
handleAddTag();
} else if (e.key === "," || e.key === "Tab") {
e.preventDefault();
handleAddTag();
}
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix keyboard trap on Tab key navigation.

Unconditionally calling e.preventDefault() when the Tab key is pressed prevents users from tabbing out of the input when it is empty. This breaks keyboard navigation and causes an accessibility blocker. You should only prevent default on Tab if there is text in tagInput to add as a tag.

  • frontend/src/pages/CreatePage.jsx#L32-L40: Adjust logic to only prevent default on Tab when tagInput is not empty.
  • frontend/src/pages/NoteDetailPage.jsx#L84-L89: Adjust logic to only prevent default on Tab when tagInput is not empty.
♿ Proposed fixes

frontend/src/pages/CreatePage.jsx

   const handleTagKeyDown = (e) => {
-    if (e.key === "Enter") {
-      e.preventDefault();
-      handleAddTag();
-    } else if (e.key === "," || e.key === "Tab") {
-      e.preventDefault();
-      handleAddTag();
-    }
+    if (e.key === "Enter" || e.key === ",") {
+      e.preventDefault();
+      handleAddTag();
+    } else if (e.key === "Tab" && tagInput.trim()) {
+      e.preventDefault();
+      handleAddTag();
+    }
   };

frontend/src/pages/NoteDetailPage.jsx

   const handleTagKeyDown = (e) => {
-    if (e.key === "Enter" || e.key === "," || e.key === "Tab") {
-      e.preventDefault();
-      handleAddTag();
-    }
+    if (e.key === "Enter" || e.key === ",") {
+      e.preventDefault();
+      handleAddTag();
+    } else if (e.key === "Tab" && tagInput.trim()) {
+      e.preventDefault();
+      handleAddTag();
+    }
   };
📝 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 handleTagKeyDown = (e) => {
if (e.key === "Enter") {
e.preventDefault();
handleAddTag();
} else if (e.key === "," || e.key === "Tab") {
e.preventDefault();
handleAddTag();
}
};
const handleTagKeyDown = (e) => {
if (e.key === "Enter" || e.key === ",") {
e.preventDefault();
handleAddTag();
} else if (e.key === "Tab" && tagInput.trim()) {
e.preventDefault();
handleAddTag();
}
};
Suggested change
const handleTagKeyDown = (e) => {
if (e.key === "Enter") {
e.preventDefault();
handleAddTag();
} else if (e.key === "," || e.key === "Tab") {
e.preventDefault();
handleAddTag();
}
};
const handleTagKeyDown = (e) => {
if (e.key === "Enter" || e.key === ",") {
e.preventDefault();
handleAddTag();
} else if (e.key === "Tab" && tagInput.trim()) {
e.preventDefault();
handleAddTag();
}
};
📍 Affects 2 files
  • frontend/src/pages/CreatePage.jsx#L32-L40 (this comment)
  • frontend/src/pages/NoteDetailPage.jsx#L84-L89
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/CreatePage.jsx` around lines 32 - 40, Update
handleTagKeyDown in frontend/src/pages/CreatePage.jsx at lines 32-40 and the
corresponding handler in frontend/src/pages/NoteDetailPage.jsx at lines 84-89 so
Tab only calls preventDefault and handleAddTag when tagInput contains text;
otherwise allow normal focus navigation. Preserve the existing Enter and comma
behavior.

Comment on lines +196 to +206
<button
onClick={() => {
setSearchQuery("");
setSelectedTag(null);
setLoading(true);
}}
className="ml-2 text-blue-600 dark:text-blue-400 hover:underline text-xs"
>
Clear all filters
</button>
</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear the debounced search state immediately to prevent redundant requests.

When clearing all filters, selectedTag updates immediately, causing fetchNotes to fire before the 300ms debounce timer has a chance to clear debouncedSearch. This results in an unnecessary API call with the old search query. Setting debouncedSearch immediately aligns both states.

🐛 Proposed fix
             <button
               onClick={() => {
                 setSearchQuery("");
+                setDebouncedSearch("");
                 setSelectedTag(null);
                 setLoading(true);
               }}
               className="ml-2 text-blue-600 dark:text-blue-400 hover:underline text-xs"
             >
               Clear all filters
             </button>
📝 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
<button
onClick={() => {
setSearchQuery("");
setSelectedTag(null);
setLoading(true);
}}
className="ml-2 text-blue-600 dark:text-blue-400 hover:underline text-xs"
>
Clear all filters
</button>
</div>
<button
onClick={() => {
setSearchQuery("");
setDebouncedSearch("");
setSelectedTag(null);
setLoading(true);
}}
className="ml-2 text-blue-600 dark:text-blue-400 hover:underline text-xs"
>
Clear all filters
</button>
</div>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/HomePage.jsx` around lines 196 - 206, Update the “Clear
all filters” handler in HomePage to immediately reset debouncedSearch alongside
searchQuery and selectedTag before triggering loading, preventing fetchNotes
from using the stale search value during the debounce window.

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