feat(search): add notes/comment text search filter - #239
Merged
Conversation
Operators routinely record POTA/SOTA park references, contest exchanges, and personal remarks in a contact's notes field, but there was no way to search them — you could find a QSO by callsign, name, QTH, grid, band, mode, date, DXCC, or QSL status, but not by what you actually wrote down. Adds a `notes` filter that does the same case-insensitive contains match as the other text fields, wired end-to-end: the WHERE-clause builder, the GET /api/contacts/search route, and the search page (input in Advanced Filters, active-filter chip, clear-all reset). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The contact search lets operators filter by callsign, name, QTH, grid, band, mode, date range, DXCC entity, and QSL status — but not by the notes/comment text on a QSO. That's where operators record the things they most often want to find a contact by later: POTA/SOTA park references (
K-1234,W7A/...), contest exchanges, special-event details, and personal reminders. Without notes search, finding "that POTA activation from last month" means paging through results by hand.Solution
Adds a
notesfilter, wired end-to-end and matching the existing text-field behavior (case-insensitiveLIKE '%value%'contains match):src/lib/contact-search.ts— newnotes?field onContactSearchFiltersand acase 'notes'in the WHERE-clause builder. The predicate binds through the samebind()helper, so placeholder numbering stays in lockstep with the params array (the invariant the existing tests guard).src/app/api/contacts/search/route.ts— reads thenotesquery param and passes it to the builder.src/app/search/page.tsx— a Notes input in the Advanced Filters section, plus the matchingSearchFiltersfield, initial/clear-all defaults, and an active-filter chip. Chip removal already routes through the default ('') case, so no handler change was needed.The filter participates in the existing debounced search and in ADIF export of search results (both build their query string from the same filter object), so exporting a notes-filtered result set works automatically.
Testing
tests/contact-search.spec.ts— added a focused test assertingnotesproducesUPPER(notes) LIKE UPPER($2)with['%POTA K-1234%'], and extended the full-filter-set test to includenotesand verify placeholder/param alignment stays correct with the extra bound value. All 14 builder tests pass.npm run typecheck— cleannpm run lint— cleannpm run build— compiles successfullyBackwards compatibility
Purely additive. The
notesparam is optional; existing searches, saved links, and the/api/contacts/searchcontract are unchanged when it's absent.Future follow-up
gridLocator,startDate,notes, …) remain camelCase, consistent with the existing surface that CLAUDE.md flags for a later snake_case sweep. This PR intentionally matches the current convention rather than expanding that drift.🤖 Generated with Claude Code