Skip to content

Conversation

@0xFirekeeper
Copy link
Member

@0xFirekeeper 0xFirekeeper commented Nov 4, 2025

Reorganized wallet-related routes under a new sidebar structure, replacing legacy pages with redirects to new user, server, and sponsored gas wallet sections. Added new layout and overview/configuration pages for server wallets and sponsored gas, updated sidebar navigation to reflect new wallet grouping, and removed legacy Account Abstraction and Vault pages in favor of the new structure.


PR-Codex overview

This PR focuses on renaming "in-app wallets" to "user wallets" throughout the codebase, along with restructuring related components and pages. It also redirects old routes to new ones related to wallet functionalities.

Detailed summary

  • Renamed "In-App Wallets" to "User Wallets" in various components and files.
  • Deleted obsolete files related to "in-app wallets" and "account abstraction" settings.
  • Updated API error messages and descriptions.
  • Refactored wallet-related page routes for user wallets.
  • Introduced new components for managing user wallets and their configurations.
  • Enhanced UI elements for user wallet selection and management.
  • Adjusted sidebar links to reflect new wallet terminology and structure.

The following files were skipped due to too many changes: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx, apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/components/sms-country-select/utils.ts, apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/components/index.tsx

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

Summary by CodeRabbit

  • New Features

    • Added pages/layouts for Server Wallets, Sponsored Gas, and User Wallets (overview + configuration); key management, analytics, and account-abstraction flows updated.
    • New In-App/User Wallet settings UI: branding, image uploads, JWT/custom auth endpoint, SMS country selector, and SMS country data/utilities.
  • Navigation Updates

    • Sidebar reorganized to group wallet features; submenu detection and mobile trigger behavior improved.
  • Behavioral Changes

    • Several legacy pages now redirect to new wallet routes.
  • UX

    • Wallet tables: URL-driven pagination, page-size-aware ranges, clearer “Showing X–Y of Z” messaging; wording updated from “In-App” to “User”; announcement banner added.

@0xFirekeeper 0xFirekeeper requested review from a team as code owners November 4, 2025 22:37
@changeset-bot
Copy link

changeset-bot bot commented Nov 4, 2025

⚠️ No Changeset found

Latest commit: e19f7a2

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

@0xFirekeeper 0xFirekeeper added the DO NOT MERGE This pull request is still in progress and is not ready to be merged. label Nov 4, 2025
@vercel
Copy link

vercel bot commented Nov 4, 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 Nov 10, 2025 10:40pm
4 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
docs-v2 Skipped Skipped Nov 10, 2025 10:40pm
nebula Skipped Skipped Nov 10, 2025 10:40pm
thirdweb_playground Skipped Skipped Nov 10, 2025 10:40pm
wallet-ui Skipped Skipped Nov 10, 2025 10:40pm

@graphite-app
Copy link
Contributor

graphite-app bot commented Nov 4, 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.

@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Nov 4, 2025
@0xFirekeeper 0xFirekeeper changed the title Refactor wallet and sidebar routes, add new wallet pages [WIP] Refactor wallet and sidebar routes, add new wallet pages Nov 4, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

Walkthrough

Reworks wallet area into server-wallets, user-wallets, and sponsored-gas subtrees; adds gated layouts/pages (overview/configuration) and analytics; introduces SMS country utilities and CountrySelector; refactors sidebar link types and recursive submenu discovery; replaces several legacy pages with redirects and updates server-wallets pagination and related UI/copy.

Changes

Cohort / File(s) Summary
Sidebar & Navigation
apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx, apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
Exported ShadcnSidebarLink type; group variant links now recursive ShadcnSidebarLink[]; added recursive active-link resolution and internal findParentSubmenu; mobile trigger logic refactored; updated Wallets grouping, relabels, and footer links.
Legacy Redirects / Removed Pages
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/page.tsx, .../settings/account-abstraction/page.tsx, .../transactions/page.tsx, .../vault/page.tsx, apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/page.tsx
Replaced prior implementations with immediate redirects to new targets (e.g., sponsored-gas, server-wallets/configuration); removed prior data-fetching, client initialization, and UI composition.
Server Wallets (new)
.../wallets/server-wallets/layout.tsx, .../wallets/server-wallets/page.tsx, .../wallets/server-wallets/configuration/page.tsx
Added auth/project-gated layout with tabs; overview page implements vault/EOA/Solana analytics and ServerWalletsTable with URL-driven pagination; configuration renders KeyManagement; pages export dynamic where applicable.
User Wallets (new)
.../wallets/user-wallets/layout.tsx, .../wallets/user-wallets/page.tsx, .../wallets/user-wallets/configuration/page.tsx
Added auth/project-gated layout and overview (in‑app/user-wallet analytics and users); configuration renders InApp/User Wallet settings and pages export dynamic where applicable.
Sponsored Gas (new)
.../wallets/sponsored-gas/layout.tsx, .../wallets/sponsored-gas/page.tsx, .../wallets/sponsored-gas/configuration/page.tsx
Added auth/project-gated layout and overview (account-abstraction analytics, billing alert, summary); configuration renders Account Abstraction settings and factory sections.
In‑App / User Wallet Settings & Refactor
apps/dashboard/src/app/.../wallets/user-wallets/configuration/components/index.tsx, apps/dashboard/src/app/.../settings/wallets/components/index.tsx, .../settings/ProjectGeneralSettingsPage.tsx
Added InAppWalletSettingsPage and InAppWalletSettingsUI (branding, JWT/auth endpoint, redirect URLs, SMS config); removed one wrapper and made embeddedWalletService and client explicit props; updated settings links/paths and copy ("In-App Wallets" → "User Wallets").
SMS Country API & Country‑Select UI
apps/dashboard/src/app/.../wallets/user-wallets/configuration/api/sms.ts, .../components/sms-country-select/*
Added SMSCountryTiers type and server fetch getSMSCountryTiers with revalidate hint; added CountrySelector component and utilities: tierPricing, countryNames, countryPrefixes, getCountryFlag; added index re-exports.
Settings Cleanup (removed API)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/api/sms.ts
Removed older getSMSCountryTiers implementation (function deleted; type may remain).
Pagination / Server Wallets Table
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
Added client-side URL-driven pagination: pageSize prop, PaginationButtons, page query param handling via navigation hooks, and "Showing X–Y of Z" range display; updated pagination calculations and props.
Minor Cleanup & Copy/Link Updates
multiple files (project-page, tx-chart, Alerts, factories, SponsorshipPolicies, key-management, analytics logs, strings, stories, pricing, AnnouncementBanner, etc.)
Removed deprecated comment; adjusted EmptyChartContent target; updated copy (Account Abstraction → Gas Sponsorship; "In-App Wallets" → "User Wallets"); changed external link targets; added Vault learn-more link; small alignment/layout and log-message text changes; AnnouncementBanner now renders UI.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Router
    participant Layout as "Server Layout"
    participant Auth
    participant Project
    participant Client
    participant Page as "Server Page"

    User->>Router: GET /team/{team}/{project}/wallets/server-wallets
    Router->>Layout: load layout
    par concurrent
        Layout->>Auth: getAuthToken()
        Layout->>Project: getProject(team_slug, project_slug)
    end
    alt no auth
        Layout->>Router: loginRedirect(basePath)
    else no project
        Layout->>Router: redirect to /team/{team_slug}
    else auth + project
        Layout->>Client: init Thirdweb client(jwt, teamId)
        Client->>Page: render ProjectPage + tabs
        Page->>Page: fetch vault/EOA/Solana data
        Page->>Page: render ServerWalletsTable (URL-driven pagination)
    end
Loading
sequenceDiagram
    participant User
    participant Router
    participant Legacy as "Legacy Route"
    participant Redirect
    participant NewConfig as "New Config Page"
    participant Auth
    participant Project

    User->>Router: open legacy path (/vault or /settings/account-abstraction)
    Router->>Legacy: load module
    Legacy->>Redirect: immediate redirect to new path
    Redirect->>Router: navigate to new path
    Router->>NewConfig: load new config page
    NewConfig->>Auth: getAuthToken()
    NewConfig->>Project: getProject()
    NewConfig->>NewConfig: render settings UI or billing alert
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas to focus:
    • Sidebar recursion, exported ShadcnSidebarLink signature change, and correctness of findParentSubmenu and active-link recursion.
    • Auth/project gating and redirect logic across new layouts (server-wallets, user-wallets, sponsored-gas).
    • ServerWallets pagination URL handling, pageSize propagation, and edge cases when totals are unknown.
    • getSMSCountryTiers fetch error handling and CountrySelector selection/toggle semantics (indeterminate/partial states).
    • InApp/User Wallet settings: API surface changes requiring explicit embeddedWalletService and client at call sites.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.16% 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 PR title clearly describes the main change: reorganizing wallet routes and sidebar structure under a new grouping with subsections.
Description check ✅ Passed The description covers the main objectives, includes a detailed summary of changes, and aligns with the PR-Codex analysis of the modifications.
✨ 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 firekeeper/wallets-dashboard-revamp

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

@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2025

size-limit report 📦

Path Size
@thirdweb-dev/nexus (esm) 104.88 KB (0%)
@thirdweb-dev/nexus (cjs) 316.6 KB (0%)

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx (1)

121-159: Restore custom active matching for sidebar links

ShadcnSidebarBaseLink exposes an isActive hook so callers can override the matching logic. The new walk helper no longer consults that callback, so any link relying on custom matching (or non-prefix URLs) stops lighting up both in the sidebar and mobile trigger. Please wire the callback back in before falling back to the default comparisons.

-    function isActive(link: ShadcnSidebarBaseLink) {
-      if (link.exactMatch) {
-        return link.href === pathname;
-      }
-      return pathname?.startsWith(link.href);
-    }
+    function isActive(link: ShadcnSidebarBaseLink) {
+      const currentPath = pathname ?? "";
+      if (link.isActive) {
+        return link.isActive(currentPath);
+      }
+      if (link.exactMatch) {
+        return link.href === currentPath;
+      }
+      return currentPath.startsWith(link.href);
+    }
🧹 Nitpick comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx (1)

1-11: Clean redirect pattern, but consider adding server-only directive.

The refactor from a complex page to a simple redirect is well-executed and follows the pattern established in other wallet redirect pages in this PR. The target page (wallets/server-wallets/overview/page.tsx) properly handles the full implementation including authorization, data fetching, and UI rendering.

However, per coding guidelines, server components should start with import "server-only" to enforce server-side-only execution. This applies to all similar redirect pages in this PR (vault, account-abstraction, wallets, server-wallets).

Consider adding the directive at the top of the file:

+import "server-only";
+
 import { redirect } from "next/navigation";

Note: This same pattern should be applied to the other redirect pages in this PR for consistency with the coding guidelines.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/layout.tsx (1)

19-23: Consider using a constant or helper for the redirect path.

The hardcoded redirect path /team/${params.team_slug}/${params.project_slug}/wallets/user-wallets could be extracted to a constant or helper function to improve maintainability and reduce duplication if this path is used elsewhere in the wallets section.

@0xFirekeeper 0xFirekeeper changed the title [WIP] Refactor wallet and sidebar routes, add new wallet pages [Dashboard] New Project > Wallets product grouping and subsections Nov 10, 2025
@codecov
Copy link

codecov bot commented Nov 10, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 54.77%. Comparing base (c37af4f) to head (e19f7a2).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8359   +/-   ##
=======================================
  Coverage   54.77%   54.77%           
=======================================
  Files         919      919           
  Lines       60768    60768           
  Branches     4119     4119           
=======================================
  Hits        33284    33284           
  Misses      27382    27382           
  Partials      102      102           
Flag Coverage Δ
packages 54.77% <ø> (ø)
🚀 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: 1

🧹 Nitpick comments (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx (1)

118-118: Clarify variable name to reflect actual check.

The variable hasTransactions checks wallet count (wallets.length > 0), not transaction count. Consider renaming to hasWallets for clarity.

-  const hasTransactions = wallets.length > 0;
+  const hasWallets = wallets.length > 0;

And update line 133:

-        hasTransactions && !testTxWithWallet && !testSolanaTxWithWallet
+        hasWallets && !testTxWithWallet && !testSolanaTxWithWallet
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx (2)

88-119: Consider exposing a className prop for composability.

Per coding guidelines, dashboard components should expose a className prop on the root element for flexible styling and composition.

As per coding guidelines

 interface ServerWalletsTableProps {
   evmWallets: EVMWallet[];
   // ... other props
   authToken: string;
   pageSize: number;
+  className?: string;
 }

 export function ServerWalletsTable(props: ServerWalletsTableProps) {
   const {
     // ... destructure other props
     pageSize,
+    className,
   } = props;

   return (
-    <div>
+    <div className={className}>
       <div className="overflow-hidden rounded-xl border border-border bg-card">

368-381: Simplify pagination calculation logic.

The fallback logic with effectivePageSize and computedCount adds unnecessary complexity. Since pageSize is always provided from the interface, the fallbacks to currentCount are defensive but make the code harder to reason about.

Consider simplifying to:

-  const effectivePageSize = pageSize > 0 ? pageSize : currentCount;
-  const rangeStart =
-    totalRecords && effectivePageSize
-      ? Math.min((currentPage - 1) * effectivePageSize + 1, totalRecords)
-      : 0;
-  const computedCount = currentCount
-    ? currentCount
-    : totalRecords && effectivePageSize
-      ? Math.min(effectivePageSize, totalRecords - rangeStart + 1)
-      : 0;
-  const rangeEnd = totalRecords
-    ? Math.min(rangeStart + Math.max(computedCount - 1, 0), totalRecords)
-    : 0;
+  const rangeStart = totalRecords > 0
+    ? Math.min((currentPage - 1) * pageSize + 1, totalRecords)
+    : 0;
+  const rangeEnd = totalRecords > 0
+    ? Math.min(currentPage * pageSize, totalRecords)
+    : 0;
📜 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 2b13c3f and 26980ab.

📒 Files selected for processing (2)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx (6 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each 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
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from @/types where applicable
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query 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

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/_ (e.g., Button, Input, Tabs, Card)
Use NavLink for internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names with cn() from @/lib/utils for conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start with import "server-only"; use next/headers, server‑only env, heavy data fetching, and redirect() where appropriate
Client Components must start with 'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: call getAuthToken() from cookies, send Authorization: Bearer <token> header, and return typed results (avoid any)
Client-side data fetching: wrap calls in React Query with descriptive, stable queryKeys and set sensible staleTime/cacheTime (≥ 60s default); keep tokens secret via internal routes or server actions
Do not import posthog-js in server components (client-side only)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
apps/{dashboard,playground}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Expose a className prop on the root element of every component

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
🧠 Learnings (37)
📓 Common learnings
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : Unified `Wallet` and `Account` interfaces in wallet architecture
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : EIP-1193, EIP-5792, EIP-7702 standard support in wallet modules
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : Smart wallets with account abstraction
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : Support for in-app wallets (social/email login)
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Pages requiring fast transitions where data is prefetched on the client.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{ts,tsx} : Heavy data fetching that should not ship to the client (e.g. analytics, billing).

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-05-21T05:17:31.283Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/layout.tsx : Building layout shells (`layout.tsx`) and top-level pages that mainly assemble data.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Server Components must start with `import "server-only"`; use `next/headers`, server‑only env, heavy data fetching, and `redirect()` where appropriate

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Prefer API routes or server actions to keep tokens secret; the browser only sees relative paths.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Server Components (Node edge): Start files with `import "server-only";`

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-06-05T13:59:49.886Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7285
File: apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/uri-based-deploy.tsx:57-57
Timestamp: 2025-06-05T13:59:49.886Z
Learning: In the thirdweb dashboard Next.js app, when using loginRedirect() in server components, ensure to add a return statement after the redirect call to prevent further code execution and potential security issues.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-05-30T18:14:57.074Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7228
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/settings/page.tsx:23-25
Timestamp: 2025-05-30T18:14:57.074Z
Learning: In the dashboard codebase, the `loginRedirect` function performs an actual page redirect that automatically stops execution, similar to Next.js `redirect()`. No return statement is needed after calling `loginRedirect` as it handles flow control internally.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{ts,tsx} : Redirect logic using `redirect()` from `next/navigation`.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-06-18T02:13:34.500Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7364
File: apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx:36-41
Timestamp: 2025-06-18T02:13:34.500Z
Learning: In the logout flow in apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx, when `doLogout()` fails, the cleanup steps (resetAnalytics(), wallet disconnect, router refresh) should NOT execute. This is intentional to maintain consistency - if server-side logout fails, client-side cleanup should not occur.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-05-26T16:31:02.480Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx:43-49
Timestamp: 2025-05-26T16:31:02.480Z
Learning: In the thirdweb dashboard codebase, when `redirectToContractLandingPage()` is called, an explicit return statement is not required afterward because the function internally calls Next.js's `redirect()` which throws an error to halt execution.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Always call `getAuthToken()` to retrieve JWT from cookies on server side

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-06-24T21:37:26.869Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7434
File: apps/dashboard/src/app/(app)/team/~/~/contract/[chain]/[contractAddress]/page.tsx:40-42
Timestamp: 2025-06-24T21:37:26.869Z
Learning: MananTank confirmed that loginRedirect function calls Next.js redirect internally, so no return statement is needed after calling loginRedirect() as it handles flow control internally by throwing an exception.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Always call `getAuthToken()` to get the JWT from cookies.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Keep tokens secret via internal API routes or server actions

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Prefix files with `import "server-only";` so they never end up in the client bundle.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Co-locate data helpers under `@/api/**` and mark them with "server-only".

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-07T21:21:47.488Z
Learnt from: saminacodes
Repo: thirdweb-dev/js PR: 7543
File: apps/portal/src/app/pay/page.mdx:4-4
Timestamp: 2025-07-07T21:21:47.488Z
Learning: In the thirdweb-dev/js repository, lucide-react icons must be imported with the "Icon" suffix (e.g., ExternalLinkIcon, RocketIcon) as required by the new linting rule, contrary to the typical lucide-react convention of importing without the suffix.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-06-18T04:27:16.172Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7365
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx:16-17
Timestamp: 2025-06-18T04:27:16.172Z
Learning: Next.js Link component supports external URLs without throwing errors. When used with absolute URLs (like https://...), it behaves like a regular anchor tag without client-side routing, but does not cause runtime crashes or errors as previously believed.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use `NavLink` (`@/components/ui/NavLink`) for internal navigation so active states are handled automatically.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Use `NavLink` for internal navigation to get active state handling

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `NavLink` for internal navigation with automatic active states in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : When you need access to browser APIs (localStorage, window, IntersectionObserver etc.).

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-06-18T04:30:04.326Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7365
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx:16-17
Timestamp: 2025-06-18T04:30:04.326Z
Learning: Next.js Link component fully supports both internal and external URLs and works appropriately with all standard anchor attributes including target="_blank", rel="noopener noreferrer", etc. Using Link for external URLs is completely appropriate and recommended.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/_` (e.g., Button, Input, Tabs, Card)

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx
🧬 Code graph analysis (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx (4)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_THIRDWEB_VAULT_URL (4-5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/solana-wallets/wallet-table/types.ts (1)
  • SolanaWallet (1-11)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/analytics/analytics-page.tsx (1)
  • TransactionsAnalyticsPageContent (14-95)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx (1)
  • ServerWalletsTable (88-346)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx (1)
apps/dashboard/src/@/components/blocks/pagination-buttons.tsx (1)
  • PaginationButtons (18-221)
⏰ 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, vite)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/overview/page.tsx (4)

34-38: The authentication redirect is implemented correctly.

The past review comment claiming an infinite redirect loop is incorrect. The loginRedirect() function redirects to /login?next=${encodeURIComponent(path)}, not back to the same page, so unauthenticated users are properly sent to the login page with a return URL.


40-53: LGTM!

Concurrent fetching with appropriate error handling. The catch-and-check pattern for vaultClient and the redirect for missing projects are implemented correctly.


125-171: LGTM!

The rendering logic cleanly separates analytics content and wallet tables, with appropriate error handling for EVM wallet fetch failures.


1-14: Add "server-only" import directive.

Server components that perform heavy data fetching must begin with import "server-only"; to prevent accidental client-side bundling.

As per coding guidelines

Apply this diff:

+import "server-only";
+
 import { createVaultClient, listEoas } from "@thirdweb-dev/vault-sdk";
 import { redirect } from "next/navigation";
⛔ Skipped due to learnings
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Server Components must start with `import "server-only"`; use `next/headers`, server‑only env, heavy data fetching, and `redirect()` where appropriate
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Server Components (Node edge): Start files with `import "server-only";`
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7812
File: apps/dashboard/src/app/(app)/team/~/~project/[[...paths]]/page.tsx:1-11
Timestamp: 2025-08-07T17:24:31.965Z
Learning: In Next.js App Router, page components (page.tsx files) are server components by default and do not require the "server-only" import directive. The "server-only" directive is primarily used for utility functions, API helpers, and data access modules that should never be included in the client bundle.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Prefix files with `import "server-only";` so they never end up in the client bundle.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Do not import `posthog-js` in server components (client-side only)
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/*.client.tsx : Client components must start with `'use client';` before imports.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Prefer API routes or server actions to keep tokens secret; the browser only sees relative paths.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Co-locate data helpers under `@/api/**` and mark them with "server-only".
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Pages requiring fast transitions where data is prefetched on the client.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : When you need access to browser APIs (localStorage, window, IntersectionObserver etc.).
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx (3)

1-86: LGTM!

The imports and interface updates appropriately support the new URL-driven pagination with pageSize control.


331-340: LGTM!

The pagination component is conditionally rendered with appropriate props including the new pageSize parameter.


382-412: LGTM!

The URL parameter handling and pagination UI render correctly. Clean URL behavior (removing page=1) and proper range display formatting are well implemented.

@vercel vercel bot temporarily deployed to Preview – thirdweb_playground November 10, 2025 08:35 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula November 10, 2025 08:35 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui November 10, 2025 08:35 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 November 10, 2025 08:35 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: 0

🧹 Nitpick comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx (2)

71-71: Consider more descriptive variable naming.

The variable config is assigned props.embeddedWalletService but the name doesn't clearly convey what it contains. Consider using a more descriptive name like embeddedWalletConfig or keeping the original embeddedWalletService for clarity.

-  const config = props.embeddedWalletService;
+  const embeddedWalletConfig = props.embeddedWalletService;

Then update references throughout the function accordingly.


98-102: Extract duplicate SMS default countries to a constant.

The default SMS countries ["US", "CA"] appear in two locations (form initialization and SMS switch toggle). Extracting this to a named constant improves maintainability.

Add a constant near the top of the file:

const DEFAULT_SMS_COUNTRIES = ["US", "CA"] as const;

Then update both locations:

     smsEnabledCountryISOs: config.smsEnabledCountryISOs
       ? config.smsEnabledCountryISOs
       : canEditSmsCountries
-        ? ["US", "CA"]
+        ? DEFAULT_SMS_COUNTRIES
         : [],
           onCheckedChange: (checked) =>
             props.form.setValue(
               "smsEnabledCountryISOs",
               checked
-                ? // by default, enable US and CA only
-                  ["US", "CA"]
+                ? DEFAULT_SMS_COUNTRIES
                 : [],
             ),

Also applies to: 408-414

📜 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 26980ab and 7c757da.

📒 Files selected for processing (4)
  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/api/sms.ts (0 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/components/index.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/api/sms.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/components/index.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each 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
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from @/types where applicable
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size

Files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query 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

Files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/_ (e.g., Button, Input, Tabs, Card)
Use NavLink for internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names with cn() from @/lib/utils for conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start with import "server-only"; use next/headers, server‑only env, heavy data fetching, and redirect() where appropriate
Client Components must start with 'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: call getAuthToken() from cookies, send Authorization: Bearer <token> header, and return typed results (avoid any)
Client-side data fetching: wrap calls in React Query with descriptive, stable queryKeys and set sensible staleTime/cacheTime (≥ 60s default); keep tokens secret via internal routes or server actions
Do not import posthog-js in server components (client-side only)

Files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
apps/{dashboard,playground}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Expose a className prop on the root element of every component

Files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
🧠 Learnings (29)
📓 Common learnings
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : Unified `Wallet` and `Account` interfaces in wallet architecture
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : Support for in-app wallets (social/email login)
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : EIP-1193, EIP-5792, EIP-7702 standard support in wallet modules
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `NavLink` for internal navigation with automatic active states in dashboard and playground apps
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Prefer API routes or server actions to keep tokens secret; the browser only sees relative paths.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Pages requiring fast transitions where data is prefetched on the client.
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use `NavLink` (`@/components/ui/NavLink`) for internal navigation so active states are handled automatically.
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Layouts should reuse `SidebarLayout` / `FullWidthSidebarLayout` (`@/components/blocks/SidebarLayout`).

Applied to files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `NavLink` for internal navigation with automatic active states in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use `NavLink` (`@/components/ui/NavLink`) for internal navigation so active states are handled automatically.

Applied to files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/layout.tsx : Building layout shells (`layout.tsx`) and top-level pages that mainly assemble data.

Applied to files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Use `NavLink` for internal navigation to get active state handling

Applied to files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-08-07T20:43:21.864Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7812
File: apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/token-banner.tsx:48-60
Timestamp: 2025-08-07T20:43:21.864Z
Learning: In the TokenBanner component at apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/token-banner.tsx, the Link components use target="_blank" with internal application routes (starting with "/") to open pages in new tabs within the same application. These internal links do not require rel="noopener noreferrer" security attributes, which are only needed for external URLs.

Applied to files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/**/index.ts : Group related components in their own folder and expose a single barrel `index.ts` where necessary.

Applied to files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.

Applied to files:

  • apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/_` (e.g., Button, Input, Tabs, Card)

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-08-20T10:37:10.123Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/page.tsx:1-1
Timestamp: 2025-08-20T10:37:10.123Z
Learning: In apps/dashboard, prefer importing UI components from "workspace/ui/components/*" where possible, as per jnsdls preference, rather than from "@/components/ui/*".

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : For notices & skeletons rely on `AnnouncementBanner`, `GenericLoadingPage`, `EmptyStateCard`.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : Support for in-app wallets (social/email login)

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-10T10:18:33.238Z
Learnt from: arcoraven
Repo: thirdweb-dev/js PR: 7505
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx:186-204
Timestamp: 2025-07-10T10:18:33.238Z
Learning: The ThirdwebBarChart component in apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx does not accept standard accessibility props like `aria-label` and `role` in its TypeScript interface, causing compilation errors when added.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Use React Query (`tanstack/react-query`) for all client data fetching.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Wrap client-side data fetching calls in React Query (`tanstack/react-query`)

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Icons come from `lucide-react` or the project-specific `…/icons` exports – never embed raw SVG.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-06-10T15:59:29.585Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/_common/SocialUrls.tsx:24-25
Timestamp: 2025-06-10T15:59:29.585Z
Learning: In the SocialUrlsFieldset component in React Hook Form with TypeScript generics, when using useFieldArray with a generic form type T that extends WithSocialUrls, the type assertion `as unknown as UseFormReturn<WithSocialUrls>` is the preferred approach rather than trying to use `as keyof T`, because useFieldArray needs specific type information about the array field structure.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
Repo: thirdweb-dev/js PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Client Components must start with `'use client'`; handle interactivity with hooks and browser APIs

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
📚 Learning: 2025-05-26T16:28:50.772Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx:41-48
Timestamp: 2025-05-26T16:28:50.772Z
Learning: The `projectMeta` prop is not required for the server-rendered `ContractTokensPage` component in the tokens shared page, unlike some other shared pages where it's needed for consistency.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx
⏰ 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). (3)
  • GitHub Check: Size
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (6)
apps/dashboard/src/@/components/blocks/full-width-sidebar-layout.tsx (4)

41-53: LGTM! Clean type refactoring enables recursive nesting.

Exporting ShadcnSidebarLink and making the group variant recursive (links: ShadcnSidebarLink[]) properly supports nested sidebar structures while maintaining type safety.


100-116: LGTM! Mobile trigger correctly uses the new helper.

The refactoring to use findParentSubmenu cleanly extracts the parent-finding logic and properly handles the rendering condition.


131-159: LGTM! Recursive walk elegantly handles nested sidebar structures.

The refactored logic correctly handles all link variants:

  • Submenus: iterates flat sublinks
  • Base links: checks active state
  • Groups: recursively walks nested links
  • Separators: naturally skipped

The explicit return type and clear type guards maintain type safety throughout the recursion.


164-188: LGTM! Helper correctly identifies parent submenus in nested structures.

The recursive search properly distinguishes between submenu containers and groups, and the exact href match on line 174 is correct since activeHref is the link's own href property, not the current pathname.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx (2)

1-1: Correct use of client directive.

The "use client" directive is correctly placed at the top of the file, as this component uses hooks (useState, useForm, useMutation) and is interactive.


106-160: Excellent validation and error handling.

The form submission logic includes thorough validation for both custom JWT and auth endpoint configurations with clear, actionable error messages. The service mapping correctly preserves other services while updating only the embeddedWallets configuration.

@vercel vercel bot temporarily deployed to Preview – nebula November 10, 2025 18:38 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui November 10, 2025 18:38 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 November 10, 2025 18:38 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground November 10, 2025 18:38 Inactive
@graphite-app
Copy link
Contributor

graphite-app bot commented Nov 10, 2025

Merge activity

graphite-app bot pushed a commit that referenced this pull request Nov 10, 2025
…8359)

Reorganized wallet-related routes under a new sidebar structure, replacing legacy pages with redirects to new user, server, and sponsored gas wallet sections. Added new layout and overview/configuration pages for server wallets and sponsored gas, updated sidebar navigation to reflect new wallet grouping, and removed legacy Account Abstraction and Vault pages in favor of the new structure.

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on renaming "in-app wallets" to "user wallets" across the codebase and updating related functionality, including routing and UI components. It also includes the removal of deprecated components and the introduction of new configurations for user wallet management.

### Detailed summary
- Renamed "in-app wallets" to "user wallets" in various files.
- Updated API error messages to reflect the new terminology.
- Refactored routing paths for wallet configurations.
- Removed deprecated `ProjectSettingsBreadcrumb` component.
- Added new `CountrySelector` component for SMS country selection.
- Updated UI components to reflect changes in terminology and functionality.
- Removed old vault and account abstraction pages, redirecting to new paths.
- Introduced pagination for server wallets and user wallets tables.
- Enhanced error handling for API requests related to wallets.

> The following files were skipped due to too many changes: `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx`, `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/components/sms-country-select/utils.ts`, `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/components/index.tsx`

> ✨ 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**
  * Pages and layouts for Server Wallets, Sponsored Gas, and User Wallets (overview + configuration).
  * In-app wallet settings UI: branding, JWT/custom auth endpoint, image uploads, SMS country selector, and SMS country data/utilities.

* **Navigation Updates**
  * Sidebar reorganized to group wallet features; submenu discovery and mobile behavior improved.

* **Behavioral Changes**
  * Legacy analytics/settings pages replaced with redirects to new wallet routes.

* **UX**
  * Wallet tables: URL-driven pagination, page-size-aware ranges, and clearer “Showing X–Y of Z” messaging.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@graphite-app graphite-app bot force-pushed the firekeeper/wallets-dashboard-revamp branch from 7d6c8b5 to aa8e245 Compare November 10, 2025 22:23
@vercel vercel bot temporarily deployed to Preview – wallet-ui November 10, 2025 22:23 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 November 10, 2025 22:23 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula November 10, 2025 22:23 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground November 10, 2025 22:23 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/key-management.tsx (1)

10-18: Add explicit return type annotation.

Per the TypeScript guidelines, functions should have explicit return types. Add : JSX.Element to the function signature.

As per coding guidelines.

Apply this diff:

-export function KeyManagement({
+export function KeyManagement({
   maskedAdminKey,
   project,
   isManagedVault,
 }: {
   maskedAdminKey?: string;
   project: Project;
   isManagedVault: boolean;
-}) {
+}): JSX.Element {
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx (1)

43-68: Rename component and types to match "user wallets" terminology.

The PR renames "in-app wallets" to "user wallets" across the codebase, but this component and its types still use the InAppWallet prefix. This creates naming inconsistency that could confuse developers.

Additionally, the component lacks an explicit return type, which violates the TypeScript coding guidelines.

Apply this refactor to align naming and add explicit return type:

-type InAppWalletSettingsPageProps = {
+type UserWalletSettingsPageProps = {
   project: Project;
   teamId: string;
   teamSlug: string;
   teamPlan: Team["billingPlan"];
   smsCountryTiers: SMSCountryTiers;
   client: ThirdwebClient;
 };

 type UpdateAPIKeyTrackingData = {
   hasCustomBranding: boolean;
   hasCustomJwt: boolean;
   hasCustomAuthEndpoint: boolean;
 };

-export const InAppWalletSettingsUI: React.FC<
-  InAppWalletSettingsPageProps & {
+export const UserWalletSettingsUI: React.FC<
+  UserWalletSettingsPageProps & {
     updateApiKey: (
       projectValues: Partial<Project>,
       trackingData: UpdateAPIKeyTrackingData,
     ) => void;
     isUpdating: boolean;
     embeddedWalletService: ProjectEmbeddedWalletsService;
     client: ThirdwebClient;
   }
-> = (props) => {
+>: React.ReactElement = (props) => {

As per coding guidelines.

♻️ Duplicate comments (6)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx (2)

116-116: Use lowercase "user wallets" for consistency.

The error messages use "User Wallets" (capitalized), but other wallet configuration files use lowercase "user wallets". This inconsistency may confuse users.

Apply this diff for consistency:

-          "To use User Wallets with Custom JSON Web Token, provide JWKS URI and AUD.",
+          "To use user wallets with Custom JSON Web Token, provide JWKS URI and AUD.",

127-127: Use lowercase "user wallets" for consistency.

Similar to Line 116, use lowercase to match the convention in user-wallets configuration files.

Apply this diff:

-            "To use User Wallets with Custom Authentication Endpoint, provide a valid URL.",
+            "To use user wallets with Custom Authentication Endpoint, provide a valid URL.",
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/components/index.tsx (1)

60-91: Re-plumb updateApiKey so tracking data isn’t dropped.

InAppWalletSettingsUI still collects UpdateAPIKeyTrackingData, but handleUpdateProject only accepts projectValues, so the second argument passed at Line 228 is discarded. We again lose the analytics payload flagged in the earlier review. Please accept the tracking payload and thread it through the mutation so downstream instrumentation can use it.

-  const updateProject = useMutation({
-    mutationFn: async (projectValues: Partial<Project>) => {
-      await updateProjectClient(
-        {
-          projectId: props.project.id,
-          teamId: props.teamId,
-        },
-        projectValues,
-      );
-    },
-  });
-
-  function handleUpdateProject(projectValues: Partial<Project>) {
-    updateProject.mutate(projectValues, {
+  const updateProject = useMutation({
+    mutationFn: async (input: {
+      projectValues: Partial<Project>;
+      trackingData: UpdateAPIKeyTrackingData;
+    }) => {
+      await updateProjectClient(
+        {
+          projectId: props.project.id,
+          teamId: props.teamId,
+        },
+        input.projectValues,
+      );
+      return input.trackingData;
+    },
+  });
+
+  function handleUpdateProject(
+    projectValues: Partial<Project>,
+    trackingData: UpdateAPIKeyTrackingData,
+  ) {
+    updateProject.mutate(
+      { projectValues, trackingData },
+      {
         onError: (err) => {
           toast.error("Failed to update an API Key");
           console.error(err);
         },
-      onSuccess: () => {
-        toast.success("Configuration updated successfully");
-      },
-    });
+        onSuccess: (_, variables) => {
+          toast.success("Configuration updated successfully");
+          // TODO: forward variables?.trackingData to analytics
+        },
+      },
+    );
   }
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/sponsored-gas/page.tsx (1)

52-62: Anchor preset ranges once and validate custom inputs.

Calling getLastNDaysRange(rangeType) twice creates windows anchored to different “now” instants, and the custom branch still trusts searchParams.from/to even when they’re missing or invalid—exactly the issues raised previously. Please sanitize the custom bounds and reuse a single preset snapshot.

-  const range: Range = {
-    from:
-      rangeType === "custom"
-        ? searchParams.from
-        : getLastNDaysRange(rangeType).from,
-    to:
-      rangeType === "custom"
-        ? searchParams.to
-        : getLastNDaysRange(rangeType).to,
-    type: rangeType,
-  };
+  const fallbackRange = getLastNDaysRange("last-120");
+  const presetRange =
+    rangeType === "custom" ? undefined : getLastNDaysRange(rangeType);
+
+  const coerceDate = (value: unknown, fallback: Date) =>
+    value instanceof Date && !Number.isNaN(value.valueOf())
+      ? value
+      : fallback;
+
+  const range: Range =
+    rangeType === "custom"
+      ? {
+          from: coerceDate(searchParams.from, fallbackRange.from),
+          to: coerceDate(searchParams.to, fallbackRange.to),
+          type: rangeType,
+        }
+      : presetRange ?? fallbackRange;
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/page.tsx (2)

63-66: Clamp pagination params before calling Vault.

Number.parseInt on searchParams.page/solana_page will yield NaN for empty, malformed, or negative values. That flows into listEoas as page: NaN, causing Vault to reject the request—same problem as last time. Normalize the inputs and clamp them to ≥ 1.

-  const currentPage = Number.parseInt(searchParams.page ?? "1");
-  const solanaCurrentPage = Number.parseInt(searchParams.solana_page ?? "1");
+  const normalizePage = (value: string | string[] | undefined) => {
+    const raw = Array.isArray(value) ? value[0] : value;
+    const parsed = Number.parseInt(raw ?? "1", 10);
+    return Number.isNaN(parsed) || parsed < 1 ? 1 : parsed;
+  };
+
+  const currentPage = normalizePage(searchParams.page);
+  const solanaCurrentPage = normalizePage(searchParams.solana_page);

106-107: Guard .includes when message is undefined.

If solanaAccounts.error is null (happy path), solanaAccounts.error?.message resolves to undefined, and accessing .includes on it throws—exact regression already reported. Add optional chaining on message.

-  const isSolanaPermissionError =
-    solanaAccounts.error?.message.includes("AUTH_INSUFFICIENT_SCOPE") ?? false;
+  const isSolanaPermissionError =
+    solanaAccounts.error?.message?.includes("AUTH_INSUFFICIENT_SCOPE") ?? false;
🧹 Nitpick comments (4)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/vault/components/key-management.tsx (2)

1-1: Consider standardizing link component usage.

The file now uses two different approaches for external links:

  • UnderlineLink component (lines 64-70)
  • Link with className="underline" (line 106)

Both link to the same domain (portal.thirdweb.com) with identical attributes. Consider using the same component for consistency—either migrate line 106 to use UnderlineLink, or vice versa.

Also applies to: 64-70, 106-113


88-89: Consider removing async if not needed.

The CreateVaultAccountAlert function is declared as async but doesn't perform any asynchronous operations. If there's no specific reason for it to be async, consider simplifying it to a regular function.

Apply this diff if no async operations are planned:

-async function CreateVaultAccountAlert(props: { project: Project }) {
+function CreateVaultAccountAlert(props: { project: Project }): JSX.Element {
apps/dashboard/src/@/components/misc/AnnouncementBanner.tsx (1)

8-44: Consider adding explicit return types and className prop.

Per coding guidelines for TypeScript files in the dashboard:

  • Both AnnouncementBannerUI and AnnouncementBanner should declare explicit return types (e.g., JSX.Element | null)
  • AnnouncementBanner should expose a className prop on its root element for composability

Apply this diff to add return types:

-function AnnouncementBannerUI(props: {
+function AnnouncementBannerUI(props: {
   href: string;
   label: string;
   trackingLabel: string;
-}) {
+}): JSX.Element | null {
   const [hasDismissedAnnouncement, setHasDismissedAnnouncement] =
     useLocalStorage(`dismissed-${props.trackingLabel}`, false, true);

-export function AnnouncementBanner() {
+export function AnnouncementBanner(): JSX.Element {
   return (

For the className prop, you could optionally forward it to the root div in AnnouncementBannerUI:

-function AnnouncementBannerUI(props: {
+function AnnouncementBannerUI(props: {
   href: string;
   label: string;
   trackingLabel: string;
+  className?: string;
 }): JSX.Element | null {

-export function AnnouncementBanner() {
+export function AnnouncementBanner({ className }: { className?: string }): JSX.Element {
   return (
     <AnnouncementBannerUI
+      className={className}
       href="https://blog.thirdweb.com/changelog/project-view-update-wallets/"

As per coding guidelines.

Also applies to: 46-54

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/configuration/page.tsx (1)

33-39: Simplify the optional value assignment.

The maskedAdminKey is already string | undefined, so the nullish coalescing with undefined is redundant.

     <KeyManagement
-      maskedAdminKey={maskedAdminKey ?? undefined}
+      maskedAdminKey={maskedAdminKey}
       isManagedVault={isManagedVault}
       project={project}
     />

…8359)

Reorganized wallet-related routes under a new sidebar structure, replacing legacy pages with redirects to new user, server, and sponsored gas wallet sections. Added new layout and overview/configuration pages for server wallets and sponsored gas, updated sidebar navigation to reflect new wallet grouping, and removed legacy Account Abstraction and Vault pages in favor of the new structure.

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on renaming "in-app wallets" to "user wallets" throughout the application, along with restructuring related components, routes, and API calls. It also introduces new configurations and adjusts UI elements to reflect these changes.

### Detailed summary
- Renamed `in-app wallets` to `user wallets` in various components and texts.
- Deleted unused files related to `in-app wallets`.
- Updated API error messages to reflect the new terminology.
- Adjusted routing paths for user wallet configurations.
- Updated UI elements and titles to align with the new terminology.
- Refactored sidebar links to include new wallet types.
- Added new components for user wallet management.
- Implemented new pagination and analytics features for user wallets.

> The following files were skipped due to too many changes: `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/page.tsx`, `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/components/sms-country-select/utils.ts`, `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/user-wallets/configuration/components/index.tsx`

> ✨ 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**
  * Pages and layouts for Server Wallets, Sponsored Gas, and User Wallets (overview + configuration); key management and analytics pages added.
  * In-app/User wallet settings UI: branding, JWT/custom auth endpoint, image uploads, SMS country selector, and SMS country data/utilities.

* **Navigation Updates**
  * Sidebar reorganized to group wallet features; submenu discovery and mobile behavior improved.

* **Behavioral Changes**
  * Legacy analytics/settings pages replaced with redirects to new wallet routes.

* **UX**
  * Wallet tables: URL-driven pagination, page-size-aware ranges, clearer “Showing X–Y of Z” messaging; wording updated from “In-App” to “User” wallets; announcement banner added.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@graphite-app graphite-app bot force-pushed the firekeeper/wallets-dashboard-revamp branch from aa8e245 to e19f7a2 Compare November 10, 2025 22:32
@vercel vercel bot temporarily deployed to Preview – wallet-ui November 10, 2025 22:32 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula November 10, 2025 22:32 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 November 10, 2025 22:32 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground November 10, 2025 22:32 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

♻️ Duplicate comments (6)
apps/dashboard/src/@/api/analytics.ts (1)

187-187: Terminology mismatch between error message and code identifiers.

The error message references "user wallets" while the function name (getInAppWalletUsage), cache key (["getInAppWalletUsage"]), and return type (InAppWalletStats) still use "InAppWallet" terminology, creating inconsistency when debugging.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx (1)

116-116: Verify text capitalization consistency across wallet configuration components.

These error messages capitalize "User Wallets", which may be inconsistent with other wallet configuration components that use lowercase "user wallets".

This issue was previously flagged in an earlier review. Please ensure consistent capitalization across all wallet-related copy in this refactor.

Also applies to: 127-127

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/sponsored-gas/page.tsx (1)

52-62: Validate custom range dates and avoid time-window skew.

Two issues with the range construction:

  1. When rangeType is "custom", searchParams.from and searchParams.to may be undefined, resulting in undefined dates in the Range object that could cause runtime errors in getUserOpUsage.

  2. Calling getLastNDaysRange(rangeType) separately for from and to can cause a time-window skew if the request straddles midnight, as each call uses new Date() independently.

Apply this diff to fix both issues:

  const interval = searchParams.interval ?? "week";
  const rangeType = searchParams.range || "last-120";

- const range: Range = {
-   from:
-     rangeType === "custom"
-       ? searchParams.from
-       : getLastNDaysRange(rangeType).from,
-   to:
-     rangeType === "custom"
-       ? searchParams.to
-       : getLastNDaysRange(rangeType).to,
-   type: rangeType,
- };
+ const range: Range =
+   rangeType === "custom"
+     ? {
+         from: searchParams.from ?? new Date(),
+         to: searchParams.to ?? new Date(),
+         type: rangeType,
+       }
+     : getLastNDaysRange(rangeType);
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/page.tsx (2)

63-66: Normalize pagination params to prevent NaN.

Number.parseInt returns NaN for invalid inputs like ?page= or ?page=foo, which flows into listEoas as page: NaN. This serializes to null and causes 400 errors from the Vault API, breaking the page on malformed query strings.

Apply this diff to normalize invalid values:

+ const normalizePage = (value: string | undefined) => {
+   const parsed = Number.parseInt(value ?? "1", 10);
+   return Number.isNaN(parsed) || parsed < 1 ? 1 : parsed;
+ };
+
- const currentPage = Number.parseInt(searchParams.page ?? "1");
- const solanaCurrentPage = Number.parseInt(searchParams.solana_page ?? "1");
+ const currentPage = normalizePage(searchParams.page);
+ const solanaCurrentPage = normalizePage(searchParams.solana_page);

106-107: Guard .includes on optional error message.

When solanaAccounts.error exists but message is undefined, the .includes call will throw a runtime error and crash the page. Add optional chaining on message.

Apply this diff:

  const isSolanaPermissionError =
-   solanaAccounts.error?.message.includes("AUTH_INSUFFICIENT_SCOPE") ?? false;
+   solanaAccounts.error?.message?.includes("AUTH_INSUFFICIENT_SCOPE") ?? false;
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/sponsored-gas/layout.tsx (1)

1-8: Add server-only directive per coding guidelines.

This layout file should include import "server-only"; at the top to guarantee it stays on the server, as specified in the coding guidelines for server components in the dashboard.

As per coding guidelines.

Apply this diff:

+import "server-only";
+
 import { redirect } from "next/navigation";

Note: Past review flagged this, and it aligns with coding guidelines, though I observe related layout files in the codebase may not consistently include it. Consider applying this pattern consistently across all layout files.

🧹 Nitpick comments (6)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/analytics/chart/index.tsx (1)

24-24: Simplify the redundant phrasing.

The description "active user wallet users" repeats "user" twice, making it awkward. Consider rephrasing for clarity.

Suggested alternatives:

-      description="The total number of active user wallet users on your project."
+      description="The total number of active users with user wallets on your project."

or

-      description="The total number of active user wallet users on your project."
+      description="The total number of unique user wallets on your project."
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/account-abstraction/page.tsx (1)

1-1: Consider adding server-only import per coding guidelines.

The coding guidelines specify that server components should begin with import "server-only"; to catch accidental client-side imports at build time. While not critical and not consistently applied across similar files, it's a recommended safeguard.

Apply this diff to add the import:

+import "server-only";
 import { redirect } from "next/navigation";
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/wallets/components/index.tsx (1)

58-68: Add className prop to component signature.

The component should expose a className prop and forward it to the root <Form> element to allow consumers to apply custom styling.

Apply this diff to add the className prop:

 export const InAppWalletSettingsUI: React.FC<
   InAppWalletSettingsPageProps & {
     updateApiKey: (
       projectValues: Partial<Project>,
       trackingData: UpdateAPIKeyTrackingData,
     ) => void;
     isUpdating: boolean;
     embeddedWalletService: ProjectEmbeddedWalletsService;
     client: ThirdwebClient;
+    className?: string;
   }
 > = (props) => {

Then update the Form element at line 163:

-    <Form {...form}>
+    <Form {...form} className={props.className}>

As per coding guidelines.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx (1)

23-26: Consider exposing className prop for composition.

Per the coding guidelines for dashboard components, consider forwarding a className prop to enable consumers to customize the layout styling.

As per coding guidelines

Apply this diff:

 export function ProjectSidebarLayout(props: {
   layoutPath: string;
   children: React.ReactNode;
+  className?: string;
 }) {

And update the return statement to forward it:

   return (
     <FullWidthSidebarLayout
+      className={props.className}
       contentSidebarLinks={contentSidebarLinks}
       footerSidebarLinks={footerSidebarLinks}
     >
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/components/server-wallets-table.client.tsx (1)

368-380: Simplify pagination calculation logic.

The pagination range calculation is overly complex with defensive fallbacks that may never execute. Since currentCount is always provided as wallets.length (line 335), the fallback logic in computedCount (lines 375-377) is unreachable. Additionally, the effectivePageSize fallback using currentCount doesn't make semantic sense if pageSize is invalid.

Consider simplifying to:

-  const effectivePageSize = pageSize > 0 ? pageSize : currentCount;
-  const rangeStart =
-    totalRecords && effectivePageSize
-      ? Math.min((currentPage - 1) * effectivePageSize + 1, totalRecords)
-      : 0;
-  const computedCount = currentCount
-    ? currentCount
-    : totalRecords && effectivePageSize
-      ? Math.min(effectivePageSize, totalRecords - rangeStart + 1)
-      : 0;
-  const rangeEnd = totalRecords
-    ? Math.min(rangeStart + Math.max(computedCount - 1, 0), totalRecords)
-    : 0;
+  const rangeStart = totalRecords > 0
+    ? Math.min((currentPage - 1) * pageSize + 1, totalRecords)
+    : 0;
+  const rangeEnd = totalRecords > 0
+    ? Math.min(rangeStart + currentCount - 1, totalRecords)
+    : 0;

This removes unused fallback paths and makes the logic clearer.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/wallets/server-wallets/page.tsx (1)

51-53: Improve error handling for Vault connection failure.

Returning a plain <div> with an error message breaks the expected page structure and doesn't provide a way for users to retry or get help. Consider using a proper error component with recovery options.

Replace with a proper error UI:

  if (!vaultClient) {
-   return <div>Error: Failed to connect to Vault</div>;
+   return (
+     <Alert variant="destructive">
+       <CircleAlertIcon className="size-5" />
+       <AlertTitle>Vault Connection Error</AlertTitle>
+       <AlertDescription>
+         Failed to connect to the Vault service. Please try refreshing the page
+         or contact support if the issue persists.
+       </AlertDescription>
+     </Alert>
+   );
  }

You'll need to add the import:

import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { CircleAlertIcon } from "lucide-react";

icon: RssIcon,
label: "RPC",
},
// linkely want to move this to `team` level eventually
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

Fix typo in comment.

"linkely" should be "likely".

Apply this diff:

-        // linkely want to move this to `team` level eventually
+        // likely want to move this to `team` level eventually
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// linkely want to move this to `team` level eventually
// likely want to move this to `team` level eventually
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
around line 111, fix the typo in the inline comment: change "linkely" to
"likely" so the comment reads "likely want to move this to `team` level
eventually".

@graphite-app graphite-app bot merged commit e19f7a2 into main Nov 10, 2025
24 checks passed
@graphite-app graphite-app bot deleted the firekeeper/wallets-dashboard-revamp branch November 10, 2025 22:42
@vercel vercel bot temporarily deployed to Production – thirdweb_playground November 10, 2025 22:42 Inactive
@vercel vercel bot temporarily deployed to Production – nebula November 10, 2025 22:42 Inactive
@vercel vercel bot temporarily deployed to Production – docs-v2 November 10, 2025 22:42 Inactive
@vercel vercel bot temporarily deployed to Production – wallet-ui November 10, 2025 22:42 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. DO NOT MERGE This pull request is still in progress and is not ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants