Skip to content

Refactor memes quick vote to undiscovered-drop flow#2179

Merged
ragnep merged 7 commits intomainfrom
quick-vote-modal-skip-logic
Mar 30, 2026
Merged

Refactor memes quick vote to undiscovered-drop flow#2179
ragnep merged 7 commits intomainfrom
quick-vote-modal-skip-logic

Conversation

@ragnep
Copy link
Copy Markdown
Contributor

@ragnep ragnep commented Mar 30, 2026

Summary by CodeRabbit

  • New Features

    • Quick Vote now exposes a single dialog state and an explicit "available" flag that enables/disables footer and trigger controls.
  • Bug Fixes

    • More reliable quick-vote flow: unified rating/skip pipeline, deduplicated queuing, optimistic advances/restores, and improved retry/invalidation behavior for a smoother experience.
  • Documentation

    • Copy updates: "unexplored" → "unrated"; button labels, tooltips and loading text refined.

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

coderabbitai Bot commented Mar 30, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces paged discovery with an undiscovered-drop lookahead buffer, shifts UI gating to an isAvailable flag, renames "unexplored" → "unrated", consolidates dialog state, and removes many legacy discovery, summary, optimistic, and prefetch helpers in favor of a session/window + rating-queue model.

Changes

Cohort / File(s) Summary
UI gating & copy
components/brain/left-sidebar/waves/MemesWaveFooter.tsx, components/brain/left-sidebar/waves/MemesWaveQuickVoteTrigger.tsx, components/brain/mobile/FloatingMemesQuickVoteTrigger.tsx
Render gating moved from isReady/uncastPower checks to isAvailable; aria/title text and numeric displays updated; collapsed trigger receives isAvailable; copy changed "unexplored" → "unrated".
Quick-vote dialog & preview
components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialog.tsx, .../MemesQuickVoteDialogSkeleton.tsx, .../MemesQuickVotePreview.tsx, .../MemesQuickVoteControls.tsx
Dialog now consumes shared dialog-state props; remount key/busy-state wiring changed; skip/advance wiring adjusted; copy updated to "unrated".
Controller & call-sites
hooks/useMemesQuickVoteDialogController.ts, components/brain/BrainMobile.tsx, components/layout/AppLayout.tsx, components/brain/left-sidebar/web/WebLeftSidebar.tsx
Controller exposes dialogState; callers spread dialogState and use quickVote.openQuickVote/prefetchQuickVote; prefetch/open branching updated; mobile hydration uses useSyncExternalStore.
Undiscovered lookahead & queue
hooks/useMemesQuickVoteQueue.ts, hooks/memesQuickVote.query.ts
Replaced paged discovery/summary with an undiscovered-drop lookahead (MEMES_QUICK_VOTE_LOOKAHEAD_COUNT) and single-endpoint fetch (/waves/{id}/undiscovered-drop); introduced session/window buffering, session state controllers, window sync with abortable requests, and changed skipDrop to return Promise.
Submit / rating queue
hooks/useMemesQuickVoteSubmit.ts
Replaced queued-vote model with unified QueuedRating (`type: "vote"
New state & reducers
hooks/memesQuickVote.queue.state.ts
Adds session & optimistic state model and pure reducers for window reconciliation, optimistic advance/restore, optimistic remaining-power reduction/reconciliation, and clamp helpers.
Removed legacy discovery/optimistic logic
hooks/useMemesQuickVoteDiscovery.ts, hooks/useMemesQuickVoteActiveDrop.ts, hooks/useMemesQuickVoteSummary.ts, hooks/useMemesQuickVoteHiddenSummaryCleanup.ts, hooks/useMemesQuickVoteQueue.optimistic.ts, hooks/memesQuickVote.queue.helpers.ts
Deleted legacy paged discovery, active-drop, summary, hidden-summary cleanup, optimistic queue state, and queue helper utilities.
Helpers & storage adjustments
hooks/memesQuickVote.helpers.ts, hooks/memesQuickVote.errors.ts, hooks/memesQuickVote.storageStore.ts
Removed many discovery-related helpers and error utilities; removed string-array storage exports; retained amount-related helpers; added isMemesQuickVoteVoteableDrop.
Footer stats hook
hooks/useMemesWaveFooterStats.ts
Now queries undiscovered-drop and returns isAvailable plus uncastPower, unratedCount, and votingLabel; removed skipped-drop recovery side effects.
Prefetch & trigger wiring
components/brain/mobile/FloatingMemesQuickVoteTrigger.tsx, components/brain/left-sidebar/waves/MemesWaveQuickVoteTrigger.tsx
Prefetch/trigger wiring switched to undiscovered-drop lookahead; triggers forward unratedCount and isAvailable and return early when not available.
API / OpenAPI
openapi.yaml
Added GET /waves/{id}/undiscovered-dropApiUndiscoveredDrop; removed ApiDropMetadataResponse and some participation submission-strategy schemas; made rating category optional; adjusted participation update refs.
Prefetch removed
hooks/usePrefetchMemesQuickVote.ts
Removed previous batch prefetch implementation and exports.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI Component
    participant Queue as useMemesQuickVoteQueue
    participant RQ as React Query
    participant API as /waves/{id}/undiscovered-drop

    Note over UI,API: Undiscovered-drop lookahead buffer flow
    UI->>Queue: request activeDrop / submit / skip
    Queue->>RQ: fetch undiscovered-drop?skip=0..N (lookahead)
    RQ->>API: GET /waves/{id}/undiscovered-drop?skip=N
    API-->>RQ: { drop, total_count }
    RQ-->>Queue: cached lookahead slot
    Queue-->>UI: activeDrop / remainingCount / isAvailable
    Queue->>RQ: invalidate undiscovered-drop keys (on advance or sync)
Loading
sequenceDiagram
    participant Dialog as MemesQuickVoteDialog
    participant Submit as useMemesQuickVoteSubmit
    participant Queue as Rating Queue
    participant API2 as /drops/{id}/ratings
    participant CB as Callbacks

    Dialog->>Submit: submitVote(drop, amount) / submitSkip(drop)
    Submit->>Queue: enqueue QueuedRating({type, dropId, amount})
    Queue->>CB: onRatingQueued(drop, amount, type)
    Queue->>Submit: trigger flush
    loop process queue
        Submit->>API2: POST /drops/{id}/ratings (rating or skip)
        alt success
            API2-->>Submit: { remaining_power }
            Submit->>CB: onRatingSuccess(drop, amount, nextRemainingPower, type)
        else failure
            API2-->>Submit: Error
            Submit->>CB: onRatingFailure(drop, amount, type)
        end
    end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • 6529-Collections/6529seize-frontend#2159 — Overlaps major quick-vote components, controller and queue refactor changes.
  • 6529-Collections/6529seize-frontend#2168 — Overlaps OpenAPI schema edits (drop metadata and participation changes).
  • 6529-Collections/6529seize-frontend#2169 — Overlaps quick-vote discovery/queue and related UI component changes.

Suggested reviewers

  • simo6529

"I nibble bytes and hop on branches,
I swap 'unexplored' for 'unrated' dances.
Four-lookahead buffers hum and flow—
Quick votes hop, the queue's aglow.
A tiny rabbit cheers the new show!" 🐇✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main architectural change: refactoring the memes quick vote feature from a discovery-based queue flow to a simpler undiscovered-drop-focused flow.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch quick-vote-modal-skip-logic

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

🧹 Nitpick comments (3)
openapi.yaml (1)

8526-8529: Document when category may actually be omitted.

ApiWaveVotingConfig.credit_category can still be unset, so callers need a contract-level rule for when category is required versus when null is accepted. Otherwise SDKs will treat omission as universally safe.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openapi.yaml` around lines 8526 - 8529, The schema for the category field is
ambiguous about whether omission is allowed versus explicit null; update the
ApiWaveVotingConfig.credit_category definition (the category property in the
ApiWaveVotingConfig schema) to include a clear description that states exactly
when the field may be omitted vs set to null, and adjust the OpenAPI keywords if
needed (e.g., add/remove it from the required list or keep nullable: true) so
SDKs know the contract-level rule for omission versus null; reference the
property as ApiWaveVotingConfig.credit_category (property name "category") when
making the change.
hooks/useMemesQuickVoteSubmit.ts (1)

291-302: Refs in dependency array are unnecessary but harmless.

isFlushingRef, queuedDropIdsRef, and ratingQueueRef are React refs with stable identity—they don't need to be in the dependency array. Including them doesn't cause bugs but adds noise.

🔧 Optional cleanup
   }, [
     invalidateDrops,
-    isFlushingRef,
     onRatingFailure,
     onRatingSuccess,
-    queuedDropIdsRef,
     ratingMutation,
-    ratingQueueRef,
     requestAuth,
     setPendingRatingCount,
     setToast,
   ]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/useMemesQuickVoteSubmit.ts` around lines 291 - 302, The dependency
array for the effect in useMemesQuickVoteSubmit includes React refs that have
stable identities and are unnecessary: remove isFlushingRef, queuedDropIdsRef,
and ratingQueueRef from the dependency array and keep the real dependencies
(invalidateDrops, onRatingFailure, onRatingSuccess, ratingMutation, requestAuth,
setPendingRatingCount, setToast). Update the dependency list used in the effect
closure so only actual changing values remain; if an ESLint rule complains,
prefer referencing ref.current inside the effect and suppress the specific rule
with an inline comment rather than including the refs themselves.
hooks/usePrefetchMemesQuickVote.ts (1)

11-12: Source the lookahead size from one place.

useBufferedUndiscoveredDrops() in hooks/useMemesQuickVoteQueue.ts (Lines 290-313) hardcodes the same 4. If these ever drift, prefetch will warm a different number of slots than the queue consumes. Exporting a shared constant would remove that coupling risk.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/usePrefetchMemesQuickVote.ts` around lines 11 - 12, Export a single
shared constant (e.g., MEMES_QUICK_VOTE_LOOKAHEAD_COUNT) from one module and
import it where needed instead of hardcoding 4; update
usePrefetchMemesQuickVote.ts to import and use that exported constant and modify
useBufferedUndiscoveredDrops in useMemesQuickVoteQueue.ts to replace its
hardcoded 4 with the same imported constant so both prefetch and queue
consumption use a single source of truth.
🤖 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/useMemesQuickVoteQueue.ts`:
- Around line 615-623: stateKey currently omits proxyId so optimistic state
(created via createInitialOptimisticAdvanceState and
createInitialOptimisticRemainingPowerState) is shared across proxies; include
proxyId in the key construction (combine sessionId, proxyId, waveId,
contextProfile) when building stateKey used by the useState initializers to
ensure proxy-scoped optimisticAdvanceState and optimisticRemainingPowerState;
update any reference that constructs stateKey in this file to use the new
proxy-inclusive ordering to avoid cross-proxy reuse.
- Around line 325-344: The exhaustion logic can briefly be wrong because it
waits for other queries; change isExhausted and isLoading to use primaryQuery as
the source of truth: set isExhausted to enabled && primaryQuery?.isSuccess ===
true && primaryDrop === null && !hasDiscoveryError (remove dependence on other
queries/fetching state), and set isLoading to enabled && primaryDrop === null &&
!hasDiscoveryError && primaryQuery?.isPending === true (or isFetching) so only
primaryQuery decides empty-vs-loading; update any uses of queries/isFetching
accordingly in the isExhausted and isLoading expressions in this hook.

In `@hooks/useMemesQuickVoteStorage.ts`:
- Around line 18-23: The test mocks still include the removed property
skippedDropIds from the UseMemesQuickVoteStorageResult type—remove all
occurrences of skippedDropIds in your test mocks and assertions so the mocks
match the new API; specifically, update the mock objects used in
usePrefetchMemesQuickVote.test.tsx and memesQuickVote.queue.helpers.test.* to
omit skippedDropIds, adjust any destructuring or expectations that referenced
skippedDropIds, and run the tests to ensure no additional mock properties need
updating.

In `@hooks/useMemesWaveFooterStats.ts`:
- Around line 53-70: The footer readiness logic in useMemesWaveFooterStats
currently marks any numeric uncastPower as ready; change the isReady calculation
to match useMemesQuickVoteQueue by requiring the drop be unrated
(query.data.total_count > 0) and have max_rating > 0: keep the existing guards
around activeDrop and uncastPower, but set isReady to (uncastPower > 0 &&
query.data.total_count > 0) so the isReady value in useMemesWaveFooterStats
lines up with the readiness rule used by useMemesQuickVoteQueue.

In `@openapi.yaml`:
- Around line 10941-10944: The schema for the property "drop" uses anyOf with a
type: "null" which is invalid for OpenAPI 3.0.3; replace that pattern by making
"drop" reference the ApiDrop schema via allOf and set nullable: true (i.e., use
allOf: - $ref: "#/components/schemas/ApiDrop" and add nullable: true on the
"drop" property) so the property can be an ApiDrop or null while remaining
spec-compliant with OpenAPI 3.0.3.

---

Nitpick comments:
In `@hooks/useMemesQuickVoteSubmit.ts`:
- Around line 291-302: The dependency array for the effect in
useMemesQuickVoteSubmit includes React refs that have stable identities and are
unnecessary: remove isFlushingRef, queuedDropIdsRef, and ratingQueueRef from the
dependency array and keep the real dependencies (invalidateDrops,
onRatingFailure, onRatingSuccess, ratingMutation, requestAuth,
setPendingRatingCount, setToast). Update the dependency list used in the effect
closure so only actual changing values remain; if an ESLint rule complains,
prefer referencing ref.current inside the effect and suppress the specific rule
with an inline comment rather than including the refs themselves.

In `@hooks/usePrefetchMemesQuickVote.ts`:
- Around line 11-12: Export a single shared constant (e.g.,
MEMES_QUICK_VOTE_LOOKAHEAD_COUNT) from one module and import it where needed
instead of hardcoding 4; update usePrefetchMemesQuickVote.ts to import and use
that exported constant and modify useBufferedUndiscoveredDrops in
useMemesQuickVoteQueue.ts to replace its hardcoded 4 with the same imported
constant so both prefetch and queue consumption use a single source of truth.

In `@openapi.yaml`:
- Around line 8526-8529: The schema for the category field is ambiguous about
whether omission is allowed versus explicit null; update the
ApiWaveVotingConfig.credit_category definition (the category property in the
ApiWaveVotingConfig schema) to include a clear description that states exactly
when the field may be omitted vs set to null, and adjust the OpenAPI keywords if
needed (e.g., add/remove it from the required list or keep nullable: true) so
SDKs know the contract-level rule for omission versus null; reference the
property as ApiWaveVotingConfig.credit_category (property name "category") when
making the change.
🪄 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: 92219837-5da5-40ee-8f53-6831489b03c6

📥 Commits

Reviewing files that changed from the base of the PR and between 1d9a249 and 22d62ce.

⛔ Files ignored due to path filters (14)
  • generated/models/ApiCreateNewWaveParticipationConfig.ts is excluded by !**/generated/**
  • generated/models/ApiDrop.ts is excluded by !**/generated/**
  • generated/models/ApiDropRatingRequest.ts is excluded by !**/generated/**
  • generated/models/ApiDropWithoutWave.ts is excluded by !**/generated/**
  • generated/models/ApiUndiscoveredDrop.ts is excluded by !**/generated/**
  • generated/models/ApiUpdateWaveParticipationConfig.ts is excluded by !**/generated/**
  • generated/models/ApiUpdateWaveRequest.ts is excluded by !**/generated/**
  • generated/models/ApiWaveParticipationConfig.ts is excluded by !**/generated/**
  • generated/models/ApiWaveParticipationIdentitySubmissionAllowDuplicates.ts is excluded by !**/generated/**
  • generated/models/ApiWaveParticipationIdentitySubmissionWhoCanBeSubmitted.ts is excluded by !**/generated/**
  • generated/models/ApiWaveParticipationSubmissionStrategy.ts is excluded by !**/generated/**
  • generated/models/ApiWaveParticipationSubmissionStrategyIdentityConf.ts is excluded by !**/generated/**
  • generated/models/ApiWaveParticipationSubmissionStrategyType.ts is excluded by !**/generated/**
  • generated/models/ObjectSerializer.ts is excluded by !**/generated/**
📒 Files selected for processing (23)
  • components/brain/left-sidebar/waves/MemesWaveFooter.tsx
  • components/brain/left-sidebar/waves/MemesWaveQuickVoteTrigger.tsx
  • components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteControls.tsx
  • components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialog.tsx
  • components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialogSkeleton.tsx
  • components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVotePreview.tsx
  • components/brain/mobile/FloatingMemesQuickVoteTrigger.tsx
  • hooks/memesQuickVote.errors.ts
  • hooks/memesQuickVote.helpers.ts
  • hooks/memesQuickVote.query.ts
  • hooks/memesQuickVote.queue.helpers.ts
  • hooks/memesQuickVote.storageStore.ts
  • hooks/useMemesQuickVoteActiveDrop.ts
  • hooks/useMemesQuickVoteDiscovery.ts
  • hooks/useMemesQuickVoteHiddenSummaryCleanup.ts
  • hooks/useMemesQuickVoteQueue.optimistic.ts
  • hooks/useMemesQuickVoteQueue.ts
  • hooks/useMemesQuickVoteStorage.ts
  • hooks/useMemesQuickVoteSubmit.ts
  • hooks/useMemesQuickVoteSummary.ts
  • hooks/useMemesWaveFooterStats.ts
  • hooks/usePrefetchMemesQuickVote.ts
  • openapi.yaml
💤 Files with no reviewable changes (9)
  • hooks/useMemesQuickVoteActiveDrop.ts
  • hooks/memesQuickVote.storageStore.ts
  • hooks/memesQuickVote.errors.ts
  • hooks/useMemesQuickVoteHiddenSummaryCleanup.ts
  • hooks/useMemesQuickVoteSummary.ts
  • hooks/memesQuickVote.queue.helpers.ts
  • hooks/useMemesQuickVoteDiscovery.ts
  • hooks/memesQuickVote.helpers.ts
  • hooks/useMemesQuickVoteQueue.optimistic.ts

Comment thread hooks/useMemesQuickVoteQueue.ts Outdated
Comment thread hooks/useMemesQuickVoteQueue.ts
Comment thread hooks/useMemesQuickVoteStorage.ts
Comment thread hooks/useMemesWaveFooterStats.ts
Comment thread openapi.yaml
Comment thread openapi.yaml
ragnep added 2 commits March 30, 2026 12:19
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: 2

♻️ Duplicate comments (2)
hooks/useMemesQuickVoteQueue.ts (2)

599-607: ⚠️ Potential issue | 🟠 Major

Keep the optimistic state proxy-scoped.

The undiscovered-drop query key and invalidation path already include proxyId, but stateKey still does not. Switching proxies within the same session/profile/wave reuses the previous proxy’s blocked-drop and remaining-power state against the new buffer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/useMemesQuickVoteQueue.ts` around lines 599 - 607, stateKey currently
omits the proxy identifier so optimisticAdvanceState (created via
createInitialOptimisticAdvanceState and held by
optimisticAdvanceState/setOptimisticAdvanceState) is reused across proxy
switches; include the proxy id in the key (e.g. `${sessionId}:${waveId ??
""}:${contextProfile ?? ""}:${proxyId ?? ""}` or whatever local proxy identifier
is available) so the stateKey is proxy-scoped and the optimistic state resets
per proxy change.

313-325: ⚠️ Potential issue | 🟠 Major

isExhausted still waits on the lookahead slots.

If skip=0 has already resolved with drop: null, the queue is empty. Waiting for skip=1..n to settle still leaves this hook in the blank activeDrop === null / isLoading === false / isExhausted === false state for a moment.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/useMemesQuickVoteQueue.ts` around lines 313 - 325, The hook currently
keeps isExhausted false while waiting for lookahead slots even when skip=0
resolved with primaryDrop === null; update the exhaustion logic in the
isExhausted calculation so that when primaryQuery?.isSuccess === true and
primaryDrop === null (i.e., the skip=0 result is empty) the queue is considered
exhausted immediately regardless of pending lookahead queries; adjust isLoading
to reflect that by not treating primaryQuery?.isPending or ?.isFetching as
loading when primaryQuery is success with primaryDrop === null. Target the
symbols isExhausted, isLoading, primaryQuery, primaryDrop, and any
quick-vote/lookahead logic (e.g., isQuickVoteUnavailable) to make this change.
🤖 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/useMemesQuickVoteQueue.ts`:
- Around line 354-361: The sync loop is reading the raw keyed optimistic state
(via getCurrentOptimisticAdvanceState) instead of the reconciled result, causing
shouldContinueSync to remain true after a real advance; update the loop to use
the reconciled optimisticAdvance produced by getResolvedOptimisticAdvanceState
(the variable constructed from getResolvedOptimisticAdvanceState with
bufferedDrops, isFetching, and getCurrentOptimisticAdvanceState using
stateKey/optimisticAdvanceState) wherever the loop checks advance state (e.g.,
shouldContinueSync/advance completion and invalidation logic), and apply the
same change to the other occurrence noted (the block that spans the later region
referenced) so the loop reads the resolved state that respects cleared
blockedDropIds from useResolvedMemesQuickVoteDrops.
- Around line 296-312: Derived values (primaryDrop, lookaheadDrops,
bufferedDrops, hasDiscoveryError and any totalCount/remainingCount derivations)
must be computed only when the query is actually enabled; update the code that
uses primaryQuery/queries (symbols: primaryQuery, primaryDrop, lookaheadDrops,
bufferedDrops, hasDiscoveryError, isQuickVoteUnavailable) to first check
isQueryEnabled (or the existing enabled flag) and return null/empty arrays or
zero counts when disabled, e.g. set primaryDrop = isQueryEnabled ?
primaryQuery?.data?.drop ?? null : null and lookaheadDrops = isQueryEnabled ?
... : [], and likewise gate hasDiscoveryError and any totalCount/remainingCount
calculations behind isQueryEnabled so disabled queries cannot surface stale
cached data.

---

Duplicate comments:
In `@hooks/useMemesQuickVoteQueue.ts`:
- Around line 599-607: stateKey currently omits the proxy identifier so
optimisticAdvanceState (created via createInitialOptimisticAdvanceState and held
by optimisticAdvanceState/setOptimisticAdvanceState) is reused across proxy
switches; include the proxy id in the key (e.g. `${sessionId}:${waveId ??
""}:${contextProfile ?? ""}:${proxyId ?? ""}` or whatever local proxy identifier
is available) so the stateKey is proxy-scoped and the optimistic state resets
per proxy change.
- Around line 313-325: The hook currently keeps isExhausted false while waiting
for lookahead slots even when skip=0 resolved with primaryDrop === null; update
the exhaustion logic in the isExhausted calculation so that when
primaryQuery?.isSuccess === true and primaryDrop === null (i.e., the skip=0
result is empty) the queue is considered exhausted immediately regardless of
pending lookahead queries; adjust isLoading to reflect that by not treating
primaryQuery?.isPending or ?.isFetching as loading when primaryQuery is success
with primaryDrop === null. Target the symbols isExhausted, isLoading,
primaryQuery, primaryDrop, and any quick-vote/lookahead logic (e.g.,
isQuickVoteUnavailable) to make this change.
🪄 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: 650811d6-688c-4ef6-8bae-81ab6ec14426

📥 Commits

Reviewing files that changed from the base of the PR and between 22d62ce and f5e6b2e.

📒 Files selected for processing (9)
  • components/brain/BrainMobile.tsx
  • components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialog.tsx
  • components/brain/left-sidebar/web/WebLeftSidebar.tsx
  • components/layout/AppLayout.tsx
  • hooks/memesQuickVote.query.ts
  • hooks/useMemesQuickVoteDialogController.ts
  • hooks/useMemesQuickVoteQueue.ts
  • hooks/useMemesQuickVoteSubmit.ts
  • hooks/usePrefetchMemesQuickVote.ts

Comment thread hooks/useMemesQuickVoteQueue.ts Outdated
Comment thread hooks/useMemesQuickVoteQueue.ts Outdated
ragnep added 2 commits March 30, 2026 13:03
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.

🧹 Nitpick comments (1)
hooks/useMemesQuickVoteDialogController.ts (1)

93-108: Consider memoizing dialogState to prevent unnecessary re-renders.

The dialogState object is recreated on every render. Consumers using shallow equality checks (e.g., in useEffect deps or React.memo) may re-render unnecessarily even when the underlying values haven't changed.

♻️ Suggested refactor using useMemo
+  const dialogState = useMemo(
+    (): MemesQuickVoteDialogState => ({
+      activeDrop: quickVoteQueue.activeDrop,
+      hasDiscoveryError: quickVoteQueue.hasDiscoveryError,
+      isExhausted: quickVoteQueue.isExhausted,
+      isOpen: isQuickVoteOpen,
+      latestUsedAmount: quickVoteQueue.latestUsedAmount,
+      onClose: closeQuickVote,
+      recentAmounts: quickVoteQueue.recentAmounts,
+      remainingCount: quickVoteQueue.remainingCount,
+      retryDiscovery: quickVoteQueue.retryDiscovery,
+      sessionId: quickVoteSessionId,
+      skipDrop: quickVoteQueue.skipDrop,
+      submitVote: quickVoteQueue.submitVote,
+      uncastPower: quickVoteQueue.uncastPower,
+      votingLabel: quickVoteQueue.votingLabel,
+    }),
+    [
+      closeQuickVote,
+      isQuickVoteOpen,
+      quickVoteQueue.activeDrop,
+      quickVoteQueue.hasDiscoveryError,
+      quickVoteQueue.isExhausted,
+      quickVoteQueue.latestUsedAmount,
+      quickVoteQueue.recentAmounts,
+      quickVoteQueue.remainingCount,
+      quickVoteQueue.retryDiscovery,
+      quickVoteQueue.skipDrop,
+      quickVoteQueue.submitVote,
+      quickVoteQueue.uncastPower,
+      quickVoteQueue.votingLabel,
+      quickVoteSessionId,
+    ]
+  );
+
   return {
     closeQuickVote,
-    dialogState: {
-      activeDrop: quickVoteQueue.activeDrop,
-      hasDiscoveryError: quickVoteQueue.hasDiscoveryError,
-      isExhausted: quickVoteQueue.isExhausted,
-      isOpen: isQuickVoteOpen,
-      latestUsedAmount: quickVoteQueue.latestUsedAmount,
-      onClose: closeQuickVote,
-      recentAmounts: quickVoteQueue.recentAmounts,
-      remainingCount: quickVoteQueue.remainingCount,
-      retryDiscovery: quickVoteQueue.retryDiscovery,
-      sessionId: quickVoteSessionId,
-      skipDrop: quickVoteQueue.skipDrop,
-      submitVote: quickVoteQueue.submitVote,
-      uncastPower: quickVoteQueue.uncastPower,
-      votingLabel: quickVoteQueue.votingLabel,
-    },
+    dialogState,
     isQuickVoteOpen,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/useMemesQuickVoteDialogController.ts` around lines 93 - 108,
dialogState is recreated every render causing unnecessary re-renders; wrap the
dialogState object in a useMemo in useMemesQuickVoteDialogController so it only
changes when its real inputs change (include quickVoteQueue.activeDrop,
hasDiscoveryError, isExhausted, latestUsedAmount, recentAmounts, remainingCount,
retryDiscovery, skipDrop, submitVote, uncastPower, votingLabel,
quickVoteQueue.hasDiscoveryError etc., plus isQuickVoteOpen, closeQuickVote,
quickVoteSessionId) — build the memoized object with those exact properties
(matching the current keys: activeDrop, hasDiscoveryError, isExhausted, isOpen,
latestUsedAmount, onClose, recentAmounts, remainingCount, retryDiscovery,
sessionId, skipDrop, submitVote, uncastPower, votingLabel) and return that
memoized dialogState from the hook so consumers relying on shallow equality
won't get spurious updates.
🤖 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/useMemesQuickVoteDialogController.ts`:
- Around line 93-108: dialogState is recreated every render causing unnecessary
re-renders; wrap the dialogState object in a useMemo in
useMemesQuickVoteDialogController so it only changes when its real inputs change
(include quickVoteQueue.activeDrop, hasDiscoveryError, isExhausted,
latestUsedAmount, recentAmounts, remainingCount, retryDiscovery, skipDrop,
submitVote, uncastPower, votingLabel, quickVoteQueue.hasDiscoveryError etc.,
plus isQuickVoteOpen, closeQuickVote, quickVoteSessionId) — build the memoized
object with those exact properties (matching the current keys: activeDrop,
hasDiscoveryError, isExhausted, isOpen, latestUsedAmount, onClose,
recentAmounts, remainingCount, retryDiscovery, sessionId, skipDrop, submitVote,
uncastPower, votingLabel) and return that memoized dialogState from the hook so
consumers relying on shallow equality won't get spurious updates.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1efc53f7-972e-49e9-b39b-139fcfbbca9d

📥 Commits

Reviewing files that changed from the base of the PR and between c9213c7 and 2c6be62.

📒 Files selected for processing (3)
  • hooks/useMemesQuickVoteDialogController.ts
  • hooks/useMemesQuickVoteQueue.ts
  • hooks/usePrefetchMemesQuickVote.ts
💤 Files with no reviewable changes (1)
  • hooks/usePrefetchMemesQuickVote.ts

ragnep added 2 commits March 30, 2026 13:30
Signed-off-by: ragnep <ragneinfo@gmail.com>
Signed-off-by: ragnep <ragneinfo@gmail.com>
@sonarqubecloud
Copy link
Copy Markdown

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.

🧹 Nitpick comments (1)
hooks/useMemesQuickVoteQueue.ts (1)

168-188: Unused syncRetryTimeoutRef can be removed.

The syncRetryTimeoutRef is declared and cleared but never assigned a value. The retry logic is handled by the effect at lines 340-375 using setTimeout directly. Consider removing this dead code.

Proposed cleanup
 const useMemesQuickVoteWindowSync = ({
   ...
 }: UseMemesQuickVoteWindowSyncOptions) => {
   const syncAbortControllerRef = useRef<AbortController | null>(null);
   const syncRequestIdRef = useRef(0);
-  const syncRetryTimeoutRef = useRef<ReturnType<
-    typeof globalThis.setTimeout
-  > | null>(null);

-  const clearSyncRetryTimeout = useCallback(() => {
-    if (syncRetryTimeoutRef.current === null) {
-      return;
-    }
-
-    globalThis.clearTimeout(syncRetryTimeoutRef.current);
-    syncRetryTimeoutRef.current = null;
-  }, []);

   const stopActiveSync = useCallback(() => {
     syncRequestIdRef.current += 1;
     syncAbortControllerRef.current?.abort();
     syncAbortControllerRef.current = null;
-    clearSyncRetryTimeout();
-  }, [clearSyncRetryTimeout]);
+  }, []);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/useMemesQuickVoteQueue.ts` around lines 168 - 188, Remove the unused
retry timeout ref and its clear helper: delete the declaration
syncRetryTimeoutRef and the clearSyncRetryTimeout function, and update
stopActiveSync to stop incrementing syncRequestIdRef.current and abort/clear
abort controller only (remove the call to clearSyncRetryTimeout); ensure no
other code references syncRetryTimeoutRef or clearSyncRetryTimeout before
committing.
🤖 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 168-188: Remove the unused retry timeout ref and its clear helper:
delete the declaration syncRetryTimeoutRef and the clearSyncRetryTimeout
function, and update stopActiveSync to stop incrementing
syncRequestIdRef.current and abort/clear abort controller only (remove the call
to clearSyncRetryTimeout); ensure no other code references syncRetryTimeoutRef
or clearSyncRetryTimeout before committing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 63267ebc-43ad-4863-9946-26bb2ddcc3cc

📥 Commits

Reviewing files that changed from the base of the PR and between 2c6be62 and 8eb65c8.

📒 Files selected for processing (4)
  • hooks/memesQuickVote.helpers.ts
  • hooks/memesQuickVote.queue.state.ts
  • hooks/useMemesQuickVoteQueue.ts
  • hooks/useMemesWaveFooterStats.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • hooks/useMemesWaveFooterStats.ts
  • hooks/memesQuickVote.helpers.ts

@ragnep ragnep merged commit 6c6400e into main Mar 30, 2026
8 checks passed
@ragnep ragnep deleted the quick-vote-modal-skip-logic branch March 30, 2026 10:40
@coderabbitai coderabbitai Bot mentioned this pull request Apr 2, 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