Skip to content

Create wave modal bug fix#1578

Merged
ragnep merged 4 commits intomainfrom
discover-page-create-wave-fix
Oct 29, 2025
Merged

Create wave modal bug fix#1578
ragnep merged 4 commits intomainfrom
discover-page-create-wave-fix

Conversation

@ragnep
Copy link
Copy Markdown
Contributor

@ragnep ragnep commented Oct 29, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Restored the Create Wave modal on Discover for web: opens/closes reliably, respects URL params, and coexists with direct message creation.
  • New Features / Interaction

    • Improved author/contributor controls and card interactions to support in-app navigation, modifier-key shortcuts, and middle‑click opening in a new tab.
  • UI Changes

    • Wave titles now render as non-link elements for more consistent card behavior and interaction handling.
  • Documentation

    • Added a ticket and state-board entry describing the modal restoration plan and acceptance criteria.
  • Tests

    • Updated tests to mock navigation for component interaction verification.

Signed-off-by: ragnep <ragneinfo@gmail.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Oct 29, 2025

Walkthrough

Restores the Create Wave modal on the Discover page, adds ticket TKT-0021 to codex state, replaces Link-based navigation in WaveItem and WaveItemDropped with button/handler-driven routing (supporting modifier/middle-click), adds a next/navigation mock in tests, and sets an experimental MCP server env var for dev.

Changes

Cohort / File(s) Summary
Ticketing / State
codex/STATE.md, codex/tickets/TKT-0021.md
Added TKT-0021 to the Codex board and a detailed ticket documenting restoration of the Discover Create Wave modal, plan/checklist, acceptance criteria, logging notes, and timestamps.
Modal rendering
components/waves/Waves.tsx
Imports and conditionally renders CreateWaveModal (controlled by modal state) alongside existing CreateDirectMessageModal for non-app flows; simplified activeView selection logic.
Wave item interaction — list & dropped
components/waves/list/WaveItem.tsx, components/waves/list/WaveItemDropped.tsx
Replaced Link/anchor elements with interactive button/span patterns and event handlers using next/navigation's router.push and window.open for modifier/middle-click; added handlers to stop propagation/prevent default and aria labels/data attributes for interactivity.
Tests
__tests__/components/waves/list/WaveItemDropped.test.tsx
Mocked next/navigation's useRouter (mocked push) to accommodate router-based navigation in tests.
Dev script
scripts/dev-with-fallback.cjs
Added __NEXT_EXPERIMENTAL_MCP_SERVER: "true" to the environment passed to the Next.js dev server process.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Waves as Waves.tsx
    participant ModalState as Modal State
    participant CreateWaveModal
    participant CreateDMModal

    User->>Waves: Open Discover page
    Waves->>ModalState: read isWaveModalOpen, isDirectMessageModalOpen
    alt isWaveModalOpen
        Waves->>CreateWaveModal: Render (isWaveModalOpen=true)
        User->>CreateWaveModal: Interact (open/close/form)
    else isDirectMessageModalOpen
        Waves->>CreateDMModal: Render (isDirectMessageModalOpen=true)
        User->>CreateDMModal: Interact
    else
        Waves->>Waves: Render main content only
    end
Loading
sequenceDiagram
    participant User
    participant WaveItem as WaveItem.tsx
    participant Router

    User->>WaveItem: Click / middle-click / modifier-click
    alt Standard click (no modifiers)
        WaveItem->>Router: router.push(waveUrl)
    else Middle-click or Ctrl/Meta
        WaveItem->>WaveItem: window.open(waveUrl, "_blank")
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Check accessibility (keyboard focus, role/tabIndex, aria labels) for elements that replaced Links.
  • Verify correct propagation/preventDefault in nested interactive areas (WaveItem, WaveItemDropped).
  • Confirm tests properly mock next/navigation and validate router.push behavior.
  • Confirm modal state logic in Waves.tsx doesn't cause duplicate/conflicting modals.

Possibly related PRs

Suggested reviewers

  • simo6529
  • analyticsflowee

Poem

🐇 I hopped into code with a tiny cheer,
Restored the modal that we missed this year,
Clicks leap to routes or open a new tab,
Buttons listen closely — no more broken path,
The rabbit nods: the UI’s clear! ✨

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 pull request title "Create wave modal bug fix" directly relates to the main changes in the changeset. The primary modifications across Waves.tsx, WaveItem.tsx, and WaveItemDropped.tsx focus on restoring the Create Wave modal functionality, specifically wiring it back into the web interface while adjusting navigation patterns. The title accurately captures this main objective and would be immediately understandable to a teammate reviewing the commit history. While the title could be more specific (e.g., mentioning "Discover page" or "restore"), it provides sufficient clarity about the core change without being misleading or overly broad.
✨ 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 discover-page-create-wave-fix

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.

Signed-off-by: ragnep <ragneinfo@gmail.com>
Signed-off-by: ragnep <ragneinfo@gmail.com>
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

🧹 Nitpick comments (6)
__tests__/components/waves/list/WaveItemDropped.test.tsx (1)

5-5: Router mock looks good; consider centralizing and preparing for interaction assertions.

This aligns with the new router.push-based navigation. Optional: move this mock to a shared test util and add a window.open mock for future click/aux-click tests. You can also drop the unused next/link mock in this file.

components/waves/list/WaveItemDropped.tsx (2)

11-25: Support Shift+Click to match link semantics.

Buttons don’t open a new tab on Shift+Click. Add shiftKey to match anchor behavior.

Apply this diff:

-        if (event.metaKey || event.ctrlKey) {
+        if (event.metaKey || event.ctrlKey || event.shiftKey) {
           event.preventDefault();
           event.stopPropagation();
           window.open(href, "_blank", "noopener,noreferrer");
           return;
         }

Optionally, extract this open-in-new-tab check into a shared helper to reuse across WaveItem and here.


27-38: Verify onAuxClick support in target browsers.

onAuxClick isn’t uniformly fired in some older browsers. If you need widest support, add a middle-button check on onMouseDown/onMouseUp as a fallback.

components/waves/list/WaveItem.tsx (3)

178-194: Match full link semantics and dedupe navigation helpers.

  • Add Shift+Click support like anchors.
  • Logic duplicates WaveItemDropped; consider a small shared util (e.g., openInNewTabIfModifier(event, href)).

Apply this diff:

-      if (event.metaKey || event.ctrlKey) {
+      if (event.metaKey || event.ctrlKey || event.shiftKey) {
         event.preventDefault();
         event.stopPropagation();
         window.open(authorHref, "_blank", "noopener,noreferrer");
         return;
       }

Also applies to: 196-206


220-238: Avoid nesting interactive controls inside a Link (invalid HTML, a11y risk).

CardContainer renders a Link around the entire card; this inserts a as a descendant of an , which HTML disallows (interactive descendants). Screen readers may announce unpredictably, and some browsers may mis-handle events.

Recommended restructure (non-breaking UX):

  • Render CardContainer as a non-link container (
    ) when it contains nested interactive children, and handle meta/ctrl/middle in code; or
  • Use an absolutely-positioned Link overlay as a sibling inside the container, with interactive children above it (z-index), avoiding nesting.

If you go with the first approach, adjust handleCardClick to open a new tab when no anchor is present:

-      if (event.button === 1 || event.metaKey || event.ctrlKey) {
-        return;
-      }
+      if (event.button === 1 || event.metaKey || event.ctrlKey || event.shiftKey) {
+        if (!(event.currentTarget instanceof HTMLAnchorElement)) {
+          event.preventDefault();
+          event.stopPropagation();
+          window.open(waveHref, "_blank", "noopener,noreferrer");
+        }
+        return;
+      }

I can draft a small CardContainer variant that switches to

when nested interactive content is present, if helpful.


321-323: Non-link title is fine; card remains the primary tap target.

Minor note: the file still uses Heroicons. Our TSX guideline prefers FontAwesome; consider standardizing icons in a follow-up across components.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 03bff76 and a28c757.

📒 Files selected for processing (4)
  • __tests__/components/waves/list/WaveItemDropped.test.tsx (1 hunks)
  • codex/tickets/TKT-0021.md (1 hunks)
  • components/waves/list/WaveItem.tsx (5 hunks)
  • components/waves/list/WaveItemDropped.tsx (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • codex/tickets/TKT-0021.md
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Use TypeScript across the codebase

Files:

  • components/waves/list/WaveItemDropped.tsx
  • components/waves/list/WaveItem.tsx
  • __tests__/components/waves/list/WaveItemDropped.test.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Use React functional components with hooks for UI components

Files:

  • components/waves/list/WaveItemDropped.tsx
  • components/waves/list/WaveItem.tsx
  • __tests__/components/waves/list/WaveItemDropped.test.tsx
__tests__/**

📄 CodeRabbit inference engine (tests/AGENTS.md)

Place Jest test suites under the __tests__ directory mirroring source folders (e.g., components, contexts, hooks, utils)

Files:

  • __tests__/components/waves/list/WaveItemDropped.test.tsx
__tests__/components/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use @testing-library/react and @testing-library/user-event for React component tests

Files:

  • __tests__/components/waves/list/WaveItemDropped.test.tsx
**/__tests__/**

📄 CodeRabbit inference engine (AGENTS.md)

Place tests in __tests__ directories when organizing test suites

Files:

  • __tests__/components/waves/list/WaveItemDropped.test.tsx
**/*.test.tsx

📄 CodeRabbit inference engine (AGENTS.md)

When colocating tests with components, name them ComponentName.test.tsx

Files:

  • __tests__/components/waves/list/WaveItemDropped.test.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Mock external dependencies and APIs in tests

Files:

  • __tests__/components/waves/list/WaveItemDropped.test.tsx
🧬 Code graph analysis (1)
components/waves/list/WaveItemDropped.tsx (1)
generated/models/ApiWave.ts (1)
  • ApiWave (27-177)
⏰ 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 (3)
components/waves/list/WaveItemDropped.tsx (1)

79-93: A11y and interaction setup looks solid.

Button semantics + aria-label + data-wave-item-interactive with preventDefault/stopPropagation is correct for nested interactive containment.

If you plan to add keyboard tests, ensure Space/Enter activate this button and do not trigger card navigation.

components/waves/list/WaveItem.tsx (2)

63-63: Underline removal via class is fine.

tw-no-underline on the interactive card container keeps styling consistent without inline styles.


258-264: Good containment: stop navigation when clicking nested interactive.

preventDefault + stopPropagation on interactive-child clicks avoids accidental card nav.

Comment thread components/waves/list/WaveItemDropped.tsx
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

♻️ Duplicate comments (1)
components/waves/list/WaveItem.tsx (1)

178-206: Code duplication with WaveItemDropped.tsx handlers.

These navigation handlers duplicate the logic in WaveItemDropped.tsx (lines 11-38). See the earlier comment on that file for the suggested shared helper extraction.

🧹 Nitpick comments (1)
components/waves/list/WaveItemDropped.tsx (1)

11-38: Extract shared navigation handlers to reduce duplication.

These click and auxiliary-click handlers are nearly identical to handleAuthorClick and handleAuthorAuxClick in WaveItem.tsx (lines 178-206). Both implement the same pattern: handle modifier keys for new tabs, middle-click for new tabs, and fallback to router.push.

Consider extracting a shared helper:

function createNavigationHandlers(router: ReturnType<typeof useRouter>, href: string) {
  const handleClick = useCallback(
    (event: MouseEvent<HTMLButtonElement>) => {
      if (event.metaKey || event.ctrlKey) {
        event.preventDefault();
        event.stopPropagation();
        window.open(href, "_blank", "noopener,noreferrer");
        return;
      }
      event.preventDefault();
      event.stopPropagation();
      router.push(href);
    },
    [href, router]
  );

  const handleAuxClick = useCallback(
    (event: MouseEvent<HTMLButtonElement>) => {
      if (event.button !== 1) {
        return;
      }
      event.preventDefault();
      event.stopPropagation();
      window.open(href, "_blank", "noopener,noreferrer");
    },
    [href]
  );

  return { handleClick, handleAuxClick };
}

Then use it in both components:

const { handleClick, handleAuxClick } = createNavigationHandlers(router, contributorHref);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a28c757 and a803a5d.

📒 Files selected for processing (2)
  • components/waves/list/WaveItem.tsx (5 hunks)
  • components/waves/list/WaveItemDropped.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Use TypeScript across the codebase

Files:

  • components/waves/list/WaveItem.tsx
  • components/waves/list/WaveItemDropped.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Use React functional components with hooks for UI components

Files:

  • components/waves/list/WaveItem.tsx
  • components/waves/list/WaveItemDropped.tsx
🧬 Code graph analysis (1)
components/waves/list/WaveItemDropped.tsx (1)
generated/models/ApiWave.ts (1)
  • ApiWave (27-177)
🔇 Additional comments (6)
components/waves/list/WaveItemDropped.tsx (2)

1-2: LGTM: Imports support the new navigation pattern.

The React hooks and Next.js router imports are appropriate for the button-based navigation handlers added below.

Note: The missing "use client" directive has already been flagged in a previous review.


79-92: LGTM: Button-based navigation with proper accessibility.

The button implementation correctly:

  • Uses type="button" to prevent form submission
  • Adds data-wave-item-interactive for parent click handler coordination
  • Includes descriptive aria-label
  • Applies appropriate styling to remove default button appearance
components/waves/list/WaveItem.tsx (4)

63-63: LGTM: Removes default link underline.

The tw-no-underline class appropriately removes text decoration from the card link, maintaining clean visual styling.


220-237: LGTM: Author button with proper interaction handlers.

The button-based author navigation correctly:

  • Implements the same navigation pattern as contributor buttons
  • Includes data-wave-item-interactive for parent handler coordination
  • Provides accessible labeling
  • Maintains visual consistency with text-left alignment

257-264: LGTM: Proper delegation between nested interactive elements and card navigation.

The updated logic correctly handles three scenarios:

  1. Nested interactive elements (lines 258-261): Prevents card navigation when clicking nested buttons, stopping event propagation
  2. Modifier/middle-clicks (line 262): Allows default Link behavior for opening in new tabs
  3. Normal clicks (lines 265-268): Uses router.push for in-app navigation

This coordination ensures nested buttons (author, contributors, follow) work independently while preserving the card's link functionality.


321-323: LGTM: Wave name as non-interactive element.

Changing the wave name from a Link to a span simplifies the interaction model by consolidating navigation to the card level. The group-hover styling still provides visual feedback, maintaining good UX.

Signed-off-by: ragnep <ragneinfo@gmail.com>
@sonarqubecloud
Copy link
Copy Markdown

@ragnep ragnep merged commit 8238690 into main Oct 29, 2025
7 of 8 checks passed
@ragnep ragnep deleted the discover-page-create-wave-fix branch October 29, 2025 08:28
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/waves/list/WaveItemDropped.tsx (1)

81-94: Consider adding keyboard focus indicator.

The interactive button lacks visible focus styles for keyboard navigation. Consider adding focus-visible styles to improve accessibility.

Apply this diff to add keyboard focus indicator:

                <button
                  type="button"
                  data-wave-item-interactive="true"
                  onClick={handleContributorClick(contributorHref)}
                  onAuxClick={handleContributorAuxClick(contributorHref)}
-                  className="tw-cursor-pointer tw-bg-transparent tw-border-none tw-p-0 tw-m-0 tw-inline-flex"
+                  className="tw-cursor-pointer tw-bg-transparent tw-border-none tw-p-0 tw-m-0 tw-inline-flex focus-visible:tw-outline focus-visible:tw-outline-2 focus-visible:tw-outline-primary-400 focus-visible:tw-rounded-lg"
                  aria-label={
                    c.contributor_identity
                      ? `View @${c.contributor_identity}`
                      : "View contributor profile"
                  }
                >
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a803a5d and cc617b3.

📒 Files selected for processing (2)
  • codex/tickets/TKT-0021.md (1 hunks)
  • components/waves/list/WaveItemDropped.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • codex/tickets/TKT-0021.md
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Use TypeScript across the codebase

Files:

  • components/waves/list/WaveItemDropped.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Use React functional components with hooks for UI components

Files:

  • components/waves/list/WaveItemDropped.tsx
🧬 Code graph analysis (1)
components/waves/list/WaveItemDropped.tsx (1)
generated/models/ApiWave.ts (1)
  • ApiWave (27-177)
⏰ 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 (3)
components/waves/list/WaveItemDropped.tsx (3)

1-1: LGTM: "use client" directive properly added.

The addition of the "use client" directive resolves the previous review concern and correctly enables client-side hooks (useRouter, useCallback) in the App Router.


13-27: LGTM: Click handler properly implements modifier-key navigation.

The handleContributorClick implementation correctly:

  • Detects modifier keys to open in new tab
  • Prevents default behavior and stops propagation
  • Uses router.push for standard navigation
  • Is properly memoized with router dependency

29-40: LGTM: Middle-click handler properly implemented.

The handleContributorAuxClick correctly handles middle-click (button === 1) navigation with appropriate event prevention and new-tab behavior using secure window.open parameters.

@coderabbitai coderabbitai Bot mentioned this pull request Oct 30, 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