feat: add leaderboard sort toggle with SSR-safe preference persistence - #142
Merged
Conversation
- Add blue Switch toggle component with smooth animations - Extend useSettings hook with leaderboardSortBy preference (localStorage) - Add client-side sorting in LeaderboardClient with rank recalculation - Fix hydration error by deferring localStorage read to useEffect
- Extract LeaderboardRow as memo() component to prevent re-renders - Use data-current-user attribute instead of transient prop - Use data-rank attribute with CSS selectors instead of inline styles - Add useCallback for stable row click handler - Memoize formatted values inside row component
- Add sortBy query param to /api/leaderboard (tokens | cost) - Add sortBy to /api/leaderboard/user/[username] for correct rank calculation - Update getLeaderboard.ts with dynamic ORDER BY clause - Remove client-side sorting from LeaderboardClient (server handles it) - User rank card now reflects correct rank based on sort preference
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
2 issues found across 8 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/frontend/src/components/Switch.tsx">
<violation number="1" location="packages/frontend/src/components/Switch.tsx:67">
P2: Set an explicit button type to avoid accidental form submission when this switch is placed inside a form.</violation>
</file>
<file name="packages/frontend/src/lib/useSettings.ts">
<violation number="1" location="packages/frontend/src/lib/useSettings.ts:30">
P2: Validate `leaderboardSortBy` from localStorage before accepting it; otherwise an arbitrary stored value can flow into settings and break sort logic.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- Add type="button" to Switch to prevent accidental form submission - Validate leaderboardSortBy from localStorage before accepting it
- Move all color/bg/border styles into styled-components definitions - Add StatValuePrimary, SubmitCount, RetryButton components - Removes object allocations on every render for better performance - Net reduction: 50 lines of code
- Create shared constants.ts for server/client sortBy validation - Sync sortBy preference to cookie when user changes it - Read cookie in page.tsx for SSR with correct sort order - Pass initialSortBy to LeaderboardClient to prevent hydration mismatch
Contributor
There was a problem hiding this comment.
1 issue found across 4 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/frontend/src/app/(main)/page.tsx">
<violation number="1" location="packages/frontend/src/app/(main)/page.tsx:13">
P2: Using `cookies()` opts this page into dynamic rendering, making `export const revalidate = 60` ineffective. The page will now render on every request instead of being cached.
If dynamic rendering is intentional, remove the misleading `revalidate` export. If caching is needed, consider reading the sort preference client-side only or using middleware to set a variant header.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- Wrap leaderboard in Suspense boundary for streaming - Move cookie reading inside Suspense (preserves static shell) - Navigation, Hero, Footer render instantly (static) - Leaderboard streams in with user's sort preference - No flash on page load with correct sortBy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add a toggle to sort the leaderboard by Tokens or Cost, with server-side sorting for correct global rankings and SSR-safe preference persistence via Suspense streaming.
Features
Architecture
Changes
UI (
LeaderboardClient.tsx)Switchcomponent with Tokens/Cost labelsLeaderboardRowfor smooth togglingstyle={{}}with styled-componentsinitialSortByprop to prevent hydration mismatchAPI (
/api/leaderboard,/api/leaderboard/user/[username])sortByquery parameter (tokens|cost)ORDER BYclause ingetLeaderboard.tsSSR (
page.tsx,useSettings.ts,constants.ts)<Suspense>for streamingconstants.tsfor server/clientCommits
b43eb9f- feat: add leaderboard sort toggle UIe8163d5- perf: memoize LeaderboardRow for faster togglef4c8015- feat(api): add server-side sortBy param7f627ec- fix: add type="button", validate localStorage6ab1212- refactor: replace inline styles with styled-componentsf21be27- fix(ssr): use cookie for sortBy preference7c1d24e- refactor(ssr): use Suspense for personalized contentTesting