Bug
The search handlers in NavBar.tsx (handleSearchClick, handleSearchKeyDown,
handleExactSearchClick) embed searchString directly as a URL path segment.
Searching with an empty string breaks in two different ways depending on
whether "exact" is checked, because the route is defined as
/search/:search_string/:exact? (App.tsx):
- Without exact:
navigate(`/search/${searchString}`) with an empty
string becomes /search/. Since :search_string is a required param, this
doesn't match the route at all and falls through to the catch-all
(<Route path="*" element={<Legend />} />) — the user lands on the Legend
page with no indication of what happened.
- With exact:
navigate(`/search/${searchString}/exact`) with an empty
string becomes /search//exact, which the browser normalizes to
/search/exact. This matches the route with search_string="exact" —
the app silently searches for the literal string "exact", and the actual
exact-match flag is lost (:exact ends up undefined).
Root cause
Two optional/ambiguous path segments in sequence (:search_string?/:exact?
has the same problem even if both are marked optional) can't unambiguously
represent "search_string omitted, exact specified" — the resulting URL
collides with a valid search_string value. This is a structural limit of
path params here, not a one-off bug in the handlers.
Discussion: proposed fix
Move from path params to query params:
App.tsx: route becomes /search (no params)
Search.tsx: useParams → useSearchParams (existing react-router-dom
API, no new dependency)
NavBar.tsx: the three navigate() calls become
/search?q=...&exact=true
This removes the ambiguity entirely since query params don't have positional
meaning. Open to alternative approaches if there's a preference for keeping
path params (e.g. validating/blocking empty search client-side instead) —
posting this as a discussion before implementing since it touches routing
structure, not just the buggy handlers.
Bug
The search handlers in
NavBar.tsx(handleSearchClick,handleSearchKeyDown,handleExactSearchClick) embedsearchStringdirectly as a URL path segment.Searching with an empty string breaks in two different ways depending on
whether "exact" is checked, because the route is defined as
/search/:search_string/:exact?(App.tsx):navigate(`/search/${searchString}`)with an emptystring becomes
/search/. Since:search_stringis a required param, thisdoesn't match the route at all and falls through to the catch-all
(
<Route path="*" element={<Legend />} />) — the user lands on the Legendpage with no indication of what happened.
navigate(`/search/${searchString}/exact`)with an emptystring becomes
/search//exact, which the browser normalizes to/search/exact. This matches the route withsearch_string="exact"—the app silently searches for the literal string "exact", and the actual
exact-match flag is lost (
:exactends upundefined).Root cause
Two optional/ambiguous path segments in sequence (
:search_string?/:exact?has the same problem even if both are marked optional) can't unambiguously
represent "search_string omitted, exact specified" — the resulting URL
collides with a valid
search_stringvalue. This is a structural limit ofpath params here, not a one-off bug in the handlers.
Discussion: proposed fix
Move from path params to query params:
App.tsx: route becomes/search(no params)Search.tsx:useParams→useSearchParams(existingreact-router-domAPI, no new dependency)
NavBar.tsx: the threenavigate()calls become/search?q=...&exact=trueThis removes the ambiguity entirely since query params don't have positional
meaning. Open to alternative approaches if there's a preference for keeping
path params (e.g. validating/blocking empty search client-side instead) —
posting this as a discussion before implementing since it touches routing
structure, not just the buggy handlers.