Skip to content

ContactBook's SearchBar and useContactSearch are fully implemented and tested but never wired into ContactBook #27

Description

@abayomicornelius

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26bugSomething isn't workingenhancementNew feature or requestvery hardVery difficult / senior-level bounty issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions