Skip to content

Conversation

@MananTank
Copy link
Member

@MananTank MananTank commented Dec 8, 2025


PR-Codex overview

This PR focuses on enhancing the analytics components of the dashboard by refining data handling and visualization, adding new properties to interfaces, and improving the rendering logic for charts and highlights.

Detailed summary

  • Updated maximumFractionDigits to 2 in project-wallet-details.tsx.
  • Added stackedKeys to CombinedBarChartConfig in CombinedBarChartCard.
  • Enhanced BarChart to handle stackedKeys for conditional rendering.
  • Introduced x402Settlements handling in ProjectHighlightCard.
  • Added new utility functions for generating test data in highlights-card-ui.stories.tsx.
  • Refined data processing logic in ProjectHighlightsCard to include bridgeRevenue and x402Revenue.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Stacked data visualization support for charts.
    • Integrated x402 revenue into analytics highlights.
    • Option to hide specific chart tabs from display.
  • Improvements

    • USD currency formatting refined to 2 decimal places.
    • Analytics CTA now renders only when a link is provided.
  • Refactor

    • Simplified settlement data structures by consolidating common fields.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Dec 8, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
thirdweb-www Ready Ready Preview Comment Dec 8, 2025 7:03pm
4 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
docs-v2 Skipped Skipped Dec 8, 2025 7:03pm
nebula Skipped Skipped Dec 8, 2025 7:03pm
thirdweb_playground Skipped Skipped Dec 8, 2025 7:03pm
wallet-ui Skipped Skipped Dec 8, 2025 7:03pm

@linear
Copy link

linear bot commented Dec 8, 2025

@changeset-bot
Copy link

changeset-bot bot commented Dec 8, 2025

⚠️ No Changeset found

Latest commit: 9856ee4

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel vercel bot temporarily deployed to Preview – nebula December 8, 2025 18:14 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui December 8, 2025 18:14 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground December 8, 2025 18:14 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 December 8, 2025 18:14 Inactive
@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Dec 8, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 8, 2025

Walkthrough

Adds x402 settlement revenue into project highlights (fetch, propagate, and aggregate), enables stacked chart bars with per-key stackedKeys and hideAsTab options, refactors X402 settlement types to extend a common overall interface, tightens USD formatting precision, and makes an empty-chart CTA link optional.

Changes

Cohort / File(s) Summary
x402 settlement types & API
apps/dashboard/src/@/types/analytics.ts, apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx, apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx, apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
Refactored X402 settlement interfaces to extend X402SettlementsOverall; added getX402Settlements API use and wire-up. ProjectHighlightsCard now accepts x402Settlements, computes x402Revenue and bridgeRevenue, updates time-series processing and internal selected-chart state. Storybook stories added/updated with synthetic x402 data.
Chart stacking & tab options
apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx, apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
Extended BarChart to support per-key stackedKeys (renders multiple stacked Bars with stackId and per-key color resolution). Exported CombinedBarChartConfig and added hideAsTab?: boolean and stackedKeys?: string[]; tabs filter by hideAsTab and render per-tab stats/indicator.
UI/formatting/types tweaks
apps/dashboard/src/@/components/analytics/empty-chart-state.tsx, apps/dashboard/src/@/utils/number.ts, apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/types.ts
Made EmptyChartStateGetStartedCTA link prop optional and render CTA only when provided. Reduced USD formatter maximumFractionDigits from 6 to 2. Removed appHighlights from PageSearchParams.
Minor component refactor
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx
Removed local client destructuring and access client via props.client instead; no public API change.

Sequence Diagram(s)

sequenceDiagram
    participant Wrapper as AsyncAppHighlightsCard
    participant API as Analytics API
    participant Card as ProjectHighlightsCard
    participant Processor as TimeSeriesProcessor
    participant Charts as BarChart / UI

    Wrapper->>API: getX402Settlements()
    API-->>Wrapper: x402Settlements[]
    Wrapper->>API: getAggregatedUserStats()
    API-->>Wrapper: InAppWalletStats[]
    Wrapper->>API: getUniversalBridgeStats()
    API-->>Wrapper: UniversalBridgeStats[]
    Wrapper->>Card: render(x402Settlements, userStats, volumeStats)
    Card->>Processor: processTimeSeriesData(userStats, volumeStats, x402Settlements)
    Processor->>Processor: normalize dates, compute bridgeRevenue & x402Revenue, aggregate metrics
    Processor-->>Card: TimeSeriesMetrics[]
    Card->>Charts: render(timeSeriesData, chartConfig with stackedKeys)
    Charts-->>Card: stacked / single-bar visuals
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Focus review on:
    • highlights-card-ui.tsx / highlights-card.tsx: date normalization, aggregation of bridgeRevenue and x402Revenue, and interaction with chart config.
    • @/types/analytics.ts: interface inheritance changes and export visibility (ensure consumers still compatible).
    • BarChart.tsx & CombinedBarChartCard.tsx: stackedKeys rendering, stackId usage, color selection, and tab filtering by hideAsTab.
    • empty-chart-state.tsx: optional CTA rendering (verify no runtime null access).

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete and does not follow the template structure. While PR-Codex provides a summary, required template sections (Notes for reviewer, How to test) are missing. Add 'Notes for the reviewer' section to highlight important changes and 'How to test' section with testing instructions for the analytics updates.
Out of Scope Changes check ⚠️ Warning Several changes appear out of scope: modifications to EmptyChartStateGetStartedCTA (unrelated to Revenue tab), SwapProjectWalletModalContent refactoring, and updates to number.ts currency formatting not mentioned in the issue. Clarify the necessity of changes to EmptyChartStateGetStartedCTA, project-wallet-details.tsx, and number.ts formatting, or move them to a separate PR focused on those improvements.
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: updating the Project highlights card revenue tab, directly related to the primary objective.
Linked Issues check ✅ Passed The PR successfully implements the linked issue objectives: removes Bridge Fee Revenue from the Revenue tab and restructures it to display only active users, new users, and revenue, utilizing x402Settlements and bridgeRevenue in the refactored components.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pro-138

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • TEAM-0000: Entity not found: Issue - Could not find referenced Issue.

Comment @coderabbitai help to get the list of available commands and usage tips.

@MananTank MananTank marked this pull request as ready for review December 8, 2025 18:14
@MananTank MananTank requested review from a team as code owners December 8, 2025 18:14
Copy link
Member Author

MananTank commented Dec 8, 2025


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@codecov
Copy link

codecov bot commented Dec 8, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 54.65%. Comparing base (3c768a0) to head (9856ee4).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8515   +/-   ##
=======================================
  Coverage   54.65%   54.65%           
=======================================
  Files         920      920           
  Lines       61114    61114           
  Branches     4141     4141           
=======================================
  Hits        33399    33399           
  Misses      27613    27613           
  Partials      102      102           
Flag Coverage Δ
packages 54.65% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

🧹 Nitpick comments (4)
apps/dashboard/src/@/types/analytics.ts (1)

120-126: Consider extending X402SettlementsOverall for consistency.

X402SettlementsByAsset duplicates the same fields (date, totalRequests, totalValue, totalValueUSD) instead of extending X402SettlementsOverall like the other settlement types. This could lead to drift if the base type changes.

-interface X402SettlementsByAsset {
-  date: string;
+interface X402SettlementsByAsset extends X402SettlementsOverall {
   asset: string;
-  totalRequests: number;
-  totalValue: number;
-  totalValueUSD: number;
 }
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx (1)

97-122: Minor: Redundant ternary checks after status verification.

Lines 108-111 contain a ternary check for walletUserStatsTimeSeries.status === "fulfilled", but this is already guaranteed by the outer if condition on line 98. The same applies to universalBridgeUsage on lines 113-117.

       <ProjectHighlightsCard
         aggregatedUserStats={
           aggregatedUserStats.status === "fulfilled"
             ? aggregatedUserStats.value
             : []
         }
-        userStats={
-          walletUserStatsTimeSeries.status === "fulfilled"
-            ? walletUserStatsTimeSeries.value
-            : []
-        }
-        volumeStats={
-          universalBridgeUsage.status === "fulfilled"
-            ? universalBridgeUsage.value
-            : []
-        }
+        userStats={walletUserStatsTimeSeries.value}
+        volumeStats={universalBridgeUsage.value}
         x402Settlements={
           x402Settlements.status === "fulfilled" ? x402Settlements.value : []
         }
       />
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx (1)

103-158: Good story coverage.

The three stories provide useful scenarios: full 30-day data, single-day revenue, and no x402 settlements. Consider adding an edge case with empty bridgeVolumeStats but populated x402Settlements to verify x402-only revenue display.

export function SingleDayRevenueX402Only() {
  const days = 1;
  const data = {
    aggregatedUserStats: [],
    userStats: [],
    bridgeVolumeStats: [],
    x402Settlements: generateX402Settlements(days),
  };

  return (
    <ProjectHighlightsCard
      aggregatedUserStats={data.aggregatedUserStats}
      userStats={data.userStats}
      volumeStats={data.bridgeVolumeStats}
      x402Settlements={data.x402Settlements}
    />
  );
}
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx (1)

98-102: Redundant field declarations in TimeSeriesMetrics.

TimeSeriesMetrics extends AggregatedMetrics which already includes bridgeRevenue and x402Revenue. Re-declaring them here is unnecessary.

 type TimeSeriesMetrics = AggregatedMetrics & {
   date: string;
-  bridgeRevenue: number;
-  x402Revenue: number;
 };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3c768a0 and 6ff4367.

📒 Files selected for processing (10)
  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx (2 hunks)
  • apps/dashboard/src/@/types/analytics.ts (1 hunks)
  • apps/dashboard/src/@/utils/number.ts (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/types.ts (0 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx (0 hunks)
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx (2 hunks)
💤 Files with no reviewable changes (2)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/types.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoid any and unknown in TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.) in TypeScript

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose

Files:

  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Use cn() from @/lib/utils for conditional Tailwind class merging
Use design system tokens for styling (backgrounds: bg-card, borders: border-border, muted text: text-muted-foreground)
Expose className prop on root element for component overrides

Files:

  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/dashboard/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/dashboard/src/**/*.{ts,tsx}: Use NavLink for internal navigation with automatic active states in dashboard
Start server component files with import "server-only"; in Next.js
Read cookies/headers with next/headers in server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic with redirect() from next/navigation in server components
Begin client component files with 'use client'; directive in Next.js
Handle interactive UI with React hooks (useState, useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage, window, IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header for API calls – never embed tokens in URLs
Return typed results (Project[], User[]) from server-side data fetches – avoid any
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys in React Query for cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components – only use analytics client-side

Files:

  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/dashboard/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under @/components/ui/* for reusable core UI components like Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge
Use NavLink from @/components/ui/NavLink for internal navigation to ensure active states are handled automatically
For notices and skeletons, rely on AnnouncementBanner, GenericLoadingPage, and EmptyStateCard components
Import icons from lucide-react or the project-specific …/icons exports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names with cn from @/lib/utils to keep conditional logic readable
Stick to design tokens: use bg-card, border-border, text-muted-foreground and other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*, py-*, gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm, md, lg, xl)
Never hard-code colors; always use Tailwind variables
Combine class names via cn, and expose className prop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks

Files:

  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/dashboard/**/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

Add className prop to the root element of every component to allow external overrides

Files:

  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
**/*.{js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Biome governs formatting and linting; its rules live in biome.json. Run pnpm fix & pnpm lint before committing, ensure there are no linting errors

Files:

  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/{dashboard,playground}/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions

Files:

  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/components/**/*.{tsx,ts}: Group feature-specific components under feature/components/_ and expose a barrel index.ts when necessary
Expose a className prop on the root element of every component for styling overrides

Files:

  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only

Files:

  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/@/types/analytics.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Lazy-import optional features; avoid top-level side-effects

Files:

  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/@/types/analytics.ts
**/*.stories.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Add Storybook stories (*.stories.tsx) alongside new UI components for documentation

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
**/*.stories.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

For new UI components, add Storybook stories (*.stories.tsx) alongside the code

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
apps/dashboard/**/*analytics*

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

Use human-readable event names in <subject> <verb> phrase format (e.g., "contract deployed")

Files:

  • apps/dashboard/src/@/types/analytics.ts
🧬 Code graph analysis (5)
apps/dashboard/src/@/components/analytics/empty-chart-state.tsx (1)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Link (46-64)
apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx (2)
apps/dashboard/src/app/(app)/team/components/Analytics/Stat.tsx (1)
  • Stat (3-32)
apps/dashboard/src/@/utils/number.ts (1)
  • toUSD (10-12)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx (1)
  • ProjectHighlightsCard (22-96)
apps/dashboard/src/@/types/analytics.ts (3)
  • InAppWalletStats (14-19)
  • UniversalBridgeStats (42-50)
  • X402SettlementsOverall (97-102)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx (1)
apps/dashboard/src/@/api/analytics.ts (3)
  • getInAppWalletUsage (303-308)
  • getUniversalBridgeUsage (740-745)
  • getX402Settlements (1040-1042)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx (2)
apps/dashboard/src/@/types/analytics.ts (3)
  • InAppWalletStats (14-19)
  • UniversalBridgeStats (42-50)
  • X402SettlementsOverall (97-102)
apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx (1)
  • CombinedBarChartConfig (7-16)
⏰ 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). (4)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: Size
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (12)
apps/dashboard/src/@/utils/number.ts (1)

1-8: LGTM!

Reducing maximumFractionDigits from 6 to 2 is appropriate for compact USD currency display. This improves readability for revenue metrics (e.g., $1.5K vs $1.500000K).

apps/dashboard/src/@/components/analytics/empty-chart-state.tsx (1)

38-73: LGTM!

Making the link prop optional with conditional rendering is a clean approach that allows the CTA to be used in contexts where no navigation action is needed, while maintaining type safety.

apps/dashboard/src/@/types/analytics.ts (1)

104-118: Good use of inheritance for shared fields.

Extending X402SettlementsOverall for the settlement subtypes reduces duplication and improves maintainability.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx (1)

49-95: LGTM!

Good use of Promise.allSettled to fetch x402 settlements alongside existing data sources, allowing graceful degradation if the x402 API fails.

apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx (2)

28-48: LGTM!

Good implementation of stacking support. The isEmpty check correctly handles both stacked and non-stacked data by verifying if all stacked keys are zero when stackedKeys is present.


104-128: LGTM!

Clean conditional rendering for stacked vs. single bars. The color fallback chain (per-key → activeKey → default) and consistent stackId assignment ensure proper stacking behavior.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx (1)

10-27: LGTM!

Good Storybook setup with appropriate decorator for responsive search params context. As per coding guidelines, adding stories alongside new UI components is the right approach.

apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx (2)

7-16: LGTM!

Good addition of hideAsTab and stackedKeys to the config type. Exporting CombinedBarChartConfig enables type-safe configuration in consuming components.


59-86: LGTM!

Clean implementation of tab filtering with hideAsTab. This allows metrics like bridgeRevenue and x402Revenue to be hidden as individual tabs while still contributing to the stacked "Revenue" visualization.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx (3)

31-39: LGTM!

Moving to local useState for chart selection simplifies the component. The x402Settlements integration follows the same pattern as other data sources.


87-93: Verify trend calculation logic.

The trendFn compares data[data.length - 2] (second-to-last) against data[0] (first). This calculates the overall trend from start to near-end, not period-over-period change. If period-over-period is intended:

       trendFn={(data, key) =>
         data.filter((d) => (d[key] as number) > 0).length >= 2
-          ? ((data[data.length - 2]?.[key] as number) ?? 0) /
-              ((data[0]?.[key] as number) ?? 0) -
+          ? ((data[data.length - 1]?.[key] as number) ?? 0) /
+              ((data[data.length - 2]?.[key] as number) ?? 0) -
             1
           : undefined
       }

155-157: LGTM!

ignoreTimePeriod correctly normalizes ISO timestamps to YYYY-MM-DD format for consistent date matching across datasets with different time components.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 8, 2025

size-limit report 📦

Path Size
@thirdweb-dev/nexus (esm) 105.66 KB (0%)
@thirdweb-dev/nexus (cjs) 319.47 KB (0%)

@graphite-app
Copy link
Contributor

graphite-app bot commented Dec 8, 2025

Merge activity

<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the analytics components by adding new functionalities and refining existing code for better performance and readability. It introduces new data handling for `x402Settlements`, updates chart configurations, and improves conditional rendering in various components.

### Detailed summary
- Added `x402Settlements` data handling in `AsyncAppHighlightsCard`.
- Updated `CombinedBarChartConfig` to include `stackedKeys`.
- Improved conditional rendering for the `EmptyChartStateGetStartedCTA`.
- Refined the `BarChart` component for better data processing.
- Enhanced `ProjectHighlightsCard` to include `bridgeRevenue` and `x402Revenue`.
- Introduced utility functions for generating mock data in stories.
- Updated types in various components for better type safety.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Added stacked data visualization support to charts.
  * Integrated x402 revenue tracking into analytics highlights.
  * Added ability to hide specific chart tabs from display.

* **Improvements**
  * Refined USD currency formatting to display 2 decimal places for cleaner presentation.
  * Made analytics CTA buttons conditionally displayed based on configuration.

* **Refactor**
  * Simplified settlement data model with inheritance to reduce redundancy.

<sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@vercel vercel bot temporarily deployed to Preview – docs-v2 December 8, 2025 18:55 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground December 8, 2025 18:55 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula December 8, 2025 18:55 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui December 8, 2025 18:55 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: 1

🧹 Nitpick comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx (1)

155-157: Consider adding JSDoc for clarity.

The ignoreTimePeriod helper is clear but undocumented. Adding a brief JSDoc comment would explain the UTC normalization behavior.

+/**
+ * Normalizes a date string to YYYY-MM-DD format in UTC.
+ * Used to aggregate metrics by calendar day regardless of time.
+ */
 function ignoreTimePeriod(date: string) {
   return new Date(date).toISOString().slice(0, 10);
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6ff4367 and 9856ee4.

📒 Files selected for processing (10)
  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx (2 hunks)
  • apps/dashboard/src/@/types/analytics.ts (1 hunks)
  • apps/dashboard/src/@/utils/number.ts (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/types.ts (0 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx (0 hunks)
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx (2 hunks)
💤 Files with no reviewable changes (2)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/types.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/project-wallet/project-wallet-details.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/dashboard/src/@/components/analytics/empty-chart-state.tsx
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoid any and unknown in TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.) in TypeScript

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose

Files:

  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Use cn() from @/lib/utils for conditional Tailwind class merging
Use design system tokens for styling (backgrounds: bg-card, borders: border-border, muted text: text-muted-foreground)
Expose className prop on root element for component overrides

Files:

  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/dashboard/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/dashboard/src/**/*.{ts,tsx}: Use NavLink for internal navigation with automatic active states in dashboard
Start server component files with import "server-only"; in Next.js
Read cookies/headers with next/headers in server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic with redirect() from next/navigation in server components
Begin client component files with 'use client'; directive in Next.js
Handle interactive UI with React hooks (useState, useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage, window, IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header for API calls – never embed tokens in URLs
Return typed results (Project[], User[]) from server-side data fetches – avoid any
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys in React Query for cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components – only use analytics client-side

Files:

  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/dashboard/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under @/components/ui/* for reusable core UI components like Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge
Use NavLink from @/components/ui/NavLink for internal navigation to ensure active states are handled automatically
For notices and skeletons, rely on AnnouncementBanner, GenericLoadingPage, and EmptyStateCard components
Import icons from lucide-react or the project-specific …/icons exports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names with cn from @/lib/utils to keep conditional logic readable
Stick to design tokens: use bg-card, border-border, text-muted-foreground and other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*, py-*, gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm, md, lg, xl)
Never hard-code colors; always use Tailwind variables
Combine class names via cn, and expose className prop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks

Files:

  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/@/types/analytics.ts
**/*.{js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Biome governs formatting and linting; its rules live in biome.json. Run pnpm fix & pnpm lint before committing, ensure there are no linting errors

Files:

  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/{dashboard,playground}/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions

Files:

  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only

Files:

  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/@/types/analytics.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Lazy-import optional features; avoid top-level side-effects

Files:

  • apps/dashboard/src/@/utils/number.ts
  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
  • apps/dashboard/src/@/types/analytics.ts
apps/dashboard/**/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

Add className prop to the root element of every component to allow external overrides

Files:

  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/components/**/*.{tsx,ts}: Group feature-specific components under feature/components/_ and expose a barrel index.ts when necessary
Expose a className prop on the root element of every component for styling overrides

Files:

  • apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx
  • apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx
**/*.stories.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Add Storybook stories (*.stories.tsx) alongside new UI components for documentation

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
**/*.stories.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

For new UI components, add Storybook stories (*.stories.tsx) alongside the code

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx
apps/dashboard/**/*analytics*

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

Use human-readable event names in <subject> <verb> phrase format (e.g., "contract deployed")

Files:

  • apps/dashboard/src/@/types/analytics.ts
🧬 Code graph analysis (3)
apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx (2)
apps/dashboard/src/app/(app)/team/components/Analytics/Stat.tsx (1)
  • Stat (3-32)
apps/dashboard/src/@/utils/number.ts (1)
  • toUSD (10-12)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx (1)
apps/dashboard/src/@/api/analytics.ts (3)
  • getInAppWalletUsage (303-308)
  • getUniversalBridgeUsage (740-745)
  • getX402Settlements (1040-1042)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx (1)
  • ProjectHighlightsCard (22-96)
apps/dashboard/src/@/types/analytics.ts (3)
  • InAppWalletStats (14-19)
  • UniversalBridgeStats (42-50)
  • X402SettlementsOverall (97-102)
⏰ 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). (7)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Lint Packages
  • GitHub Check: Vercel Agent Review
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (17)
apps/dashboard/src/@/utils/number.ts (1)

1-8: LGTM!

Reducing maximumFractionDigits from 6 to 2 aligns with standard USD display conventions where cents-level precision is sufficient for user-facing currency values.

apps/dashboard/src/app/(app)/team/components/Analytics/CombinedBarChartCard.tsx (2)

7-16: LGTM!

Good type extension with hideAsTab and stackedKeys optional properties. Exporting the type enables reuse across analytics components.


59-86: Tab filtering and rendering logic looks correct.

The filtering with hideAsTab and the visual indicator for active state are well-implemented. One minor note: on line 73, trendFn(data, key) || undefined converts 0 to undefined, but since Stat already guards with {trend && ...}, this is effectively correct behavior (zero trends aren't displayed).

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card.tsx (3)

4-8: LGTM!

Clean import addition for getX402Settlements alongside existing analytics API functions.


49-95: LGTM! Good use of Promise.allSettled for independent data fetching.

The parallel fetching of all four data sources with Promise.allSettled is appropriate for independent API calls, allowing graceful degradation if individual sources fail.


97-122: Verify intentional exclusion of x402Settlements from render condition.

The render condition on lines 97-99 only checks walletUserStatsTimeSeries and universalBridgeUsage fulfilled status, not x402Settlements. This means the card renders even if x402 fetching fails (passing an empty array). If this graceful degradation is intentional, this is fine. Otherwise, consider whether x402 failures should also show the empty state.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.stories.tsx (3)

10-29: LGTM!

Good Storybook meta configuration with proper decorators for ResponsiveSearchParamsProvider and container styling. The nextjs.appDirectory parameter is correctly set for Next.js app router support.


31-101: Well-structured mock data generators.

The helper functions create realistic mock data matching the expected type interfaces (InAppWalletStats, UniversalBridgeStats, X402SettlementsOverall). The generateDateSeries produces proper ISO date strings, and randomValue ensures non-negative values with Math.max(0, ...).


103-158: Good story coverage for different scenarios.

The three stories cover useful test cases:

  • ThirtyDays: Full dataset with all metrics
  • SingleDayRevenue: Edge case with minimal data points
  • SingleDayRevenueNoX402: Tests graceful handling when x402 data is empty
apps/dashboard/src/app/(app)/team/components/Analytics/BarChart.tsx (3)

28-32: Type extension for stackedKeys support.

The intersection type with an index signature works, though it's somewhat redundant with ChartConfig's existing index signature. This approach is acceptable for adding the optional stackedKeys property.


40-48: Correct isEmpty logic for stacked charts.

The empty state detection properly handles both scenarios:

  • For stacked charts: checks if all stackedKeys values are zero across all data points
  • For non-stacked: checks if activeKey values are all zero

The defensive type assertion on line 41 ensures safe property access.


104-128: LGTM! Stacked bar rendering implementation.

The conditional rendering correctly:

  • Uses stackId={activeKey} to group stacked bars together
  • Applies per-key colors with sensible fallback chain
  • Maintains consistent styling (radius, strokeWidth, className) across both paths
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx (4)

3-8: LGTM!

The new imports (useState and X402SettlementsOverall) correctly support the component's updated functionality.


31-33: Verify loss of deep-linking is acceptable.

The component now uses local state instead of URL search params for chart selection. This simplifies the implementation but removes the ability to deep-link to a specific chart view or persist the selection across page refreshes.

If deep-linking was a desired feature, consider keeping the URL-based approach or adding logic to sync local state with URL params.


107-153: Logic is sound, but watch for timezone edge cases.

The time-series aggregation correctly:

  • Combines dates from all three data sources (lines 115-118)
  • Filters bridge revenue to only completed transactions (line 134)
  • Sums x402 revenue from totalValueUSD (line 140)
  • Composes feesCollected from both revenue streams (line 145)

However, ignoreTimePeriod converts dates to UTC via toISOString() (line 156). If input dates are in different timezones, this could misalign data points at day boundaries.

Verify that all input data sources (userStats, volumeStats, x402Settlements) use consistent timezone-aware date strings, or that UTC normalization is the intended behavior for daily aggregation.


41-63: Both hideAsTab and stackedKeys are supported by CombinedBarChartCard. The type definition in CombinedBarChartConfig includes both optional properties, and the implementation actively uses them: hideAsTab filters which charts appear in the tab list, and stackedKeys enables rendering multiple bars stacked together in the chart.

apps/dashboard/src/@/types/analytics.ts (1)

104-118: Good refactoring—DRY compliance improved.

The inheritance approach eliminates duplicate field declarations across the X402Settlement interfaces. The removal of the export on X402SettlementsByReceiver is safe; this type has no external consumers.

Comment on lines 98 to 102
type TimeSeriesMetrics = AggregatedMetrics & {
date: string;
bridgeRevenue: number;
x402Revenue: number;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate field declarations.

TimeSeriesMetrics extends AggregatedMetrics (line 98), which already includes bridgeRevenue and x402Revenue (lines 18-19). Re-declaring them here (lines 100-101) is redundant.

 type TimeSeriesMetrics = AggregatedMetrics & {
   date: string;
-  bridgeRevenue: number;
-  x402Revenue: number;
 };
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/_analytics/highlights-card-ui.tsx
around lines 98 to 102, the TimeSeriesMetrics type re-declares bridgeRevenue and
x402Revenue even though they are already defined on AggregatedMetrics; remove
the duplicate bridgeRevenue and x402Revenue properties from the
TimeSeriesMetrics definition so it simply extends AggregatedMetrics and adds
only the date field.

@graphite-app graphite-app bot merged commit 9856ee4 into main Dec 8, 2025
24 of 25 checks passed
@graphite-app graphite-app bot deleted the pro-138 branch December 8, 2025 19:03
@vercel vercel bot temporarily deployed to Production – nebula December 8, 2025 19:03 Inactive
@vercel vercel bot temporarily deployed to Production – docs-v2 December 8, 2025 19:03 Inactive
@vercel vercel bot temporarily deployed to Production – thirdweb_playground December 8, 2025 19:03 Inactive
@vercel vercel bot temporarily deployed to Production – wallet-ui December 8, 2025 19:03 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dashboard Involves changes to the Dashboard.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants