Conversation
WalkthroughReplaced local outcome-calculation with a new hook Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Component as WaveSmallLeaderboardItemOutcomes
participant Hook as useWaveRankReward
participant QMeta as react-query (useWaveOutcomesQuery)
participant QDist as react-query (distribution useQueries)
participant API as Wave Outcomes API
Note over Component,Hook: Render when a drop is shown (has drop.wave.id and drop.rank)
User->>Component: view drop
Component->>Hook: call useWaveRankReward(waveId, rank, enabled)
Hook->>QMeta: fetch outcomes metadata (useWaveOutcomesQuery)
QMeta->>API: GET /waves/:waveId/outcomes
API-->>QMeta: outcomes list
QMeta-->>Hook: outcomes metadata
Loop per outcome (relevant to rank)
Hook->>QDist: fetch outcome distribution page (WAVE_OUTCOME_DISTRIBUTION_PAGE)
QDist->>API: GET /outcomes/:id/distribution?page=N
API-->>QDist: distribution page
QDist-->>Hook: distribution data
end
Hook-->>Component: { nicTotal, repTotal, manualOutcomes, isLoading }
alt isLoading
Component->>Component: render pulsing skeleton
else has outcomes
Component->>Component: render button + tooltip with nic/rep/manual outcomes
else no outcomes
Component->>Component: render null
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used📓 Path-based instructions (4)**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (.cursorrules)
Files:
**/*.{tsx,jsx}📄 CodeRabbit inference engine (.cursorrules)
Files:
**/*.{js,jsx,ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (2)📚 Learning: 2025-12-03T14:52:34.271ZApplied to files:
📚 Learning: 2025-12-03T14:52:34.271ZApplied to files:
🧬 Code graph analysis (2)components/waves/leaderboard/drops/DefaultWaveLeaderboardDrop.tsx (1)
components/waves/leaderboard/drops/footer/WaveLeaderboardDropFooter.tsx (1)
⏰ 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)
🔇 Additional comments (3)
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.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx (2)
15-23: Remove unusedwaveprop from interface and update destructuring.The
waveprop is defined inWaveSmallLeaderboardDefaultDropPropsbut is no longer destructured or used. This creates an inconsistency where callers might passwavethinking it's used.Proposed fix
interface WaveSmallLeaderboardDefaultDropProps { readonly drop: ExtendedDrop; - readonly wave: ApiWave; readonly onDropClick: (drop: ExtendedDrop) => void; }
3-3: Remove unusedApiWaveimport.The
ApiWaveimport is no longer used after removing thewaveprop from the interface.Proposed fix
import { ExtendedDrop } from "@/helpers/waves/drop.helpers"; -import { ApiWave } from "@/generated/models/ApiWave"; import Link from "next/link";components/waves/leaderboard/drops/footer/WaveLeaderboardDropFooter.tsx (2)
6-13: Remove unusedwaveprop from interface.The
waveprop is defined inWaveLeaderboardDropFooterPropsbut is not destructured or used. This creates an inconsistency.Proposed fix
interface WaveLeaderboardDropFooterProps { readonly drop: ExtendedDrop; - readonly wave: ApiWave; } export const WaveLeaderboardDropFooter: React.FC< WaveLeaderboardDropFooterProps -> = ({ drop }) => { +> = ({ drop }) => {
3-3: Remove unusedApiWaveimport.The
ApiWaveimport is no longer used after removing thewaveprop from the interface.Proposed fix
import { ExtendedDrop } from "@/helpers/waves/drop.helpers"; -import { ApiWave } from "@/generated/models/ApiWave"; import { WaveSmallLeaderboardItemOutcomes } from "@/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes";components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx (1)
14-22: Remove unusedwaveprop from interface.The interface declares
wave: ApiWaveat line 16, but the implementation at line 22 only destructuresdropandonDropClick. This creates a type mismatch where the prop is declared but never used.🔎 Proposed fix
interface WaveSmallLeaderboardTopThreeDropProps { readonly drop: ExtendedDrop; - readonly wave: ApiWave; readonly onDropClick: (drop: ExtendedDrop) => void; }
🧹 Nitpick comments (5)
hooks/waves/useWaveRankReward.ts (3)
29-31: Remove comments per coding guidelines.The comment on line 29 should be removed. The code should be self-explanatory as per the project's coding guidelines for TypeScript files.
Proposed fix
const { outcomes, isEnabled: isOutcomesEnabled } = useWaveOutcomesQuery({ waveId, - // We only need the types of outcomes to know what to fetch enabled: enabled && !!rank, });
33-37: Remove comments per coding guidelines.Comments on lines 33-35 should be removed. Consider extracting the calculation into a well-named helper function if the logic needs clarification.
Proposed fix
- // Calculate which page the rank falls into. - // Rank 1 -> index 0. Page 1 (indices 0-99). - // Rank 101 -> index 100. Page 2 (indices 100-199). const targetIndex = rank ? rank - 1 : 0; const page = Math.floor(targetIndex / DISTRIBUTION_PAGE_SIZE) + 1;
76-93: Remove comment per coding guidelines.Proposed fix
- // Iterate over outcomes and their corresponding query results outcomes.forEach((outcome, i) => {components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx (1)
84-89: Replace<img>with<Image />fromnext/image.Per coding guidelines,
<img>elements should be replaced with<Image />fromnext/imageto satisfy the@next/next/no-img-elementESLint rule.Proposed fix
+import Image from "next/image";{drop.author.pfp ? ( - <img + <Image className="tw-size-6 tw-flex-shrink-0 tw-rounded-lg tw-bg-iron-800 tw-ring-1 tw-ring-inset tw-ring-white/10" src={drop.author.pfp} alt="" + width={24} + height={24} />components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx (1)
67-88: Consider extracting repeated rank check.The condition
drop.rank && drop.rank <= 3is repeated four times in the boxShadow computation. Extracting this to a variable would improve readability and maintainability.🔎 Suggested refactor
+ const isTopThree = drop.rank && drop.rank <= 3; + const rankColor = isTopThree + ? getRankTextColor(drop.rank)?.replace("tw-text-", "").trim() + : "#60606C"; style={{ border: "1px solid transparent", - boxShadow: `inset 2px 0 0 ${drop.rank && drop.rank <= 3 - ? getRankTextColor(drop.rank)?.replace("tw-text-", "").trim() - : "#60606C" - }, - inset 0 1px 0 ${drop.rank && drop.rank <= 3 - ? getRankTextColor(drop.rank) - ?.replace("tw-text-", "") - .trim() - : "#60606C" - }20, - inset -1px 0 0 ${drop.rank && drop.rank <= 3 - ? getRankTextColor(drop.rank) - ?.replace("tw-text-", "") - .trim() - : "#60606C" - }20, - inset 0 -1px 0 ${drop.rank && drop.rank <= 3 - ? getRankTextColor(drop.rank) - ?.replace("tw-text-", "") - .trim() - : "#60606C" - }20`, + boxShadow: `inset 2px 0 0 ${rankColor}, + inset 0 1px 0 ${rankColor}20, + inset -1px 0 0 ${rankColor}20, + inset 0 -1px 0 ${rankColor}20`, transition: "box-shadow 0.2s ease, background-color 0.2s ease", }}
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsxcomponents/react-query-wrapper/ReactQueryWrapper.tsxcomponents/waves/drop/SingleWaveDropInfoAuthorSection.tsxcomponents/waves/leaderboard/drops/footer/WaveLeaderboardDropFooter.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxhooks/waves/useWaveRankReward.ts
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version
**/*.{ts,tsx,js,jsx}: Replace<img>elements with<Image />fromnext/imageto satisfy@next/next/no-img-elementESLint rule
Use<Link href="/path">from Next.js for internal navigation instead of plain HTML links to satisfy@next/next/no-html-link-for-pagesESLint rule
Files:
components/react-query-wrapper/ReactQueryWrapper.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.tsxcomponents/waves/drop/SingleWaveDropInfoAuthorSection.tsxcomponents/waves/leaderboard/drops/footer/WaveLeaderboardDropFooter.tsx__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxhooks/waves/useWaveRankReward.tscomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always addreadonlybefore props in React components
Files:
components/react-query-wrapper/ReactQueryWrapper.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.tsxcomponents/waves/drop/SingleWaveDropInfoAuthorSection.tsxcomponents/waves/leaderboard/drops/footer/WaveLeaderboardDropFooter.tsx__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use<Link>, images should usenext/image, and adopt Next's ESLint rules (Core Web Vitals)
**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)
Files:
components/react-query-wrapper/ReactQueryWrapper.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.tsxcomponents/waves/drop/SingleWaveDropInfoAuthorSection.tsxcomponents/waves/leaderboard/drops/footer/WaveLeaderboardDropFooter.tsx__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxhooks/waves/useWaveRankReward.tscomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Must passtsc --noEmittype checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") overReact.namespace usage (React.useMemo,React.useRef, etc.)
If thereact-hooks/exhaustive-depslint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic inuseEffectEvent
**/*.{ts,tsx}: Must passtsc --noEmitfor TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
UseuseEffectEventfor non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs:<Link>for internal links,next/imagefor images, adopt Next's ESLint rules
Use'use cache'directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace<img>elements with<Image />fromnext/image
Use<Link href="/path">for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with'use server'directive
Files:
components/react-query-wrapper/ReactQueryWrapper.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.tsxcomponents/waves/drop/SingleWaveDropInfoAuthorSection.tsxcomponents/waves/leaderboard/drops/footer/WaveLeaderboardDropFooter.tsx__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxhooks/waves/useWaveRankReward.tscomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
**/@(__tests__|*.test).{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Tests should live in
__tests__/orComponentName.test.tsx; mock external dependencies and APIs in tests
Files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
**/__tests__/**/*.{ts,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Place tests in
__tests__/directory or asComponentName.test.tsxalongside components
Files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Mock external dependencies and APIs in tests
Files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
__tests__/**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (tests/AGENTS.md)
Use Jest +
ts-jestfor TypeScript testing
Files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
__tests__/**/*.{ts,tsx}
📄 CodeRabbit inference engine (tests/AGENTS.md)
Functions must have ≤ 15 cognitive complexity; extract deep ternaries (>3 levels) and break down complex logic
Files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
__tests__/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (tests/AGENTS.md)
__tests__/**/*.{ts,tsx,js}: Preferfor...ofloops overforEachas it allowsbreak/continueand works with async/await
Usearray.at(-1)andarray.at(-2)instead of index-based array access for negative indexing
UseString.prototype.replaceAll()instead ofreplace()for global string replacements
UseglobalThis.fetch()instead of directfetch()calls
Organize imports with one import per module in order: external → internal → types, with no duplicates
Useelement.remove()instead ofparent.removeChild(element)for DOM manipulation
Catch errors only when meaningful; no empty catch blocks; log errors with context
Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (?.)
Files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
__tests__/**/{components,contexts,hooks}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (tests/AGENTS.md)
Use semantic HTML elements (
<label>,<output>) over ARIA attributes when possible; every form control must have a label
Files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
🧠 Learnings (8)
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (`?.`)
Applied to files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/{components,contexts,hooks}/**/*.{ts,tsx} : Use semantic HTML elements (`<label>`, `<output>`) over ARIA attributes when possible; every form control must have a label
Applied to files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/@(__tests__|*.test).{ts,tsx} : Tests should live in `__tests__/` or `ComponentName.test.tsx`; mock external dependencies and APIs in tests
Applied to files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Fix with modernization (no `// eslint-disable` unless explicitly instructed); prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Applied to files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/components/**/*.test.{ts,tsx} : Use testing-library/react + user-event for React component tests
Applied to files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: TypeScript + React functional components with hooks; follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)
Applied to files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.test.{ts,tsx} : Mock external dependencies and APIs in tests
Applied to files:
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Remove unnecessary Effects; if Effect only derives state, compute during render instead
Applied to files:
components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx
🧬 Code graph analysis (3)
components/waves/drop/SingleWaveDropInfoAuthorSection.tsx (1)
components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.tsx (1)
WaveSmallLeaderboardItemOutcomes(16-160)
__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx (1)
components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.tsx (1)
WaveSmallLeaderboardItemOutcomes(16-160)
hooks/waves/useWaveRankReward.ts (2)
hooks/waves/useWaveOutcomesQuery.ts (1)
useWaveOutcomesQuery(41-105)generated/models/ApiWaveOutcomeDistributionItemsPage.ts (1)
ApiWaveOutcomeDistributionItemsPage(16-58)
⏰ 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 (10)
hooks/waves/useWaveRankReward.ts (2)
39-59: LGTM!The
useQueriesimplementation correctly maps over outcomes to create parallel distribution queries with appropriate caching and conditional enablement.
61-70: LGTM!The early return correctly handles the disabled state, returning zeros and
isLoading: falsesince no queries are executed when the hook is disabled.components/waves/drop/SingleWaveDropInfoAuthorSection.tsx (1)
25-27: LGTM!The change correctly removes the
waveprop fromWaveSmallLeaderboardItemOutcomessince the component now extractswaveIdfromdrop.wave.idvia the newuseWaveRankRewardhook.components/react-query-wrapper/ReactQueryWrapper.tsx (1)
98-98: LGTM!The new query key
WAVE_OUTCOME_DISTRIBUTION_PAGEfollows the existing naming convention and is correctly positioned afterWAVE_OUTCOME_DISTRIBUTION.components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx (1)
132-132: LGTM!The change correctly passes only
droptoWaveSmallLeaderboardItemOutcomes, aligning with the refactored component signature.components/waves/leaderboard/drops/footer/WaveLeaderboardDropFooter.tsx (1)
14-14: LGTM!The component correctly passes only
droptoWaveSmallLeaderboardItemOutcomes, consistent with the refactored component signature.components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx (1)
164-164: LGTM!The component correctly passes only
droptoWaveSmallLeaderboardItemOutcomes, matching the updated component signature.__tests__/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.test.tsx (1)
5-52: LGTM!The test file correctly mocks the new
useWaveRankRewardhook and comprehensively tests all three states:
- Rendering when outcomes exist
- Hiding when no outcomes and not loading
- Showing loading state
The mock setup with
beforeEachreset and the drop fixture withwave.idare appropriate for the refactored component.components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes.tsx (2)
45-49: LGTM!The loading state with a pulsing placeholder provides appropriate visual feedback while data is being fetched.
114-116: LGTM!The condensed className construction is more readable and maintainable than the previous implementation.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
hooks/waves/useWaveRankReward.ts (3)
32-33: Optional: Simplify targetIndex calculation.The ternary fallback to
0is redundant since!rankis handled by the guard at line 59. For clarity, you could use non-null assertion or simplify the logic.🔎 Suggested simplification
- const targetIndex = rank ? rank - 1 : 0; + const targetIndex = (rank ?? 1) - 1; const page = Math.floor(targetIndex / DISTRIBUTION_PAGE_SIZE) + 1;Alternatively, after adding validation as suggested earlier, you can safely assume
rankis valid at this point.
59-66: Optional: Consider moving the guard earlier.The guard correctly returns early when
rankis invalid, but it executes after theuseQuerieshook setup. While the queries won't run (due toenabled: false), moving the validation before query setup would be more efficient and clearer.🔎 Suggested restructuring
Move the guard to before the queries:
const { outcomes, isEnabled: isOutcomesEnabled } = useWaveOutcomesQuery({ waveId, enabled: enabled && !!rank, }); + if (!rank || !enabled) { + return { + nicTotal: 0, + repTotal: 0, + manualOutcomes: [], + isLoading: false + } + } + const targetIndex = rank ? rank - 1 : 0; const page = Math.floor(targetIndex / DISTRIBUTION_PAGE_SIZE) + 1; const distributionQueries = useQueries({ // ... queries }); const isLoading = distributionQueries.some((q) => q.isLoading); - if (!rank || !enabled) { - return { - nicTotal: 0, - repTotal: 0, - manualOutcomes: [], - isLoading: false - } - }Note: React hooks cannot be called conditionally, so
useWaveOutcomesQuerymust remain before the guard. However, theuseQueriescall happens after all other hooks, so this pattern would still violate the rules of hooks. The current implementation is actually correct given hook constraints. Disregard this suggestion.
90-95: Consider exposing error state to consumers.The hook doesn't return any error information from the distribution queries. If a query fails, consumers won't know and may display incomplete or incorrect data.
🔎 Suggested error handling
Update the interface:
export interface WaveRankRewards { readonly nicTotal: number; readonly repTotal: number; readonly manualOutcomes: string[]; readonly isLoading: boolean; + readonly error?: string; }Add error checking:
const isLoading = distributionQueries.some((q) => q.isLoading); + const error = distributionQueries.find((q) => q.error)?.error; + const errorMessage = error instanceof Error ? error.message : undefined; if (!rank || !enabled) { return { nicTotal: 0, repTotal: 0, manualOutcomes: [], - isLoading: false + isLoading: false, + error: undefined } }And in the return:
return { nicTotal, repTotal, manualOutcomes, isLoading, + error: errorMessage, };
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsxcomponents/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxhooks/waves/useWaveRankReward.ts
💤 Files with no reviewable changes (1)
- components/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
- components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version
**/*.{ts,tsx,js,jsx}: Replace<img>elements with<Image />fromnext/imageto satisfy@next/next/no-img-elementESLint rule
Use<Link href="/path">from Next.js for internal navigation instead of plain HTML links to satisfy@next/next/no-html-link-for-pagesESLint rule
Files:
components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsxhooks/waves/useWaveRankReward.ts
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always addreadonlybefore props in React components
Files:
components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use<Link>, images should usenext/image, and adopt Next's ESLint rules (Core Web Vitals)
**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)
Files:
components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsxhooks/waves/useWaveRankReward.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Must passtsc --noEmittype checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") overReact.namespace usage (React.useMemo,React.useRef, etc.)
If thereact-hooks/exhaustive-depslint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic inuseEffectEvent
**/*.{ts,tsx}: Must passtsc --noEmitfor TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
UseuseEffectEventfor non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs:<Link>for internal links,next/imagefor images, adopt Next's ESLint rules
Use'use cache'directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace<img>elements with<Image />fromnext/image
Use<Link href="/path">for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with'use server'directive
Files:
components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsxhooks/waves/useWaveRankReward.ts
🧬 Code graph analysis (1)
hooks/waves/useWaveRankReward.ts (2)
hooks/waves/useWaveOutcomesQuery.ts (1)
useWaveOutcomesQuery(41-105)generated/models/ApiWaveOutcomeDistributionItemsPage.ts (1)
ApiWaveOutcomeDistributionItemsPage(16-58)
⏰ 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 (6)
hooks/waves/useWaveRankReward.ts (4)
1-10: LGTM!Imports are clean and the distribution page size of 100 is reasonable for pagination.
11-16: LGTM!Interface follows readonly conventions and is well-structured.
68-88: LGTM!The aggregation logic correctly processes each outcome type and safely checks for data existence before accumulating values.
35-55: QueryKey is properly exported and defined.
QueryKey.WAVE_OUTCOME_DISTRIBUTION_PAGEis correctly defined and exported in theQueryKeyenum at line 98 ofReactQueryWrapper.tsx. The implementation is correct.components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsx (1)
11-11: LGTM!The removal of the
waveprop is consistent throughout the component. Child components will now rely ondrop.waveor theuseWaveRankRewardhook for wave-related data, which centralizes the data fetching logic.components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx (1)
13-13: LGTM!Consistent with the refactoring across leaderboard components. The
waveprop removal is complete and child components now receive only thedropprop.
|



Summary by CodeRabbit
Refactor
Tests
✏️ Tip: You can customize this high-level summary in your review settings.