Skip to content

Comments

feat/px-points-migration-board#334

Merged
RanaBug merged 3 commits intostagingfrom
feat/px-points-migration-board
Jun 17, 2025
Merged

feat/px-points-migration-board#334
RanaBug merged 3 commits intostagingfrom
feat/px-points-migration-board

Conversation

@RanaBug
Copy link
Collaborator

@RanaBug RanaBug commented Jun 16, 2025

Description

  • FE implementation and refactoring of the Leaderboard App, with migration and trading boards

How Has This Been Tested?

  • Unit Tests and Manual Testing

Screenshots (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Summary by CodeRabbit

  • New Features

    • Introduced a migration leaderboard with new API endpoints and data sources, enabling migration-specific rankings.
    • Added new leaderboard tabs and filter buttons for switching between all-time, weekly, migration, and trading leaderboards.
    • Implemented summary cards displaying PX points, ranks, gas usage, and migration progress.
    • Added an info banner component and tooltips for enhanced user guidance.
    • Improved leaderboard responsiveness with a grid-based layout and enhanced mobile support.
    • Added hooks for leaderboard data fetching, rank comparison, and weekly date range calculations.
    • Introduced new components for points display, gas usage, and leaderboard overview.
    • Enhanced user info display with responsive wallet address truncation and updated copy-to-clipboard UI.
  • Bug Fixes

    • Improved wallet address display and copy-to-clipboard functionality for better usability.
  • Style

    • Updated color palette and layout for improved visual clarity and consistency.
    • Refined grid layouts for leaderboard entries and tabs to enhance responsiveness.
  • Documentation

    • Added detailed type definitions for leaderboard and migration data.
  • Chores

    • Integrated Redux for centralized leaderboard state management.
    • Refactored leaderboard app to use Redux and consolidated data fetching logic.

@RanaBug RanaBug requested a review from IAmKio June 16, 2025 15:01
@RanaBug RanaBug self-assigned this Jun 16, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 16, 2025

Walkthrough

This update introduces a comprehensive migration and trading leaderboard system. It adds new API slices, Redux state management, React components, hooks, and utility functions to manage and display leaderboard data, including migration-specific logic. The UI is refactored for improved responsiveness, and new types are defined for detailed tracking of points, migration progress, and user transactions.

Changes

File(s) Change Summary
src/apps/leaderboard/api/leaderboard.ts Added migration API slice, new endpoint, retry logic, exported React hook, and refactored naming for clarity.
src/apps/leaderboard/components/InfoBanner/InfoBanner.tsx Added new dismissible InfoBanner component.
src/apps/leaderboard/components/LeaderboardTab/LeaderboardTab.tsx Unified data type, improved address matching, and refactored layout to responsive CSS grid.
src/apps/leaderboard/components/LeaderboardTabsButton/LeaderboardFiltersButton.tsx Added LeaderboardFiltersButton component with conditional styling.
src/apps/leaderboard/components/LeaderboardTabsButton/LeaderboardTabsButton.tsx Refactored to Redux-connected component, removed props, and updated styling.
src/apps/leaderboard/components/Leaderboards/Leaderboards.tsx Introduced Leaderboards component for conditional rendering based on data state.
src/apps/leaderboard/components/PointsCards/GasNewDropCard.tsx Added GasNewDropCard component to display gas usage and next drop info.
src/apps/leaderboard/components/PointsCards/OverviewPointsCard.tsx Added OverviewPointsCard for displaying user's points overview.
src/apps/leaderboard/components/PointsCards/PointsCard.tsx Added PointsCard component with tooltip, rank, and points display.
src/apps/leaderboard/components/PxPointsSummary/PxPointsSummary.tsx Added PxPointsSummary component for summarizing user points and eligibility.
src/apps/leaderboard/components/UserInfo/UserInfo.tsx Updated address truncation, replaced copy icon logic, and refined layout.
src/apps/leaderboard/hooks/useDateRanges.tsx Added useDateRanges hook for weekly date calculations.
src/apps/leaderboard/hooks/useLeaderboardData.tsx Added useLeaderboardData hook to aggregate and process leaderboard data.
src/apps/leaderboard/hooks/useRankComparison.tsx Added useRankComparison hook for rank change detection.
src/apps/leaderboard/hooks/useReducerHooks.tsx Added typed Redux hooks useAppDispatch and useAppSelector.
src/apps/leaderboard/index.tsx Refactored to use Redux state, centralized data fetching, and reorganized UI structure.
src/apps/leaderboard/reducer/LeaderboardSlice.ts Introduced leaderboardSlice Redux reducer, state types, and action creators.
src/apps/leaderboard/tailwind.leaderboard.config.js Updated Tailwind config: new breakpoint, color adjustments, and new color added.
src/apps/leaderboard/utils/index.tsx Added utilities for migration week logic and leaderboard data merging.
src/apps/pillarx-app/components/ReceiveModal/ReceiveModal.tsx,
src/apps/pillarx-app/components/WalletAdddressOverview/WalletAddressOverview.tsx
Changed copy icon import from SVG to PNG.
src/store.ts Registered leaderboardSlice with Redux store.
src/types/api.ts Extended and updated types for points, migration, and leaderboard data.

Sequence Diagram(s)

sequenceDiagram
    participant UI
    participant ReduxStore
    participant API
    participant Utils

    UI->>ReduxStore: Dispatch setActiveTab/setTimeTab
    UI->>ReduxStore: useAppSelector to read state
    UI->>API: useLeaderboardData hook triggers API queries
    API->>API: Fetch trading/migration data (weekly, all-time)
    API->>Utils: Process and merge leaderboard data
    Utils-->>API: Return merged/processed data
    API-->>UI: Provide data, loading, error states
    UI->>UI: Render InfoBanner, PxPointsSummary, Leaderboards, etc.
Loading

Poem

In the garden of code where the leaderboards grow,
New tabs and banners shimmer and glow.
Migration and trading, points tallied with care,
Redux keeps order, the rankings are fair.
Rabbits hop in, their progress to see—
All-time or weekly, who will it be?
🥕✨ The leaderboard blooms for all to compare!

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-17T09_29_03_298Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jun 16, 2025

Deploying x with  Cloudflare Pages  Cloudflare Pages

Latest commit: 97ee70b
Status: ✅  Deploy successful!
Preview URL: https://6b5a3d0c.x-e62.pages.dev
Branch Preview URL: https://feat-px-points-migration-boa.x-e62.pages.dev

View logs

Copy link
Contributor

@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: 14

🔭 Outside diff range comments (2)
src/apps/leaderboard/api/leaderboard.ts (1)

41-43: Unsafe string concatenation when building query

Manual templating is error-prone and skips URL encoding.
Refactor to new URLSearchParams() (or qs library) to:

• auto-encode values (address)
• drop trailing & noise
• simplify maintenance

This will also allow re-use between volume & migration endpoints.

src/apps/leaderboard/components/UserInfo/UserInfo.tsx (1)

74-88: Undefined rankChange shows a red down-triangle by default

Because the fallback path covers both “increased” and undefined, wallets with no delta get a misleading red indicator. Guard explicitly:

const rankChangeTriangle = rankChange === undefined
  ? null
  : rankChange === LeaderboardRankChange.DECREASED ? (/* green up */) : (/* red down */);

Ensures accurate visual cues.

🧹 Nitpick comments (23)
src/apps/leaderboard/hooks/useRankComparison.tsx (1)

6-12: Confirm semantic correctness of rank direction

“Higher index ⇒ INCREASED” assumes that e.g. moving from rank #1#3 is an “increase”. If the product treats lower numbers as better ranks (common for leaderboards), this should instead be flagged as a decrease. Please double-check the intended wording before this goes live.

src/types/api.ts (1)

758-865: Inconsistent casing & singular/plural naming

New migration-related types mix camelCase (totalAmountUsd) with snake_case (amount_usd) and singular history item (transactionHistory) vs plural (transactionHistory[] elsewhere). Consistency eases API consumption—align names or document the deviation.

src/apps/pillarx-app/components/WalletAdddressOverview/WalletAddressOverview.tsx (1)

8-50: Minor UI polish

  • style={{ width: 'full', height: 'full' }} is invalid CSS; use '100%' or rely on Tailwind classes.
  • Alt text typo: "copy-adress-icon""copy-address-icon".
    These tweaks improve accessibility & rendering fidelity.
src/apps/pillarx-app/components/ReceiveModal/ReceiveModal.tsx (1)

115-120: Use valid width/height values

className="w-3 h-3.5" already sizes the icon; the inline style isn’t needed, but if kept, avoid non-numeric "12px" literals inside an object intended for numbers.

src/apps/leaderboard/tailwind.leaderboard.config.js (1)

18-27: Hard-coded palette strings – extract to theme tokens

Multiple hex strings are sprinkled here and inside components (e.g., InfoBanner, GasNewDropCard).
Move these to a single colors map (already started here) and reference via class utilities (bg-dark_blue etc.).
Keeps palette changes single-source and prevents drift across the codebase.

src/apps/leaderboard/hooks/useDateRanges.tsx (1)

8-12: Time-zone implicitness

DateTime.now() uses the client locale. If your backend expects UTC timestamps, convert explicitly:

-const now = DateTime.now();
+const now = DateTime.now().toUTC();

This avoids users in different zones sending mismatched epoch values.

src/apps/leaderboard/components/InfoBanner/InfoBanner.tsx (1)

11-14: Dismissal state is ephemeral

visible resets to true on every mount, so the banner re-appears after page reloads or route changes.
If this banner should stay dismissed for the session/user, persist the flag (e.g., localStorage, Redux, or URL param).

src/apps/leaderboard/components/PointsCards/GasNewDropCard.tsx (1)

37-47: newDropTime needs human-readable formatting

Raw epoch/seconds won’t be meaningful to users.
Format with luxon or date-fns, e.g.:

<DateTime
  fromSeconds={newDropTime}
  .toRelative() // “in 3 h”
/>

Improves UX and keeps consistency with other date displays.

src/apps/leaderboard/components/PointsCards/PointsCard.tsx (2)

25-32: Guard-render the tooltip to avoid empty (and still focusable) overlay

textTooltip is optional, but the tooltip DOM is always rendered.
When textTooltip is undefined, an empty absolutely-positioned element is injected, which can create unexpected layout / accessibility side-effects.

-        <div className="absolute ...">
-          {textTooltip}
-        </div>
+        {textTooltip && (
+          <div className="absolute ...">
+            {textTooltip}
+          </div>
+        )}

25-32: Add basic a11y attributes

While you are touching the tooltip, add role="tooltip" and aria-label={textTooltip} for screen-reader support.
A11y is cheap here and pays off immediately.

src/apps/leaderboard/components/LeaderboardTabsButton/LeaderboardFiltersButton.tsx (1)

12-18: Expose active state via aria-pressed for better accessibility

Tab / filter buttons are essentially toggle buttons. Conveying the state only through colour leaves screen-reader users in the dark.

-    <button
+    <button
       type="button"
+      aria-pressed={isActive}
src/apps/leaderboard/components/PointsCards/OverviewPointsCard.tsx (1)

59-60: Alt texts don’t match the images

alt="pillarx-icon" for WeeklyRankIcon (and likewise for EarnedLastWeekIcon) is misleading and harms accessibility.
Provide descriptive, image-specific alt text.

Also applies to: 73-74

src/apps/leaderboard/components/Leaderboards/Leaderboards.tsx (1)

30-36: Minor: avoid index as key in static skeleton list

Indexes are okay for static, non-reordering lists, but a constant string is even simpler and avoids ESLint noise:

-        {[...Array(3)].map((_, index) => (
-          <SkeletonLoader key={index} ... />
+        {Array.from({ length: 3 }).map((_, i) => (
+          <SkeletonLoader key={`skeleton-${i}`} ... />
         ))}
src/apps/leaderboard/components/PxPointsSummary/PxPointsSummary.tsx (1)

35-48: Consider memoising findMatchingEntry results

findMatchingEntry scans the full data array on every re-render.
Wrap each call in useMemo (keyed by [walletAddress, data]) to avoid unnecessary linear scans on unrelated state updates. Not critical but improves perf on large leaderboards.

src/apps/leaderboard/hooks/useLeaderboardData.tsx (1)

92-133: Effect silently retains stale weekly data when tab switches

weeklyTradingData is only recomputed while timeTab === 'weekly'.
Switching back to “All Time” keeps the last weekly snapshot in state, which can leak into consumers that don’t additionally gate on timeTab.

Consider clearing this slice when leaving the weekly tab or compute it unconditionally in useMemo to guarantee consistency.

src/apps/leaderboard/api/leaderboard.ts (1)

47-56: Duplicate base-query boilerplate – consider a helper

baseVolumeQuery and baseMigrationQuery are identical apart from baseUrl.
Extract a factory (createRetriedBaseQuery(baseUrl)) to DRY the slice setup and keep retry policy in one place.

src/apps/leaderboard/components/LeaderboardTabsButton/LeaderboardTabsButton.tsx (1)

19-37: Add accessibility attributes to tab buttons

The buttons visually behave as tab toggles but lack ARIA hints.
Add role="tab" and aria-selected={timeTab==='weekly'} (likewise for “All Time”) to improve keyboard navigation and screen-reader context.

src/apps/leaderboard/components/UserInfo/UserInfo.tsx (2)

35-46: Repeated string slicing in resize handler

walletAddress.slice(...) runs on every resize event; minor, but can be avoided by computing once and memoising with breakpoint checks, or by using CSS text-overflow: ellipsis for a simpler solution.


125-140: Missing aria-label on copy button

Add aria-label="Copy wallet address" to the clickable div to meet accessibility guidelines.

src/apps/leaderboard/index.tsx (2)

63-74: Collapse the three nearly-identical tab handlers

handleAllTabClick, handleMigrationTabClick, and handleTradingTabClick differ only by the dispatched payload. A single factory/helper keeps the component slimmer and avoids three useCallbacks capturing the same deps.

-const handleAllTabClick   = useCallback(() => dispatch(setActiveTab('all')),        [dispatch]);
-const handleMigrationTabClick = useCallback(() => dispatch(setActiveTab('migration')), [dispatch]);
-const handleTradingTabClick   = useCallback(() => dispatch(setActiveTab('trading')),   [dispatch]);
+const onTabClick = useCallback(
+  (tab: LeaderboardTabsType) => dispatch(setActiveTab(tab)),
+  [dispatch],
+);

…then pass onTabClick('all' | 'migration' | 'trading') to the buttons.


91-124: Move calculateTotals outside useMemo

Defining calculateTotals inside useMemo recreates the same function every render, defeating memo-isation’s point. Pull it out (or wrap with useCallback) so the memo truly caches on the dependency array.

src/apps/leaderboard/components/LeaderboardTab/LeaderboardTab.tsx (1)

30-51: Observer recreated each scroll batch

useEffect depends on visibleCount; every 10 rows it tears down & rebuilds the IntersectionObserver. Observing once on mount is enough:

-}, [visibleCount]);
+// eslint-disable-next-line react-hooks/exhaustive-deps
+}, []);

Minimises GC churn while scrolling.

src/apps/leaderboard/utils/index.tsx (1)

188-209: Union, not intersection, of addresses when collapsing overlaps

When multiple migration entries share addresses you return only commonAddresses, losing unique aliases and making reverse look-ups miss. Consider:

-addresses: commonAddresses,
+addresses: Array.from(
+  new Set(allEntries.flatMap((e) => e.addresses)),
+),

so every PX-linked address survives the merge.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4151c7 and 141b4c2.

⛔ Files ignored due to path filters (11)
  • src/apps/leaderboard/images/current-rank-icon.svg is excluded by !**/*.svg
  • src/apps/leaderboard/images/earned-last-week-icon.svg is excluded by !**/*.svg
  • src/apps/leaderboard/images/gas-icon.svg is excluded by !**/*.svg
  • src/apps/leaderboard/images/info-icon.svg is excluded by !**/*.svg
  • src/apps/leaderboard/images/lottery-qualified-icon.png is excluded by !**/*.png
  • src/apps/leaderboard/images/migration-icon.svg is excluded by !**/*.svg
  • src/apps/leaderboard/images/new-drop-icon.svg is excluded by !**/*.svg
  • src/apps/leaderboard/images/pillar-wallet-icon.svg is excluded by !**/*.svg
  • src/apps/leaderboard/images/pillarx-icon.svg is excluded by !**/*.svg
  • src/apps/leaderboard/images/trading-icon.svg is excluded by !**/*.svg
  • src/apps/leaderboard/images/weekly-rank-icon.svg is excluded by !**/*.svg
📒 Files selected for processing (23)
  • src/apps/leaderboard/api/leaderboard.ts (3 hunks)
  • src/apps/leaderboard/components/InfoBanner/InfoBanner.tsx (1 hunks)
  • src/apps/leaderboard/components/LeaderboardTab/LeaderboardTab.tsx (3 hunks)
  • src/apps/leaderboard/components/LeaderboardTabsButton/LeaderboardFiltersButton.tsx (1 hunks)
  • src/apps/leaderboard/components/LeaderboardTabsButton/LeaderboardTabsButton.tsx (1 hunks)
  • src/apps/leaderboard/components/Leaderboards/Leaderboards.tsx (1 hunks)
  • src/apps/leaderboard/components/PointsCards/GasNewDropCard.tsx (1 hunks)
  • src/apps/leaderboard/components/PointsCards/OverviewPointsCard.tsx (1 hunks)
  • src/apps/leaderboard/components/PointsCards/PointsCard.tsx (1 hunks)
  • src/apps/leaderboard/components/PxPointsSummary/PxPointsSummary.tsx (1 hunks)
  • src/apps/leaderboard/components/UserInfo/UserInfo.tsx (3 hunks)
  • src/apps/leaderboard/hooks/useDateRanges.tsx (1 hunks)
  • src/apps/leaderboard/hooks/useLeaderboardData.tsx (1 hunks)
  • src/apps/leaderboard/hooks/useRankComparison.tsx (1 hunks)
  • src/apps/leaderboard/hooks/useReducerHooks.tsx (1 hunks)
  • src/apps/leaderboard/index.tsx (1 hunks)
  • src/apps/leaderboard/reducer/LeaderboardSlice.ts (1 hunks)
  • src/apps/leaderboard/tailwind.leaderboard.config.js (1 hunks)
  • src/apps/leaderboard/utils/index.tsx (1 hunks)
  • src/apps/pillarx-app/components/ReceiveModal/ReceiveModal.tsx (1 hunks)
  • src/apps/pillarx-app/components/WalletAdddressOverview/WalletAddressOverview.tsx (1 hunks)
  • src/store.ts (2 hunks)
  • src/types/api.ts (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
src/store.ts (1)
src/apps/leaderboard/reducer/LeaderboardSlice.ts (1)
  • leaderboardSlice (35-36)
src/apps/leaderboard/hooks/useReducerHooks.tsx (1)
src/store.ts (2)
  • AppDispatch (100-100)
  • RootState (98-98)
src/apps/leaderboard/components/PointsCards/OverviewPointsCard.tsx (1)
src/types/api.ts (1)
  • LeaderboardTableData (857-865)
src/apps/leaderboard/components/PxPointsSummary/PxPointsSummary.tsx (1)
src/types/api.ts (1)
  • LeaderboardTableData (857-865)
src/apps/leaderboard/api/leaderboard.ts (3)
src/utils/blockchain.ts (1)
  • isTestnet (29-35)
src/types/api.ts (1)
  • MigrationApiResponse (853-855)
src/store.ts (1)
  • addMiddleware (50-60)
src/apps/leaderboard/components/LeaderboardTabsButton/LeaderboardTabsButton.tsx (2)
src/apps/leaderboard/hooks/useReducerHooks.tsx (2)
  • useAppDispatch (5-5)
  • useAppSelector (6-6)
src/apps/leaderboard/reducer/LeaderboardSlice.ts (2)
  • LeaderboardTimeTabsType (5-5)
  • setTimeTab (26-28)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: build
🔇 Additional comments (2)
src/store.ts (1)

14-15: Verify slice shape matches addReducer contract

addReducer expects an object with reducerPath & reducer. A plain RTK slice produced by createSlice doesn’t have reducerPath, so leaderboardSlice must follow the same custom convention as the other slices.
If it’s a standard slice, pass:

addReducer({ reducerPath: 'leaderboard', reducer: leaderboardSlice.reducer });

to avoid runtime key undefined in middlewareReducers.

Also applies to: 91-92

src/apps/leaderboard/tailwind.leaderboard.config.js (1)

11-16: Breakpoint overlap – confirm intended cascade

desktop starts at 1024px while tablet has max: 1024px.
Because Tailwind’s max includes the boundary value, both breakpoints fire at exactly 1024px.
If the overlap is unintended, bump one value (1023px/1025px) to avoid ambiguous styling.

@github-actions github-actions bot requested a deployment to Preview (feat/px-points-migration-board) June 16, 2025 17:06 Abandoned
Copy link
Contributor

@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: 3

🔭 Outside diff range comments (1)
src/apps/leaderboard/components/LeaderboardTab/test/LeaderboardTab.test.tsx (1)

74-85: ** Assertion too strict on full wallet address**

UserInfo truncates addresses for desktop/tablet, so the raw 0xAddress1 string might never appear in the DOM.
This test will become flaky across breakpoints.

Suggest matching the truncated form (same helper as component) or asserting on the “My rank” label alone.

-expect(
-  screen.getAllByText(new RegExp(mockWalletAddress, 'i')).length
-).toBeGreaterThanOrEqual(2);
+expect(screen.getByText(/my rank/i)).toBeInTheDocument();
🧹 Nitpick comments (15)
src/apps/leaderboard/components/PointsCards/tests/OverviewPointsCard.test.tsx (3)

27-45: Reduce reliance on broad snapshot tests

Both test cases use full-DOM snapshots (expect(container).toMatchSnapshot()). These quickly become noisy and brittle when purely presentational details or third-party library upgrades change the markup.
Consider replacing them with narrowly scoped expectations that assert only the bits of DOM that actually matter for behaviour (e.g. specific text content, aria roles, class names, etc.). This will cut down on snapshot churn and make failures more meaningful.


47-65: String-literal assertions are fragile against number formatting

getByText('1234'), getByText('1'), getByText('3'), and getByText('345') assume the component renders raw numbers. If the UI starts using toLocaleString, rounding, or abbreviation (e.g. “1,234” or “1.2k”), this test will break even though the UI is still correct.

Prefer a more resilient approach:

- expect(screen.getByText('1234')).toBeInTheDocument();
+ expect(screen.getByText(/1[,.]?234/)).toBeInTheDocument();   // or use regex / formatter

Even better, query by test-id or role where possible to decouple from formatting details.


67-76: Dash-count assertion is brittle

expect(screen.getAllByText('-').length).toBe(2); presumes the component will always render exactly two “-” symbols when data is missing. A future design tweak (e.g. additional placeholders or changing the placeholder character) will cause an unnecessary failure.

- expect(screen.getAllByText('-').length).toBe(2);
+ expect(screen.getAllByText('-', { exact: true })).toHaveLength(2);          // at least keeps the exact match
+ // or, if the number of placeholders is not important:
+ expect(screen.getByText('-', { exact: true })).toBeInTheDocument();

Alternatively, assert specific sections (points placeholder, rank placeholder) individually by test-id to make intent clearer.

src/apps/leaderboard/components/PointsCards/tests/GasNewDropCard.test.tsx (3)

7-17: Snapshot-only assertions are brittle – favour explicit expectations.

The first two tests rely exclusively on Jest snapshots.
UI-focused snapshots tend to generate noisy diffs for minor cosmetic changes and often mask the real intent of the tests (business logic). You are already asserting the important conditional rendering a few lines below; consider dropping the snapshot cases or, at minimum, asserting key DOM nodes/values instead.


19-25: Hard-coded currency / number strings may break on formatting changes.

expect(screen.getByText('$1234')) will fail if the component later formats the value as $1,234, 1 234 $, etc.
Prefer a regexp that ignores thousand separators (or query by test-id) to make the test resilient:

- expect(screen.getByText('$1234')).toBeInTheDocument();
+ expect(screen.getByText(/\$?\s?1[, ]?234/)).toBeInTheDocument();

27-39: Minor duplication – group similar assertions through describe.each.

The last two cases only vary by isMigrated flag and expected presence of “Gas Used”. Parameterising them reduces duplication and makes intent clear:

describe.each`
  isMigrated | shouldShowGas
  ${false}   | ${false}
  ${undefined} | ${false}
`('renders correctly when isMigrated=$isMigrated', ({ isMigrated, shouldShowGas }) => {
  // ...
});
src/apps/leaderboard/components/PointsCards/tests/PointsCard.test.tsx (3)

16-28: Snapshot may hide regression on dynamic props.

Similar to the previous file: snapshotting an entire card that receives many props (points, rank, tooltip, colours) can quickly become noisy. Focus on explicit expectations (you already cover most of them) and drop the snapshot unless you have a very stable static markup.


42-47: Alt-text assertion coupled to implementation detail.

getByAltText('Trading-icon') will fail if someone changes the alt text to a more accessible variant ('Trading icon'). Prefer:

- const icon = screen.getByAltText('Trading-icon');
+ const icon = screen.getByRole('img', { name: /trading/i });

This keeps the test aligned with accessibility guidelines rather than string exactness.


88-100: Zero-points case good – minor readability nit.

Using a regex would avoid potential false negatives when the component localises the number:

- expect(screen.getByText('0')).toBeInTheDocument();
+ expect(screen.getByText(/^0$/)).toBeInTheDocument();
src/apps/leaderboard/components/PxPointsSummary/tests/PxPointsSummary.test.tsx (2)

150-164: Good conditional-render coverage – include negative assertion for lottery badge.

In the “does not show migration card” case you already check positive renders; also assert that “Qualified” badge is absent to capture unintended regressions:

expect(screen.queryByText('Qualified')).not.toBeInTheDocument();

185-201: Great graceful-degradation test – consider adding zero-state snapshot.

To document the zero-data UI, consider adding a small snapshot or specific assertions for points = 0 / ranks = '–' in this path.

src/apps/leaderboard/components/Leaderboards/tests/Leaderboards.test.tsx (2)

20-25: Skeleton count assertion is brittle

Hard-coding 3 skeletons will break as soon as the component changes the placeholder count (e.g. responsive layouts).
Prefer asserting at least one skeleton or querying by role/test-id instead of count.

-expect(SkeletonLoader).toHaveBeenCalledTimes(3);
-expect(screen.getAllByText('SkeletonLoader Mock')).toHaveLength(3);
+expect(SkeletonLoader).toHaveBeenCalled();
+expect(screen.getAllByText('SkeletonLoader Mock').length).toBeGreaterThan(0);

66-68: toHaveBeenCalledWith second argument is React-version dependent

React only passes the legacy context param to function components in very old versions.
expect(LeaderboardTab).toHaveBeenCalledWith({ data: mockData }) is future-proof and avoids false negatives once the team bumps React.

src/apps/leaderboard/components/LeaderboardTab/test/LeaderboardTab.test.tsx (1)

51-61: Loading more copy tightly coupled

Any wording tweak (“Load more”, button replacement, i18n) will break these assertions.
Prefer selecting by role, data-testid, or a regex that tolerates variations.

src/apps/leaderboard/components/LeaderboardTabsButton/test/LeaderboardTabsButton.test.tsx (1)

28-36: Snapshot test relies on mocked selector but still wires real store

Since useAppSelector is mocked, wrapping with <Provider store={store}> is redundant noise and can be removed to speed up the test.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 141b4c2 and 8f45faf.

⛔ Files ignored due to path filters (12)
  • src/apps/leaderboard/components/LeaderboardTab/test/__snapshots__/LeaderboardTab.test.tsx.snap is excluded by !**/*.snap
  • src/apps/leaderboard/components/LeaderboardTabsButton/test/__snapshots__/LeaderboardTabsButton.test.tsx.snap is excluded by !**/*.snap
  • src/apps/leaderboard/components/PointsCards/tests/__snapshots__/GasNewDropCard.test.tsx.snap is excluded by !**/*.snap
  • src/apps/leaderboard/components/PointsCards/tests/__snapshots__/OverviewPointsCard.test.tsx.snap is excluded by !**/*.snap
  • src/apps/leaderboard/components/PointsCards/tests/__snapshots__/PointsCard.test.tsx.snap is excluded by !**/*.snap
  • src/apps/leaderboard/components/PxPointsSummary/tests/__snapshots__/PxPointsSummary.test.tsx.snap is excluded by !**/*.snap
  • src/apps/leaderboard/components/UserInfo/test/__snapshots__/UserInfo.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pillarx-app/components/MediaGridCollection/tests/__snapshots__/DisplayCollectionImage.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pillarx-app/components/PortfolioOverview/test/__snapshots__/PortfolioOverview.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pillarx-app/components/TokenMarketDataRow/tests/__snapshots__/LeftColumnTokenMarketDataRow.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pillarx-app/components/TokensWithMarketDataTile/test/__snapshots__/TokensWithMarketDataTile.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pillarx-app/components/WalletAdddressOverview/test/__snapshots__/WalletAddressOverview.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (9)
  • src/apps/leaderboard/components/LeaderboardTab/test/LeaderboardTab.test.tsx (4 hunks)
  • src/apps/leaderboard/components/LeaderboardTabsButton/test/LeaderboardTabsButton.test.tsx (1 hunks)
  • src/apps/leaderboard/components/Leaderboards/tests/Leaderboards.test.tsx (1 hunks)
  • src/apps/leaderboard/components/PointsCards/tests/GasNewDropCard.test.tsx (1 hunks)
  • src/apps/leaderboard/components/PointsCards/tests/OverviewPointsCard.test.tsx (1 hunks)
  • src/apps/leaderboard/components/PointsCards/tests/PointsCard.test.tsx (1 hunks)
  • src/apps/leaderboard/components/PxPointsSummary/PxPointsSummary.tsx (1 hunks)
  • src/apps/leaderboard/components/PxPointsSummary/tests/PxPointsSummary.test.tsx (1 hunks)
  • src/apps/leaderboard/components/UserInfo/test/UserInfo.test.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/apps/leaderboard/components/PxPointsSummary/PxPointsSummary.tsx
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/apps/leaderboard/components/PointsCards/tests/OverviewPointsCard.test.tsx (1)
src/types/api.ts (1)
  • LeaderboardTableData (857-865)
src/apps/leaderboard/components/PxPointsSummary/tests/PxPointsSummary.test.tsx (1)
src/types/api.ts (1)
  • LeaderboardTableData (857-865)
src/apps/leaderboard/components/LeaderboardTab/test/LeaderboardTab.test.tsx (1)
src/types/api.ts (1)
  • LeaderboardTableData (857-865)
src/apps/leaderboard/components/LeaderboardTabsButton/test/LeaderboardTabsButton.test.tsx (1)
src/apps/leaderboard/reducer/LeaderboardSlice.ts (1)
  • setTimeTab (26-28)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: build
🔇 Additional comments (4)
src/apps/leaderboard/components/PointsCards/tests/PointsCard.test.tsx (1)

68-85: Tooltip interaction not fully asserted.

You trigger mouseOver but never verify the tooltip visibility change. Add an expectation such as:

fireEvent.mouseOver(screen.getByText('Trading'));
expect(screen.getByText('This is a tooltip')).toHaveClass('opacity-100');

(or however the component reveals the tooltip). Without it, the interaction part of the test provides no coverage.

src/apps/leaderboard/components/PxPointsSummary/tests/PxPointsSummary.test.tsx (2)

1-3: Missing explicit React import inside TSX mocks can break type-checking.

Because the file declares inline JSX inside jest.mock, older TS configs (or strict builds) still require import React from 'react';. Add once at the top to satisfy both classic and react-jsx runtimes:

+import React from 'react';

166-183: Edge-case modification correctly covered – nice.

Solid test ensuring badge suppression when completedSwap is falsy.
No action required.

src/apps/leaderboard/components/UserInfo/test/UserInfo.test.tsx (1)

79-88: Icon expectations reversed?

The test labelled “rank decrease” expects leaderboard-rank-up, while “rank increase” expects leaderboard-rank-down.
Double-check the component: if ⬆️ actually represents a better (numerically lower) rank, rename the tests to avoid cognitive dissonance.
If not, swap the expected test-ids.

@github-actions github-actions bot requested a deployment to Preview (feat/px-points-migration-board) June 16, 2025 17:26 Abandoned
Copy link
Collaborator

@IAmKio IAmKio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's just one small question but other than that it LGTM and it's not a showstopper

@github-actions github-actions bot temporarily deployed to Preview (feat/px-points-migration-board) June 17, 2025 09:26 Inactive
Copy link
Contributor

@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

🧹 Nitpick comments (1)
src/apps/leaderboard/hooks/useLeaderboardData.tsx (1)

216-233: Variable naming & comment mismatch could confuse future readers

const lastAddress = entry.addresses[0]; // comment: “last address”
  1. The identifier says “lastAddress” but grabs first element.
  2. The preceding comment “based on last address” contradicts the implementation.

Either rename the variable to firstAddress or use entry.addresses[entry.addresses.length - 1].

-const lastAddress = entry.addresses[0];
+const addressKey = entry.addresses[0]; // single-address array in merged data

Small but valuable for maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f45faf and 97ee70b.

⛔ Files ignored due to path filters (5)
  • src/apps/leaderboard/components/LeaderboardTab/test/__snapshots__/LeaderboardTab.test.tsx.snap is excluded by !**/*.snap
  • src/apps/leaderboard/components/PointsCards/tests/__snapshots__/GasNewDropCard.test.tsx.snap is excluded by !**/*.snap
  • src/apps/leaderboard/components/PointsCards/tests/__snapshots__/OverviewPointsCard.test.tsx.snap is excluded by !**/*.snap
  • src/apps/leaderboard/components/UserInfo/test/__snapshots__/UserInfo.test.tsx.snap is excluded by !**/*.snap
  • src/apps/pillarx-app/components/MediaGridCollection/tests/__snapshots__/DisplayCollectionImage.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (8)
  • src/apps/leaderboard/api/leaderboard.ts (4 hunks)
  • src/apps/leaderboard/components/PointsCards/GasNewDropCard.tsx (1 hunks)
  • src/apps/leaderboard/components/PointsCards/OverviewPointsCard.tsx (1 hunks)
  • src/apps/leaderboard/components/PointsCards/tests/GasNewDropCard.test.tsx (1 hunks)
  • src/apps/leaderboard/components/UserInfo/UserInfo.tsx (3 hunks)
  • src/apps/leaderboard/hooks/useLeaderboardData.tsx (1 hunks)
  • src/apps/leaderboard/utils/index.tsx (1 hunks)
  • src/types/api.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/apps/leaderboard/components/PointsCards/tests/GasNewDropCard.test.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/apps/leaderboard/components/PointsCards/GasNewDropCard.tsx
  • src/apps/leaderboard/api/leaderboard.ts
  • src/apps/leaderboard/components/PointsCards/OverviewPointsCard.tsx
  • src/apps/leaderboard/utils/index.tsx
  • src/apps/leaderboard/components/UserInfo/UserInfo.tsx
  • src/types/api.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/apps/leaderboard/hooks/useLeaderboardData.tsx (5)
src/apps/leaderboard/reducer/LeaderboardSlice.ts (1)
  • LeaderboardTimeTabsType (5-5)
src/apps/leaderboard/hooks/useDateRanges.tsx (1)
  • useDateRanges (4-14)
src/apps/leaderboard/hooks/useRankComparison.tsx (1)
  • useRankComparison (6-13)
src/types/api.ts (1)
  • LeaderboardTableData (857-865)
src/apps/leaderboard/utils/index.tsx (4)
  • getMergeLeaderboardMigrationDataByAddresses (158-217)
  • getCurrentWeekMigrationData (27-64)
  • getLastWeekMigrationData (70-107)
  • getMergeLeaderboardData (112-151)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: build
🔇 Additional comments (2)
src/apps/leaderboard/hooks/useLeaderboardData.tsx (2)

115-118: totalPoints is populated with USD value – intentional?

Both totalPoints and totalAmountUsd are set to currentUserData.totalSwapAmountUsd.
If points and USD are distinct concepts in the UI, this will double-count the same figure and break any aggregate statistics.

Confirm the API payload – if you really want points here, replace with the correct field (e.g. currentUserData.totalPoints).


65-90: All-time data processing looks solid

Clear transformation, memoised correctly, and leverages the merge helper. No concerns here.

@RanaBug RanaBug merged commit 55cc4b9 into staging Jun 17, 2025
7 of 8 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Jul 10, 2025
3 tasks
@coderabbitai coderabbitai bot mentioned this pull request Jul 30, 2025
3 tasks
@coderabbitai coderabbitai bot mentioned this pull request Aug 19, 2025
3 tasks
@coderabbitai coderabbitai bot mentioned this pull request Jan 6, 2026
3 tasks
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