Skip to content

Conversation

@Yash094
Copy link
Member

@Yash094 Yash094 commented Dec 31, 2025


PR-Codex overview

This PR introduces a new "Rewind" feature to the account section, allowing users to view their yearly statistics. It includes a modal for displaying these stats, analytics tracking, and UI components for better user engagement.

Detailed summary

  • Added new route for Rewind in layout.tsx.
  • Introduced RewindModalClient to manage modal display logic.
  • Created RewindBadge component for UI integration.
  • Implemented analytics reporting for rewind viewed events.
  • Added getYearInReview API for fetching yearly stats.
  • Developed RewindModal for displaying yearly statistics.
  • Enhanced RewindPage with a button to trigger modal.
  • Integrated RewindBadge into existing headers and UI components.

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

Summary by CodeRabbit

  • New Features
    • Year in Review (2025) showing totals for RPC requests, wallet connections, and mainnet sponsored transactions
    • Rewind badge button added to account and team headers for quick access
    • Multi-slide Rewind modal with animated intro, metrics, and sharing support
    • Dedicated Rewind page and new "Rewind" account tab
    • Automatic Rewind display in December/January on first visit; view events are reported for analytics

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

@Yash094 Yash094 requested review from a team as code owners December 31, 2025 12:40
@changeset-bot
Copy link

changeset-bot bot commented Dec 31, 2025

⚠️ No Changeset found

Latest commit: 21312f6

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
Copy link

vercel bot commented Dec 31, 2025

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

Project Deployment Review Updated (UTC)
thirdweb-www Ready Ready Preview, Comment Dec 31, 2025 1:15pm
4 Skipped Deployments
Project Deployment Review Updated (UTC)
docs-v2 Skipped Skipped Dec 31, 2025 1:15pm
nebula Skipped Skipped Dec 31, 2025 1:15pm
thirdweb_playground Skipped Skipped Dec 31, 2025 1:15pm
wallet-ui Skipped Skipped Dec 31, 2025 1:15pm

@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Dec 31, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 31, 2025

Walkthrough

Adds a 2025 "Year in Review" feature: backend aggregation endpoint, analytics reporter, a modal UI with intro/metric/share slides, client auto-open logic, a dedicated rewind page, header badges, and an API route that returns aggregated stats for teams.

Changes

Cohort / File(s) Summary
Analytics Event Reporter
apps/dashboard/src/@/analytics/report.ts
New exported reportRewindViewed(properties) to capture "rewind viewed" with structured properties (year, totalRpcRequests, totalWalletConnections, totalMainnetSponsoredTransactions).
Backend aggregation API
apps/dashboard/src/@/api/rewind/get-year-in-review.ts
New YearInReviewStats type and exported getYearInReview(authToken, teamIds) that aggregates RPC requests, wallet connections, and mainnet-sponsored transactions across teams (per-team error handling, global fallback).
Next.js API route
apps/dashboard/src/app/api/rewind/route.ts
New GET route at /api/rewind that retrieves auth token, team IDs, calls getYearInReview(), and returns JSON (500 on error).
Modal & Client wrapper
apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx, apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
New client modal component with React Query fetch, multi-slide UI (intro animation, 3 metric slides, share), sharing (Web Share + clipboard), number formatting, and reports analytics; client wrapper manages auto-open timing, month gating (Dec/Jan), and localStorage "seen" flag.
Rewind page
apps/dashboard/src/app/(app)/account/rewind/page.tsx
New client page (default export) rendering year badge, title, description, and button to open the modal.
Badge component & placements
apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx, apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx, apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
New RewindBadge client component (button showing year, toggles modal). Inserted into account and team headers after the logo.
Account page integration & layout
apps/dashboard/src/app/(app)/account/page.tsx, apps/dashboard/src/app/(app)/account/layout.tsx
Renders RewindModalClient on account page; adds "Rewind" tab link at /account/rewind in account layout navigation.

Sequence Diagram

sequenceDiagram
    participant User
    participant Badge as RewindBadge
    participant Client as RewindModalClient
    participant Modal as RewindModal
    participant API as /api/rewind
    participant Backend as getYearInReview()
    participant Analytics as reportRewindViewed()

    Note over User,Badge: user opens Rewind (click or auto-open)
    User->>Badge: click
    Badge->>Client: request open
    Client->>Modal: open (auto or manual)

    Modal->>API: GET /api/rewind (fetchYearInReview)
    API->>Backend: getYearInReview(authToken, teamIds)
    Backend->>Backend: aggregate RPC, wallets, sponsored txs across teams
    Backend-->>API: YearInReviewStats
    API-->>Modal: JSON stats

    Modal->>Analytics: reportRewindViewed(stats)
    Analytics-->>Analytics: capture event

    User->>Modal: navigate slides / share
    Modal->>User: use Web Share API or clipboard
    User->>Client: close
    Client->>Client: persist "rewind-seen-2025" in localStorage
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete, missing required template sections like issue tag, detailed notes for reviewers, and testing instructions despite the template requirements. Fill in the template sections: add issue tag (TEAM-XXXX format), provide reviewer notes on testing approach, and explain how to verify the feature works correctly.
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title "2025 wrapped" is vague and generic, using colloquial phrasing that doesn't clearly convey the specific feature being added (a year-in-review rewind feature for the dashboard account section). Revise the title to be more descriptive, such as "[Dashboard] Feature: Add year-in-review Rewind feature" or "Add 2025 Rewind feature with yearly analytics modal."
✨ Finishing touches
  • 📝 Generate docstrings

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.

@codecov
Copy link

codecov bot commented Dec 31, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 53.19%. Comparing base (805b838) to head (21312f6).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8598   +/-   ##
=======================================
  Coverage   53.19%   53.19%           
=======================================
  Files         922      922           
  Lines       61480    61480           
  Branches     4032     4032           
=======================================
  Hits        32706    32706           
  Misses      28676    28676           
  Partials       98       98           
Flag Coverage Δ
packages 53.19% <ø> (ø)
🚀 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: 5

🧹 Nitpick comments (13)
apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx (1)

40-40: Consider adding RewindBadge to mobile header for consistent UX.

The RewindBadge is only added to AccountHeaderDesktopUI but not AccountHeaderMobileUI. While mobile users can still access the Rewind feature via the tab navigation, adding the badge to mobile would provide a consistent experience across viewports.

apps/dashboard/src/app/api/rewind/route.ts (1)

7-27: Add explicit return type annotation.

Per coding guidelines, functions should have explicit return types for clarity. The GET handler should specify its return type.

🔎 Proposed fix
-export async function GET() {
+export async function GET(): Promise<NextResponse> {
apps/dashboard/src/@/analytics/report.ts (1)

706-722: Specify a person as the event owner, not a team handle.

Per coding guidelines, the JSDoc should specify who owns the event using a GitHub username (e.g., @jnsdls, @MananTank). @thirdweb is a team handle rather than a specific person responsible for maintaining this event.

🔎 Proposed fix
  * ### Who is responsible for this event?
- * @thirdweb
+ * @Yash094
  */
apps/dashboard/src/app/(app)/account/rewind/page.tsx (1)

8-39: Add explicit return type annotation.

Per coding guidelines, functions should have explicit return types. Consider adding JSX.Element or React.ReactNode as the return type.

🔎 Proposed fix
-export default function RewindPage() {
+export default function RewindPage(): JSX.Element {
apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx (2)

17-20: Hardcoded gradient colors deviate from design system.

The gradient uses hardcoded colors (from-blue-500 to-purple-500) rather than design tokens. While this may be intentional for a distinctive seasonal feature, consider whether these could be defined as CSS variables for easier theming/maintenance.


8-28: Add explicit return type annotation.

Per coding guidelines, functions should have explicit return types for clarity.

🔎 Proposed fix
-export function RewindBadge({ className }: { className?: string }) {
+export function RewindBadge({ className }: { className?: string }): JSX.Element {
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx (2)

8-10: Unused variable and potential timing edge case.

_currentDay (line 10) is declared but never used. Additionally, calling new Date() three times could theoretically yield inconsistent values if executed exactly at midnight, though this is unlikely in practice.

Consider consolidating into a single Date instance:

🔎 Proposed fix
 export function RewindModalClient() {
   const [open, setOpen] = useState(false);
-  const currentYear = new Date().getFullYear();
-  const currentMonth = new Date().getMonth();
-  const _currentDay = new Date().getDate();
+  const now = new Date();
+  const currentYear = now.getFullYear();
+  const currentMonth = now.getMonth();

30-36: Consider wrapping localStorage calls in try-catch.

localStorage can throw in private browsing mode or restricted contexts. While unlikely to cause issues for most users, wrapping in try-catch prevents silent failures.

🔎 Proposed fix
   const handleOpenChange = (newOpen: boolean) => {
     setOpen(newOpen);
     if (!newOpen) {
       // Mark as seen for this year
-      localStorage.setItem(`rewind-seen-${currentYear}`, "true");
+      try {
+        localStorage.setItem(`rewind-seen-${displayYear}`, "true");
+      } catch {
+        // Ignore localStorage errors (e.g., private browsing)
+      }
     }
   };
apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (5)

19-24: Duplicate type definition.

YearInReviewStats is already exported from @/api/rewind/get-year-in-review.ts (see external_snippet_1). Re-import to avoid drift and follow DRY.

🔎 Proposed fix
+import type { YearInReviewStats } from "@/api/rewind/get-year-in-review";
 import { reportRewindViewed } from "@/analytics/report";
 import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
 import { cn } from "@/lib/utils";
 import { ThirdwebMiniLogo } from "../../components/ThirdwebMiniLogo";

-type YearInReviewStats = {
-  totalRpcRequests: number;
-  totalWalletConnections: number;
-  totalMainnetSponsoredTransactions: number;
-  year: number;
-};

90-91: Unused state variable _introPhase.

_introPhase is set via setIntroPhase but never read. If it's not used for rendering or other logic, consider removing it.


124-136: Analytics event may fire on every modal re-open.

When the user closes and reopens the modal within the same session, open toggles while data remains cached, causing reportRewindViewed to fire again. Consider tracking whether the event was already reported for this session.

🔎 Proposed fix
+  const [hasReportedAnalytics, setHasReportedAnalytics] = useState(false);

   // Report analytics when data loads
   // eslint-disable-next-line no-restricted-syntax
   useEffect(() => {
-    if (data && open) {
+    if (data && open && !hasReportedAnalytics) {
       reportRewindViewed({
         year: displayYear,
         totalRpcRequests: data.totalRpcRequests,
         totalWalletConnections: data.totalWalletConnections,
         totalMainnetSponsoredTransactions:
           data.totalMainnetSponsoredTransactions,
       });
+      setHasReportedAnalytics(true);
     }
-  }, [data, open]);
+  }, [data, open, hasReportedAnalytics]);

215-235: Use XIcon from lucide-react instead of inline SVG.

The close button SVG is duplicated in two places and embeds raw SVG. Per coding guidelines, icons should be imported from lucide-react. This also removes duplication.

🔎 Proposed fix

Add to imports:

 import {
   ChevronLeftIcon,
   ChevronRightIcon,
   SendIcon,
   Share2Icon,
   WalletIcon,
+  XIcon,
   ZapIcon,
 } from "lucide-react";

Replace inline SVG (both occurrences):

               <button
                 type="button"
                 onClick={() => onOpenChange(false)}
                 className="text-muted-foreground hover:text-foreground transition-colors"
                 aria-label="Close"
               >
-                <svg
-                  className="h-5 w-5"
-                  fill="none"
-                  viewBox="0 0 24 24"
-                  stroke="currentColor"
-                  aria-hidden="true"
-                >
-                  <path
-                    strokeLinecap="round"
-                    strokeLinejoin="round"
-                    strokeWidth={2}
-                    d="M6 18L18 6M6 6l12 12"
-                  />
-                </svg>
+                <XIcon className="h-5 w-5" aria-hidden="true" />
               </button>

Also applies to: 253-273


150-167: Unhandled clipboard.writeText rejection.

navigator.clipboard.writeText() returns a Promise that can reject (e.g., permission denied). Both the catch fallback (line 162) and the else branch (line 165) don't handle this, potentially leaving the user without feedback.

🔎 Proposed fix
   const handleShare = () => {
     if (!data) return;
     const text = `I sent ${formatNumber(data.totalRpcRequests)} RPC requests, connected ${formatNumber(data.totalWalletConnections)} wallets, and sponsored ${formatNumber(data.totalMainnetSponsoredTransactions)} mainnet transactions on thirdweb this year! 🚀`;

     if (navigator.share) {
       navigator
         .share({
           title: `My ${displayYear} thirdweb Rewind`,
           text,
           url: window.location.href,
         })
         .catch(() => {
-          navigator.clipboard.writeText(text);
+          navigator.clipboard.writeText(text).catch(() => {
+            // Clipboard write failed silently
+          });
         });
     } else {
-      navigator.clipboard.writeText(text);
+      navigator.clipboard.writeText(text).catch(() => {
+        // Clipboard write failed silently
+      });
     }
   };
📜 Review details

Configuration used: Organization 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 805b838 and d516022.

📒 Files selected for processing (11)
  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx
  • apps/dashboard/src/app/(app)/account/layout.tsx
  • apps/dashboard/src/app/(app)/account/page.tsx
  • apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx
  • apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/app/(app)/account/rewind/page.tsx
  • apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
  • apps/dashboard/src/app/api/rewind/route.ts
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{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/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/app/(app)/account/page.tsx
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/page.tsx
  • apps/dashboard/src/app/api/rewind/route.ts
  • apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx
  • apps/dashboard/src/app/(app)/account/layout.tsx
  • apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.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/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/app/(app)/account/page.tsx
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/page.tsx
  • apps/dashboard/src/app/api/rewind/route.ts
  • apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx
  • apps/dashboard/src/app/(app)/account/layout.tsx
  • apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.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/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/app/(app)/account/page.tsx
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/page.tsx
  • apps/dashboard/src/app/api/rewind/route.ts
  • apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx
  • apps/dashboard/src/app/(app)/account/layout.tsx
  • apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.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/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/app/(app)/account/page.tsx
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/page.tsx
  • apps/dashboard/src/app/api/rewind/route.ts
  • apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx
  • apps/dashboard/src/app/(app)/account/layout.tsx
  • apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.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/TeamHeader/TeamHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/components/RewindBadge.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/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/app/(app)/account/page.tsx
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/page.tsx
  • apps/dashboard/src/app/api/rewind/route.ts
  • apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx
  • apps/dashboard/src/app/(app)/account/layout.tsx
  • apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.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/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/app/(app)/account/page.tsx
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/page.tsx
  • apps/dashboard/src/app/api/rewind/route.ts
  • apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx
  • apps/dashboard/src/app/(app)/account/layout.tsx
  • apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.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/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/components/RewindBadge.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/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/app/(app)/account/page.tsx
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/page.tsx
  • apps/dashboard/src/app/api/rewind/route.ts
  • apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx
  • apps/dashboard/src/app/(app)/account/layout.tsx
  • apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/analytics/report.ts
  • apps/dashboard/src/app/(app)/account/page.tsx
  • apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx
  • apps/dashboard/src/app/(app)/account/rewind/page.tsx
  • apps/dashboard/src/app/api/rewind/route.ts
  • apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx
  • apps/dashboard/src/app/(app)/account/layout.tsx
  • apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
apps/dashboard/src/**/@/analytics/report.ts

📄 CodeRabbit inference engine (CLAUDE.md)

apps/dashboard/src/**/@/analytics/report.ts: Name analytics events with human-readable <subject> <verb> format (e.g. "contract deployed")
Name analytics event reporter functions as report<Subject><Verb> in PascalCase
Include JSDoc comment explaining why the analytics event is needed and responsible person (@username) for maintenance

Files:

  • apps/dashboard/src/@/analytics/report.ts
apps/dashboard/**/@/analytics/report.{ts,tsx}

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

apps/dashboard/**/@/analytics/report.{ts,tsx}: Create reporting helper functions named report<Subject><Verb> in PascalCase under src/@/analytics/report.ts
Add mandatory JSDoc to analytics reporting functions explaining why the event exists and who owns it (@username)
Accept a single typed properties object in analytics reporting functions and pass it unchanged to posthog.capture

Files:

  • apps/dashboard/src/@/analytics/report.ts
apps/{dashboard,playground}/src/@/analytics/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Only add analytics events that answer a clear product or business question. Check src/@/analytics/report.ts first to avoid duplicates

Files:

  • apps/dashboard/src/@/analytics/report.ts
apps/{dashboard,playground}/src/@/analytics/report.ts

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/src/@/analytics/report.ts: Use the naming convention: Event name as human-readable phrase in the form ' ' (e.g., 'contract deployed'). Reporting function: 'report' (PascalCase). All reporting helpers live in the shared report.ts file
Add a JSDoc header to analytics event reporters explaining Why the event exists and Who owns it (@username). Accept a single typed properties object and forward it unchanged to posthog.capture()

Files:

  • apps/dashboard/src/@/analytics/report.ts
apps/dashboard/**/page.{ts,tsx}

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

Use the container class with a max-w-7xl cap for consistent page width

Files:

  • apps/dashboard/src/app/(app)/account/page.tsx
  • apps/dashboard/src/app/(app)/account/rewind/page.tsx
apps/dashboard/**/api/**/*.{ts,tsx}

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

apps/dashboard/**/api/**/*.{ts,tsx}: Co-locate data helpers under @/api/** and mark them with "server-only" import
Always call getAuthToken() to get the JWT from cookies in server-side data fetching functions
Prefix server files with import "server-only"; so they never end up in the client bundle
Pass the JWT token in the Authorization: Bearer header in server-side fetches; never embed it in the URL
Return typed results (Project[], User[], etc.) from server-side data fetching functions; avoid any

Files:

  • apps/dashboard/src/app/api/rewind/route.ts
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
apps/dashboard/**/layout.{ts,tsx}

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

apps/dashboard/**/layout.{ts,tsx}: Reuse SidebarLayout or FullWidthSidebarLayout from @/components/blocks/SidebarLayout for all layouts
Export default async functions without 'use client'; in server components; they run on the Node edge

Files:

  • apps/dashboard/src/app/(app)/account/layout.tsx
🧬 Code graph analysis (9)
apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx (1)
apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx (1)
  • RewindBadge (8-28)
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx (1)
apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (1)
  • RewindModal (74-464)
apps/dashboard/src/app/(app)/account/page.tsx (1)
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx (1)
  • RewindModalClient (6-39)
apps/dashboard/src/app/(app)/account/components/AccountHeaderUI.tsx (1)
apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx (1)
  • RewindBadge (8-28)
apps/dashboard/src/app/(app)/account/rewind/page.tsx (1)
apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (1)
  • RewindModal (74-464)
apps/dashboard/src/app/api/rewind/route.ts (3)
apps/dashboard/src/@/utils/redirects.ts (1)
  • loginRedirect (3-9)
apps/dashboard/src/@/api/team/get-team.ts (1)
  • getTeams (58-73)
apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)
  • getYearInReview (19-59)
apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (3)
apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)
  • YearInReviewStats (8-13)
apps/dashboard/src/@/analytics/report.ts (1)
  • reportRewindViewed (715-722)
apps/dashboard/src/app/(app)/components/ThirdwebMiniLogo.tsx (1)
  • ThirdwebMiniLogo (7-90)
apps/dashboard/src/app/(app)/account/components/RewindBadge.tsx (2)
packages/thirdweb/src/react/web/adapters/WindowAdapter.ts (1)
  • open (14-17)
apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (1)
  • RewindModal (74-464)
apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)
apps/dashboard/src/@/api/analytics.ts (3)
  • getRpcUsageByType (563-568)
  • getEOAAndInAppWalletConnections (262-270)
  • getAggregateUserOpUsage (452-457)
⏰ 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). (8)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Unit Tests
  • GitHub Check: Build Packages
  • GitHub Check: Size
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
apps/dashboard/src/app/(app)/account/page.tsx (1)

9-9: LGTM!

The RewindModalClient import and placement are appropriate. Rendering the client component at the end of the server component ensures the modal overlay doesn't interfere with the main content layout, and the component properly handles its own visibility state via localStorage.

Also applies to: 53-54

apps/dashboard/src/app/(app)/account/layout.tsx (1)

81-84: LGTM!

The Rewind tab is appropriately positioned for discoverability. The configuration follows the existing pattern for tab links.

apps/dashboard/src/app/(app)/team/components/TeamHeader/TeamHeaderUI.tsx (1)

12-12: LGTM!

The RewindBadge placement mirrors AccountHeaderDesktopUI, maintaining consistency across the application's header components. Same note as AccountHeaderUI: consider adding to mobile for consistent UX.

Also applies to: 57-57

apps/dashboard/src/app/(app)/account/rewind/page.tsx (1)

3-3: The import from @workspace/ui/components/button is consistent with the established pattern throughout the apps/dashboard/src/app/ directory. While coding guidelines specify @/components/ui/*, the actual codebase standard used across dashboard app files is @workspace/ui/components/*. This file follows the prevailing import convention in the codebase.

Likely an incorrect or invalid review comment.

apps/dashboard/src/@/api/rewind/get-year-in-review.ts (3)

1-6: LGTM!

Proper use of "server-only" import and well-organized imports from @/api/analytics.


8-13: LGTM!

Clean type definition with clear field names.


144-145: Verified: getAggregateUserOpUsage does filter out testnets automatically during aggregation (it skips chainIds with testnet: true), so the "mainnet sponsored transactions" metric is accurate.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 31, 2025

size-limit report 📦

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

@vercel vercel bot temporarily deployed to Preview – wallet-ui December 31, 2025 13:07 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 December 31, 2025 13:07 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula December 31, 2025 13:07 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground December 31, 2025 13:07 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)/account/rewind/RewindModalClient.tsx (1)

15-28: Include displayYear in the dependency array for completeness.

While displayYear is a constant and won't change, React's exhaustive-deps rule recommends including all referenced values in the dependency array for consistency and to avoid potential issues if the code evolves.

🔎 Proposed fix
   useEffect(() => {
     const hasSeenRewind = localStorage.getItem(`rewind-seen-${displayYear}`);
     const shouldShowRewind =
       (currentMonth === 11 || currentMonth === 0) && !hasSeenRewind;

     if (shouldShowRewind) {
       // Small delay for better UX
       const timer = setTimeout(() => {
         setOpen(true);
       }, 1000);

       return () => clearTimeout(timer);
     }
-  }, [currentMonth]);
+  }, [currentMonth, displayYear]);
📜 Review details

Configuration used: Organization 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 d516022 and 21312f6.

📒 Files selected for processing (3)
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
  • apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/app/api/rewind/route.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{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/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
  • apps/dashboard/src/app/api/rewind/route.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/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
  • apps/dashboard/src/app/api/rewind/route.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/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
  • apps/dashboard/src/app/api/rewind/route.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/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
  • apps/dashboard/src/app/api/rewind/route.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/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
  • apps/dashboard/src/app/api/rewind/route.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/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
  • apps/dashboard/src/app/api/rewind/route.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/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
  • apps/dashboard/src/app/api/rewind/route.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx
  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
  • apps/dashboard/src/app/api/rewind/route.ts
apps/dashboard/**/api/**/*.{ts,tsx}

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

apps/dashboard/**/api/**/*.{ts,tsx}: Co-locate data helpers under @/api/** and mark them with "server-only" import
Always call getAuthToken() to get the JWT from cookies in server-side data fetching functions
Prefix server files with import "server-only"; so they never end up in the client bundle
Pass the JWT token in the Authorization: Bearer header in server-side fetches; never embed it in the URL
Return typed results (Project[], User[], etc.) from server-side data fetching functions; avoid any

Files:

  • apps/dashboard/src/@/api/rewind/get-year-in-review.ts
  • apps/dashboard/src/app/api/rewind/route.ts
🧬 Code graph analysis (3)
apps/dashboard/src/app/(app)/account/rewind/RewindModalClient.tsx (2)
packages/thirdweb/src/react/web/adapters/WindowAdapter.ts (1)
  • open (14-17)
apps/dashboard/src/app/(app)/account/rewind/RewindModal.tsx (1)
  • RewindModal (74-464)
apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)
apps/dashboard/src/@/api/analytics.ts (3)
  • getRpcUsageByType (563-568)
  • getEOAAndInAppWalletConnections (262-270)
  • getAggregateUserOpUsage (452-457)
apps/dashboard/src/app/api/rewind/route.ts (2)
apps/dashboard/src/@/api/team/get-team.ts (1)
  • getTeams (58-73)
apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)
  • getYearInReview (19-59)
⏰ 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). (8)
  • GitHub Check: Build Packages
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Size
  • GitHub Check: Lint Packages
  • GitHub Check: Unit Tests
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/dashboard/src/@/api/rewind/get-year-in-review.ts (1)

1-182: LGTM!

The implementation is well-structured with:

  • Proper "server-only" import to prevent client bundling
  • Comprehensive error handling with per-team try-catch blocks that prevent single team failures from affecting others
  • Consistent patterns across all three aggregation helpers
  • Type-safe return values with the exported YearInReviewStats type
  • Appropriate fallback behavior (returning 0) when data is unavailable

The previous issues regarding per-team error handling have been properly addressed.

Comment on lines +7 to +11
export async function GET(request: Request) {
const authToken = await getAuthToken();
if (!authToken) {
return NextResponse.redirect(new URL("/account/rewind", request.url));
}
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 | 🟠 Major

API routes should return HTTP status codes, not redirects.

Line 10 redirects unauthenticated requests to /account/rewind, but:

  1. This is a JSON API endpoint, and clients expect JSON responses (with appropriate status codes like 401), not HTML redirects.
  2. Redirecting to /account/rewind will likely fail since that page also requires authentication, creating confusion.
  3. API consumers (e.g., React Query in RewindModal) cannot follow redirects as intended.
🔎 Proposed fix
 export async function GET(request: Request) {
   const authToken = await getAuthToken();
   if (!authToken) {
-    return NextResponse.redirect(new URL("/account/rewind", request.url));
+    return NextResponse.json(
+      { error: "Unauthorized" },
+      { status: 401 }
+    );
   }
🤖 Prompt for AI Agents
In apps/dashboard/src/app/api/rewind/route.ts around lines 7 to 11, replace the
redirect for unauthenticated requests with a proper JSON response and HTTP
status code: detect missing authToken and return a 401 Unauthorized JSON
response (e.g., a small JSON body like { error: "Unauthorized" }) instead of
NextResponse.redirect, so API clients receive a machine-readable error and
correct status code.

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