Skip to content

Fix mobile search in wave#1747

Merged
simo6529 merged 2 commits intomainfrom
fix-mobile-search-in-wave
Jan 15, 2026
Merged

Fix mobile search in wave#1747
simo6529 merged 2 commits intomainfrom
fix-mobile-search-in-wave

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Jan 15, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added wave-based search functionality to allow searching within a specific wave context
    • Search modal now supports toggling between "In this Wave" and "Site-wide" search modes with paginated results display
  • Tests

    • Updated test suites to reflect component prop changes

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

This pull request introduces wave-specific search functionality to the header search components. A new wave prop is added to HeaderSearchButton and HeaderSearchModal, enabling a dual-mode search (WAVE vs SITE). The wave prop is threaded through AppHeader to relevant components. A new useWaveDropsSearch hook handles wave-specific drop searches with debouncing. Tests and related layout components are updated to support the new prop.

Changes

Cohort / File(s) Summary
Header Search Components
components/header/header-search/HeaderSearchButton.tsx, components/header/header-search/HeaderSearchModal.tsx
Added optional wave: ApiWave | null prop to both components. HeaderSearchButton threads wave to HeaderSearchModal. HeaderSearchModal implements dual-mode search (WAVE vs SITE) with separate debounce logic (250ms for wave), state management via SEARCH_MODE enum, WaveDrops results panel, and conditional rendering for wave/site results.
Header Container Components
components/header/AppHeader.tsx, components/layout/SmallScreenHeader.tsx
AppHeader now imports and uses useNavigationHistoryContext and useMyStreamOptional, derives current wave from context, and passes wave (or null) to HeaderSearchButton based on route context. SmallScreenHeader updated to pass wave={null} to HeaderSearchButton.
Layout Sidebar
components/layout/sidebar/WebSidebarNav.tsx
HeaderSearchModal now receives explicit wave={null} prop. Minor refactoring of submenu state logic and dependency arrays; className reordering.
Wave Search Hook
hooks/useWaveDropsSearch.ts
Updated to accept wave: ApiWave | null (previously required non-null). Enhanced toWaveMin mapping to include additional wave fields (admin_group_id, voting_period_*, voting_credit_type, eligibility fields). Query enabled condition and endpoint construction updated to handle null wave.
Header Search Test Suite
__tests__/components/header/HeaderSearchModal.test.tsx, __tests__/components/header/header-search/HeaderSearchButton.test.tsx, __tests__/components/header/header-search/HeaderSearchModalFocus.test.tsx
Updated to pass wave={null} prop in render calls. Formatting standardized to use double-quoted strings for consistency; test expectations and mock paths adjusted accordingly.

Sequence Diagram

sequenceDiagram
    actor User
    participant HeaderSearchModal
    participant useWaveDropsSearch
    participant API
    participant ResultsPanel

    User->>HeaderSearchModal: Type search term (Wave mode)
    HeaderSearchModal->>HeaderSearchModal: Debounce input (250ms)
    HeaderSearchModal->>useWaveDropsSearch: Fetch wave drops
    useWaveDropsSearch->>API: GET wave drops?waveId={id}&term={term}
    API-->>useWaveDropsSearch: Return drops
    useWaveDropsSearch-->>HeaderSearchModal: Update results
    HeaderSearchModal->>ResultsPanel: Render wave drops
    User->>ResultsPanel: Select a drop
    ResultsPanel->>HeaderSearchModal: handleWaveDropSelect
    HeaderSearchModal->>HeaderSearchModal: Close modal / Update navigation
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • prxt6529

🐰✨ A wave of search, now surfing bright,
Finding drops in every site,
Dual modes dance, both swift and wide,
Wave-specific treasures, no need to hide! 🌊

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding wave-aware search functionality to the mobile/header search modal, with the wave prop threaded through HeaderSearchButton and HeaderSearchModal components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
5.4% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@components/header/AppHeader.tsx`:
- Around line 101-104: The current branch in AppHeader returns wave.name after
the loading guard but does not ensure wave is defined; update the block that
checks waveId/isLoading/isFetching/wave?.id so that after those checks you also
verify wave is truthy before accessing wave.name (e.g., if (!wave) return a safe
fallback such as an empty string or a "not found" element), referencing the
wave, waveId, isLoading, isFetching, and the existing wave?.id check to locate
and modify the code.
🧹 Nitpick comments (3)
components/header/header-search/HeaderSearchButton.tsx (1)

44-46: Consider supporting Ctrl+K for Windows/Linux users.

The keyboard shortcut only responds to metaKey (Cmd on Mac). Windows and Linux users typically use Ctrl+K for search shortcuts.

Proposed fix
-  useKey((event) => event.metaKey && event.key === "k", handleOpen, {
+  useKey((event) => (event.metaKey || event.ctrlKey) && event.key === "k", handleOpen, {
     event: "keydown",
   });
components/header/header-search/HeaderSearchModal.tsx (1)

1117-1153: Wave search results lack keyboard navigation support.

Unlike site-wide search results which support arrow key navigation, wave drop results are only clickable. Consider adding keyboard navigation for accessibility parity, or document this as a known limitation.

__tests__/components/header/header-search/HeaderSearchButton.test.tsx (1)

26-31: Consider verifying wave prop forwarding in the mock.

The mock for HeaderSearchModal doesn't verify that the wave prop is correctly passed through from HeaderSearchButton. While the current tests validate button behavior, adding a verification could catch regressions if the prop forwarding is accidentally removed.

Optional enhancement to verify prop forwarding
 jest.mock("@/components/header/header-search/HeaderSearchModal", () => ({
   __esModule: true,
-  default: (props: any) => (
-    <div data-testid="modal" onClick={() => props.onClose()}></div>
+  default: (props: any) => (
+    <div data-testid="modal" data-wave={props.wave === null ? "null" : "present"} onClick={() => props.onClose()}></div>
   ),
 }));

Then in a test:

expect(screen.getByTestId("modal")).toHaveAttribute("data-wave", "null");
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b161ab5 and 9ff68d5.

📒 Files selected for processing (9)
  • __tests__/components/header/HeaderSearchModal.test.tsx
  • __tests__/components/header/header-search/HeaderSearchButton.test.tsx
  • __tests__/components/header/header-search/HeaderSearchModalFocus.test.tsx
  • components/header/AppHeader.tsx
  • components/header/header-search/HeaderSearchButton.tsx
  • components/header/header-search/HeaderSearchModal.tsx
  • components/layout/SmallScreenHeader.tsx
  • components/layout/sidebar/WebSidebarNav.tsx
  • hooks/useWaveDropsSearch.ts
🧰 Additional context used
🧬 Code graph analysis (7)
components/layout/sidebar/WebSidebarNav.tsx (1)
components/header/header-search/HeaderSearchModal.tsx (1)
  • HeaderSearchModal (158-1279)
__tests__/components/header/HeaderSearchModal.test.tsx (1)
components/header/header-search/HeaderSearchModal.tsx (1)
  • HeaderSearchModal (158-1279)
components/header/AppHeader.tsx (3)
components/navigation/BackButton.tsx (1)
  • BackButton (19-118)
components/ipfs/IPFSContext.tsx (1)
  • resolveIpfsUrlSync (77-89)
components/header/header-search/HeaderSearchButton.tsx (1)
  • HeaderSearchButton (17-83)
components/layout/SmallScreenHeader.tsx (1)
components/header/header-search/HeaderSearchButton.tsx (1)
  • HeaderSearchButton (17-83)
hooks/useWaveDropsSearch.ts (3)
generated/models/ApiWave.ts (1)
  • ApiWave (28-180)
generated/models/ApiDropWithoutWavesPageWithoutCount.ts (1)
  • ApiDropWithoutWavesPageWithoutCount (17-52)
helpers/waves/wave-drops.helpers.ts (1)
  • mapToExtendedDrops (36-45)
components/header/header-search/HeaderSearchButton.tsx (2)
generated/models/ApiWave.ts (1)
  • ApiWave (28-180)
components/header/header-search/HeaderSearchModal.tsx (1)
  • HeaderSearchModal (158-1279)
__tests__/components/header/header-search/HeaderSearchButton.test.tsx (1)
hooks/useDeviceInfo.ts (1)
  • useDeviceInfo (23-105)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (21)
components/header/header-search/HeaderSearchButton.tsx (2)

13-17: LGTM!

The new wave prop is properly typed with readonly modifier and correctly threaded through to the component. The interface definition is clean and follows TypeScript best practices.


77-77: LGTM!

The wave prop is correctly passed to HeaderSearchModal, aligning with its updated signature.

components/header/AppHeader.tsx (2)

152-158: LGTM!

The wave prop logic correctly passes the wave object only when inside a wave context and on appropriate routes, with proper null fallback.


73-73: Potential null reference on pathname.

usePathname() can return null during initial render or in certain navigation states. Calling .split() on null will throw a TypeError.

Proposed fix
-  const pathSegments = pathname.split("/").filter(Boolean);
+  const pathSegments = (pathname ?? "").split("/").filter(Boolean);

Likely an incorrect or invalid review comment.

hooks/useWaveDropsSearch.ts (2)

66-70: LGTM - non-null assertion is safe here.

The enabled condition on line 66 ensures wave !== null before queryFn can execute, making the wave!.id assertion on line 70 safe. React Query guarantees queryFn is only called when enabled is true.


83-93: LGTM!

Good defensive programming with the early return when waveMin is falsy. The memoization correctly handles the nullable wave input.

components/header/header-search/HeaderSearchModal.tsx (4)

54-57: LGTM!

Clean enum definition for the dual search modes. The naming is clear and follows conventions.


173-176: LGTM!

Search mode correctly defaults to WAVE when a wave is provided, otherwise SITE. This provides good UX by defaulting to contextual search.


643-653: LGTM!

The handleWaveDropSelect function handles both scenarios well:

  1. Uses scroll context when available (in-wave navigation)
  2. Falls back to URL params when scroll context isn't available

Good defensive null check on wave at the start.


1155-1168: LGTM!

The "Load more" pagination button correctly handles the loading state and disabled condition. Good use of infinite query pattern.

components/layout/SmallScreenHeader.tsx (2)

33-33: LGTM!

Correctly passes wave={null} since SmallScreenHeader is used in contexts outside of wave views, ensuring the modal defaults to site-wide search mode.


34-40: LGTM!

Menu button styling is well-structured with appropriate accessibility attributes (aria-label), focus states, and hover interactions.

__tests__/components/header/HeaderSearchModal.test.tsx (1)

210-210: LGTM!

The test correctly passes wave={null} to align with the updated HeaderSearchModal signature. This ensures existing tests continue to validate site-wide search behavior.

__tests__/components/header/header-search/HeaderSearchModalFocus.test.tsx (2)

155-155: LGTM!

The test correctly passes wave={null} to HeaderSearchButton, aligning with the updated component signature while maintaining focus on accessibility testing.


186-186: LGTM!

Consistent with the first test case update.

components/layout/sidebar/WebSidebarNav.tsx (3)

61-63: LGTM!

Formatting change for better readability.


213-221: LGTM!

Adding submenuAnchor and submenuTrigger to the dependency array is correct since the callback references both values. This ensures proper memoization behavior.


356-359: LGTM!

Correctly passes wave={null} to HeaderSearchModal for site-wide search functionality from the sidebar navigation.

__tests__/components/header/header-search/HeaderSearchButton.test.tsx (3)

52-52: LGTM!

Test correctly passes wave={null} to align with the updated component signature.


64-64: LGTM!

Consistent with other test cases.


79-79: LGTM!

Consistent with other test cases.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment thread components/header/AppHeader.tsx
@simo6529 simo6529 merged commit c1855b6 into main Jan 15, 2026
6 of 7 checks passed
@simo6529 simo6529 deleted the fix-mobile-search-in-wave branch January 15, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants