Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughPropagates a new leftThisRoundCount field from the API through hooks, queue/state, helpers, and components; UI and accessibility text now present both “left this round” and “unrated” counts; tests and OpenAPI updated to match the new undiscovered-drop response shape. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as Client UI
participant Hook as useMemesWaveFooterStats / useMemesQuickVoteQueue
participant API as UndiscoveredDrop API
participant Queue as QuickVote Queue/State
participant Trigger as MemesWaveQuickVoteTrigger
UI->>Hook: request footer/quick-vote stats
Hook->>API: GET /waves/{waveId}/undiscovered-drop (with AbortSignal)
API-->>Hook: { left_to_vote_in_current_round, total_count, drop }
Hook->>Queue: applyFetchedWindowState(left_to_vote_in_current_round, total_count)
Queue-->>Hook: session state (leftThisRoundCount, unratedCount, isRestartingRound)
Hook-->>UI: stats object (leftThisRoundCount, unratedCount, isAvailable)
UI->>Trigger: render button with formatted texts
Trigger-->>UI: accessible label and badge showing leftThisRoundCount / unratedCount
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 138644d865
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
openapi.yaml (1)
10966-10968: Consider tightening the new count field contract.Since this is a count, adding
minimum: 0and a short description would improve API validation/docs.Suggested schema tweak
left_to_vote_in_current_round: + description: Number of drops left to vote in the current round. type: integer format: int64 + minimum: 0🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openapi.yaml` around lines 10966 - 10968, The schema for the count field left_to_vote_in_current_round should be tightened by adding validation and documentation: update the left_to_vote_in_current_round property (type: integer, format: int64) to include minimum: 0 and add a short description (e.g., "Number of entities remaining to vote in the current round; non-negative integer") so the OpenAPI spec enforces non-negativity and improves generated docs/validation.__tests__/hooks/useMemesWaveFooterStats.test.tsx (1)
146-174: Assert the newisAvailablecontract in this hook test.Footer visibility now gates on
isAvailable, but these cases only pinisReadyand the count fields. If availability mapping regresses, the UI can disappear while this spec still passes.♻️ Suggested assertions
await waitFor(() => expect(result.current.isReady).toBe(true)); + expect(result.current.isAvailable).toBe(true); expect(result.current.leftThisRoundCount).toBe(2); expect(result.current.uncastPower).toBe(5_000); expect(result.current.unratedCount).toBe(7);expect(result.current.isReady).toBe(false); + expect(result.current.isAvailable).toBe(false); expect(result.current.leftThisRoundCount).toBe(0); expect(result.current.uncastPower).toBeNull(); expect(result.current.unratedCount).toBe(0);Also applies to: 176-200
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@__tests__/hooks/useMemesWaveFooterStats.test.tsx` around lines 146 - 174, The test for useMemesWaveFooterStats currently only asserts isReady and count fields but omits the new isAvailable contract that controls footer visibility; update the test "fetches the first unvoted leaderboard item and derives footer stats from it" (and the similar spec around the other block) to assert the isAvailable boolean returned from useMemesWaveFooterStats — e.g. add expect(result.current.isAvailable).toBe(true/false) as appropriate for the mocked response — so regressions to availability mapping fail the test; reference the useMemesWaveFooterStats hook and the result.current.isAvailable property when adding the assertion.__tests__/components/brain/mobile/FloatingMemesQuickVoteTrigger.test.tsx (1)
13-23: KeepunratedCountobservable in the mock.The test double currently throws away
unratedCount, so this spec still passes ifFloatingMemesQuickVoteTriggerstops forwarding the new prop. Surface it in the mock output or assert the child props directly.♻️ One simple way to keep the prop covered
default: ({ leftThisRoundCount, onOpenQuickVote, onPrefetchQuickVote, - unratedCount: _unratedCount, + unratedCount, }: { readonly leftThisRoundCount: number; readonly onOpenQuickVote: () => void; readonly onPrefetchQuickVote?: (() => void) | undefined; readonly unratedCount: number; }) => ( <button type="button" data-testid="floating-quick-vote-trigger" + data-unrated-count={unratedCount} onClick={onOpenQuickVote} onFocus={onPrefetchQuickVote} onMouseEnter={onPrefetchQuickVote} > {leftThisRoundCount} </button> ),const trigger = screen.getByTestId("floating-quick-vote-trigger"); + expect(trigger).toHaveAttribute("data-unrated-count", "9");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@__tests__/components/brain/mobile/FloatingMemesQuickVoteTrigger.test.tsx` around lines 13 - 23, The mock for the child in FloatingMemesQuickVoteTrigger currently renames and discards unratedCount (unratedCount: _unratedCount), so update the mock to surface that value (e.g., include unratedCount in the rendered output or props object) or change the mock to forward the prop unchanged; alternatively add an assertion that the child received unratedCount — locate the default mock function in __tests__/components/brain/mobile/FloatingMemesQuickVoteTrigger.test.tsx (the default: ({ leftThisRoundCount, onOpenQuickVote, onPrefetchQuickVote, unratedCount: _unratedCount }) => ...) and either use unratedCount in the returned JSX/text or assert it was passed through to ensure the component still forwards the prop.components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVotePreview.tsx (1)
368-375: Emit one combined SR-only status sentence here.This adds more hidden fragments to
quick-vote-preview-status. Building one comma-separated string instead of stacking extra SR-only spans will keep the spoken copy more predictable and reduce drift as more status fields get added.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVotePreview.tsx` around lines 368 - 375, Replace the two separate screen-reader-only spans inside the MemesQuickVotePreview with a single SR-only sentence by building a combined string (e.g., `${formatMemesQuickVoteLeftThisRoundText(leftThisRoundCount)}, ${formatMemesQuickVoteUnratedText(unratedCount)}`) and rendering it in one <span className="tw-sr-only"> so the hidden copy is a single predictable fragment; keep using the existing helpers formatMemesQuickVoteLeftThisRoundText and formatMemesQuickVoteUnratedText and ensure this single span is placed where the current sr-only spans were (e.g., within the quick-vote-preview-status area).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@hooks/memesQuickVote.queue.state.ts`:
- Around line 128-143: The reducer's isLoading/isExhausted logic must account
for the per-round remaining count (leftThisRoundCount) because rawUnratedCount
alone can indicate items in other rounds; compute a roundComplete flag (e.g.,
roundComplete = primaryDrop === null && leftThisRoundCount === 0 &&
rawUnratedCount > 0) and return it, then change isLoading to currentDrop ===
null && !isExhausted && !roundComplete; keep isExhausted based on currentDrop,
lookaheadDrops, hiddenDropIds, primaryDrop, and rawUnratedCount as before but
ensure it doesn't treat round-complete-as-loading. Reference: isExhausted
calculation, isLoading, rawUnratedCount, leftThisRoundCount, primaryDrop,
currentDrop.
- Around line 95-98: The branch that clears recentlyHandledDropIds uses
rawUnratedCount (fed from total_count) which can wrongly reset handled IDs when
the current round is empty; update the condition to use rawLeftThisRoundCount
instead of rawUnratedCount so the expression becomes: rawLeftThisRoundCount > 0
&& safeFetchedDropsWithoutHandled.length === 0 ? [] : resurfacedHandledDropIds.
Modify the code that computes recentlyHandledDropIds (the variables
recentlyHandledDropIds, safeFetchedDropsWithoutHandled and
resurfacedHandledDropIds) to reference rawLeftThisRoundCount from the
round-scoped data provided by useMemesQuickVoteQueue.
---
Nitpick comments:
In `@__tests__/components/brain/mobile/FloatingMemesQuickVoteTrigger.test.tsx`:
- Around line 13-23: The mock for the child in FloatingMemesQuickVoteTrigger
currently renames and discards unratedCount (unratedCount: _unratedCount), so
update the mock to surface that value (e.g., include unratedCount in the
rendered output or props object) or change the mock to forward the prop
unchanged; alternatively add an assertion that the child received unratedCount —
locate the default mock function in
__tests__/components/brain/mobile/FloatingMemesQuickVoteTrigger.test.tsx (the
default: ({ leftThisRoundCount, onOpenQuickVote, onPrefetchQuickVote,
unratedCount: _unratedCount }) => ...) and either use unratedCount in the
returned JSX/text or assert it was passed through to ensure the component still
forwards the prop.
In `@__tests__/hooks/useMemesWaveFooterStats.test.tsx`:
- Around line 146-174: The test for useMemesWaveFooterStats currently only
asserts isReady and count fields but omits the new isAvailable contract that
controls footer visibility; update the test "fetches the first unvoted
leaderboard item and derives footer stats from it" (and the similar spec around
the other block) to assert the isAvailable boolean returned from
useMemesWaveFooterStats — e.g. add
expect(result.current.isAvailable).toBe(true/false) as appropriate for the
mocked response — so regressions to availability mapping fail the test;
reference the useMemesWaveFooterStats hook and the result.current.isAvailable
property when adding the assertion.
In
`@components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVotePreview.tsx`:
- Around line 368-375: Replace the two separate screen-reader-only spans inside
the MemesQuickVotePreview with a single SR-only sentence by building a combined
string (e.g., `${formatMemesQuickVoteLeftThisRoundText(leftThisRoundCount)},
${formatMemesQuickVoteUnratedText(unratedCount)}`) and rendering it in one <span
className="tw-sr-only"> so the hidden copy is a single predictable fragment;
keep using the existing helpers formatMemesQuickVoteLeftThisRoundText and
formatMemesQuickVoteUnratedText and ensure this single span is placed where the
current sr-only spans were (e.g., within the quick-vote-preview-status area).
In `@openapi.yaml`:
- Around line 10966-10968: The schema for the count field
left_to_vote_in_current_round should be tightened by adding validation and
documentation: update the left_to_vote_in_current_round property (type: integer,
format: int64) to include minimum: 0 and add a short description (e.g., "Number
of entities remaining to vote in the current round; non-negative integer") so
the OpenAPI spec enforces non-negativity and improves generated docs/validation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8216e45e-e9e7-4d77-956a-6bcc1b2fbe80
⛔ Files ignored due to path filters (1)
generated/models/ApiUndiscoveredDrop.tsis excluded by!**/generated/**
📒 Files selected for processing (16)
__tests__/components/brain/BrainMobile.test.tsx__tests__/components/brain/left-sidebar/waves/MemesWaveFooter.test.tsx__tests__/components/brain/mobile/FloatingMemesQuickVoteTrigger.test.tsx__tests__/hooks/useMemesWaveFooterStats.test.tsxcomponents/brain/left-sidebar/waves/MemesWaveFooter.tsxcomponents/brain/left-sidebar/waves/MemesWaveQuickVoteTrigger.tsxcomponents/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteControls.tsxcomponents/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialog.tsxcomponents/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVotePreview.tsxcomponents/brain/mobile/FloatingMemesQuickVoteTrigger.tsxhooks/memesQuickVote.helpers.tshooks/memesQuickVote.queue.state.tshooks/useMemesQuickVoteDialogController.tshooks/useMemesQuickVoteQueue.tshooks/useMemesWaveFooterStats.tsopenapi.yaml
There was a problem hiding this comment.
🧹 Nitpick comments (1)
hooks/useMemesQuickVoteQueue.ts (1)
296-309: Refactor to avoidreturninfinallyblock.The
returnstatement in thefinallyblock (line 304) is flagged by Biome because it can suppress exceptions or override return values fromtry/catch. While the current catch-all handler mitigates this, inverting the condition avoids the code smell entirely.♻️ Proposed refactor
} finally { if (syncAbortControllerRef.current === abortController) { syncAbortControllerRef.current = null; } syncInFlightRef.current = false; - if (abortController.signal.aborted || !syncRerunRequestedRef.current) { - return; - } - - syncRerunRequestedRef.current = false; - runBestEffortSync(syncWindow); + if (!abortController.signal.aborted && syncRerunRequestedRef.current) { + syncRerunRequestedRef.current = false; + runBestEffortSync(syncWindow); + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hooks/useMemesQuickVoteQueue.ts` around lines 296 - 309, The finally block currently contains a return when abortController.signal.aborted || !syncRerunRequestedRef.current which Biome flags; refactor by removing the return and inverting the condition so you only proceed to reset syncRerunRequestedRef.current and call runBestEffortSync(syncWindow) when both the abort signal is false and syncRerunRequestedRef.current is true. Keep the existing cleanup of syncAbortControllerRef.current and syncInFlightRef.current first, then check if (!abortController.signal.aborted && syncRerunRequestedRef.current) { set syncRerunRequestedRef.current = false; call runBestEffortSync(syncWindow); } to avoid returning from finally while preserving behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@hooks/useMemesQuickVoteQueue.ts`:
- Around line 296-309: The finally block currently contains a return when
abortController.signal.aborted || !syncRerunRequestedRef.current which Biome
flags; refactor by removing the return and inverting the condition so you only
proceed to reset syncRerunRequestedRef.current and call
runBestEffortSync(syncWindow) when both the abort signal is false and
syncRerunRequestedRef.current is true. Keep the existing cleanup of
syncAbortControllerRef.current and syncInFlightRef.current first, then check if
(!abortController.signal.aborted && syncRerunRequestedRef.current) { set
syncRerunRequestedRef.current = false; call runBestEffortSync(syncWindow); } to
avoid returning from finally while preserving behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: be561012-3a1e-4819-9823-19317a0e0cd6
📒 Files selected for processing (3)
components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialog.tsxhooks/memesQuickVote.queue.state.tshooks/useMemesQuickVoteQueue.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialog.tsx
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialogStates.tsx`:
- Around line 103-106: The sibling text node next to the self-closing decorative
<span> inside the MemesQuickVoteDialogStates component should be wrapped in its
own element to avoid ambiguous spacing; update the JSX fragment containing the
div with className "tw-inline-flex ..." so that the text "Loading next memes..."
is enclosed in a <span> (e.g., add a text <span> after the existing decorative
<span>) to ensure consistent rendering and satisfy SonarCloud.
In `@hooks/useMemesQuickVoteQueue.ts`:
- Around line 302-315: The finally block currently contains an early return
which is unsafe; refactor to remove the return and handle the abort/rerun check
after the finally completes. Inside the finally for the async sync operation
(where syncAbortControllerRef, syncInFlightRef are updated), always clear
syncAbortControllerRef.current and set syncInFlightRef.current = false, then
after the try/catch/finally completes, check abortController.signal.aborted or
!syncRerunRequestedRef.current and only call runBestEffortSync(syncWindow) when
appropriate (and reset syncRerunRequestedRef.current = false before calling).
This keeps cleanup inside finally and moves control flow decisions (the previous
return) to follow-up code so exceptions/return values aren’t suppressed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 81f7271d-69a6-4cf8-8992-eeb34e6359e3
📒 Files selected for processing (5)
components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialog.tsxcomponents/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialogStates.tsxhooks/memesQuickVote.queue.state.tshooks/useMemesQuickVoteDialogController.tshooks/useMemesQuickVoteQueue.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- hooks/memesQuickVote.queue.state.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialog.tsx`:
- Around line 586-589: The mobile shell close gets hidden during the loading
state because showStandaloneStateShellClose is only true when activeDrop ===
null AND !isExhausted AND (hasDiscoveryError || isRestartingRound); to fix, make
the close affordance available whenever the dialog is empty but not exhausted by
changing the boolean to activeDrop === null && !isExhausted (i.e., remove the
hasDiscoveryError || isRestartingRound gate) and also ensure
MemesQuickVoteDialogSkeleton is passed an onClose handler when rendered; apply
the same change where the duplicate logic appears (the block around the 706-714
region).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 549b5b53-f3cf-474b-843a-69ebf3667b94
📒 Files selected for processing (2)
components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteControls.tsxcomponents/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialog.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteControls.tsx
|



Summary by CodeRabbit
New Features
UI/UX Improvements
Tests