Problem
src/components/ContactBook/SearchBar.tsx and src/hooks/useContactSearch.ts implement a working, debounced contact search:
// hooks/useContactSearch.ts
export function useContactSearch(contacts: Contact[], query: string) {
const debouncedQuery = useDebounce(query, 200)
return useMemo(() => {
if (!debouncedQuery.trim()) return contacts
const q = debouncedQuery.toLowerCase()
return contacts.filter(c =>
c.name.toLowerCase().includes(q) || c.address.toLowerCase().includes(q)
)
}, [contacts, debouncedQuery])
}
SearchBar.tsx has its own passing test (SearchBar.test.tsx) confirming it renders and calls onChange. But src/components/ContactBook/index.tsx — the component actually rendered by the app — never imports either SearchBar or useContactSearch:
export function ContactBook() {
const { contacts, addContact, removeContact } = useContacts()
const [name, setName] = useState(''); const [addr, setAddr] = useState('')
const submit = () => { if (name && addr) { addContact({ name, address: addr }); setName(''); setAddr('') } }
return (
<div className='p-4'>
<h2 className='text-lg font-semibold mb-4'>Contacts ({contacts.length})</h2>
{contacts.map(c => <ContactItem key={c.address} contact={c} onRemove={() => removeContact(c.address)} />)}
...
It renders contacts.map(...) directly — every saved contact, unfiltered, unpaginated — with no search box anywhere in the tree.
Why it matters
- This is a shipped-but-inaccessible feature: two files plus a test exist purely as unreachable code. Anyone reading
SearchBar.test.tsx passing in CI would reasonably assume contact search works in the product; it doesn't.
- As a practical UX gap (not just a code-hygiene issue):
ContactBook renders every contact unconditionally with no pagination, virtualization, or filtering. For a wallet with dozens/hundreds of saved contacts (a batch-send-heavy user maintaining a large contact list — directly relevant to the BatchSend feature elsewhere in this batch, where recipients are commonly picked from saved contacts) the page becomes an unfilterable, unbounded list.
useContactSearch's own debounce (useDebounce(query, 200)) is dead code from the app's perspective — it's tested in isolation but never runs against real user input, so any regression in it (e.g. if a future edit breaks the .trim()/.toLowerCase() filtering logic) would not be caught by manually using the app, only by its own unit test, which will keep passing regardless of the app's real behavior.
Reproduction
grep -rn "SearchBar\|useContactSearch" src/components/ContactBook/index.tsx — no matches.
- Open the Contacts view in the running app with several saved contacts — there is no search input anywhere on the page.
Suggested fix
- Wire
SearchBar and useContactSearch into ContactBook/index.tsx: hold a query state, render <SearchBar value={query} onChange={setQuery} /> above the contact list, and replace contacts.map(...) with useContactSearch(contacts, query).map(...).
- While doing so, also address the separate
AddContact.tsx-is-orphaned issue filed in this batch, since both are examples of the same index.tsx file not using components clearly built for it.
Edge cases
- Empty query should show all contacts (already handled by
useContactSearch's if (!debouncedQuery.trim()) return contacts early return).
- Very large contact lists (hundreds of entries) may need pagination/virtualization in addition to search, since filtering alone doesn't bound the list length for an empty query — worth scoping as a fast-follow rather than blocking this fix.
Testing strategy
- Add
ContactBook/index.test.tsx (currently doesn't exist) rendering ContactBook with several contacts, typing into the search box, and asserting the visible contact list narrows to matches — this exercises SearchBar + useContactSearch together as they'd actually run in production, closing the gap that their existing isolated unit tests don't cover.
Related issues in this batch
Same "implemented and tested, never wired in" pattern as the AddContact.tsx and orphaned TransactionHistory issues filed in this batch.
Problem
src/components/ContactBook/SearchBar.tsxandsrc/hooks/useContactSearch.tsimplement a working, debounced contact search:SearchBar.tsxhas its own passing test (SearchBar.test.tsx) confirming it renders and callsonChange. Butsrc/components/ContactBook/index.tsx— the component actually rendered by the app — never imports eitherSearchBaroruseContactSearch:It renders
contacts.map(...)directly — every saved contact, unfiltered, unpaginated — with no search box anywhere in the tree.Why it matters
SearchBar.test.tsxpassing in CI would reasonably assume contact search works in the product; it doesn't.ContactBookrenders every contact unconditionally with no pagination, virtualization, or filtering. For a wallet with dozens/hundreds of saved contacts (a batch-send-heavy user maintaining a large contact list — directly relevant to theBatchSendfeature elsewhere in this batch, where recipients are commonly picked from saved contacts) the page becomes an unfilterable, unbounded list.useContactSearch's own debounce (useDebounce(query, 200)) is dead code from the app's perspective — it's tested in isolation but never runs against real user input, so any regression in it (e.g. if a future edit breaks the.trim()/.toLowerCase()filtering logic) would not be caught by manually using the app, only by its own unit test, which will keep passing regardless of the app's real behavior.Reproduction
grep -rn "SearchBar\|useContactSearch" src/components/ContactBook/index.tsx— no matches.Suggested fix
SearchBaranduseContactSearchintoContactBook/index.tsx: hold aquerystate, render<SearchBar value={query} onChange={setQuery} />above the contact list, and replacecontacts.map(...)withuseContactSearch(contacts, query).map(...).AddContact.tsx-is-orphaned issue filed in this batch, since both are examples of the sameindex.tsxfile not using components clearly built for it.Edge cases
useContactSearch'sif (!debouncedQuery.trim()) return contactsearly return).Testing strategy
ContactBook/index.test.tsx(currently doesn't exist) renderingContactBookwith several contacts, typing into the search box, and asserting the visible contact list narrows to matches — this exercisesSearchBar+useContactSearchtogether as they'd actually run in production, closing the gap that their existing isolated unit tests don't cover.Related issues in this batch
Same "implemented and tested, never wired in" pattern as the
AddContact.tsxand orphanedTransactionHistoryissues filed in this batch.