Skip to content

Wave search drop#1654

Merged
simo6529 merged 4 commits intomainfrom
wave-search-drop
Dec 16, 2025
Merged

Wave search drop#1654
simo6529 merged 4 commits intomainfrom
wave-search-drop

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Dec 16, 2025

Summary by CodeRabbit

  • New Features
    • Added search functionality to discover and navigate to specific drops within waves
    • Introduced a searchable modal interface for browsing and selecting wave content
    • Enhanced navigation with scroll-to functionality for quick access to specific items

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

Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 16, 2025

Walkthrough

This pull request introduces a wave drops search feature with scroll coordination. It adds a WaveChatScrollContext provider for coordinating scroll-to-serialNo requests, a new WaveDropsSearchModal component for searching drops within a wave, an infinite search hook (useWaveDropsSearch), and integrates search UI into MyStreamWave tabs. URL parameter handling is simplified, and a new API endpoint for searching drops is added to the OpenAPI spec.

Changes

Cohort / File(s) Summary
Search Context & Coordination
contexts/wave/WaveChatScrollContext.tsx
New React context providing WaveChatScrollProvider and useWaveChatScrollOptional hook to coordinate scroll-to-serialNo requests between components using registered handlers and pending requests.
Search Feature Components
components/waves/drops/search/WaveDropsSearchModal.tsx
New modal component for searching drops within a wave; integrates debounced search input, renders results as clickable drops, handles selection via onSelectSerialNo callback.
Search Hook
hooks/useWaveDropsSearch.ts
New hook using infinite query to fetch search results from waves/{wave.id}/search endpoint with debounced term input; returns augmented results as ExtendedDrop array.
MyStreamWave Integration
components/brain/my-stream/MyStreamWave.tsx
Wraps content with WaveChatScrollProvider; reorders markup to nest tab structure inside provider.
MyStreamWaveChat Simplification
components/brain/my-stream/MyStreamWaveChat.tsx
Removes searchParamsDone state flag; simplifies URL parameter handling to immediately parse and reset serialNo parameter without two-step gating.
Tab Search Integration
components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx, components/brain/my-stream/tabs/MyStreamWaveTabsMeme.tsx
Both tabs: add isSearchOpen state, integrate WaveDropsSearchModal, add search trigger button (desktop) and clickable header (mobile), implement handleSearchSelect to route to scroll or URL update.
Wave Drops Scroll Handler
components/waves/drops/wave-drops-all/index.tsx
Registers scroll handler with WaveChatScrollContext via new effect to link waveId and queueSerialTarget for scroll coordination.
API Schema & Endpoint
openapi.yaml
Adds GET /waves/{waveId}/search endpoint with term, page, size query parameters; introduces ApiDropWithoutWavesPageWithoutCount response schema.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • WaveChatScrollContext logic: Handler registration, pending request queue, and cleanup require careful review to ensure proper state management and no memory leaks.
  • URL parameter handling in MyStreamWaveChat: Simplification from two-step flow to immediate effect-driven update needs verification for correctness and edge cases.
  • Search modal implementation: Verify debounce logic, focus management, FocusTrap integration, and proper event handling.
  • Effect dependencies in wave-drops-all: Ensure unsubscribe cleanup is properly wired and dependencies are complete.

Possibly related PRs

  • PR #1395: Overlaps directly with changes to MyStreamWave, tab components, and URL/tab handling modified for the new desktop layout.
  • PR #1560: Directly related through WaveChatScrollContext/provider integration and wave-drops-all scroll behavior coordination refactoring.

Suggested reviewers

  • ragnep

Poem

🐰 A hop, skip, and search away,
Through waves of drops, we scroll and play,
Context keeps the scroll aligned,
While modals search with purpose refined—
No URL delays, just instant grace,
A search for drops in the perfect place! 🌊✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Wave search drop' directly relates to the main feature added: a search modal (WaveDropsSearchModal) that allows users to search for and select drops within a wave, implemented across multiple wave tab components.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch wave-search-drop

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

sonarqubecloud Bot commented Dec 16, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
12.3% 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: 0

🧹 Nitpick comments (1)
components/brain/my-stream/tabs/MyStreamWaveTabsMeme.tsx (1)

140-183: Consider extracting shared header content to reduce duplication.

The WavePicture and wave title (h1) are rendered identically in both mobile and desktop branches. Extracting these into a small helper component or variable would reduce duplication and simplify future maintenance.

+  const headerContent = (
+    <>
+      <div className="tw-size-6 lg:tw-size-9 tw-flex-shrink-0 tw-ring-1 tw-ring-offset-1 tw-ring-offset-iron-950 tw-ring-white/30 tw-rounded-full">
+        <WavePicture
+          name={wave.name}
+          picture={wave.picture}
+          contributors={wave.contributors_overview.map((c) => ({
+            pfp: c.contributor_pfp,
+          }))}
+        />
+      </div>
+      <h1 className="tw-ml-3 tw-text-sm lg:tw-text-xl tw-font-semibold tw-text-white/95 tw-tracking-tight tw-mb-0 tw-truncate">
+        {wave.name}
+      </h1>
+    </>
+  );
+
   {isMobile ? (
     <button
       type="button"
       onClick={() => setIsSearchOpen(true)}
       aria-label="Search messages in this wave"
       className="tw-flex tw-items-center tw-bg-transparent tw-border-0 tw-p-0 tw-text-left tw-min-w-0"
     >
-      <div className="tw-size-6 lg:tw-size-9 ...">
-        <WavePicture ... />
-      </div>
-      <h1 className="tw-ml-3 ...">
-        {wave.name}
-      </h1>
+      {headerContent}
     </button>
   ) : (
     <>
-      <div className="tw-size-6 lg:tw-size-9 ...">
-        <WavePicture ... />
-      </div>
-      <h1 className="tw-ml-3 ...">
-        {wave.name}
-      </h1>
+      {headerContent}
       <button ...>
         <MagnifyingGlassIcon ... />
       </button>
     </>
   )}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c924f1b and ed1d970.

⛔ Files ignored due to path filters (3)
  • generated/models/ApiDropWithoutWavesPageWithoutCount.ts is excluded by !**/generated/**
  • generated/models/ObjectSerializer.ts is excluded by !**/generated/**
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • components/brain/my-stream/MyStreamWave.tsx (2 hunks)
  • components/brain/my-stream/MyStreamWaveChat.tsx (1 hunks)
  • components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx (5 hunks)
  • components/brain/my-stream/tabs/MyStreamWaveTabsMeme.tsx (5 hunks)
  • components/waves/drops/search/WaveDropsSearchModal.tsx (1 hunks)
  • components/waves/drops/wave-drops-all/index.tsx (2 hunks)
  • contexts/wave/WaveChatScrollContext.tsx (1 hunks)
  • hooks/useWaveDropsSearch.ts (1 hunks)
  • openapi.yaml (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • components/waves/drops/wave-drops-all/index.tsx
  • components/brain/my-stream/MyStreamWaveChat.tsx
  • components/waves/drops/search/WaveDropsSearchModal.tsx
  • components/brain/my-stream/tabs/MyStreamWaveTabsMeme.tsx
  • contexts/wave/WaveChatScrollContext.tsx
  • components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx
  • components/brain/my-stream/MyStreamWave.tsx
  • hooks/useWaveDropsSearch.ts
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

Files:

  • components/waves/drops/wave-drops-all/index.tsx
  • components/brain/my-stream/MyStreamWaveChat.tsx
  • components/waves/drops/search/WaveDropsSearchModal.tsx
  • components/brain/my-stream/tabs/MyStreamWaveTabsMeme.tsx
  • contexts/wave/WaveChatScrollContext.tsx
  • components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx
  • components/brain/my-stream/MyStreamWave.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • components/waves/drops/wave-drops-all/index.tsx
  • components/brain/my-stream/MyStreamWaveChat.tsx
  • components/waves/drops/search/WaveDropsSearchModal.tsx
  • components/brain/my-stream/tabs/MyStreamWaveTabsMeme.tsx
  • contexts/wave/WaveChatScrollContext.tsx
  • components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx
  • components/brain/my-stream/MyStreamWave.tsx
  • hooks/useWaveDropsSearch.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • components/waves/drops/wave-drops-all/index.tsx
  • components/brain/my-stream/MyStreamWaveChat.tsx
  • components/waves/drops/search/WaveDropsSearchModal.tsx
  • components/brain/my-stream/tabs/MyStreamWaveTabsMeme.tsx
  • contexts/wave/WaveChatScrollContext.tsx
  • components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx
  • components/brain/my-stream/MyStreamWave.tsx
  • hooks/useWaveDropsSearch.ts
🧠 Learnings (9)
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Remove unnecessary Effects; if Effect only derives state, compute during render instead

Applied to files:

  • components/waves/drops/wave-drops-all/index.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Use `useEffectEvent` for non-reactive logic inside Effects to avoid unnecessary re-runs

Applied to files:

  • components/waves/drops/wave-drops-all/index.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{ts,tsx} : If the `react-hooks/exhaustive-deps` lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in `useEffectEvent`

Applied to files:

  • components/waves/drops/wave-drops-all/index.tsx
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{tsx,jsx} : Use FontAwesome for icons in React components

Applied to files:

  • components/brain/my-stream/tabs/MyStreamWaveTabsMeme.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Fix with modernization (no `// eslint-disable` unless explicitly instructed); prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Applied to files:

  • components/brain/my-stream/tabs/MyStreamWaveTabsMeme.tsx
  • components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript and React functional components with hooks

Applied to files:

  • components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{ts,tsx} : Prefer direct named imports for React hooks and types (`import { useMemo, useRef, FC, etc. } from "react"`) over `React.` namespace usage (`React.useMemo`, `React.useRef`, etc.)

Applied to files:

  • components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: TypeScript + React functional components with hooks; follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Applied to files:

  • components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{tsx,jsx} : Use react-query for data fetching

Applied to files:

  • components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx
🧬 Code graph analysis (7)
components/waves/drops/wave-drops-all/index.tsx (1)
contexts/wave/WaveChatScrollContext.tsx (1)
  • useWaveChatScrollOptional (82-84)
components/brain/my-stream/MyStreamWaveChat.tsx (1)
helpers/navigation.helpers.ts (1)
  • getHomeFeedRoute (11-11)
components/waves/drops/search/WaveDropsSearchModal.tsx (2)
generated/models/ApiWave.ts (1)
  • ApiWave (27-179)
hooks/useWaveDropsSearch.ts (1)
  • useWaveDropsSearch (38-85)
components/brain/my-stream/tabs/MyStreamWaveTabsMeme.tsx (3)
contexts/wave/WaveChatScrollContext.tsx (1)
  • useWaveChatScrollOptional (82-84)
components/waves/WavePicture.tsx (1)
  • WavePicture (63-122)
components/waves/drops/search/WaveDropsSearchModal.tsx (1)
  • WaveDropsSearchModal (16-271)
components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx (2)
contexts/wave/WaveChatScrollContext.tsx (1)
  • useWaveChatScrollOptional (82-84)
components/waves/WavePicture.tsx (1)
  • WavePicture (63-122)
components/brain/my-stream/MyStreamWave.tsx (2)
contexts/wave/WaveChatScrollContext.tsx (1)
  • WaveChatScrollProvider (26-80)
components/brain/my-stream/tabs/MyStreamWaveTabs.tsx (1)
  • MyStreamWaveTabs (15-58)
hooks/useWaveDropsSearch.ts (5)
generated/models/ApiWave.ts (1)
  • ApiWave (27-179)
generated/models/ApiWaveMin.ts (1)
  • ApiWaveMin (16-163)
generated/models/ApiDropWithoutWavesPageWithoutCount.ts (1)
  • ApiDropWithoutWavesPageWithoutCount (16-51)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (16-20)
helpers/waves/wave-drops.helpers.ts (2)
  • mapToExtendedDrops (35-44)
  • generateUniqueKeys (78-91)
⏰ 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 (12)
openapi.yaml (1)

2620-2662: Wave search endpoint and page schema look consistent with client usage

The new /waves/{waveId}/search definition and ApiDropWithoutWavesPageWithoutCount schema align with the client hook (term/page/size, next + page pagination and ApiDropWithoutWave[] payload). I don’t see spec‑level issues here.

Also applies to: 5284-5294

hooks/useWaveDropsSearch.ts (1)

13-85: Infinite wave‑search hook is correctly wired to the new API and helpers

Mapping ApiWave → ApiWaveMin, query key construction, pagination via page/next, and transformation through mapToExtendedDrops/generateUniqueKeys are all consistent and look correct for the /waves/{waveId}/search endpoint. No issues from a hooks/typing perspective.

contexts/wave/WaveChatScrollContext.tsx (1)

3-84: Scroll coordination context is minimal and correctly handles registration and pending requests

The provider and hooks manage a single wave scroll handler with sensible semantics (pending request replay, guarded unregister, optional consumer). The implementation is straightforward and sound for the intended single‑wave use.

components/waves/drops/wave-drops-all/index.tsx (1)

21-22: Wave chat scroll handler registration is correctly scoped and cleaned up

Registering queueSerialTarget as the wave’s scroll handler when the context is available (with guarded cleanup) is a clean integration; dependencies look correct and this remains a no‑op when the provider isn’t present.

Also applies to: 187-195

components/waves/drops/search/WaveDropsSearchModal.tsx (1)

1-271: Wave drop search modal is well‑structured and aligns with the hook/API behavior

Debounced querying, open/close lifecycle (click‑away, Escape, focus management), state handling (loading/error/empty/results), and selection flow (onSelectSerialNo then onClose) are all coherent and match useWaveDropsSearch’s contract. I don’t see functional or accessibility issues here.

components/brain/my-stream/MyStreamWave.tsx (1)

20-21: WaveChatScrollProvider is correctly introduced without disturbing existing behavior

Wrapping the MyStream wave layout in WaveChatScrollProvider keeps hook ordering intact while enabling scroll coordination across tabs and content. The not‑found URL handling and stable key usage remain effectively unchanged.

Also applies to: 98-115

components/brain/my-stream/tabs/MyStreamWaveTabsDefault.tsx (1)

1-149: Search modal + scroll behavior are cleanly integrated into default wave tabs

The new search state, WaveDropsSearchModal usage, and handleSearchSelect logic (prefer context scroll, fall back to URL serialNo + replace) are coherent and correctly tied into the existing tab system and routing. Header tweaks for mobile/desktop look consistent with current patterns.

components/brain/my-stream/MyStreamWaveChat.tsx (1)

39-60: No changes needed. The URL parameter cleanup works as intended and does not interfere with the deep link scroll behavior.

components/brain/my-stream/tabs/MyStreamWaveTabsMeme.tsx (4)

21-28: LGTM!

The new imports are appropriate and consistent with the existing patterns in this file. HeroIcons usage aligns with the other icons already imported.


48-49: LGTM!

State and context hook are properly initialized. The optional nature of waveChatScroll is correctly handled in the handleSearchSelect function.


113-123: LGTM!

The search selection handler is well-implemented:

  • Correctly switches to CHAT tab before scrolling
  • Uses the scroll context when available for smooth in-page scrolling
  • Falls back to URL params when context is unavailable, preserving navigation history appropriately with router.replace

228-233: LGTM!

The WaveDropsSearchModal is properly integrated with all required props correctly wired to local state and handlers.

@simo6529 simo6529 merged commit d6c3c01 into main Dec 16, 2025
8 of 9 checks passed
@simo6529 simo6529 deleted the wave-search-drop branch December 16, 2025 13:11
@coderabbitai coderabbitai Bot mentioned this pull request Dec 29, 2025
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.

2 participants