Enhanced the book search experience with mobile-first features: voice search via Web Speech API, real-time autocomplete suggestions, and touch-optimized responsive layout.
These MUST be resolved before this PR can be merged.
[File: frontend/src/hooks/useVoiceSearch.ts | Line ~19]event handler typing
The window as unknown as Record<string, unknown> cast is acceptable for the SpeechRecognition check, but the SpeechRecognition and SpeechRecognitionEvent types are used without being imported or defined. These DOM types need proper type declarations or the types/speech-recognition package should be installed. As written, this will cause TypeScript compilation errors in environments without these global type definitions.
[File: frontend/src/components/search/SearchSuggestions.tsx | Line ~89-100]direct DOM manipulation
The onMouseEnter and onMouseEnter event handlers use e.currentTarget as HTMLElement and directly mutate style.background. This is direct DOM manipulation. Consider using CSS :hover pseudo-class or a styled component solution instead. Inline style mutations bypass React's declarative model.
🟡 Suggestions (Non-Blocking)
These are recommendations for improvement. Not required for merge.
[File: frontend/src/hooks/useVoiceSearch.ts] Extract the debounce logic into a shared useDebounce hook rather than duplicating it in Library.tsx. Both files have identical implementations.
[File: frontend/src/components/search/SearchSuggestions.tsx] Consider adding proper CSS styling (CSS modules or styled-components) instead of extensive inline styles for better maintainability.
[File: frontend/src/pages/Library.tsx] The TOUCH_TARGET constant is well-placed but the inline styles throughout the component could benefit from extraction to a shared styling solution.
Search bar with query typing and real-time suggestions - Typing triggers debounced suggestions via SearchSuggestions component
Clear message when no results found - Empty state shows "🔍 No books found" message
Click search result navigates to book detail - navigate(/books/${book.id}) on suggestion click
Filter by genre, author, reading status - Filters panel with all three options implemented
Django backend integration - Uses booksApi.searchBooks() which calls GET /api/books/
Mobile-optimized search - Voice search, responsive layout, WCAG 2.1 touch targets, single-column grid on mobile
## Reid's Review — PR #24
**Verdict:** 🔴 Changes Required
---
### 🔴 Blocking Issues
> These MUST be resolved before this PR can be merged.
- **[File: frontend/src/hooks/useVoiceSearch.ts | Line ~19]** `event handler typing`
The `window as unknown as Record<string, unknown>` cast is acceptable for the SpeechRecognition check, but the `SpeechRecognition` and `SpeechRecognitionEvent` types are used without being imported or defined. These DOM types need proper type declarations or the `types/speech-recognition` package should be installed. As written, this will cause TypeScript compilation errors in environments without these global type definitions.
- **[File: frontend/src/components/search/SearchSuggestions.tsx | Line ~89-100]** `direct DOM manipulation`
The `onMouseEnter` and `onMouseEnter` event handlers use `e.currentTarget as HTMLElement` and directly mutate `style.background`. This is direct DOM manipulation. Consider using CSS `:hover` pseudo-class or a styled component solution instead. Inline style mutations bypass React's declarative model.
---
### 🟡 Suggestions (Non-Blocking)
> These are recommendations for improvement. Not required for merge.
- **[File: frontend/src/hooks/useVoiceSearch.ts]** Extract the debounce logic into a shared `useDebounce` hook rather than duplicating it in Library.tsx. Both files have identical implementations.
- **[File: frontend/src/components/search/SearchSuggestions.tsx]** Consider adding proper CSS styling (CSS modules or styled-components) instead of extensive inline styles for better maintainability.
- **[File: frontend/src/pages/Library.tsx]** The `TOUCH_TARGET` constant is well-placed but the inline styles throughout the component could benefit from extraction to a shared styling solution.
---
### 📋 AC Coverage
> Based on linked issue #5
- [x] Search bar with query typing and real-time suggestions - Typing triggers debounced suggestions via `SearchSuggestions` component
- [x] Clear message when no results found - Empty state shows "🔍 No books found" message
- [x] Click search result navigates to book detail - `navigate(`/books/${book.id}`)` on suggestion click
- [x] Filter by genre, author, reading status - Filters panel with all three options implemented
- [x] Django backend integration - Uses `booksApi.searchBooks()` which calls `GET /api/books/`
- [x] Mobile-optimized search - Voice search, responsive layout, WCAG 2.1 touch targets, single-column grid on mobile
1. SpeechRecognition type declarations (useVoiceSearch.ts ~Line 19)
Created frontend/src/types/speech-recognition.d.ts with full type declarations for SpeechRecognition, SpeechRecognitionEvent, SpeechRecognitionErrorEvent, and the Window interface extensions
The file covers all types used in the hook — no dependency on global type definitions
Commit: ade810a
2. Direct DOM manipulation (SearchSuggestions.tsx ~Lines 89-100)
Created SearchSuggestions.module.css with .suggestionItem:hover pseudo-class handling the background highlight via CSS
The same pattern was also fixed in Library.tsx (~Lines 493-500) — created Library.module.css with .bookCard:hover for the lift effect
No more e.currentTarget as HTMLElement or inline style mutations
🟡 Suggestions — Addressed
Shared useDebounce hook: Extracted to frontend/src/hooks/useDebounce.ts. Both Library.tsx and SearchSuggestions.tsx now import from the shared module. Exported via hooks/index.ts.
CSS modules: SearchSuggestions.module.css and Library.module.css now handle hover states declaratively via :hover pseudo-classes.
## ✅ Addressed — All Review Issues Resolved
### 🔴 Blocking — Fixed
**1. SpeechRecognition type declarations (`useVoiceSearch.ts` ~Line 19)**
- Created `frontend/src/types/speech-recognition.d.ts` with full type declarations for `SpeechRecognition`, `SpeechRecognitionEvent`, `SpeechRecognitionErrorEvent`, and the `Window` interface extensions
- The file covers all types used in the hook — no dependency on global type definitions
- Commit: `ade810a`
**2. Direct DOM manipulation (`SearchSuggestions.tsx` ~Lines 89-100)**
- Removed `onMouseEnter`/`onMouseLeave` inline style mutations entirely
- Created `SearchSuggestions.module.css` with `.suggestionItem:hover` pseudo-class handling the background highlight via CSS
- The same pattern was also fixed in `Library.tsx` (~Lines 493-500) — created `Library.module.css` with `.bookCard:hover` for the lift effect
- No more `e.currentTarget as HTMLElement` or inline style mutations
### 🟡 Suggestions — Addressed
- **Shared `useDebounce` hook**: Extracted to `frontend/src/hooks/useDebounce.ts`. Both `Library.tsx` and `SearchSuggestions.tsx` now import from the shared module. Exported via `hooks/index.ts`.
- **CSS modules**: `SearchSuggestions.module.css` and `Library.module.css` now handle hover states declaratively via `:hover` pseudo-classes.
crisleo94
approved these changes 2026-05-29 05:12:58 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Implement: Mobile Book Search and Discovery
Enhanced the book search experience with mobile-first features: voice search via Web Speech API, real-time autocomplete suggestions, and touch-optimized responsive layout.
Changes
API Client Fixes (missing from merged PR #13):
frontend/src/types/book.ts- AddedBookSearchParamsinterface andREADING_STATUS_OPTIONSconstantfrontend/src/api/books.ts- AddedsearchBooks,getBook,getGenres,getAuthorsmethods tobooksApiMobile Features (new):
frontend/src/hooks/useVoiceSearch.ts- Web Speech API hook for voice searchfrontend/src/hooks/useMediaQuery.ts- Responsive breakpoints utilityfrontend/src/components/search/SearchSuggestions.tsx- Real-time autocomplete dropdownfrontend/src/pages/Library.tsx- Voice search, suggestions, mobile-responsive gridfrontend/src/pages/BookDetailPage.tsx- Mobile-responsive detail layoutDocumentation:
docs/frontend/mobile-search-spec.md- Full spec for mobile search featuresCloses #5 (re-opened) - missing API methods now added.
Reid's Review — PR #24
Verdict: 🔴 Changes Required
🔴 Blocking Issues
[File: frontend/src/hooks/useVoiceSearch.ts | Line ~19]
event handler typingThe
window as unknown as Record<string, unknown>cast is acceptable for the SpeechRecognition check, but theSpeechRecognitionandSpeechRecognitionEventtypes are used without being imported or defined. These DOM types need proper type declarations or thetypes/speech-recognitionpackage should be installed. As written, this will cause TypeScript compilation errors in environments without these global type definitions.[File: frontend/src/components/search/SearchSuggestions.tsx | Line ~89-100]
direct DOM manipulationThe
onMouseEnterandonMouseEnterevent handlers usee.currentTarget as HTMLElementand directly mutatestyle.background. This is direct DOM manipulation. Consider using CSS:hoverpseudo-class or a styled component solution instead. Inline style mutations bypass React's declarative model.🟡 Suggestions (Non-Blocking)
[File: frontend/src/hooks/useVoiceSearch.ts] Extract the debounce logic into a shared
useDebouncehook rather than duplicating it in Library.tsx. Both files have identical implementations.[File: frontend/src/components/search/SearchSuggestions.tsx] Consider adding proper CSS styling (CSS modules or styled-components) instead of extensive inline styles for better maintainability.
[File: frontend/src/pages/Library.tsx] The
TOUCH_TARGETconstant is well-placed but the inline styles throughout the component could benefit from extraction to a shared styling solution.📋 AC Coverage
SearchSuggestionscomponentnavigate(/books/${book.id})on suggestion clickbooksApi.searchBooks()which callsGET /api/books/✅ Addressed — All Review Issues Resolved
🔴 Blocking — Fixed
1. SpeechRecognition type declarations (
useVoiceSearch.ts~Line 19)frontend/src/types/speech-recognition.d.tswith full type declarations forSpeechRecognition,SpeechRecognitionEvent,SpeechRecognitionErrorEvent, and theWindowinterface extensionsade810a2. Direct DOM manipulation (
SearchSuggestions.tsx~Lines 89-100)onMouseEnter/onMouseLeaveinline style mutations entirelySearchSuggestions.module.csswith.suggestionItem:hoverpseudo-class handling the background highlight via CSSLibrary.tsx(~Lines 493-500) — createdLibrary.module.csswith.bookCard:hoverfor the lift effecte.currentTarget as HTMLElementor inline style mutations🟡 Suggestions — Addressed
useDebouncehook: Extracted tofrontend/src/hooks/useDebounce.ts. BothLibrary.tsxandSearchSuggestions.tsxnow import from the shared module. Exported viahooks/index.ts.SearchSuggestions.module.cssandLibrary.module.cssnow handle hover states declaratively via:hoverpseudo-classes.