Skip to content

Conversation

@MananTank
Copy link
Member

@MananTank MananTank commented Oct 17, 2025


PR-Codex overview

This PR focuses on refactoring the BuyAndSwapEmbed component to improve its structure and functionality. It introduces new props for handling buy and swap operations, enhances type safety, and removes deprecated code, ensuring a more efficient and organized codebase.

Detailed summary

  • Deleted constants.ts and an unused image file.
  • Updated BuyAndSwapEmbed to accept buyTab and swapTab props for better token handling.
  • Refactored UniversalBridgeEmbed to use the new props structure.
  • Introduced generateTokenPairSlugs and getTokenPairData functions for improved token pair management.
  • Simplified BridgePageUI to utilize the new BuyAndSwapEmbed structure.
  • Enhanced metadata generation for the bridge page.
  • Removed unused imports and components to streamline the code.

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

Summary by CodeRabbit

  • New Features

    • Added Bridge UI and dedicated token-pair pages with static routes, metadata, and token-pair utilities for cross-chain slugs.
    • Introduced a Bridge page UI with FAQ, data summary, and an embedded universal bridge widget.
  • Improvements

    • Unified buy/sell input structure for embeds and prefills; embeds now consume structured buyTab/swapTab data.
    • Improved chain/token handling and reporting; removed legacy testnet flag usage.
  • Refactor

    • Simplified bridge page rendering by delegating UI to a shared BridgePageUI.
  • Chores

    • Removed legacy bridge client initialization and related wiring.

@linear
Copy link

linear bot commented Oct 17, 2025

@changeset-bot
Copy link

changeset-bot bot commented Oct 17, 2025

⚠️ No Changeset found

Latest commit: b1a7808

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

This PR includes no changesets

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

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

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

@vercel
Copy link

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

💡 Enable Vercel Agent with $100 free credit for automated AI reviews

@vercel vercel bot temporarily deployed to Preview – wallet-ui October 17, 2025 22:24 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground October 17, 2025 22:24 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula October 17, 2025 22:24 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 October 17, 2025 22:24 Inactive
@MananTank MananTank marked this pull request as ready for review October 17, 2025 22:24
@MananTank MananTank requested review from a team as code owners October 17, 2025 22:24
@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Oct 17, 2025
Copy link
Member Author

MananTank commented Oct 17, 2025


How to use the Graphite Merge Queue

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

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

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

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

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

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 17, 2025

Walkthrough

Replace flat buy/sell props with structured buyTab/swapTab objects across embeds and callers, add BridgePageUI and dynamic bridge token-pair pages (slug utilities + static route generation), and remove bridge Thirdweb client wiring from bridge constants.

Changes

Cohort / File(s) Summary
BuyAndSwap API & Internal
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
New exported BuyAndSwapEmbedProps type; replaced flat props (chain, tokenAddress, buyAmount, isTestnet) with structured buyTab and swapTab. Chain/token/amount now derived from buyTab/swapTab; handlers (onError/onCancel/onSuccess) compute guarded buyChainId; removed isTestnet.
Local buy callsites
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx, apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
Updated callsites to pass buyTab/swapTab objects (often using NATIVE_TOKEN_ADDRESS and chainId); removed prior direct chain, tokenAddress, buyAmount, and isTestnet args.
Universal bridge embed
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
Public API changed from { chainId?, token?, amount? } to { buyTab?, swapTab? }; removed internal chain/testnet resolution and forwards buyTab/swapTab to BuyAndSwapEmbed.
Bridge UI component
apps/dashboard/src/app/bridge/components/bridge-page.tsx
Added BridgePageUI component rendering header, dots background, UniversalBridgeEmbed (wired to buyTab/swapTab), data pills, and FAQ content; exports BridgePageUI.
Bridge top-level page
apps/dashboard/src/app/bridge/page.tsx
Replaced server-heavy BridgePage with plain Page that renders BridgePageUI (title prop) and removed prior searchParams/data-fetching and auxiliary UI composition.
Token-pair routing & utilities
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx, apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
Added dynamic token-pair page with generateStaticParams, generateMetadata, runtime Page that resolves token/chain metadata and renders BridgePageUI. New slug-map.ts provides getTokenPairData(slug) and generateTokenPairSlugs() for static route generation.
Bridge constants removal
apps/dashboard/src/app/bridge/constants.ts
Removed bridge Thirdweb client wiring and exported bridgeAppThirdwebClient (deleted client setup and environment-based logic).

Sequence Diagram(s)

sequenceDiagram
    participant StaticGen as Next build
    participant SlugMap as slug-map.ts
    participant PageBuild as [token-pair]/page.tsx (generateMetadata)
    participant TokenAPI as Token metadata source

    rect rgb(235,245,255)
      Note over StaticGen,SlugMap: Build-time static params
      StaticGen->>SlugMap: generateTokenPairSlugs()
      SlugMap-->>StaticGen: list of route slugs
    end

    rect rgb(235,245,255)
      Note over PageBuild,TokenAPI: Build-time metadata resolution
      PageBuild->>SlugMap: getTokenPairData(slug)
      SlugMap-->>PageBuild: TokenPairData
      PageBuild->>TokenAPI: fetch token metadata
      TokenAPI-->>PageBuild: token metadata -> Next.js metadata
    end
Loading
sequenceDiagram
    participant Caller as Page/Component
    participant BridgeUI as BridgePageUI
    participant UniversalEmbed as UniversalBridgeEmbed
    participant BuySwap as BuyAndSwapEmbed

    Caller->>BridgeUI: render(title, buyTab?, swapTab?)
    BridgeUI->>UniversalEmbed: pass buyTab/swapTab
    UniversalEmbed->>BuySwap: forward buyTab/swapTab
    BuySwap->>BuySwap: derive chainId / tokenAddress / amount (guards) and handle events
    BuySwap-->>Caller: embedded UI rendered
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "[MNY-274] Dashboard: Generate swap token pages for popular tokens" directly aligns with the main objective described in linked issue MNY-274, which is to generate token-pair pages for bridge to improve SEO. The title is specific and concise, clearly communicating the primary change: creating dynamic pages for popular token swap pairs. The title accurately reflects the core implementation work of introducing token-pair page generation infrastructure and new page routes like /bridge/exchange/[token-pair].
Linked Issues Check ✅ Passed The code changes directly implement the core objective of MNY-274: generating token-pair pages for bridge to improve SEO. The PR introduces key infrastructure including generateTokenPairSlugs() and getTokenPairData() functions in slug-map.ts for token pair enumeration and lookup, a new dynamic page at /bridge/exchange/[token-pair]/page.tsx with generateStaticParams() for static route generation, and generateMetadata() for SEO-friendly page metadata. The BuyAndSwapEmbed component refactoring supports the new buy/swap tab structure needed for displaying different token-pair configurations. All component updates (BuyFundsSection, erc20.tsx, UniversalBridgeEmbed, BridgePageUI) are aligned with routing token-pair data through the application to render appropriate pages for queries like "swap ETH for USDT."
Out of Scope Changes Check ✅ Passed The changes are primarily focused on generating token-pair pages as required by MNY-274. The refactoring of BuyAndSwapEmbed, updates to component consumers (BuyFundsSection, erc20.tsx), creation of new bridge infrastructure (slug-map.ts, dynamic page generation), and UI component restructuring are all directly related to implementing the token-pair page generation feature. The removal of bridgeAppThirdwebClient from constants.ts and unused assets appears to be cleanup of code that was no longer needed after the infrastructure refactoring, which is supporting work aligned with the overall refactoring effort.
Description Check ✅ Passed The PR description follows the required template format with the title in the correct "[MNY-274] Dashboard:" format. While the "Notes for the reviewer" and "How to test" sections are not explicitly populated (containing only template placeholders), the description includes a comprehensive PR-Codex overview that summarizes the key changes: the BuyAndSwapEmbed component refactoring, new token pair management functions, UI component updates, and code cleanup. This provides sufficient context about the changes, even though the optional reviewer notes and testing guidance sections lack detail.
✨ 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 mny-274

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

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

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

@codecov
Copy link

codecov bot commented Oct 17, 2025

Codecov Report

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

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8278   +/-   ##
=======================================
  Coverage   54.89%   54.89%           
=======================================
  Files         919      919           
  Lines       60622    60622           
  Branches     4126     4126           
=======================================
  Hits        33278    33278           
  Misses      27242    27242           
  Partials      102      102           
Flag Coverage Δ
packages 54.89% <ø> (ø)
🚀 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.

@vercel vercel bot temporarily deployed to Preview – wallet-ui October 17, 2025 22:27 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 October 17, 2025 22:27 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula October 17, 2025 22:27 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground October 17, 2025 22:27 Inactive
@github-actions
Copy link
Contributor

github-actions bot commented Oct 17, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.51 KB (0%) 1.3 s (0%) 162 ms (+229.8% 🔺) 1.5 s
thirdweb (cjs) 365.68 KB (0%) 7.4 s (0%) 534 ms (+2.02% 🔺) 7.9 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 45 ms (+1966.36% 🔺) 160 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 40 ms (+933.45% 🔺) 51 ms
thirdweb/react (minimal + tree-shaking) 19.13 KB (0%) 383 ms (0%) 45 ms (+1550.75% 🔺) 427 ms

@vercel vercel bot temporarily deployed to Preview – nebula October 17, 2025 22:33 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui October 17, 2025 22:33 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 October 17, 2025 22:33 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground October 17, 2025 22:33 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: 9

🧹 Nitpick comments (7)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)

17-39: Prop unification looks good; consider extracting wallet list.

The new buy/sell shape aligns with BuyAndSwapEmbed. Extract bridgeWallets to a small shared module (no "use client") so both header and embed can import without pulling a client module into server code paths.

apps/dashboard/src/app/bridge/components/bridge-page.tsx (2)

1-1: Unify cn import to project-standard path.

Import cn from "@/lib/utils" for consistency with our dashboard guidelines. As per coding guidelines.


25-28: Reuse shared DotsBackgroundPattern; remove local duplicate.

We already expose a DotsBackgroundPattern in "@/components/ui/background-patterns". Import and use it, then delete the local implementation to avoid drift.

-import { cn } from "@workspace/ui/lib/utils";
+import { cn } from "@/lib/utils";
+import { DotsBackgroundPattern } from "@/components/ui/background-patterns";
@@
-      <div className="flex grow items-center justify-center px-4 relative pt-12 pb-20 lg:py-28 min-h-[calc(100dvh-60px)]">
-        <DotsBackgroundPattern />
+      <div className="flex grow items-center justify-center px-4 relative pt-12 pb-20 lg:py-28 min-h-[calc(100dvh-60px)]">
+        <DotsBackgroundPattern className="-inset-x-36 -inset-y-24 hidden lg:block text-foreground/20 dark:text-muted-foreground/20" />
         <UniversalBridgeEmbed buy={props.buy} sell={props.sell} />
       </div>
@@
-function DotsBackgroundPattern(props: { className?: string }) {
-  return (
-    <div
-      className={cn(
-        "pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block",
-        props.className,
-      )}
-      style={{
-        backgroundImage: "radial-gradient(currentColor 1px, transparent 1px)",
-        backgroundSize: "24px 24px",
-        maskImage:
-          "radial-gradient(ellipse 100% 100% at 50% 50%, black 30%, transparent 50%)",
-      }}
-    />
-  );
-}
+// removed local DotsBackgroundPattern in favor of shared component

Also applies to: 60-66, 68-83

apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (2)

18-22: Constrain static generation to a curated set (avoid explosion).

generateStaticParams over all tokens can explode build time/size. Start with a curated list (top queries), and fallback dynamic for the rest, or paginate the static set.


87-93: Deduplicate cleanedChainName; import shared util instead.

We already have a cleanedChainName in packages/thirdweb (swap-widget/utils). Reuse it or extract a small shared util in the dashboard to avoid divergence.

apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)

123-123: Add explicit return type annotation.

The function should explicitly declare its return type for better type safety and documentation.

Apply this diff:

-export function generateTokenPairSlugs() {
+export function generateTokenPairSlugs(): string[] {
   const tokenIds = Object.keys(tokens);
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)

116-125: Consider extracting buyChainId resolution.

The same buyChainId extraction pattern is repeated in three callbacks (onError, onCancel, onSuccess). Consider extracting this to a helper function to reduce duplication.

Example helper function to add above the component:

function extractBuyChainId(quote: { type: string; intent: any } | undefined): number | undefined {
  return quote?.type === "buy"
    ? quote.intent.destinationChainId
    : quote?.type === "onramp"
      ? quote.intent.chainId
      : undefined;
}

Then use it in the callbacks:

-  const buyChainId =
-    quote?.type === "buy"
-      ? quote.intent.destinationChainId
-      : quote?.type === "onramp"
-        ? quote.intent.chainId
-        : undefined;
+  const buyChainId = extractBuyChainId(quote);

Also applies to: 149-158, 181-190

📜 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 9bb65ad and 79b9a44.

⛔ Files ignored due to path filters (1)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/opengraph-image.png is excluded by !**/*.png
📒 Files selected for processing (8)
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (8 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1 hunks)
  • apps/dashboard/src/app/bridge/page.tsx (2 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/bridge/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.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/bridge/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.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/bridge/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.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/bridge/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.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/bridge/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
🧠 Learnings (1)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#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/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
🧬 Code graph analysis (7)
apps/dashboard/src/app/bridge/page.tsx (2)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1)
  • Page (53-85)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
  • BridgePageUI (6-39)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx (3)
apps/dashboard/src/@/components/blocks/grid-pattern-embed-container.tsx (1)
  • GridPatternEmbedContainer (3-23)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
  • BuyAndSwapEmbed (35-277)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • NATIVE_TOKEN_ADDRESS (31-31)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (4)
apps/dashboard/src/app/bridge/components/header.tsx (1)
  • BridgePageHeader (14-68)
apps/dashboard/src/@/components/ui/background-patterns.tsx (1)
  • DotsBackgroundPattern (4-19)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
  • UniversalBridgeEmbed (17-41)
apps/dashboard/src/@/components/blocks/faq-section.tsx (1)
  • FaqAccordion (8-23)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (4)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)
  • generateTokenPairSlugs (123-150)
  • getTokenPairData (72-89)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
  • BridgePageUI (6-39)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts (1)
  • cleanedChainName (1-3)
apps/dashboard/src/@/constants/thirdweb-client.server.ts (1)
  • serverThirdwebClient (8-11)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
apps/dashboard/src/@/analytics/report.ts (3)
  • reportTokenBuyFailed (264-266)
  • reportTokenBuyCancelled (276-278)
  • reportTokenBuySuccessful (252-254)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • NATIVE_TOKEN_ADDRESS (31-31)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
  • BuyAndSwapEmbed (35-277)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Unit Tests
  • GitHub Check: Build Packages
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
apps/dashboard/src/app/bridge/page.tsx (1)

17-27: LGTM on simplified Bridge page.

Clean wrapper around BridgePageUI; metadata is consistent with copy.

apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1)

53-55: Verify Next.js params-as-Promise pattern.

Typing params as Promise and awaiting it is non-standard in many routes. Confirm this is intended for your Next version/setup; otherwise switch to { params }: { params: Params } and drop await.

Also applies to: 24-31

apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)

1-10: LGTM: Clean type definitions.

The import and type structure appropriately supports both native and ERC20 tokens with proper undefined guards.


91-121: LGTM: Proper token resolution with guards.

The helper correctly handles both native tokens (single slug) and ERC20 tokens (hyphenated slug) with appropriate undefined guards.

apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)

36-52: LGTM: Clean prop structure refactor.

The new buy/sell object structure provides better clarity and separation of concerns compared to the previous flat props.


100-104: LGTM: Proper optional handling.

The chain and amount extraction correctly uses optional chaining with sensible defaults.


230-242: LGTM: Prefill logic correctly updated.

The SwapWidget prefill properly maps the new buy/sell structure to the expected format with appropriate optional handling.

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 (4)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)

213-213: Avoid unsafe tokenAddress cast; validate or omit.

Casting may pass malformed/native addresses to BuyWidget.

- tokenAddress={props.buy?.tokenAddress as `0x${string}` | undefined}
+ tokenAddress={
+   props.buy?.tokenAddress && props.buy.tokenAddress.startsWith("0x")
+     ? (props.buy.tokenAddress as `0x${string}`)
+     : undefined
+ }

Optionally add a small isHexAddress helper or reuse a shared validator.


139-145: Derive is_testnet from chainId (don’t hardcode false).

Hardcoding corrupts analytics on testnets. Compute once and reuse.

+// near top-level (after imports)
+const TESTNET_CHAIN_IDS = new Set<number>([
+  5,        // Goerli
+  11155111, // Sepolia
+  80001,    // Polygon Mumbai
+  84531,    // Base Goerli
+  421613,   // Arbitrum Goerli
+  43113,    // Avalanche Fuji
+  97,       // BSC Testnet
+]);
+
@@
   reportAssetBuyFailed({
     assetType: "coin",
     chainId: buyChainId,
     error: errorMessage,
     contractType: undefined,
-    is_testnet: false,
+    is_testnet: TESTNET_CHAIN_IDS.has(buyChainId),
   });
@@
   reportAssetBuyCancelled({
     assetType: "coin",
     chainId: buyChainId,
     contractType: undefined,
-    is_testnet: false,
+    is_testnet: TESTNET_CHAIN_IDS.has(buyChainId),
   });
@@
   reportAssetBuySuccessful({
     assetType: "coin",
     chainId: buyChainId,
     contractType: undefined,
-    is_testnet: false,
+    is_testnet: TESTNET_CHAIN_IDS.has(buyChainId),
   });

Alternatively, centralize this in a shared util. Based on learnings.

Also applies to: 171-177, 204-209

apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (2)

63-72: Fix buy/sell inversion to match “from → to”.

For route “X-to-Y”: sell must be X (origin), buy must be Y (destination). Currently inverted.

       <BridgePageUI
-      buy={{
-        tokenAddress: fromToken.address,
-        chainId: fromToken.chainId,
-      }}
-      sell={{
-        tokenAddress: toToken.address,
-        chainId: toToken.chainId,
-      }}
+      buy={{
+        tokenAddress: toToken.address,
+        chainId: toToken.chainId,
+      }}
+      sell={{
+        tokenAddress: fromToken.address,
+        chainId: fromToken.chainId,
+      }}

95-101: Fix reversed slug parsing and remove debug log.

The bug is confirmed: getTokenPairData assigns reversed variable names—const [toSlug, fromSlug] should be const [fromSlug, toSlug]. Since URL format is {fromSlug}-to-{toSlug}, the current split swaps origin and destination. The code in page.tsx does not compensate for this inversion; swapped data flows directly through, causing incorrect token pair routing.

In apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts:

- const [toSlug, fromSlug] = slug.split("-to-");
+ const [fromSlug, toSlug] = slug.split("-to-");
- console.log("routeSlugs", routeSlugs);
🧹 Nitpick comments (7)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)

17-32: Add explicit return type and keep prop shape in sync with BuyAndSwapEmbed.

Annotate the component’s return type to satisfy our TS guideline and reduce drift.

Apply:

-export function UniversalBridgeEmbed(props: {
+export function UniversalBridgeEmbed(props: {
   buy:
@@
-    | undefined;
-}) {
+    | undefined;
+}): JSX.Element {

Optionally, export a shared type TokenSide = { chainId: number; tokenAddress: string; amount?: string } from BuyAndSwapEmbed and import it here to avoid duplicate structural types. As per coding guidelines.

apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (3)

14-17: Use correct Next.js params types; avoid Promise-typed params and unnecessary await.

Next App Router passes params as a plain object. Clean up typings and remove await.

 type PageProps = {
-  params: Promise<Params>;
+  params: Params;
 };

-export async function generateMetadata(
-  props: PageProps,
-): Promise<Metadata | undefined> {
-  const params = await props.params;
+export async function generateMetadata(
+  { params }: PageProps,
+): Promise<Metadata | undefined> {
   const tokenPair = params["token-pair"];
-export default async function Page(props: { params: Promise<Params> }) {
-  const params = await props.params;
+export default async function Page(props: { params: Params }) {
+  const params = props.params;

As per coding guidelines.

Also applies to: 24-31, 53-55


95-101: Don’t call redirect from a shared data helper used by generateMetadata.

Let callers decide. Return undefined here; keep the redirect in Page.

 async function getTokenMetadata(slug: string) {
   const tokenPairData = getTokenPairData(slug);
   if (!tokenPairData) {
-    redirect("/bridge");
+    return undefined;
   }
@@
-  if (!fromToken || !toToken || !fromChain || !toChain) {
-    return undefined;
-  }
+  if (!fromToken || !toToken || !fromChain || !toChain) return undefined;

This avoids swallowing Next’s redirect in generateMetadata.

Also applies to: 120-122


87-93: Add explicit return types to helpers.

Small TS hygiene to match our standards.

-function cleanedChainName(chainName: string) {
+function cleanedChainName(chainName: string): string {
   return chainName.replaceAll("mainnet", "").replaceAll("Mainnet", "").trim();
 }
 
-function cleanTokenName(tokenName: string) {
+function cleanTokenName(tokenName: string): string {
   return tokenName.replaceAll("Token", "").replaceAll("token", "").trim();
 }
 
-function getTitle(data: {
+function getTitle(data: {
   fromToken: {
@@
   toChain: ChainMetadata;
-}) {
+}): string {

As per coding guidelines.

Also applies to: 132-173

apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)

35-52: Add explicit return type to component.

Matches our TS guideline and improves DX.

-export function BuyAndSwapEmbed(props: {
+export function BuyAndSwapEmbed(props: {
   buy:
@@
-  wallets?: Wallet[];
-}) {
+  wallets?: Wallet[];
+}): JSX.Element {

As per coding guidelines.


1-1: Remove broad eslint-disable for no-restricted-syntax.

No restricted syntax used; keep disables scoped or remove.

-/* eslint-disable no-restricted-syntax */
@@
-  // eslint-disable-next-line no-restricted-syntax
   useEffect(() => {

Also applies to: 58-60


236-242: Comment does not match behavior.

Code always sets sellToken when props.sell is provided; it does not skip for native buy tokens.

  • Either update the comment to reflect behavior, or
  • Implement the guard:
- // sell the native token by default (but if buytoken is a native token, don't set)
- sellToken: props.sell?.chainId
+ // prefill sell token if provided
+ sellToken: props.sell?.chainId
   ? { chainId: props.sell.chainId, tokenAddress: props.sell.tokenAddress }
   : undefined,

If you want the native-token exception, import NATIVE_TOKEN_ADDRESS and add a check against props.buy?.tokenAddress.

📜 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 79b9a44 and 30a6e13.

⛔ Files ignored due to path filters (1)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/opengraph-image.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (8 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/constants.ts (0 hunks)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1 hunks)
  • apps/dashboard/src/app/bridge/page.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/dashboard/src/app/bridge/constants.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
🧰 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/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.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/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.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/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.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/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.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/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
🧠 Learnings (2)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#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/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
📚 Learning: 2025-08-28T12:24:37.171Z
Learnt from: MananTank
PR: thirdweb-dev/js#7933
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx:0-0
Timestamp: 2025-08-28T12:24:37.171Z
Learning: In the token creation flow, the tokenAddress field in erc20Asset_poolMode is always initialized with nativeTokenAddress and is never undefined, so conditional checks for undefined tokenAddress are not needed.

Applied to files:

  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
🧬 Code graph analysis (3)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (4)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)
  • generateTokenPairSlugs (123-150)
  • getTokenPairData (72-89)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
  • BridgePageUI (6-39)
apps/dashboard/src/@/constants/thirdweb-client.server.ts (1)
  • serverThirdwebClient (8-11)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • NATIVE_TOKEN_ADDRESS (31-31)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
  • BuyAndSwapEmbed (35-277)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
apps/dashboard/src/@/analytics/report.ts (3)
  • reportTokenBuyFailed (264-266)
  • reportTokenBuyCancelled (276-278)
  • reportTokenBuySuccessful (252-254)
⏰ 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). (1)
  • GitHub Check: Size

@vercel vercel bot temporarily deployed to Preview – thirdweb_playground October 17, 2025 23:06 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 October 17, 2025 23:06 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula October 17, 2025 23:06 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui October 17, 2025 23:06 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

♻️ Duplicate comments (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx (1)

202-210: Fix same-asset prefill: default sell to native token.

Setting both buy and sell to the ERC20 yields an invalid swap. Use the chain’s native token for sell.

+import { NATIVE_TOKEN_ADDRESS } from "thirdweb";
 ...
       <BuyAndSwapEmbed
-        // chain={props.clientContract.chain}
-        sell={{
-          chainId: props.clientContract.chain.id,
-          tokenAddress: props.clientContract.address,
-        }}
+        sell={{
+          chainId: props.clientContract.chain.id,
+          tokenAddress: NATIVE_TOKEN_ADDRESS,
+        }}
         buy={{
           chainId: props.clientContract.chain.id,
           tokenAddress: props.clientContract.address,
         }}
         pageType="asset"
       />
🧹 Nitpick comments (11)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)

17-31: Extract a shared TradeSide type and add an explicit return type.

Define a TradeSide alias and use optional props to reduce repetition and align with guidelines; also annotate the function’s return type.
[As per coding guidelines]

+type TradeSide = {
+  tokenAddress: `0x${string}`;
+  chainId: number;
+  amount?: string;
+};
-
-export function UniversalBridgeEmbed(props: {
-  buy:
-    | {
-        tokenAddress: string;
-        chainId: number;
-        amount?: string;
-      }
-    | undefined;
-  sell:
-    | {
-        chainId: number;
-        tokenAddress: string;
-        amount?: string;
-      }
-    | undefined;
-}) {
+export function UniversalBridgeEmbed(props: {
+  buy?: TradeSide;
+  sell?: TradeSide;
+}): JSX.Element {
apps/dashboard/src/app/bridge/components/bridge-page.tsx (4)

6-20: Expose className, share TradeSide type, and annotate return type.

Make the root style-overridable, avoid inline type repetition, and add an explicit return type.
[As per coding guidelines]

-export function BridgePageUI(props: {
-  title: React.ReactNode;
-  buy:
-    | {
-        tokenAddress: string;
-        chainId: number;
-      }
-    | undefined;
-  sell:
-    | {
-        chainId: number;
-        tokenAddress: string;
-      }
-    | undefined;
-}) {
+type TradeSide = { tokenAddress: `0x${string}`; chainId: number };
+export function BridgePageUI(props: {
+  title: React.ReactNode;
+  className?: string;
+  buy?: TradeSide;
+  sell?: TradeSide;
+}): JSX.Element {

21-38: Wire className into the root container.

Enable composition per app guidelines.
[As per coding guidelines]

-  return (
-    <div className="grow flex flex-col">
+  return (
+    <div className={cn("grow flex flex-col", props.className)}>

1-5: Mark as a server component.

Add the directive for clarity and to prevent accidental client-only imports leaking here.
[As per coding guidelines]

+import "server-only";
 import { cn } from "@workspace/ui/lib/utils";

68-83: Deduplicate Dots background by reusing the shared UI component.

Import and use DotsBackgroundPattern from @/components/ui/background-patterns instead of redefining it.

-function DotsBackgroundPattern(props: { className?: string }) {
-  return (
-    <div
-      className={cn(
-        "pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block",
-        props.className,
-      )}
-      style={{
-        backgroundImage: "radial-gradient(currentColor 1px, transparent 1px)",
-        backgroundSize: "24px 24px",
-        maskImage:
-          "radial-gradient(ellipse 100% 100% at 50% 50%, black 30%, transparent 50%)",
-      }}
-    />
-  );
-}
+import { DotsBackgroundPattern } from "@/components/ui/background-patterns";
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (2)

18-22: Consider curating static params to the SEO target list.

Generating all pairs is O(N²). For MNY‑274, statically prebuild only the high‑priority routes; render others on demand.

-export async function generateStaticParams(): Promise<Params[]> {
-  return generateTokenPairSlugs().map((slug) => ({
-    "token-pair": slug,
-  }));
-}
+export async function generateStaticParams(): Promise<Params[]> {
+  // TODO: move to slug-map.ts and keep a single source of truth
+  const curated = new Set<string>([
+    // Examples; fill in exact slugs present in tokens map:
+    "eth-to-eth-usdt",
+    "eth-usdc-to-eth-usdt",
+    "bnb-to-eth",
+    "bnb-ada-to-eth",
+    "avax-to-eth",
+    "eth-shib-to-eth",
+    "doge-to-eth",
+    "eth-to-eth-usdc",
+    "base-to-eth",
+    "bnb-to-arb",
+    "pol-to-bnb",
+    "base-to-pol",
+    "pol-to-eth",
+  ]);
+  return generateTokenPairSlugs()
+    .filter((slug) => curated.has(slug))
+    .map((slug) => ({ "token-pair": slug }));
+}

I can generate the exact curated slugs from your tokens map to avoid mismatches.


1-9: Mark server file and reuse existing utilities where possible.

  • Add import "server-only";.
  • cleanedChainName duplicates an existing util; prefer importing a shared helper to avoid drift.
+import "server-only";
 import type { Metadata } from "next";
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (3)

123-149: Optional: add a curated generator for SEO pages to avoid O(N²) growth.

Provide generatePopularTokenPairSlugs() that returns a vetted allowlist and (optionally) validates via getTokenPairData before returning.

 export function generateTokenPairSlugs() {
@@
   return routeSlugs;
 }
+
+// Curated list for SEO-targeted pages; keep in sync with issue MNY‑274.
+export function generatePopularTokenPairSlugs() {
+  const curated: string[] = [
+    // fill with slugs that exist in `tokens`; e.g.,
+    // "eth-to-eth-usdt", "eth-usdc-to-eth-usdt", "bnb-to-eth", ...
+  ];
+  return curated.filter((s) => !!getTokenPairData(s));
+}

12-58: Normalize token addresses to EIP‑55 checksum and narrow types.

Mixed casing reduces human checks; prefer checksum and the 0x${string} literal type for safety.

-const tokens: Tokens = {
+const tokens: Tokens = {
   eth: {
     chainId: 1,
     tokens: {
-      usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
-      usdt: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
-      shib: "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE",
+      usdc: "0xA0b86991C6218B36C1d19D4a2e9Eb0cE3606eB48",
+      usdt: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
+      shib: "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE",
     },
   },
@@
-      usdc: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
-      weth: "0x4200000000000000000000000000000000000006",
+      usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bDA02913",
+      weth: "0x4200000000000000000000000000000000000006",
     },
   },
@@
-      usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
-      bnb: "0x3BA4c387f786bFEE076A58914F5Bd38d668B42c3",
-      shib: "0x6f8a06447ff6fcf75d803135a7de15ce88c1d4ec",
-      weth: "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619",
-      avax: "0x2C89bbc92BD86F8075d1DEcc58C7F4E0107f286b",
+      usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
+      bnb: "0x3BA4c387f786bFEE076A58914F5Bd38d668B42c3",
+      shib: "0x6F8A06447Ff6fCF75D803135a7dE15Ce88C1D4eC",
+      weth: "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
+      avax: "0x2C89bbc92BD86F8075d1DEcc58C7F4E0107f286b",
     },
   },
@@
-      usdc: "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
+      usdc: "0xAf88d065e77c8cC2239327C5EDb3A432268e5831",
     },
   },
 };

Optionally, enforce tokenAddress: \0x${string}`inTokenPairDataandTradeSide` for stronger typing.


91-121: Minor robustness: normalize incoming slugs to lowercase.

Guard against mixed‑case URLs without relying on routing config.

-  const [chainSlug, tokenSlug] = slug.split("-");
+  const [chainSlug, tokenSlug] = slug.toLowerCase().split("-");
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)

36-49: Excellent refactoring to structured buy/sell objects.

The new API with structured buy and sell objects is much cleaner and more maintainable than individual flat props. The optional nature and included properties are well-designed.

Consider normalizing property order for consistency:

  buy:
    | {
-        tokenAddress: string;
         chainId: number;
+        tokenAddress: string;
         amount?: string;
      }
    | undefined;
📜 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 30a6e13 and 5285868.

⛔ Files ignored due to path filters (1)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/opengraph-image.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (8 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/constants.ts (0 hunks)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1 hunks)
  • apps/dashboard/src/app/bridge/page.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/dashboard/src/app/bridge/constants.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.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/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.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/bridge/components/bridge-page.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.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/bridge/components/bridge-page.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.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/bridge/components/bridge-page.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.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/bridge/components/bridge-page.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
🧠 Learnings (3)
📚 Learning: 2025-10-17T22:59:11.851Z
Learnt from: MananTank
PR: thirdweb-dev/js#8278
File: apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx:144-144
Timestamp: 2025-10-17T22:59:11.851Z
Learning: The BuyAndSwapEmbed component in apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx cannot be used in testnets, so the hardcoded `is_testnet: false` in asset reporting calls is intentional and correct.

Applied to files:

  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
📚 Learning: 2025-08-28T12:24:37.171Z
Learnt from: MananTank
PR: thirdweb-dev/js#7933
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx:0-0
Timestamp: 2025-08-28T12:24:37.171Z
Learning: In the token creation flow, the tokenAddress field in erc20Asset_poolMode is always initialized with nativeTokenAddress and is never undefined, so conditional checks for undefined tokenAddress are not needed.

Applied to files:

  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#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/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
🧬 Code graph analysis (5)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (4)
apps/dashboard/src/app/bridge/components/header.tsx (1)
  • BridgePageHeader (14-68)
apps/dashboard/src/@/components/ui/background-patterns.tsx (1)
  • DotsBackgroundPattern (4-19)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
  • UniversalBridgeEmbed (17-41)
apps/dashboard/src/@/components/blocks/faq-section.tsx (1)
  • FaqAccordion (8-23)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
apps/dashboard/src/@/analytics/report.ts (3)
  • reportTokenBuyFailed (264-266)
  • reportTokenBuyCancelled (276-278)
  • reportTokenBuySuccessful (252-254)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
  • BuyAndSwapEmbed (35-277)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • NATIVE_TOKEN_ADDRESS (31-31)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (5)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)
  • generateTokenPairSlugs (123-149)
  • getTokenPairData (72-89)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
  • BridgePageUI (6-39)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts (1)
  • cleanedChainName (1-3)
apps/dashboard/src/@/constants/thirdweb-client.server.ts (1)
  • serverThirdwebClient (8-11)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • NATIVE_TOKEN_ADDRESS (31-31)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (8)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)

34-39: LGTM: Propagation into BuyAndSwapEmbed matches the new API.

buy/sell are forwarded intact; pageType="bridge" and wallets are correct.

apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (3)

63-72: LGTM: buy = destination, sell = origin.

Mapping matches “from → to” semantics and the SwapWidget prefill.


14-16: Fix Next.js params typing (it’s not a Promise).

Use params: Params and drop the await to align with App Router types.
[As per coding guidelines]

-type PageProps = {
-  params: Promise<Params>;
-};
+type PageProps = { params: Params };
@@
-export default async function Page(props: { params: Promise<Params> }) {
-  const params = await props.params;
+export default async function Page(props: { params: Params }) {
+  const params = props.params;

Also applies to: 53-55

⛔ Skipped due to learnings
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx:2-10
Timestamp: 2025-05-26T16:28:10.079Z
Learning: In Next.js 14+, the `params` object in page components is always a Promise that needs to be awaited, so the correct typing is `params: Promise<ParamsType>` rather than `params: ParamsType`.
Learnt from: jnsdls
PR: thirdweb-dev/js#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.

24-31: Also fix generateMetadata param typing and remove unnecessary await.
[As per coding guidelines]

 export async function generateMetadata(
-  props: PageProps,
+  props: PageProps,
 ): Promise<Metadata | undefined> {
-  const params = await props.params;
+  const params = props.params;
⛔ Skipped due to learnings
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx:2-10
Timestamp: 2025-05-26T16:28:10.079Z
Learning: In Next.js 14+, the `params` object in page components is always a Promise that needs to be awaited, so the correct typing is `params: Promise<ParamsType>` rather than `params: ParamsType`.
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)

71-89: LGTM: Correct slug split order and validation.

[fromSlug, toSlug] aligns with <from>-to-<to>; early undefined checks are good.

apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)

116-125: Well-implemented guard logic prevents undefined chainId.

The defensive pattern of deriving buyChainId from the quote and early-returning when undefined is excellent. This prevents potential runtime errors in the asset reporting calls and handles both "buy" and "onramp" quote types correctly.

Also applies to: 149-158, 181-190


101-104: Widget integration properly uses the new buy/sell structure.

Both BuyWidget and SwapWidget are correctly updated to consume the new structured props. The use of defineChain to convert chainId to a Chain object is appropriate, and the conditional prefill logic for the swap widget ensures that tokens are only set when the data is available.

Also applies to: 230-242


141-144: Asset reporting correctly uses derived buyChainId.

The asset reporting calls now properly use the buyChainId derived from the quote context, which is more accurate than relying on the original props. The hardcoded is_testnet: false is correct for this component. Based on learnings.

Also applies to: 174-176, 206-208

@vercel vercel bot temporarily deployed to Preview – docs-v2 October 17, 2025 23:29 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui October 17, 2025 23:29 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula October 17, 2025 23:29 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground October 17, 2025 23:29 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/bridge/components/bridge-page.tsx (1)

59-74: Consider reusing shared DotsBackgroundPattern.

A similar DotsBackgroundPattern exists in @/components/ui/background-patterns.tsx (lines 3-18). The shared version accepts a className prop, allowing you to override the default styling.

Replace the local implementation with:

+import { DotsBackgroundPattern } from "@/components/ui/background-patterns";
...
-function DotsBackgroundPattern(props: { className?: string }) {
-  return (
-    <div
-      className={cn(
-        "pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block",
-        props.className,
-      )}
-      style={{
-        backgroundImage: "radial-gradient(currentColor 1px, transparent 1px)",
-        backgroundSize: "24px 24px",
-        maskImage:
-          "radial-gradient(ellipse 100% 100% at 50% 50%, black 30%, transparent 50%)",
-      }}
-    />
-  );
-}

Then use it with:

<DotsBackgroundPattern className="-inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block" />
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)

124-126: Consider documenting token address format expectation.

The type assertion assumes callers provide valid 0x-prefixed addresses. Consider adding a JSDoc comment on the BuyAndSwapEmbedProps type to document this requirement.

Example:

/**
 * Props for BuyAndSwapEmbed component
 * @remarks tokenAddress should be a valid 0x-prefixed address or NATIVE_TOKEN_ADDRESS constant
 */
export type BuyAndSwapEmbedProps = {
  // ...
📜 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 5285868 and bffc7c3.

⛔ Files ignored due to path filters (1)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/opengraph-image.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (8 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (2 hunks)
  • apps/dashboard/src/app/bridge/constants.ts (0 hunks)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1 hunks)
  • apps/dashboard/src/app/bridge/page.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/dashboard/src/app/bridge/constants.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
🧰 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)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.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)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.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)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.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)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.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)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
🧠 Learnings (4)
📚 Learning: 2025-10-17T22:59:11.851Z
Learnt from: MananTank
PR: thirdweb-dev/js#8278
File: apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx:144-144
Timestamp: 2025-10-17T22:59:11.851Z
Learning: The BuyAndSwapEmbed component in apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx cannot be used in testnets, so the hardcoded `is_testnet: false` in asset reporting calls is intentional and correct.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#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/bridge/components/client/UniversalBridgeEmbed.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
📚 Learning: 2025-08-28T12:24:37.171Z
Learnt from: MananTank
PR: thirdweb-dev/js#7933
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx:0-0
Timestamp: 2025-08-28T12:24:37.171Z
Learning: In the token creation flow, the tokenAddress field in erc20Asset_poolMode is always initialized with nativeTokenAddress and is never undefined, so conditional checks for undefined tokenAddress are not needed.

Applied to files:

  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
📚 Learning: 2025-09-24T11:08:43.783Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx:34-41
Timestamp: 2025-09-24T11:08:43.783Z
Learning: In BridgeWidgetProps for packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx, the Swap onError callback signature requires a non-undefined SwapPreparedQuote parameter (unlike Buy's onError which allows undefined quote). This is intentional - SwapWidget's onError is only called when a quote is available.

Applied to files:

  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
🧬 Code graph analysis (6)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx (3)
apps/dashboard/src/@/components/blocks/grid-pattern-embed-container.tsx (1)
  • GridPatternEmbedContainer (3-23)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
  • BuyAndSwapEmbed (69-286)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • NATIVE_TOKEN_ADDRESS (31-31)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)
  • BuyAndSwapEmbedProps (35-67)
  • BuyAndSwapEmbed (69-286)
apps/dashboard/src/app/bridge/page.tsx (2)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1)
  • Page (53-93)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
  • BridgePageUI (7-30)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (4)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)
  • generateTokenPairSlugs (123-149)
  • getTokenPairData (72-89)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
  • BridgePageUI (7-30)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts (1)
  • cleanedChainName (1-3)
apps/dashboard/src/@/constants/thirdweb-client.server.ts (1)
  • serverThirdwebClient (8-11)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
apps/dashboard/src/@/analytics/report.ts (3)
  • reportTokenBuyFailed (264-266)
  • reportTokenBuyCancelled (276-278)
  • reportTokenBuySuccessful (252-254)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (5)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
  • BuyAndSwapEmbedProps (35-67)
apps/dashboard/src/app/bridge/components/header.tsx (1)
  • BridgePageHeader (14-68)
apps/dashboard/src/@/components/ui/background-patterns.tsx (1)
  • DotsBackgroundPattern (4-19)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
  • UniversalBridgeEmbed (20-32)
apps/dashboard/src/@/components/blocks/faq-section.tsx (1)
  • FaqAccordion (8-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Unit Tests
  • GitHub Check: Build Packages
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (10)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)

20-31: LGTM! Clean refactor to structured props.

The refactor from flat props to the buyTab/swapTab structure is well-executed. Type safety is maintained via BuyAndSwapEmbedProps, and the component remains a clean pass-through wrapper.

apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)

7-30: LGTM! Well-structured UI composition.

The component cleanly composes header, embed, heading, and FAQ sections with proper spacing and type-safe props.

apps/dashboard/src/app/bridge/page.tsx (1)

17-30: LGTM! Clean delegation to BridgePageUI.

Passing undefined for buyTab and swapTab allows the bridge widget to start without prefill, which is appropriate for the main bridge landing page.

apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (4)

24-51: LGTM! Proper metadata generation with error handling.

The function correctly handles missing token pairs by returning undefined and constructs appropriate OpenGraph metadata.


53-93: LGTM! Correct buy/sell mapping.

The token mapping is correct: for a route "X-to-Y", swapTab.sellToken uses fromToken (X) and both buyTab.buyToken and swapTab.buyToken use toToken (Y), matching the expected "sell X to buy Y" flow.


103-138: LGTM! Robust metadata fetching with proper error handling.

The function correctly uses Promise.all for parallel fetching and handles errors gracefully by returning undefined, which triggers the redirect in the Page component.


140-181: LGTM! Comprehensive title generation logic.

The function handles multiple edge cases well:

  • Native token detection via NATIVE_TOKEN_ADDRESS
  • Same-symbol cross-chain swaps
  • Cross-chain vs same-chain formatting
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)

35-67: LGTM! Well-designed type structure.

The nested optional structure for buyTab and swapTab provides good flexibility while maintaining type safety.


116-237: LGTM! Proper derivation and error handling.

The buyChainId derivation with guard clauses correctly handles both "buy" and "onramp" quote types, preventing undefined access in callbacks. The is_testnet: false is correct based on learnings.


239-283: LGTM! Clean SwapWidget integration.

The prefill structure correctly uses swapTab data, and callbacks properly extract intent properties for analytics reporting.

@graphite-app
Copy link
Contributor

graphite-app bot commented Oct 17, 2025

Merge activity

)

<!--

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

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

## Notes for the reviewer

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

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview

This PR focuses on refactoring the `BuyAndSwapEmbed` component and related functionalities to improve the handling of buy and swap operations across different tokens and chains, enhancing the user experience in the bridge application.

### Detailed summary

- Removed `chain` and `tokenAddress` props from `BuyAndSwapEmbed`.
- Introduced `buyTab` and `swapTab` props to manage buy/sell token information.
- Updated `UniversalBridgeEmbed` to accept new props structure.
- Added token pair management in `slug-map.ts`.
- Created utility functions for token pair data retrieval.
- Refactored `BridgePageUI` to accommodate the new props and structure.
- Enhanced error handling and reporting in `BuyAndSwapEmbed`.

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

<!-- end pr-codex -->

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

- **New Features**
  - Added a Bridge UI and dedicated token-pair pages with static routes, metadata, and token-pair utilities for cross-chain slugs.
  - Introduced a Bridge page UI with FAQ, data summary, and an embedded universal bridge widget.

- **Improvements**
  - Unified buy/sell input structure for embeds and prefills, simplifying embed wiring and page rendering.
  - More robust handling of chain/token data and reporting for buy/swap flows; removed legacy testnet flag usage.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground October 17, 2025 23:49 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 October 17, 2025 23:49 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui October 17, 2025 23:49 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula October 17, 2025 23:49 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: 3

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/BuyAndSwapEmbed.tsx (1)

288-292: Add explicit return type to TabButton function.

The TabButton function is missing an explicit return type, which violates the coding guideline requiring explicit return types in TypeScript.

As per coding guidelines, apply this diff:

 function TabButton(props: {
   label: string;
   onClick: () => void;
   isActive: boolean;
-}) {
+}): JSX.Element {
♻️ Duplicate comments (3)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1)

63-81: LGTM: buy/sell mapping now matches “from → to”.

buyTab uses the destination token; swapTab.sellToken uses the origin token. Correct.

apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)

71-89: LGTM: Correct <from>-to-<to> parsing.

Destructuring order is now correct; resolves prior reversal.

apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)

124-126: Type assertion may mask invalid addresses.

The type assertion as \0x${string}` | undefinedbypasses TypeScript's type checking. Ifprops.buyTab?.buyToken?.tokenAddress` contains a malformed address, this could cause runtime issues with the BuyWidget.

Consider validating the token address format:

- tokenAddress={
-   props.buyTab?.buyToken?.tokenAddress as `0x${string}` | undefined
- }
+ tokenAddress={
+   props.buyTab?.buyToken?.tokenAddress &&
+   props.buyTab.buyToken.tokenAddress.startsWith('0x')
+     ? props.buyTab.buyToken.tokenAddress as `0x${string}`
+     : undefined
+ }

Alternatively, verify that all callers pass properly formatted addresses and document this requirement in JSDoc.

🧹 Nitpick comments (12)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)

20-23: Solid API migration; consider a small props type alias for clarity.

Inline props are correct. For readability and reuse, define a local alias and use it in the signature.

+type UniversalBridgeEmbedProps = Pick<BuyAndSwapEmbedProps, "buyTab" | "swapTab">;
-export function UniversalBridgeEmbed(props: {
-  buyTab: BuyAndSwapEmbedProps["buyTab"];
-  swapTab: BuyAndSwapEmbedProps["swapTab"];
-}) {
+export function UniversalBridgeEmbed(props: UniversalBridgeEmbedProps) {
apps/dashboard/src/app/bridge/components/bridge-page.tsx (3)

1-6: Mark as a Server Component.

Per dashboard guidelines, add the server-only directive at the top.

+import "server-only";
 import { cn } from "@workspace/ui/lib/utils";
 import type { BuyAndSwapEmbedProps } from "@/components/blocks/BuyAndSwapEmbed";
 import { FaqAccordion } from "@/components/blocks/faq-section";
 import { UniversalBridgeEmbed } from "./client/UniversalBridgeEmbed";
 import { BridgePageHeader } from "./header";

Confirm no client-only APIs are used in this file after the change.


7-14: Expose className and forward to the root; make tab props optional.

Expose a className on BridgePageUI’s root and make buyTab/swapTab optional so callers don’t pass undefined.

-export function BridgePageUI(props: {
-  title: React.ReactNode;
-  buyTab: BuyAndSwapEmbedProps["buyTab"];
-  swapTab: BuyAndSwapEmbedProps["swapTab"];
-}) {
-  return (
-    <div className="grow flex flex-col">
+export function BridgePageUI(props: {
+  title: React.ReactNode;
+  buyTab?: BuyAndSwapEmbedProps["buyTab"];
+  swapTab?: BuyAndSwapEmbedProps["swapTab"];
+  className?: string;
+}) {
+  return (
+    <div className={cn("grow flex flex-col", props.className)}>
...
-      <HeadingSection title={props.title} />
+      <HeadingSection title={props.title} />

Also applies to: 21-29


32-49: Optional: expose className on subcomponents for consistency.

Add className?: string to HeadingSection, DataPill, and BridgeFaqSection and merge via cn().

-function HeadingSection(props: { title: React.ReactNode }) {
+function HeadingSection(props: { title: React.ReactNode; className?: string }) {
   return (
-    <div className="container">
+    <div className={cn("container", props.className)}>
...
-function DataPill(props: { children: React.ReactNode }) {
+function DataPill(props: { children: React.ReactNode; className?: string }) {
   return (
-    <p className="bg-card flex items-center text-xs lg:text-sm gap-1.5 text-foreground border rounded-full px-8 lg:px-3 py-1.5 hover:text-foreground transition-colors duration-300">
+    <p className={cn(
+      "bg-card flex items-center text-xs lg:text-sm gap-1.5 text-foreground border rounded-full px-8 lg:px-3 py-1.5 hover:text-foreground transition-colors duration-300",
+      props.className,
+    )}>
       {props.children}
     </p>
   );
 }
...
-function BridgeFaqSection() {
+function BridgeFaqSection(props: { className?: string }) {
   return (
-    <section className="container max-w-2xl">
+    <section className={cn("container max-w-2xl", props.className)}>

As per coding guidelines

Also applies to: 51-57, 104-113

apps/dashboard/src/app/bridge/page.tsx (2)

1-3: Add server-only directive.

Mark this as a Server Component.

+import "server-only";
 import type { Metadata } from "next";
 import { BridgePageUI } from "./components/bridge-page";

As per coding guidelines


17-27: Avoid passing undefined explicitly if props are optional.

After making buyTab/swapTab optional in BridgePageUI, simplify the call.

 export default function Page() {
   return (
-    <BridgePageUI
-      buyTab={undefined}
-      swapTab={undefined}
-      title={
+    <BridgePageUI
+      title={
         <h1 className="text-3xl md:text-6xl font-semibold tracking-tighter text-balance text-center">
           Bridge and Swap tokens <br className="max-sm:hidden" /> across any
           chain, instantly
         </h1>
       }
     />
   );
 }
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (3)

1-9: Mark as a Server Component.

Add the server-only directive at the top.

+import "server-only";
 import type { Metadata } from "next";
 import { redirect } from "next/navigation";
 import { Bridge, NATIVE_TOKEN_ADDRESS } from "thirdweb";
 import type { ChainMetadata } from "thirdweb/chains";
 import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
 import { fetchChain } from "@/utils/fetchChain";
 import { BridgePageUI } from "../../components/bridge-page";
 import { generateTokenPairSlugs, getTokenPairData } from "./slug-map";

As per coding guidelines


18-22: Limit static params to curated SEO pairs to avoid O(N²) build bloat.

Generate only the pairs listed in MNY-274 (e.g., ETH→USDT, USDC→USDT, BNB→ETH, etc.) and let others render dynamically.

-export async function generateStaticParams(): Promise<Params[]> {
-  return generateTokenPairSlugs().map((slug) => ({
-    "token-pair": slug,
-  }));
-}
+export async function generateStaticParams(): Promise<Params[]> {
+  const slugs = generateTokenPairSlugs({ popularOnly: true });
+  return slugs.map((slug) => ({ "token-pair": slug }));
+}

If you prefer not to change the signature, expose generatePopularTokenPairSlugs() in slug-map and use that here. Based on learnings

I can wire the exact slug list derived from the issue text.


24-51: Add explicit return types and cache token metadata to prevent duplicate fetch.

  • Add explicit return types for TS helpers and the default export.
  • Cache getTokenMetadata so generateMetadata and Page share results per slug.
-export async function generateMetadata(
+export async function generateMetadata(
   props: PageProps,
-): Promise<Metadata | undefined> {
+): Promise<Metadata | undefined> {
...
-export default async function Page(props: { params: Promise<Params> }) {
+export default async function Page(props: { params: Promise<Params> }): Promise<JSX.Element> {
...
-function cleanedChainName(chainName: string) {
+function cleanedChainName(chainName: string): string {
   return chainName.replaceAll("mainnet", "").replaceAll("Mainnet", "").trim();
 }
 
-function cleanTokenName(tokenName: string) {
+function cleanTokenName(tokenName: string): string {
   return tokenName.replaceAll("Token", "").replaceAll("token", "").trim();
 }
 
-async function getTokenMetadata(slug: string) {
+import { cache } from "react";
+const getTokenMetadata = cache(async function getTokenMetadata(slug: string): Promise<{
+  fromToken: { name: string; symbol: string; address: string };
+  toToken: { name: string; symbol: string; address: string };
+  fromChain: ChainMetadata;
+  toChain: ChainMetadata;
+} | undefined> {
   const tokenPairData = getTokenPairData(slug);
   if (!tokenPairData) {
     redirect("/bridge");
   }
...
   if (!fromToken || !toToken || !fromChain || !toChain) {
     return undefined;
   }
 
   return {
     fromToken,
     toToken,
     fromChain,
     toChain,
   };
-}
+});
 
-function getTitle(data: {
+function getTitle(data: {
   fromToken: {
     name: string;
     symbol: string;
     address: string;
   };
   toToken: {
     name: string;
     symbol: string;
     address: string;
   };
   fromChain: ChainMetadata;
   toChain: ChainMetadata;
-}) {
+}): string {

As per coding guidelines

Also applies to: 53-93, 95-181

apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)

123-149: Add a curated popular-slugs generator and stronger typings.

Reduce build surface and improve type safety.

-import { NATIVE_TOKEN_ADDRESS } from "thirdweb";
+import { NATIVE_TOKEN_ADDRESS } from "thirdweb";
+
+type HexAddress = `0x${string}`;
+type ChainSlug = "eth" | "bnb" | "avax" | "doge" | "base" | "pol" | "arb";
+type TokenSlug =
+  | "usdc"
+  | "usdt"
+  | "shib"
+  | "weth"
+  | "bnb"
+  | "avax"
+  | "ada";
 
 type Tokens = Record<
-  string,
+  ChainSlug,
   | {
       chainId: number;
-      tokens: Record<string, string | undefined>;
+      tokens: Record<string, HexAddress | undefined>;
     }
   | undefined
 >;
@@
-export function generateTokenPairSlugs() {
+export function generateTokenPairSlugs(opts?: { popularOnly?: boolean }) {
   const tokenIds = Object.keys(tokens);
@@
-  const routeSlugs: string[] = [];
+  const routeSlugs: string[] = [];
   for (const fromSlug of tokenSlugs) {
     for (const toSlug of tokenSlugs) {
       if (fromSlug === toSlug) {
         continue;
       }
       routeSlugs.push(`${fromSlug}-to-${toSlug}`);
     }
   }
 
-  return routeSlugs;
+  if (opts?.popularOnly) {
+    const POPULAR: ReadonlyArray<string> = [
+      // From issue MNY-274 (mapped to current slugs)
+      "eth-to-eth-usdt",
+      "eth-usdc-to-eth-usdt",
+      "bnb-to-eth",
+      "bnb-ada-to-eth",
+      "avax-to-eth",
+      "eth-shib-to-eth",
+      "doge-to-eth",
+      "eth-to-eth-usdc",
+      "base-to-eth",
+      "bnb-to-arb",
+      "pol-to-bnb",
+      "base-to-pol",
+      "pol-to-eth",
+    ];
+    return routeSlugs.filter((s) => POPULAR.includes(s));
+  }
+  return routeSlugs;
 }

If you want, I can validate these slugs against getTokenPairData() and adjust any that don’t resolve.

apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)

1-1: Consider scoping the eslint-disable directive.

The global eslint-disable at the file level disables no-restricted-syntax for the entire file, but it appears only the useEffect at line 76 requires this exception (which already has its own inline disable comment). A file-level disable is overly broad.

Remove the global disable and rely on the existing inline directive at line 75:

-/* eslint-disable no-restricted-syntax */
 "use client";

35-67: Add JSDoc to document the props structure.

The BuyAndSwapEmbedProps type has a deeply nested optional structure. Adding JSDoc would help callers understand when to populate buyTab vs swapTab and the purpose of each nested token object.

Add documentation above the type:

/**
 * Props for BuyAndSwapEmbed component.
 * @param buyTab - Configuration for the "Buy" tab; populate buyToken to enable buying a specific token
 * @param swapTab - Configuration for the "Swap" tab; populate sellToken and buyToken to prefill swap pairs
 * @param pageType - Context for analytics (asset/bridge/chain page)
 * @param wallets - Optional wallet instances for connection
 */
export type BuyAndSwapEmbedProps = {
📜 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 bffc7c3 and b1a7808.

⛔ Files ignored due to path filters (1)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/opengraph-image.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (8 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (2 hunks)
  • apps/dashboard/src/app/bridge/constants.ts (0 hunks)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1 hunks)
  • apps/dashboard/src/app/bridge/page.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/dashboard/src/app/bridge/constants.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.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/app/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.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/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.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/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.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/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.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/bridge/exchange/[token-pair]/page.tsx
  • apps/dashboard/src/app/bridge/components/bridge-page.tsx
  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/page.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
🧠 Learnings (4)
📚 Learning: 2025-10-17T22:59:11.851Z
Learnt from: MananTank
PR: thirdweb-dev/js#8278
File: apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx:144-144
Timestamp: 2025-10-17T22:59:11.851Z
Learning: The BuyAndSwapEmbed component in apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx cannot be used in testnets, so the hardcoded `is_testnet: false` in asset reporting calls is intentional and correct.

Applied to files:

  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
📚 Learning: 2025-08-28T12:24:37.171Z
Learnt from: MananTank
PR: thirdweb-dev/js#7933
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx:0-0
Timestamp: 2025-08-28T12:24:37.171Z
Learning: In the token creation flow, the tokenAddress field in erc20Asset_poolMode is always initialized with nativeTokenAddress and is never undefined, so conditional checks for undefined tokenAddress are not needed.

Applied to files:

  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#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/@/components/blocks/BuyAndSwapEmbed.tsx
  • apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
📚 Learning: 2025-09-24T11:08:43.783Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx:34-41
Timestamp: 2025-09-24T11:08:43.783Z
Learning: In BridgeWidgetProps for packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx, the Swap onError callback signature requires a non-undefined SwapPreparedQuote parameter (unlike Buy's onError which allows undefined quote). This is intentional - SwapWidget's onError is only called when a quote is available.

Applied to files:

  • apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
🧬 Code graph analysis (6)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (4)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)
  • generateTokenPairSlugs (123-149)
  • getTokenPairData (72-89)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
  • BridgePageUI (7-30)
apps/dashboard/src/@/constants/thirdweb-client.server.ts (1)
  • serverThirdwebClient (8-11)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • NATIVE_TOKEN_ADDRESS (31-31)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (4)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
  • BuyAndSwapEmbedProps (35-67)
apps/dashboard/src/app/bridge/components/header.tsx (1)
  • BridgePageHeader (14-68)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
  • UniversalBridgeEmbed (20-32)
apps/dashboard/src/@/components/blocks/faq-section.tsx (1)
  • FaqAccordion (8-23)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • NATIVE_TOKEN_ADDRESS (31-31)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
apps/dashboard/src/@/analytics/report.ts (3)
  • reportTokenBuyFailed (264-266)
  • reportTokenBuyCancelled (276-278)
  • reportTokenBuySuccessful (252-254)
apps/dashboard/src/app/bridge/page.tsx (2)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1)
  • Page (53-93)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
  • BridgePageUI (7-30)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)
  • BuyAndSwapEmbedProps (35-67)
  • BuyAndSwapEmbed (69-286)
⏰ 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). (6)
  • GitHub Check: Unit Tests
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)

}) {
};

export function BuyAndSwapEmbed(props: BuyAndSwapEmbedProps) {
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add explicit return type to function declaration.

The function is missing an explicit return type, which violates the coding guideline requiring explicit return types in TypeScript.

As per coding guidelines, apply this diff:

-export function BuyAndSwapEmbed(props: BuyAndSwapEmbedProps) {
+export function BuyAndSwapEmbed(props: BuyAndSwapEmbedProps): JSX.Element {
🤖 Prompt for AI Agents
In apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx around line 69,
the BuyAndSwapEmbed function declaration lacks an explicit return type; update
the function signature to include the correct React return type (e.g.,
React.ReactElement or JSX.Element | null as appropriate) so the declaration
becomes explicitly typed, and import React types if needed.

Comment on lines +138 to +147
const buyChainId =
quote?.type === "buy"
? quote.intent.destinationChainId
: quote?.type === "onramp"
? quote.intent.chainId
: undefined;

if (!buyChainId) {
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Extract duplicated buyChainId logic into a helper function.

The buyChainId extraction logic is duplicated across onError, onCancel, and onSuccess callbacks. This violates the DRY principle and increases maintenance burden.

Extract a helper function at the top of the file:

function getBuyChainId(
  quote:
    | { type: "buy"; intent: { destinationChainId: number } }
    | { type: "onramp"; intent: { chainId: number } }
    | undefined
): number | undefined {
  return quote?.type === "buy"
    ? quote.intent.destinationChainId
    : quote?.type === "onramp"
      ? quote.intent.chainId
      : undefined;
}

Then simplify all three callbacks:

 onError={(e, quote) => {
   const errorMessage = parseError(e);
-  const buyChainId =
-    quote?.type === "buy"
-      ? quote.intent.destinationChainId
-      : quote?.type === "onramp"
-        ? quote.intent.chainId
-        : undefined;
-
-  if (!buyChainId) {
-    return;
-  }
+  const buyChainId = getBuyChainId(quote);
+  if (!buyChainId) return;

Apply the same pattern to onCancel and onSuccess.

Also applies to: 171-180, 203-212

🤖 Prompt for AI Agents
In apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx around lines
138-147 (and similarly at 171-180 and 203-212), the logic that derives
buyChainId from the quote object is duplicated in the onError, onCancel, and
onSuccess callbacks; extract that logic into a single helper function
getBuyChainId (as specified in the review) placed near the top of the file,
returning number | undefined, then replace the repeated conditional blocks in
each callback with a call to getBuyChainId(quote) and use the returned value
(early return if undefined) so all three callbacks share the same
implementation.

Comment on lines +59 to +74
function DotsBackgroundPattern(props: { className?: string }) {
return (
<div
className={cn(
"pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block",
props.className,
)}
style={{
backgroundImage: "radial-gradient(currentColor 1px, transparent 1px)",
backgroundSize: "24px 24px",
maskImage:
"radial-gradient(ellipse 100% 100% at 50% 50%, black 30%, transparent 50%)",
}}
/>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace inline styles with Tailwind arbitrary properties.

Inline style violates the Tailwind-only rule. Use arbitrary properties instead.

 function DotsBackgroundPattern(props: { className?: string }) {
   return (
     <div
-      className={cn(
-        "pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block",
-        props.className,
-      )}
-      style={{
-        backgroundImage: "radial-gradient(currentColor 1px, transparent 1px)",
-        backgroundSize: "24px 24px",
-        maskImage:
-          "radial-gradient(ellipse 100% 100% at 50% 50%, black 30%, transparent 50%)",
-      }}
+      className={cn(
+        "pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block",
+        "bg-[radial-gradient(currentColor_1px,transparent_1px)]",
+        "bg-[length:24px_24px]",
+        "[mask-image:radial-gradient(ellipse_100%_100%_at_50%_50%,black_30%,transparent_50%)]",
+        props.className,
+      )}
     />
   );
 }

As per coding guidelines

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/dashboard/src/app/bridge/components/bridge-page.tsx around lines 59 to
74, the component uses an inline style object for backgroundImage,
backgroundSize, and maskImage which violates the Tailwind-only rule; remove the
style prop and move those rules into the className using Tailwind arbitrary
properties (e.g. add classes like bg-[radial-gradient(...)] for
background-image, bg-[length:24px_24px] or equivalent arbitrary background-size,
and mask-image via mask-[radial-gradient(...)]), keeping the existing cn(...)
call and props.className; ensure proper escaping/encoding of parentheses and
commas in the arbitrary values and that class order preserves priority.

@graphite-app graphite-app bot merged commit b1a7808 into main Oct 17, 2025
24 checks passed
@graphite-app graphite-app bot deleted the mny-274 branch October 17, 2025 23:57
@vercel vercel bot temporarily deployed to Production – thirdweb_playground October 17, 2025 23:57 Inactive
@vercel vercel bot temporarily deployed to Production – wallet-ui October 17, 2025 23:57 Inactive
@vercel vercel bot temporarily deployed to Production – docs-v2 October 17, 2025 23:57 Inactive
@vercel vercel bot temporarily deployed to Production – nebula October 17, 2025 23:57 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dashboard Involves changes to the Dashboard.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants