feat: migrate leaderboard from REST to GraphQL#121
feat: migrate leaderboard from REST to GraphQL#1210xdevcollins merged 3 commits intoboundlessfi:mainfrom
Conversation
- Update types/leaderboard.ts to re-export generated GraphQL types - Add GraphQL queries for leaderboard, user rank, and top contributors - Refactor hooks/use-leaderboard.ts to use GraphQL client and generated documents - Remove lib/api/leaderboard.ts and all REST API references - Update components to use proper GraphQL enum values - Regenerate GraphQL types with new leaderboard schema - Ensure filtering and pagination work with GraphQL - Add GraphQL schema types for leaderboard functionality All leaderboard functionality now uses GraphQL with full type safety and feature parity with the previous REST implementation.
|
Someone is attempting to deploy a commit to the Threadflow Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughMigrates leaderboard from REST to GraphQL: removes REST API, adds GraphQL schema/operations and generated types/hooks, updates hooks and UI to use generated enums/types and fetchers, and adapts mock data and exported types to the generated outputs. Changes
Sequence Diagram(s)sequenceDiagram
participant Page as "Leaderboard Page"
participant Hook as "useLeaderboard Hook"
participant Fetcher as "GraphQL Fetcher"
participant API as "GraphQL Server"
Page->>Hook: request leaderboard (filters, pagination)
Hook->>Fetcher: execute LeaderboardDocument with variables
Fetcher->>API: GraphQL query (Leaderboard)
API-->>Fetcher: GraphQL response (entries, totalCount, userRank)
Fetcher-->>Hook: parsed data
Hook-->>Page: data / cache
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 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 |
- Replace require() calls with proper imports in hooks/use-leaderboard.ts - Remove unused setReviewStatus variable in bounty-detail-submissions-card.tsx - Fix all TypeScript ESLint errors and warnings
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
lib/graphql/operations/leaderboard-queries.graphql (1)
1-87: Extract a shared fragment for the contributor selection set.The contributor field selection (Lines 7–28, 39–60, 66–86) is duplicated across all three queries. A GraphQL fragment would reduce drift risk when fields change.
♻️ Proposed fragment extraction
+fragment ContributorFields on LeaderboardContributor { + id + userId + walletAddress + displayName + avatarUrl + totalScore + tier + stats { + totalCompleted + totalEarnings + earningsCurrency + completionRate + averageCompletionTime + currentStreak + longestStreak + nextTierThreshold + currentTierPoints + } + topTags + lastActiveAt +} + query Leaderboard($filters: LeaderboardFilters!, $pagination: LeaderboardPagination!) { leaderboard(filters: $filters, pagination: $pagination) { entries { rank previousRank rankChange contributor { - id - userId - walletAddress - displayName - avatarUrl - totalScore - tier - stats { - totalCompleted - totalEarnings - earningsCurrency - completionRate - averageCompletionTime - currentStreak - longestStreak - nextTierThreshold - currentTierPoints - } - topTags - lastActiveAt + ...ContributorFields } } totalCount currentUserRank lastUpdatedAt } }Apply the same pattern to
UserLeaderboardRankandTopContributors.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/graphql/operations/leaderboard-queries.graphql` around lines 1 - 87, Extract the duplicated contributor selection into a GraphQL fragment (e.g., fragment ContributorFields on Contributor) that includes id, userId, walletAddress, displayName, avatarUrl, totalScore, tier, stats { ... }, topTags, and lastActiveAt, then replace the inline contributor selection in the Leaderboard, UserLeaderboardRank, and TopContributors queries with the fragment spread (e.g., ...ContributorFields) and ensure the fragment is declared in the same file so all three queries reference the single source of truth.components/leaderboard/mini-leaderboard.tsx (1)
12-12: Consider importing from the re-export barrel (@/types/leaderboard) for consistency.
types/leaderboard.tsalready re-exportsLeaderboardContributor. Other files (e.g.,leaderboard-filters.tsx) use a mix of direct and re-exported imports. Picking one convention avoids confusion.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/leaderboard/mini-leaderboard.tsx` at line 12, Change the import of LeaderboardContributor in mini-leaderboard.tsx to use the project's re-export barrel to stay consistent: replace the direct import from "@/lib/graphql/generated" with the re-export from "@/types/leaderboard" so the symbol LeaderboardContributor (used in the MiniLeaderboard component) is imported from the unified types barrel.hooks/use-leaderboard.ts (1)
30-36: InconsistentgetNextPageParamlogic betweenuseLeaderboardandusePrefetchLeaderboardPage.
useLeaderboard(Line 32) uses the optimizedallPages.length * limitto estimate loaded entries, whileusePrefetchLeaderboardPage(Line 83) usesallPages.flatMap(p => p.entries).lengthfor an exact count. Both compute "has more pages" but could diverge if a page returns fewer thanlimitentries (e.g., server-side filtering). Pick one strategy for consistency — theflatMapapproach is more accurate.Also applies to: 82-88
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hooks/use-leaderboard.ts` around lines 30 - 36, The getNextPageParam logic in useLeaderboard should be made consistent with usePrefetchLeaderboardPage by switching from the optimistic calculation (allPages.length * limit) to the exact entry count using allPages.flatMap(p => p.entries).length; update the getNextPageParam implementation in both useLeaderboard and usePrefetchLeaderboardPage to compute loaded = allPages.flatMap(p => p.entries).length and then return allPages.length + 1 if loaded < lastPage.totalCount, otherwise undefined, referencing the existing getNextPageParam functions, limit, lastPage.totalCount, and allPages.flatMap usage.lib/mock-leaderboard.ts (1)
1-2: Prefer the leaderboard type barrel import for cohesion.Consider importing
ReputationTierfrom@/types/leaderboard(same asLeaderboardContributor) so app code stays decoupled from generated-module path churn.Suggested diff
-import { LeaderboardContributor } from "@/types/leaderboard"; -import { ReputationTier } from "@/lib/graphql/generated"; +import { LeaderboardContributor, ReputationTier } from "@/types/leaderboard";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/mock-leaderboard.ts` around lines 1 - 2, Replace the direct import of ReputationTier from the generated GraphQL module by importing it from the leaderboard type barrel alongside LeaderboardContributor; update the import statement that currently brings in LeaderboardContributor and ReputationTier so ReputationTier is imported from "@/types/leaderboard" (same symbol name) to keep the module decoupled from generated paths.
🤖 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/use-leaderboard.ts`:
- Around line 24-29: Replace the runtime require() usages that fetch GraphQL
document constants inside the queryFn (and other queryFn handlers) with static
ES module imports: add imports for LeaderboardDocument,
UserLeaderboardRankDocument, and TopContributorsDocument from
'@/lib/graphql/generated' at the top of the file alongside the existing type
imports, then update the fetcher calls (e.g., in queryFn:
fetcher(...LeaderboardDocument, ...), and the other places referencing
UserLeaderboardRankDocument and TopContributorsDocument) to use the imported
symbols instead of require(...).Document so the build no longer violates
`@typescript-eslint/no-require-imports`.
In `@types/leaderboard.ts`:
- Around line 1-12: The barrel is re-exporting enums as types which strips their
runtime values; update types/leaderboard.ts to re-export the actual enum values
for ReputationTier and LeaderboardTimeframe (so consumers can access enum
members at runtime) while keeping the rest as type-only re-exports (leave
ContributorStats, LeaderboardContributor, LeaderboardEntry, LeaderboardResponse,
LeaderboardFilters, LeaderboardPagination, UserLeaderboardRankResponse exported
as types). Locate the file and replace the type-only export of ReputationTier
and LeaderboardTimeframe with a value export for those two symbols and keep the
remaining exports as type exports.
---
Nitpick comments:
In `@components/leaderboard/mini-leaderboard.tsx`:
- Line 12: Change the import of LeaderboardContributor in mini-leaderboard.tsx
to use the project's re-export barrel to stay consistent: replace the direct
import from "@/lib/graphql/generated" with the re-export from
"@/types/leaderboard" so the symbol LeaderboardContributor (used in the
MiniLeaderboard component) is imported from the unified types barrel.
In `@hooks/use-leaderboard.ts`:
- Around line 30-36: The getNextPageParam logic in useLeaderboard should be made
consistent with usePrefetchLeaderboardPage by switching from the optimistic
calculation (allPages.length * limit) to the exact entry count using
allPages.flatMap(p => p.entries).length; update the getNextPageParam
implementation in both useLeaderboard and usePrefetchLeaderboardPage to compute
loaded = allPages.flatMap(p => p.entries).length and then return allPages.length
+ 1 if loaded < lastPage.totalCount, otherwise undefined, referencing the
existing getNextPageParam functions, limit, lastPage.totalCount, and
allPages.flatMap usage.
In `@lib/graphql/operations/leaderboard-queries.graphql`:
- Around line 1-87: Extract the duplicated contributor selection into a GraphQL
fragment (e.g., fragment ContributorFields on Contributor) that includes id,
userId, walletAddress, displayName, avatarUrl, totalScore, tier, stats { ... },
topTags, and lastActiveAt, then replace the inline contributor selection in the
Leaderboard, UserLeaderboardRank, and TopContributors queries with the fragment
spread (e.g., ...ContributorFields) and ensure the fragment is declared in the
same file so all three queries reference the single source of truth.
In `@lib/mock-leaderboard.ts`:
- Around line 1-2: Replace the direct import of ReputationTier from the
generated GraphQL module by importing it from the leaderboard type barrel
alongside LeaderboardContributor; update the import statement that currently
brings in LeaderboardContributor and ReputationTier so ReputationTier is
imported from "@/types/leaderboard" (same symbol name) to keep the module
decoupled from generated paths.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (11)
app/leaderboard/page.tsxcomponents/leaderboard/leaderboard-filters.tsxcomponents/leaderboard/mini-leaderboard.tsxhooks/use-leaderboard.tslib/api/leaderboard.tslib/graphql/generated.tslib/graphql/operations/leaderboard-queries.graphqllib/graphql/schema.graphqllib/mock-leaderboard.tspackage.jsontypes/leaderboard.ts
💤 Files with no reviewable changes (1)
- lib/api/leaderboard.ts
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
hooks/use-leaderboard.ts (2)
33-38:⚠️ Potential issue | 🟡 Minor
getNextPageParammath optimisation may terminate pagination early on partial pages.
allPages.length * limitoverestimates the number of loaded entries. If the server ever returns fewer thanlimititems on a page that is not the last (e.g., under filtering),allPages.length * limitcan exceedtotalCountwhileactualLoadedEntries < totalCount, causinghasNextPageto befalseprematurely.Additionally, this logic is inconsistent with
usePrefetchLeaderboardPage(Line 86), which correctly countsallPages.flatMap(p => p.entries).length. Aligning both removes the edge-case risk.♻️ Proposed fix
- getNextPageParam: (lastPage: LeaderboardResponse, allPages: LeaderboardResponse[]) => { - // Optimization: Use simple math instead of iterating all entries - if (allPages.length * limit < lastPage.totalCount) { - return allPages.length + 1; - } - return undefined; - }, + getNextPageParam: (lastPage: LeaderboardResponse, allPages: LeaderboardResponse[]) => { + const loadedCount = allPages.flatMap((p) => p.entries).length; + if (loadedCount < lastPage.totalCount) { + return allPages.length + 1; + } + return undefined; + },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hooks/use-leaderboard.ts` around lines 33 - 38, The getNextPageParam logic in getNextPageParam currently multiplies allPages.length * limit which can overestimate loaded entries and prematurely stop pagination; update getNextPageParam to compute actualLoadedEntries by summing entries across pages (e.g., allPages.flatMap(p => p.entries).length or reduce) and return allPages.length + 1 only if actualLoadedEntries < lastPage.totalCount, matching the approach used in usePrefetchLeaderboardPage to avoid the partial-page edge case.
75-93:⚠️ Potential issue | 🟡 MinorPrefetch
Promiseis not returned — errors are silently swallowed.
queryClient.prefetchInfiniteQueryreturns aPromise<void>. The inner closure discards it, so callers have no way toawaitcompletion or catch failures. If the prefetch request errors, it is silently ignored.The method works the same as
fetchQueryexcept that it will not throw or return any data. However, the returned Promise does resolve/reject based on network success, and not returning it prevents callers from chaining or awaiting the warm-up.♻️ Proposed fix
return (filters: LeaderboardFilters, page: number, limit: number) => { - queryClient.prefetchInfiniteQuery({ + return queryClient.prefetchInfiniteQuery({🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hooks/use-leaderboard.ts` around lines 75 - 93, The prefetch Promise from queryClient.prefetchInfiniteQuery is being discarded, so update the function that currently calls queryClient.prefetchInfiniteQuery (inside the exported callback in hooks/use-leaderboard.ts) to return that Promise instead of ignoring it; specifically return the result of queryClient.prefetchInfiniteQuery({...}) from the outer function so callers can await or catch errors from the prefetch. Ensure the signature still matches (returns Promise<void> or the appropriate Promise type) and keep the existing queryKey, queryFn, getNextPageParam, initialPageParam and pages options unchanged.
🧹 Nitpick comments (2)
components/bounty-detail/bounty-detail-submissions-card.tsx (1)
60-60: Replace unnecessary state with a constant.Line 60 uses
useStatefor a value that never changes. A constant is clearer and avoids an extra hook.♻️ Proposed fix
- const [reviewStatus] = useState("APPROVED"); + const reviewStatus = "APPROVED" as const;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/bounty-detail/bounty-detail-submissions-card.tsx` at line 60, Replace the unnecessary React state with a plain constant: change the declaration const [reviewStatus] = useState("APPROVED"); to const reviewStatus = "APPROVED"; and remove the useState import if it becomes unused to avoid an unused import warning.hooks/use-leaderboard.ts (1)
78-82:pageParamis typed as optional, causing an unnecessaryas numbercast.Since
initialPageParam: 1is required by TanStack Query v5 and the framework always supplies anumber, typingpageParamasnumber | undefinedis incorrect and forces the unsafe cast on Line 81. Removing the?aligns the type with TQ v5's guarantee.♻️ Proposed fix
- queryFn: ({ pageParam }: { pageParam?: number }) => { + queryFn: ({ pageParam }: { pageParam: number }) => { return fetcher<LeaderboardQuery, LeaderboardQueryVariables>( LeaderboardDocument, - { filters, pagination: { page: pageParam as number, limit } } + { filters, pagination: { page: pageParam, limit } } )().then(data => data.leaderboard); },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hooks/use-leaderboard.ts` around lines 78 - 82, The queryFn's parameter types incorrectly allow pageParam to be undefined, forcing an unsafe cast; update the queryFn signature to use ({ pageParam }: { pageParam: number }) so pageParam is a number (remove the ?), then remove the "as number" cast in the fetcher call (keep existing references to fetcher, LeaderboardQuery, LeaderboardQueryVariables, and LeaderboardDocument) to rely on TanStack Query v5's guaranteed initialPageParam.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@hooks/use-leaderboard.ts`:
- Around line 33-38: The getNextPageParam logic in getNextPageParam currently
multiplies allPages.length * limit which can overestimate loaded entries and
prematurely stop pagination; update getNextPageParam to compute
actualLoadedEntries by summing entries across pages (e.g., allPages.flatMap(p =>
p.entries).length or reduce) and return allPages.length + 1 only if
actualLoadedEntries < lastPage.totalCount, matching the approach used in
usePrefetchLeaderboardPage to avoid the partial-page edge case.
- Around line 75-93: The prefetch Promise from queryClient.prefetchInfiniteQuery
is being discarded, so update the function that currently calls
queryClient.prefetchInfiniteQuery (inside the exported callback in
hooks/use-leaderboard.ts) to return that Promise instead of ignoring it;
specifically return the result of queryClient.prefetchInfiniteQuery({...}) from
the outer function so callers can await or catch errors from the prefetch.
Ensure the signature still matches (returns Promise<void> or the appropriate
Promise type) and keep the existing queryKey, queryFn, getNextPageParam,
initialPageParam and pages options unchanged.
---
Nitpick comments:
In `@components/bounty-detail/bounty-detail-submissions-card.tsx`:
- Line 60: Replace the unnecessary React state with a plain constant: change the
declaration const [reviewStatus] = useState("APPROVED"); to const reviewStatus =
"APPROVED"; and remove the useState import if it becomes unused to avoid an
unused import warning.
In `@hooks/use-leaderboard.ts`:
- Around line 78-82: The queryFn's parameter types incorrectly allow pageParam
to be undefined, forcing an unsafe cast; update the queryFn signature to use ({
pageParam }: { pageParam: number }) so pageParam is a number (remove the ?),
then remove the "as number" cast in the fetcher call (keep existing references
to fetcher, LeaderboardQuery, LeaderboardQueryVariables, and
LeaderboardDocument) to rely on TanStack Query v5's guaranteed initialPageParam.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
components/bounty-detail/bounty-detail-submissions-card.tsxhooks/use-leaderboard.ts
- Re-export enums as values in types/leaderboard.ts for runtime access - Fix getNextPageParam logic to use actual loaded entries count - Return prefetch promise from usePrefetchLeaderboardPage - Remove unsafe cast in queryFn parameter types - Replace unnecessary React state with constant in bounty-detail-submissions-card.tsx - Import LeaderboardContributor from project type barrel in mini-leaderboard.tsx - Import ReputationTier from project type barrel in mock-leaderboard.tsx
There was a problem hiding this comment.
🧹 Nitpick comments (3)
hooks/use-leaderboard.ts (2)
33-40: DuplicategetNextPageParamlogic — consider extracting a shared helper.The
getNextPageParamimplementation is identical in bothuseLeaderboard(Lines 33–40) andusePrefetchLeaderboardPage(Lines 86–92). A divergence here would silently cause inconsistent pagination behavior between the live query and the prefetch.♻️ Suggested refactor: extract shared helper
+const getLeaderboardNextPage = ( + lastPage: LeaderboardResponse, + allPages: LeaderboardResponse[] +): number | undefined => { + const loadedCount = allPages.flatMap(p => p.entries).length; + return loadedCount < lastPage.totalCount ? allPages.length + 1 : undefined; +}; export const useLeaderboard = (filters: LeaderboardFilters, limit: number = 20) => { return useInfiniteQuery({ ... - getNextPageParam: (lastPage: LeaderboardResponse, allPages: LeaderboardResponse[]) => { - const loadedCount = allPages.flatMap(p => p.entries).length; - if (loadedCount < lastPage.totalCount) { - return allPages.length + 1; - } - return undefined; - }, + getNextPageParam: getLeaderboardNextPage, ... }); }; export const usePrefetchLeaderboardPage = () => { ... - getNextPageParam: (lastPage: LeaderboardResponse, allPages: LeaderboardResponse[]) => { - const loadedCount = allPages.flatMap((p: LeaderboardResponse) => p.entries).length; - if (loadedCount < lastPage.totalCount) { - return allPages.length + 1; - } - return undefined; - }, + getNextPageParam: getLeaderboardNextPage, ... };Also applies to: 86-92
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hooks/use-leaderboard.ts` around lines 33 - 40, Extract the duplicated pagination logic into a shared helper (e.g., a function getNextPageParamFromPages) and replace the inline implementations in useLeaderboard's getNextPageParam and usePrefetchLeaderboardPage's getNextPageParam with calls to that helper; the helper should accept (lastPage: LeaderboardResponse, allPages: LeaderboardResponse[]) and return the next page number (or undefined) by computing loadedCount = allPages.flatMap(p => p.entries).length and comparing to lastPage.totalCount, ensuring both useLeaderboard and usePrefetchLeaderboardPage reference the same function to keep pagination behavior consistent.
27-31: InconsistentpageParamtyping between the twoqueryFndefinitions.Line 27 uses a JavaScript default (
{ pageParam = 1 }) while Line 79 uses an explicit type annotation ({ pageParam }: { pageParam: number }). The default value on Line 27 is also redundant becauseinitialPageParam: 1guaranteespageParamis always set. Prefer the explicit form used in the prefetch query for clarity and consistency.♻️ Suggested fix
- queryFn: ({ pageParam = 1 }) => { + queryFn: ({ pageParam }: { pageParam: number }) => { return fetcher<LeaderboardQuery, LeaderboardQueryVariables>( LeaderboardDocument, { filters, pagination: { page: pageParam as number, limit } }Also applies to: 79-83
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@hooks/use-leaderboard.ts` around lines 27 - 31, The two queryFn definitions use inconsistent pageParam handling; update the primary queryFn signature to match the prefetch version by removing the default and adding an explicit type: change "queryFn: ({ pageParam = 1 }) => { ... }" to "queryFn: ({ pageParam }: { pageParam: number }) => { ... }" (the initialPageParam: 1 already guarantees a value), and ensure the fetcher call still uses pageParam as a number; reference the queryFn and initialPageParam symbols to locate both places to make the same change.components/leaderboard/mini-leaderboard.tsx (1)
65-65: Redundant inline type annotations on.map()callback parameters.TypeScript infers both
contributor(asLeaderboardContributor) andindex(asnumber) from thecontributorsarray type returned byuseTopContributors. The explicit annotations are not harmful but add noise.♻️ Suggested simplification
- {contributors?.map((contributor: LeaderboardContributor, index: number) => ( + {contributors?.map((contributor, index) => (🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/leaderboard/mini-leaderboard.tsx` at line 65, Remove the redundant inline type annotations on the .map callback in the MiniLeaderboard render: locate the contributors?.map((contributor: LeaderboardContributor, index: number) => ...) usage in the mini-leaderboard component and change the callback to use inferred types (contributors?.map((contributor, index) => ...)) so TypeScript relies on the array's element type from useTopContributors instead of explicit annotations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@components/leaderboard/mini-leaderboard.tsx`:
- Line 65: Remove the redundant inline type annotations on the .map callback in
the MiniLeaderboard render: locate the contributors?.map((contributor:
LeaderboardContributor, index: number) => ...) usage in the mini-leaderboard
component and change the callback to use inferred types
(contributors?.map((contributor, index) => ...)) so TypeScript relies on the
array's element type from useTopContributors instead of explicit annotations.
In `@hooks/use-leaderboard.ts`:
- Around line 33-40: Extract the duplicated pagination logic into a shared
helper (e.g., a function getNextPageParamFromPages) and replace the inline
implementations in useLeaderboard's getNextPageParam and
usePrefetchLeaderboardPage's getNextPageParam with calls to that helper; the
helper should accept (lastPage: LeaderboardResponse, allPages:
LeaderboardResponse[]) and return the next page number (or undefined) by
computing loadedCount = allPages.flatMap(p => p.entries).length and comparing to
lastPage.totalCount, ensuring both useLeaderboard and usePrefetchLeaderboardPage
reference the same function to keep pagination behavior consistent.
- Around line 27-31: The two queryFn definitions use inconsistent pageParam
handling; update the primary queryFn signature to match the prefetch version by
removing the default and adding an explicit type: change "queryFn: ({ pageParam
= 1 }) => { ... }" to "queryFn: ({ pageParam }: { pageParam: number }) => { ...
}" (the initialPageParam: 1 already guarantees a value), and ensure the fetcher
call still uses pageParam as a number; reference the queryFn and
initialPageParam symbols to locate both places to make the same change.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
components/bounty-detail/bounty-detail-submissions-card.tsxcomponents/leaderboard/mini-leaderboard.tsxhooks/use-leaderboard.tslib/mock-leaderboard.tstypes/leaderboard.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- components/bounty-detail/bounty-detail-submissions-card.tsx
Closes #120
All leaderboard functionality now uses GraphQL with full type safety and feature parity with the previous REST implementation.
Summary by CodeRabbit
New Features
Improvements