Skip to content

Mobile chat jump#1591

Merged
simo6529 merged 3 commits intomainfrom
mobile-chat-jump
Nov 2, 2025
Merged

Mobile chat jump#1591
simo6529 merged 3 commits intomainfrom
mobile-chat-jump

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Nov 2, 2025

Summary by CodeRabbit

  • New Features

    • Added Apple-device-aware handling and a pending-message badge with "reveal new messages" action in wave drops.
  • Bug Fixes

    • More resilient scroll initialization and observer setup to handle DOM readiness and async timing.
  • Refactor

    • Centralized platform detection to a device-info flag used across share, cookie banner, and waves.
  • Tests

    • Updated tests to include the new Apple-device flag and cover the pending-message reveal flow.

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 Nov 2, 2025

Walkthrough

This PR adds an isAppleMobile boolean to device detection, uses it to defer rendering new wave drops on Apple mobile (showing a reveal badge instead), threads pending-count props through wave-drop components, hardens scroll/observer setup via RAF-based deferred initialization, and updates tests to account for the new device flag and reveal behavior.

Changes

Cohort / File(s) Summary
Device Detection Hook
hooks/useDeviceInfo.ts
Added isAppleMobile: boolean to DeviceInfo and compute it from user agent (iPhone
Wave-drops: apple-mobile deferred rendering
components/waves/drops/wave-drops-all/index.tsx, components/waves/drops/wave-drops-all/subcomponents/WaveDropsContent.tsx, components/waves/drops/wave-drops-all/subcomponents/WaveDropsMessageListSection.tsx
Track visibleLatestSerial, compute renderedWaveMessages and pendingDropsCount for Apple devices, expose revealPendingDrops callback, and thread new props (pendingCount, onRevealPending) down to message list and scroll button.
Scroll Button component
components/waves/drops/WaveDropsScrollBottomButton.tsx
Added props newMessagesCount?: number and onRevealNewMessages?: () => void. Show "X new messages" badge when pending and call onRevealNewMessages on click (fallback to scrollToBottom otherwise). Updated aria-label, content, and sizing.
Scroll behavior robustness
hooks/useScrollBehavior.ts
Deferred IntersectionObserver and scroll listener setup using requestAnimationFrame until DOM refs exist. Added RAF retry loop and improved cleanup (cancel RAF, disconnect observer, remove listeners).
Platform usage updates
components/cookies/CookiesBanner.tsx, app/open-mobile/page.client.tsx
Replace ad-hoc iOS UA checks with isAppleMobile from useDeviceInfo for styling and mobile share selection.
Tests: device mock updates
__tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx, __tests__/components/header/HeaderSearchModal.test.tsx, __tests__/contexts/wave/hooks/useActiveWaveManager.test.tsx
Updated mocked useDeviceInfo return objects to include isAppleMobile: false.
Tests: device detection assertions
__tests__/hooks/useDeviceInfo.test.ts
Added assertions verifying isAppleMobile in various UA scenarios (true for iPhone/iPad/capacitor mobile UA; false for desktop without touch).
Tests: reveal/pending behavior
__tests__/components/waves/drops/WaveDropsAll.test.tsx, __tests__/components/waves/drops/WaveDropsScrollBottomButton.test.tsx
Enhanced WaveDropsAll test to inject deviceInfo and mutable wave messages, simulate Apple mobile deferred drops and reveal flow; added test asserting pending badge and onRevealNewMessages invocation in WaveDropsScrollBottomButton.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant WaveDrops as Wave Drops UI
    participant useDeviceInfo as useDeviceInfo Hook
    participant Backend

    User->>WaveDrops: Open wave (on mobile)
    WaveDrops->>useDeviceInfo: query isAppleMobile
    useDeviceInfo-->>WaveDrops: true

    Backend-->>WaveDrops: New drops arrive while user scrolled up
    WaveDrops->>WaveDrops: Increment pendingDropsCount<br/>Filter from renderedWaveMessages
    WaveDrops->>User: Show badge "N new messages"

    User->>WaveDrops: Click reveal button
    WaveDrops->>WaveDrops: Set visibleLatestSerial to newest<br/>Call revealPendingDrops
    WaveDrops->>User: Render pending drops<br/>Scroll to bottom
Loading
sequenceDiagram
    participant Component as useScrollBehavior
    participant RAF as requestAnimationFrame
    participant DOM as DOM refs
    participant Observer as IntersectionObserver

    Component->>RAF: schedule setupObserver
    RAF->>DOM: check refs
    alt refs not ready
        RAF->>RAF: retry next frame (loop)
    else refs ready
        RAF->>Observer: create & observe
        Component->>Component: attach scroll listener and call handleScroll
    end

    Component->>Component: unmount
    Component->>Observer: disconnect
    Component->>RAF: cancel pending RAF
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Key areas for focused review:
    • components/waves/drops/wave-drops-all/index.tsx — visibleLatestSerial/pending filtering and serial-number logic
    • hooks/useScrollBehavior.ts — RAF retry loops and cleanup correctness
    • components/waves/drops/WaveDropsScrollBottomButton.tsx — prop additions and click semantics (reveal vs scroll)
    • Tests: WaveDropsAll.test.tsx — timer advancement, mutable mock state, and async assertions

Possibly related PRs

Suggested reviewers

  • prxt6529
  • ragnep

Poem

🐰 Whiskers twitch on Apple nights,

New drops wait out of sight.
RAFs hum softly, observers bide,
Badges glow until revealed with pride.
Hoppity—now the drops arrive!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The PR title "Mobile chat jump" is related to the changeset in that it references mobile devices and chat functionality, which are core to the changes. However, the title uses ambiguous terminology that fails to clearly communicate the primary feature being implemented. The main objective of this PR is to add Apple mobile-specific logic for deferring new message drops and allowing users to reveal pending messages via a new "reveal" button interaction. The term "jump" is vague and doesn't specifically convey this deferred reveal functionality, leaving a teammate scanning the commit history without a clear understanding of what was actually changed.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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 mobile-chat-jump

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ef437e and ef3a36e.

📒 Files selected for processing (1)
  • hooks/useDeviceInfo.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • hooks/useDeviceInfo.ts
⏰ 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)

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.

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: 3

🧹 Nitpick comments (1)
__tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx (1)

31-36: Avoid duplicating type definitions in tests.

The local DeviceInfo type definition duplicates the interface from hooks/useDeviceInfo.ts. If the interface changes, this test will need manual updates.

Import the type from the source instead:

+import useDeviceInfo, { type DeviceInfo } from '@/hooks/useDeviceInfo';
-import useDeviceInfo from '@/hooks/useDeviceInfo';

-type DeviceInfo = {
-  isApp: boolean;
-  isMobileDevice: boolean;
-  hasTouchScreen: boolean;
-  isAppleMobile: boolean;
-};
 const useDeviceInfoMock = useDeviceInfo as jest.MockedFunction<typeof useDeviceInfo>;

Note: This assumes DeviceInfo is exported from the hook. If not, consider exporting it to improve type reusability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 25c8675 and 6ef437e.

📒 Files selected for processing (14)
  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx (2 hunks)
  • __tests__/components/header/HeaderSearchModal.test.tsx (1 hunks)
  • __tests__/components/waves/drops/WaveDropsAll.test.tsx (6 hunks)
  • __tests__/components/waves/drops/WaveDropsScrollBottomButton.test.tsx (1 hunks)
  • __tests__/contexts/wave/hooks/useActiveWaveManager.test.tsx (1 hunks)
  • __tests__/hooks/useDeviceInfo.test.ts (3 hunks)
  • app/open-mobile/page.client.tsx (2 hunks)
  • components/cookies/CookiesBanner.tsx (1 hunks)
  • components/waves/drops/WaveDropsScrollBottomButton.tsx (1 hunks)
  • components/waves/drops/wave-drops-all/index.tsx (7 hunks)
  • components/waves/drops/wave-drops-all/subcomponents/WaveDropsContent.tsx (3 hunks)
  • components/waves/drops/wave-drops-all/subcomponents/WaveDropsMessageListSection.tsx (3 hunks)
  • hooks/useDeviceInfo.ts (3 hunks)
  • hooks/useScrollBehavior.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{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

Files:

  • __tests__/components/header/HeaderSearchModal.test.tsx
  • hooks/useScrollBehavior.ts
  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx
  • components/waves/drops/wave-drops-all/index.tsx
  • components/waves/drops/wave-drops-all/subcomponents/WaveDropsMessageListSection.tsx
  • components/cookies/CookiesBanner.tsx
  • __tests__/components/waves/drops/WaveDropsScrollBottomButton.test.tsx
  • app/open-mobile/page.client.tsx
  • components/waves/drops/wave-drops-all/subcomponents/WaveDropsContent.tsx
  • components/waves/drops/WaveDropsScrollBottomButton.tsx
  • __tests__/hooks/useDeviceInfo.test.ts
  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
  • hooks/useDeviceInfo.ts
  • __tests__/contexts/wave/hooks/useActiveWaveManager.test.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

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

Files:

  • __tests__/components/header/HeaderSearchModal.test.tsx
  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx
  • components/waves/drops/wave-drops-all/index.tsx
  • components/waves/drops/wave-drops-all/subcomponents/WaveDropsMessageListSection.tsx
  • components/cookies/CookiesBanner.tsx
  • __tests__/components/waves/drops/WaveDropsScrollBottomButton.test.tsx
  • app/open-mobile/page.client.tsx
  • components/waves/drops/wave-drops-all/subcomponents/WaveDropsContent.tsx
  • components/waves/drops/WaveDropsScrollBottomButton.tsx
  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
  • __tests__/contexts/wave/hooks/useActiveWaveManager.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/header/HeaderSearchModal.test.tsx
  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx
  • __tests__/components/waves/drops/WaveDropsScrollBottomButton.test.tsx
  • __tests__/hooks/useDeviceInfo.test.ts
  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
  • __tests__/contexts/wave/hooks/useActiveWaveManager.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/header/HeaderSearchModal.test.tsx
  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx
  • __tests__/components/waves/drops/WaveDropsScrollBottomButton.test.tsx
  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
{app,pages}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Use NextJS features that match the current version

Files:

  • app/open-mobile/page.client.tsx
🧠 Learnings (11)
📚 Learning: 2025-09-28T12:33:07.561Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __mocks__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:07.561Z
Learning: Applies to __mocks__/**/__mocks__/**/*.{js,jsx,ts,tsx} : Keep mock implementations minimal—only what’s necessary for the test scenarios

Applied to files:

  • __tests__/components/header/HeaderSearchModal.test.tsx
  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx
  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
  • __tests__/contexts/wave/hooks/useActiveWaveManager.test.tsx
📚 Learning: 2025-09-28T12:33:07.561Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __mocks__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:07.561Z
Learning: Applies to __mocks__/**/__mocks__/**/*.{js,jsx,ts,tsx} : Document non-obvious expected behaviour directly in the mock file

Applied to files:

  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx
  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
  • __tests__/contexts/wave/hooks/useActiveWaveManager.test.tsx
📚 Learning: 2025-09-28T12:33:07.561Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __mocks__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:07.561Z
Learning: Applies to __mocks__/**/__mocks__/**/*.{js,jsx,ts,tsx} : Keep mocks up to date with the real implementations they represent

Applied to files:

  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx
  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
  • __tests__/contexts/wave/hooks/useActiveWaveManager.test.tsx
📚 Learning: 2025-09-28T12:33:07.561Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __mocks__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:07.561Z
Learning: Applies to __mocks__/**/__mocks__/**/*.{js,jsx,ts,tsx} : Mock only external dependencies or heavy functionality; avoid over-mocking internal logic

Applied to files:

  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx
  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
  • __tests__/contexts/wave/hooks/useActiveWaveManager.test.tsx
📚 Learning: 2025-09-28T12:33:07.561Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __mocks__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:07.561Z
Learning: Applies to __mocks__/**/*.{test,spec}.{js,jsx,ts,tsx} : In tests, use jest.mock('module') with a bare module specifier to load the corresponding manual mock

Applied to files:

  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx
  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
  • __tests__/contexts/wave/hooks/useActiveWaveManager.test.tsx
📚 Learning: 2025-09-28T12:33:07.561Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __mocks__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:07.561Z
Learning: Use Jest’s built-in mocking for module replacement; keep manual mocks simple and lightweight

Applied to files:

  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
📚 Learning: 2025-09-28T12:33:07.561Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __mocks__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:07.561Z
Learning: Applies to __mocks__/**/__mocks__/**/*.{js,jsx,ts,tsx} : Organise mocks to mirror the real module structure so import paths remain consistent

Applied to files:

  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
  • __tests__/contexts/wave/hooks/useActiveWaveManager.test.tsx
📚 Learning: 2025-09-28T12:33:07.561Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __mocks__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:07.561Z
Learning: Applies to __mocks__/**/__mocks__/**/*.{js,jsx,ts,tsx} : Name mock files to mirror the real module names so jest.mock('module') can pick them up automatically

Applied to files:

  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
📚 Learning: 2025-09-28T12:33:07.561Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __mocks__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:07.561Z
Learning: Applies to __mocks__/**/__mocks__/**/*.{js,jsx,ts,tsx} : Place manual mock modules under a __mocks__ directory so Jest can auto-resolve them

Applied to files:

  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
📚 Learning: 2025-09-28T12:33:30.950Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:30.950Z
Learning: Applies to __tests__/components/**/*.{ts,tsx,js,jsx} : Use `testing-library/react` and `testing-library/user-event` for React component tests

Applied to files:

  • __tests__/components/waves/drops/WaveDropsAll.test.tsx
📚 Learning: 2025-09-28T12:33:07.561Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __mocks__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:07.561Z
Learning: Applies to __mocks__/**/__mocks__/**/*.{js,jsx,ts,tsx} : Review mocks periodically and remove unused mock modules

Applied to files:

  • __tests__/contexts/wave/hooks/useActiveWaveManager.test.tsx
🧬 Code graph analysis (6)
__tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx (1)
hooks/useDeviceInfo.ts (1)
  • useDeviceInfo (23-95)
components/waves/drops/wave-drops-all/index.tsx (1)
hooks/useDeviceInfo.ts (1)
  • useDeviceInfo (23-95)
components/cookies/CookiesBanner.tsx (2)
hooks/useDeviceInfo.ts (1)
  • useDeviceInfo (23-95)
hooks/isMobileDevice.ts (1)
  • useIsMobileDevice (5-18)
__tests__/components/waves/drops/WaveDropsScrollBottomButton.test.tsx (1)
components/waves/drops/WaveDropsScrollBottomButton.tsx (1)
  • WaveDropsScrollBottomButton (10-73)
app/open-mobile/page.client.tsx (2)
app/open-mobile/page.tsx (1)
  • OpenMobilePage (5-7)
hooks/useDeviceInfo.ts (1)
  • useDeviceInfo (23-95)
__tests__/components/waves/drops/WaveDropsAll.test.tsx (1)
__tests__/utils/editDropTestUtils.tsx (1)
  • createMockDrop (5-39)
⏰ 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 (22)
hooks/useDeviceInfo.ts (1)

55-55: Apple mobile detection logic is correct.

The implementation correctly identifies Apple mobile devices by checking UA patterns for iPhone/iPad/iPod and handling the edge case where iPads masquerade as Macintosh in desktop mode.

hooks/useScrollBehavior.ts (2)

80-121: Robust observer initialization with deferred setup.

The RAF-based approach ensures the Intersection Observer is only created once both refs are available, preventing race conditions during component mount. Cleanup properly cancels pending RAF and disconnects the observer.


123-151: Robust scroll listener attachment with deferred setup.

The deferred attachment pattern with RAF ensures the scroll listener is only added once the container is available, and the initial handleScroll() call ensures state reflects the current scroll position. Cleanup is comprehensive.

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

141-146: Mock updated correctly for new DeviceInfo field.

The test mock now includes isAppleMobile: false, maintaining consistency with the extended DeviceInfo interface.

__tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx (1)

41-46: Test mocks updated correctly.

The mock values now include isAppleMobile: false, maintaining consistency with the extended DeviceInfo interface.

Also applies to: 72-77

__tests__/contexts/wave/hooks/useActiveWaveManager.test.tsx (1)

5-13: Mock updated correctly for new DeviceInfo field.

The test mock now includes isAppleMobile: false, maintaining consistency with the extended DeviceInfo interface.

app/open-mobile/page.client.tsx (1)

9-9: Platform detection correctly centralized.

Replacing inline iOS detection with isAppleMobile from the hook centralizes device detection logic and eliminates code duplication. The conditional rendering logic correctly handles Apple mobile, Android, and fallback cases.

Also applies to: 15-15, 46-50

components/cookies/CookiesBanner.tsx (1)

12-12: Platform detection correctly centralized.

Replacing inline iOS detection with isAppleMobile from the hook centralizes device detection logic. The styling condition isApp && isAppleMobile correctly targets iOS app environments.

Also applies to: 24-24

__tests__/hooks/useDeviceInfo.test.ts (3)

21-29: Test correctly asserts Apple mobile detection for iPhone.

The assertion expect(result.current.isAppleMobile).toBe(true) correctly validates that iPhone user agents are detected as Apple mobile devices.


31-39: Test correctly asserts Apple mobile detection for iPad in desktop mode.

The assertion validates the edge case where iPads report as "Macintosh" with touch capabilities. The detection correctly identifies this as an Apple mobile device.


41-49: Test correctly asserts non-Apple mobile detection for desktop.

The assertion expect(result.current.isAppleMobile).toBe(false) correctly validates that generic desktop user agents are not detected as Apple mobile devices.

__tests__/components/waves/drops/WaveDropsScrollBottomButton.test.tsx (1)

23-36: LGTM! Well-structured test for pending message reveal.

The test properly verifies the new pending badge rendering and reveal handler invocation. The assertions clearly validate both the UI changes and the callback behavior.

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

44-46: LGTM! Clean prop threading.

The new props are properly typed with readonly and correctly forwarded to the child component.

Also applies to: 65-67, 106-107

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

40-42: LGTM! Proper prop forwarding with clear naming.

The props are correctly threaded through to WaveDropsScrollBottomButton with appropriate name mappings.

Also applies to: 64-66, 101-102

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

93-123: Solid implementation of deferred rendering state management.

The state and effect properly handle the visibility window for Apple devices. The logic correctly defers new messages when the user is reading (not pinned to bottom) on Apple mobile.

One edge case to verify: when latestSerialNo becomes null (e.g., all drops removed), visibleLatestSerial is not reset. Ensure this behavior is intentional and handles the scenario correctly.


125-149: LGTM! Efficient filtering logic for Apple device rendering.

The memo correctly filters drops based on the visibility threshold and handles drops without serial_no gracefully by including them in the results.


151-166: LGTM! Accurate pending count calculation.

The memo correctly counts only drops with numeric serial numbers that exceed the visibility threshold, providing the right count for the badge display.


185-193: LGTM! Clean reveal handler.

The callback properly updates the visibility threshold to the newest serial and triggers a scroll to bottom, revealing all pending messages.

__tests__/components/waves/drops/WaveDropsAll.test.tsx (3)

38-46: LGTM! Comprehensive device info mock setup.

The mock properly exposes all device info properties and allows per-test configuration through setupMocks options, enabling flexible test scenarios.

Also applies to: 173-178, 252-257


209-264: Excellent mock architecture for dynamic message updates.

The mutable wave messages approach with getter/setter functions enables realistic testing of real-time message arrival scenarios. This is a clean solution for simulating dynamic data updates in tests.


592-648: LGTM! Thorough test coverage for Apple device deferred rendering.

The test comprehensively validates the entire flow:

  1. Initial state verification (no pending)
  2. New message arrival simulation
  3. Deferred rendering confirmation
  4. Reveal interaction
  5. Final state validation

The use of fake timers and userEvent properly exercises asynchronous behavior.

components/waves/drops/WaveDropsScrollBottomButton.tsx (1)

6-27: LGTM! Well-structured dual-mode button logic.

The component cleanly handles both pending message reveal and scroll-to-bottom functionality. The logic correctly prioritizes the reveal action when messages are pending.

Comment thread components/waves/drops/WaveDropsScrollBottomButton.tsx
Comment thread hooks/useDeviceInfo.ts
Comment thread hooks/useDeviceInfo.ts
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Nov 2, 2025

@simo6529 simo6529 merged commit 21bc6c5 into main Nov 2, 2025
8 checks passed
@simo6529 simo6529 deleted the mobile-chat-jump branch November 2, 2025 09:30
@coderabbitai coderabbitai Bot mentioned this pull request Dec 18, 2025
This was referenced Jan 23, 2026
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