Skip to content

Conversation

@MananTank
Copy link
Member

@MananTank MananTank commented Oct 24, 2025


PR-Codex overview

This PR focuses on UI improvements and minor adjustments in various components of the thirdweb application, enhancing the user experience in payment-related features.

Detailed summary

  • Added maximumFractionDigits and minimumFractionDigits to formatTokenBalance.
  • Updated FiatValue component to include trackingTight.
  • Enhanced PayPageWidget with additional class names and default image.
  • Adjusted theme colors for secondary buttons.
  • Modified WithHeader component styles, including margin and text weight.
  • Updated DirectPayment component for improved layout and styling.
  • Refactored PayIdPageHeader to include project icon and name.
  • Created DotsBackgroundPattern for background design in PayPage.

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

Summary by CodeRabbit

  • New Features
    • Theme toggle added to Pay page headers; streamlined Pay page header/layout and decorative background pattern.
    • Pay page metadata (title/description/openGraph) added/updated.
  • Style
    • Refined secondary/tertiary button and background colors, typography weights/letter spacing, spacing and divider styles.
    • Adjusted price and label styling, currency formatting precision, and visual spacing around branding.
    • Pay widget now uses a fallback image when no project image is provided.
  • Chores
    • Added changelog entry documenting a patch release.

@linear
Copy link

linear bot commented Oct 24, 2025

@vercel
Copy link

vercel bot commented Oct 24, 2025

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

Project Deployment Preview Comments Updated (UTC)
docs-v2 Ready Ready Preview Comment Oct 27, 2025 4:24pm
nebula Ready Ready Preview Comment Oct 27, 2025 4:24pm
thirdweb_playground Ready Ready Preview Comment Oct 27, 2025 4:24pm
thirdweb-www Ready Ready Preview Comment Oct 27, 2025 4:24pm
wallet-ui Ready Ready Preview Comment Oct 27, 2025 4:24pm

@changeset-bot
Copy link

changeset-bot bot commented Oct 24, 2025

🦋 Changeset detected

Latest commit: 23cb3bd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
thirdweb Patch
@thirdweb-dev/nebula Patch
@thirdweb-dev/wagmi-adapter Patch
wagmi-inapp Patch

Not sure what this means? Click here to learn what changesets are.

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

@MananTank MananTank marked this pull request as ready for review October 24, 2025 20:06
@MananTank MananTank requested review from a team as code owners October 24, 2025 20:06
@github-actions github-actions bot added Dashboard Involves changes to the Dashboard. packages SDK Involves changes to the thirdweb SDK labels Oct 24, 2025
Copy link
Member Author


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 24, 2025

Walkthrough

Adds a Pay page client-side header with a theme toggle, simplifies Pay page layout and data fetching, adjusts theme color tokens and multiple UI component spacing/typography, applies CheckoutWidget image fallback and className, and adds a changelog entry. No exported API removals.

Changes

Cohort / File(s) Change Summary
Changelog Entry
.changeset/curly-crews-sleep.md
Adds a changelog file documenting a patch release mentioning minor CheckoutWidget UI adjustments.
Pay page & header
apps/dashboard/src/app/pay/[id]/header.tsx, apps/dashboard/src/app/pay/[id]/page.tsx, apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx
Adds PayIdPageHeader (client-side) with a theme toggle and SSR-safe rendering; refactors page.tsx to use the new header, simplify data fetching to tokens + project metadata, export metadata, add DotsBackgroundPattern, and pass className + image fallback in PayPageWidget.client.tsx.
Theme token adjustments
apps/dashboard/src/@/utils/sdk-component-theme.ts
Updates theme override opacities: secondaryButtonBg -> hsl(var(--secondary)/70%), secondaryButtonHoverBg -> hsl(var(--secondary)), tertiaryBg -> hsl(var(--muted)/50%).
Bridge & header UI tweaks
packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx, packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx
Layout/alignment adjustments, reduced title/price weights, added trackingTight on titles, added .tw-header-image wrapper class and margin, adjusted spacers, replaced some dividers with dashed variants.
ConnectWallet formatting & typography
packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx, packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts
FiatValue adds trackingTight to rendered Text; formatTokenBalance sets Intl.NumberFormat options: maximumFractionDigits: 5, minimumFractionDigits: 0.

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant Server as Pay Page (server)
  participant Client as Client Components
  participant API as Tokens & Project Metadata API

  Browser->>Server: GET /pay/[id]
  Server-->>Browser: HTML + exported metadata
  Browser->>Client: Hydrate -> render PayIdPageHeader + PayPageWidget
  Client->>API: fetch(tokens, project metadata)
  API-->>Client: tokens + { name, image }
  Client->>PayPageWidget: render widget (image fallback if missing)
  Client->>PayIdPageHeader: render header (project icon/name)
  Note right of PayIdPageHeader: ToggleThemeButton (client-only) updates theme
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30–40 minutes

Points to review:

  • Pay page data fetching and typing changes in page.tsx (removed ENS/chain logic).
  • Client-only header and theme toggle hydration safety in header.tsx.
  • Visual impact of theme token changes and spacing/typography tweaks in Bridge and ConnectWallet components.
  • CheckoutWidget image fallback and className usage in PayPageWidget.client.tsx.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description does not follow the repository's template structure. The template requires a title in the format "[SDK/Dashboard/Portal] Feature/Fix: Concise title", a Linear issue tag section, and explicit "Notes for the reviewer" and "How to test" sections. The provided description contains only placeholder comments and a PR-Codex auto-generated summary, leaving all the critical template sections unfilled. While the PR-Codex section provides useful technical detail about the changes, it does not substitute for the structured information the template requests. The author should update the PR description to follow the template structure by filling in: (1) reformatting or confirming the title in "[SDK/Dashboard/Portal] Feature/Fix" format, (2) providing or confirming the Linear issue tag (TEAM-xxxx format), (3) adding a "Notes for the reviewer" section highlighting any important context or testing considerations, and (4) providing a "How to test" section with specific instructions for testing the UI improvements across both Dashboard and SDK components.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "Dashboard: /pay/ page UI improvements, SDK: CheckoutWidget minor UI tweaks" is directly related to the changeset. The changes across multiple files align with these two main areas: Dashboard updates to the /pay/[id] page components (header.tsx, page.tsx, PayPageWidget.client.tsx) and SDK CheckoutWidget-related UI tweaks (DirectPayment.tsx, WithHeader.tsx, FiatValue.tsx, formatTokenBalance.ts). The title is specific and clear enough to convey the primary changes without excessive noise.
✨ 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-188

📜 Recent 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 df29258 and 23cb3bd.

⛔ Files ignored due to path filters (1)
  • apps/dashboard/public/assets/pay/general-pay.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • .changeset/curly-crews-sleep.md (1 hunks)
  • apps/dashboard/src/@/utils/sdk-component-theme.ts (2 hunks)
  • apps/dashboard/src/app/pay/[id]/header.tsx (1 hunks)
  • apps/dashboard/src/app/pay/[id]/page.tsx (3 hunks)
  • apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (6 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx (3 hunks)
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .changeset/curly-crews-sleep.md
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts
  • packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.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/pay/[id]/header.tsx
  • apps/dashboard/src/app/pay/[id]/page.tsx
  • apps/dashboard/src/@/utils/sdk-component-theme.ts
**/*.{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/pay/[id]/header.tsx
  • apps/dashboard/src/app/pay/[id]/page.tsx
  • apps/dashboard/src/@/utils/sdk-component-theme.ts
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/pay/[id]/header.tsx
  • apps/dashboard/src/app/pay/[id]/page.tsx
  • apps/dashboard/src/@/utils/sdk-component-theme.ts
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/pay/[id]/header.tsx
  • apps/dashboard/src/app/pay/[id]/page.tsx
  • apps/dashboard/src/@/utils/sdk-component-theme.ts
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/pay/[id]/header.tsx
  • apps/dashboard/src/app/pay/[id]/page.tsx
🧠 Learnings (3)
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to **/*.{ts,tsx} : Use explicit function declarations and explicit return types in TypeScript

Applied to files:

  • apps/dashboard/src/app/pay/[id]/header.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Write idiomatic TypeScript with explicit function declarations and return types

Applied to files:

  • apps/dashboard/src/app/pay/[id]/header.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/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • apps/dashboard/src/app/pay/[id]/header.tsx
  • apps/dashboard/src/app/pay/[id]/page.tsx
🧬 Code graph analysis (2)
apps/dashboard/src/app/pay/[id]/header.tsx (3)
apps/playground-web/src/app/ai/components/resolveSchemeWithErrorHandler.ts (1)
  • resolveSchemeWithErrorHandler (4-21)
apps/dashboard/src/app/pay/constants.ts (1)
  • payAppThirdwebClient (59-59)
apps/dashboard/src/@/components/blocks/color-mode-toggle.tsx (1)
  • ToggleThemeButton (10-36)
apps/dashboard/src/app/pay/[id]/page.tsx (3)
apps/dashboard/src/app/pay/[id]/header.tsx (1)
  • PayIdPageHeader (12-44)
apps/dashboard/src/@/components/ui/background-patterns.tsx (1)
  • DotsBackgroundPattern (4-19)
apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx (1)
  • PayPageWidget (16-97)
⏰ 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, webpack)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Build Packages
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/dashboard/src/@/utils/sdk-component-theme.ts (1)

24-36: LGTM! Theme color adjustments improve visual consistency.

The opacity adjustments to secondaryButtonBg, secondaryButtonHoverBg, and tertiaryBg refine the visual hierarchy and align with the broader UI improvements in this PR.

apps/dashboard/src/app/pay/[id]/page.tsx (1)

52-55: LGTM! Simplified data fetching improves performance.

Removing the chain metadata and ENS resolution prefetch streamlines the page load. The token and project metadata are the essential pieces needed for initial render.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

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

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

@MananTank MananTank changed the title Dashboard: /pay/<id> page UI improvements Dashboard: /pay/<id> page UI improvements, SDK: CheckoutWidget minor UI tweaks Oct 24, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Oct 24, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.55 KB (0%) 1.3 s (0%) 309 ms (+129.06% 🔺) 1.6 s
thirdweb (cjs) 366.18 KB (0%) 7.4 s (0%) 1.4 s (+14.63% 🔺) 8.7 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 78 ms (+1367.62% 🔺) 193 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 61 ms (+1079.62% 🔺) 72 ms
thirdweb/react (minimal + tree-shaking) 19.09 KB (0%) 382 ms (0%) 54 ms (+694.83% 🔺) 436 ms

@codecov
Copy link

codecov bot commented Oct 24, 2025

Codecov Report

❌ Patch coverage is 14.28571% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 54.88%. Comparing base (dcef3f4) to head (23cb3bd).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...dweb/src/react/web/ui/Bridge/common/WithHeader.tsx 25.00% 3 Missing ⚠️
...web/ui/ConnectWallet/screens/formatTokenBalance.ts 0.00% 2 Missing ⚠️
...eb/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8310      +/-   ##
==========================================
- Coverage   54.89%   54.88%   -0.01%     
==========================================
  Files         919      919              
  Lines       60697    60701       +4     
  Branches     4129     4131       +2     
==========================================
  Hits        33318    33318              
- Misses      27277    27281       +4     
  Partials      102      102              
Flag Coverage Δ
packages 54.88% <14.28%> (-0.01%) ⬇️
Files with missing lines Coverage Δ
...eb/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx 21.95% <0.00%> (ø)
...web/ui/ConnectWallet/screens/formatTokenBalance.ts 33.33% <0.00%> (-1.81%) ⬇️
...dweb/src/react/web/ui/Bridge/common/WithHeader.tsx 12.50% <25.00%> (-0.47%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (1)

131-152: Add monospace font to price display for consistency with similar components.

The spacing token "md+" is valid and widely used throughout the codebase (defined as 20px in the design system). However, the price text at line 147 should use fontFamily: "monospace" for consistency with similar payment/token displays in PaymentOverview.tsx, TransactionPayment.tsx, and PaymentReceipt.tsx. Monospace ensures numeric values align consistently and prevents layout shifts when amounts change.

<Text color="primaryText" size="sm" style={{ fontFamily: "monospace" }}>
  {`${paymentInfo.amount} ${paymentInfo.token.symbol}`}
</Text>
🧹 Nitpick comments (5)
apps/dashboard/src/app/pay/[id]/header.tsx (4)

12-44: Missing className prop on root element.

Per coding guidelines for dashboard apps, components should expose a className prop on the root element for composability.

As per coding guidelines.

Apply this diff:

 export function PayIdPageHeader(props: {
   projectName: string;
   projectIcon: string | undefined;
+  className?: string;
 }) {
   return (
-    <div className="border-b border-border/70">
+    <div className={cn("border-b border-border/70", props.className)}>
       <header className="container flex max-w-7xl justify-between py-4">

20-31: Consider handling missing project icon more explicitly.

When resolveSchemeWithErrorHandler returns undefined due to an error, the fallback || "" sets an empty string as the src, which may result in a broken image indicator. Consider either:

  1. Not rendering the Img component when resolution fails
  2. Providing a default fallback icon
-          {props.projectIcon && (
+          {props.projectIcon &&
+            resolveSchemeWithErrorHandler({
+              uri: props.projectIcon,
+              client: payAppThirdwebClient,
+            }) && (
             <Img
               src={
                 resolveSchemeWithErrorHandler({
                   uri: props.projectIcon,
                   client: payAppThirdwebClient,
-                }) || ""
+                })!
               }

46-72: Consider consolidating duplicate ToggleThemeButton implementations.

A similar ToggleThemeButton exists in apps/dashboard/src/@/components/blocks/color-mode-toggle.tsx with slightly different styling. Consider extracting common logic or reusing the existing component to reduce duplication.

For reference, the existing implementation is at:

  • apps/dashboard/src/@/components/blocks/color-mode-toggle.tsx (lines 9-35)

65-67: Remove trailing space in className.

Line 65 has a trailing space in the className string.

-        {theme === "light" ? (
-          <SunIcon className="size-5 " />
-        ) : (
-          <MoonIcon className="size-5 " />
-        )}
+        {theme === "light" ? (
+          <SunIcon className="size-5" />
+        ) : (
+          <MoonIcon className="size-5" />
+        )}
apps/dashboard/src/app/pay/[id]/page.tsx (1)

113-128: Consider consolidating with existing DotsBackgroundPattern.

A similar DotsBackgroundPattern component exists in apps/dashboard/src/@/components/ui/background-patterns.tsx (lines 3-18). While this version has slightly different styling (negative insets, hidden on small screens), consider:

  1. Consolidating into a single component with variants
  2. If keeping separate, the component should properly utilize the className prop parameter

If keeping this separate implementation, apply the className prop properly:

 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/15 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%)",
       }}
     />
   );
 }

The className prop is already being merged with cn(), so this is correct. However, consider if this duplication is necessary or if the existing pattern component could be reused with additional props.

📜 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 46b9d2d and c8b79a4.

⛔ Files ignored due to path filters (1)
  • apps/dashboard/public/assets/pay/general-pay.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • .changeset/curly-crews-sleep.md (1 hunks)
  • apps/dashboard/src/@/utils/sdk-component-theme.ts (2 hunks)
  • apps/dashboard/src/app/pay/[id]/header.tsx (1 hunks)
  • apps/dashboard/src/app/pay/[id]/page.tsx (3 hunks)
  • apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (6 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx (3 hunks)
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

.changeset/*.md: Each change in packages/* must include a changeset for the appropriate package
Version bump rules: patch for non‑API changes; minor for new/modified public API

Files:

  • .changeset/curly-crews-sleep.md
**/*.{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:

  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts
  • packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx
  • apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx
  • apps/dashboard/src/app/pay/[id]/header.tsx
  • apps/dashboard/src/@/utils/sdk-component-theme.ts
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx
  • apps/dashboard/src/app/pay/[id]/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:

  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts
  • packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx
  • apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx
  • apps/dashboard/src/app/pay/[id]/header.tsx
  • apps/dashboard/src/@/utils/sdk-component-theme.ts
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx
  • apps/dashboard/src/app/pay/[id]/page.tsx
packages/thirdweb/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

packages/thirdweb/**/*.{ts,tsx}: Every public symbol must have comprehensive TSDoc with at least one compiling @example and a custom tag (@beta, @internal, @experimental, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g., const { jsPDF } = await import("jspdf"))

Files:

  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts
  • packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.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/pay/components/client/PayPageWidget.client.tsx
  • apps/dashboard/src/app/pay/[id]/header.tsx
  • apps/dashboard/src/@/utils/sdk-component-theme.ts
  • apps/dashboard/src/app/pay/[id]/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/pay/components/client/PayPageWidget.client.tsx
  • apps/dashboard/src/app/pay/[id]/header.tsx
  • apps/dashboard/src/@/utils/sdk-component-theme.ts
  • apps/dashboard/src/app/pay/[id]/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/pay/components/client/PayPageWidget.client.tsx
  • apps/dashboard/src/app/pay/[id]/header.tsx
  • apps/dashboard/src/app/pay/[id]/page.tsx
🧠 Learnings (1)
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
PR: thirdweb-dev/js#7227
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/OpenEditionMetadata.tsx:26-26
Timestamp: 2025-05-30T17:14:25.332Z
Learning: The ModuleCardUIProps interface already includes a client prop of type ThirdwebClient, so when components use `Omit<ModuleCardUIProps, "children" | "updateButton">`, they inherit the client prop without needing to add it explicitly.

Applied to files:

  • packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx
🧬 Code graph analysis (5)
packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx (2)
packages/thirdweb/src/react/core/design-system/index.ts (2)
  • radius (156-164)
  • spacing (142-154)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Text (18-34)
apps/dashboard/src/app/pay/[id]/header.tsx (3)
apps/playground-web/src/app/ai/components/resolveSchemeWithErrorHandler.ts (1)
  • resolveSchemeWithErrorHandler (4-21)
apps/dashboard/src/app/pay/constants.ts (1)
  • payAppThirdwebClient (59-59)
apps/dashboard/src/@/components/blocks/color-mode-toggle.tsx (1)
  • ToggleThemeButton (10-36)
packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (2)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Text (18-34)
packages/thirdweb/src/react/web/ui/components/basic.tsx (2)
  • Container (80-193)
  • Line (70-75)
packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx (1)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Text (18-34)
apps/dashboard/src/app/pay/[id]/page.tsx (3)
apps/dashboard/src/app/pay/[id]/header.tsx (1)
  • PayIdPageHeader (12-43)
apps/dashboard/src/@/components/ui/background-patterns.tsx (1)
  • DotsBackgroundPattern (4-19)
apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx (1)
  • PayPageWidget (16-97)
🪛 GitHub Check: codecov/patch
packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts

[warning] 52-53: packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts#L52-L53
Added lines #L52 - L53 were not covered by tests

packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx

[warning] 23-23: packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx#L23
Added line #L23 was not covered by tests


[warning] 31-31: packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx#L31
Added line #L31 was not covered by tests


[warning] 45-45: packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx#L45
Added line #L45 was not covered by tests

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx

[warning] 48-48: packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx#L48
Added line #L48 was not covered by tests

🔇 Additional comments (15)
packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (3)

100-129: LGTM! Clean typography and layout improvements.

The alignment change to alignItems: "end" properly aligns the price and metadata label at their baseline, and the typography adjustments (lighter font weight, uppercase label with letter-spacing and reduced opacity) create a clearer visual hierarchy that follows modern UI design patterns.


177-181: Spacing and divider standardization looks good.

The transition from "lg" to "md+" spacing and the switch to dashed dividers maintain consistency with the changes throughout the component.


191-195: Spacing consistency maintained.

The standardized "md+" spacing values in the branding section align with the component-wide spacing improvements.

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx (1)

48-48: LGTM! Typography enhancement aligns with PR objectives.

The addition of trackingTight improves text readability by applying tighter letter spacing (-0.025em). This change is consistent with similar typography refinements across other components in this PR.

apps/dashboard/src/@/utils/sdk-component-theme.ts (2)

24-25: LGTM! Improved button state visibility.

The opacity adjustments create better visual hierarchy: secondary buttons now start at 70% opacity and become fully opaque on hover (previously 100% → 80%). This improves the interactive feedback.


36-36: LGTM! Enhanced tertiary background visibility.

Increasing tertiary background opacity from 30% to 50% improves visibility while maintaining the subtle background effect.

packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx (3)

23-23: LGTM! Class name enables conditional styling.

The tw-header-image class allows parent components (like PayPageWidget) to apply conditional styling via CSS selectors, enabling the invert filter for default images.


31-31: LGTM! Improved spacing between header image and content.

Adding spacing.xxs (6px) provides visual breathing room between the header image and the content below.


45-45: LGTM! Typography refinements enhance readability.

Reducing font weight (600 → 500) and adding trackingTight creates a more refined, consistent typography system across the UI.

apps/dashboard/src/app/pay/[id]/page.tsx (3)

18-25: LGTM! Proper Next.js metadata export.

Adding the metadata export provides proper SEO and Open Graph tags for the Pay page.


52-55: LGTM! Efficient parallel data fetching.

Using Promise.all for parallel fetching of tokens and project metadata improves page load performance.


63-92: LGTM! Simplified and cleaner page structure.

The refactored layout with a dedicated header component and streamlined main area significantly improves code maintainability. The switch from forcedTheme to defaultTheme enables user theme toggling, aligning with the new theme toggle button in the header.

apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx (1)

67-72: Asset verification complete.

The default image asset exists at the expected location. The file apps/dashboard/public/assets/pay/general-pay.png is present and will correctly resolve to /assets/pay/general-pay.png in the component.

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts (1)

52-53: The review comment incorrectly applies token precision concerns to a fiat currency formatter.

The code at lines 52-53 (maximumFractionDigits: 5) is in the formatMoney() function, which is exclusively used for formatting fiat currency amounts (via formatCurrencyAmount()). Fiat currencies typically use 0-2 decimals, so 5 is a conservative and appropriate maximum.

Token amounts are formatted separately through formatTokenBalance() and formatTokenAmount(), both of which accept customizable decimals / decimalsToShow parameters. Token decimal precision is not constrained by this code.

Likely an incorrect or invalid review comment.

.changeset/curly-crews-sleep.md (1)

1-5: Verify bump type if formatTokenBalance.ts is a public API.

Per coding guidelines, use "patch" for non-API changes and "minor" for new/modified public APIs. The PR includes updates to formatTokenBalance.ts with new parameters (maximumFractionDigits, minimumFractionDigits). If this function is exported as public API, this would warrant a "minor" bump instead of "patch."

If formatTokenBalance.ts is internal-only or only has internal callers updated, the "patch" bump is appropriate. Otherwise, please adjust to "minor."

@graphite-app
Copy link
Contributor

graphite-app bot commented Oct 25, 2025

Merge activity

graphite-app bot pushed a commit that referenced this pull request Oct 25, 2025
…UI tweaks (#8310)

<!--

## 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 minor UI adjustments and enhancements in the `CheckoutWidget` and related components, improving visual styling and user experience in the payment process.

### Detailed summary
- Adjusted `maximumFractionDigits` and `minimumFractionDigits` in `formatTokenBalance.ts`.
- Enhanced `Text` components with `trackingTight` and modified `weight` properties in `FiatValue.tsx` and `DirectPayment.tsx`.
- Updated `PayPageWidget` with new `className` for styling.
- Improved button and header styling in `PayIdPageHeader`.
- Added `DotsBackgroundPattern` component for background styling.
- Changed background colors and spacing in various components for better UI consistency.
- Modified `Spacer` usage for improved layout spacing.

> ✨ 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 theme toggle button to Pay page headers, enabling light/dark mode switching.

* **Style**
  * Refined secondary button and tertiary background color values.
  * Enhanced typography weight and letter spacing across components.
  * Improved visual hierarchy with refined spacing adjustments.
  * Enhanced currency and token balance formatting precision.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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/app/pay/[id]/page.tsx (1)

27-27: Add explicit return types.

Per coding guidelines, all function declarations should have explicit return types.

As per coding guidelines

Apply this diff:

-export default async function PayPage({
+export default async function PayPage({
   params,
   searchParams,
 }: {
   params: Promise<{ id: string }>;
   searchParams: Promise<{ redirectUri?: string; theme?: "light" | "dark" }>;
-}) {
+}): Promise<JSX.Element> {

-async function getProjectMetadata(clientId: string) {
+async function getProjectMetadata(clientId: string): Promise<{ name: string; image: string | null }> {

-function DotsBackgroundPattern(props: { className?: string }) {
+function DotsBackgroundPattern(props: { className?: string }): JSX.Element {

Also applies to: 95-95, 113-113

🧹 Nitpick comments (3)
apps/dashboard/src/app/pay/[id]/header.tsx (2)

22-26: Handle undefined image gracefully.

When resolveSchemeWithErrorHandler returns undefined, the src becomes an empty string "". The Img component may not handle this gracefully.

Consider conditionally rendering the Img only when a valid URL is available:

         <div className="flex items-center gap-3">
-          {props.projectIcon && (
+          {props.projectIcon &&
+            resolveSchemeWithErrorHandler({
+              uri: props.projectIcon,
+              client: payAppThirdwebClient,
+            }) && (
             <Img
               src={
                 resolveSchemeWithErrorHandler({
                   uri: props.projectIcon,
                   client: payAppThirdwebClient,
-                }) || ""
+                })!
               }
               alt=""
               className="rounded-full size-6 object-cover"
             />
           )}

Or memoize the resolved URL to avoid calling the function twice:

+  const resolvedIcon = props.projectIcon
+    ? resolveSchemeWithErrorHandler({
+        uri: props.projectIcon,
+        client: payAppThirdwebClient,
+      })
+    : undefined;
+
   return (
     <div className="border-b border-border/70">
       <header className="container flex max-w-7xl justify-between py-4">
         <div className="flex items-center gap-3">
-          {props.projectIcon && (
+          {resolvedIcon && (
             <Img
-              src={
-                resolveSchemeWithErrorHandler({
-                  uri: props.projectIcon,
-                  client: payAppThirdwebClient,
-                }) || ""
-              }
+              src={resolvedIcon}
               alt=""
               className="rounded-full size-6 object-cover"
             />
           )}

51-51: Skeleton size mismatch.

The Skeleton is size-[36px] (36×36px), but the actual Button has p-2 (8px padding on all sides) plus a size-5 icon (20px), resulting in a total size of approximately 36×36px. However, the button's computed size may differ slightly depending on border widths and line heights.

Verify that the skeleton and button sizes match visually, or adjust the skeleton size to match the computed button dimensions more precisely.

apps/dashboard/src/app/pay/[id]/page.tsx (1)

95-111: Validate API response structure.

The type annotation at line 108 assumes a specific response structure, but there's no runtime validation to ensure the API returns the expected shape. If the API response changes or the data field is missing, this could cause runtime errors.

Add runtime validation or error handling:

 async function getProjectMetadata(clientId: string) {
   const url = new URL(`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v2/keys/lookup`);
   url.searchParams.append("clientId", clientId);
   const response = await fetch(url.toString(), {
     headers: {
       "x-service-api-key": API_SERVER_SECRET,
     },
   });
   if (!response.ok) {
     throw new Error("Failed to fetch project");
   }

-  const { data } = (await response.json()) as {
+  const json = await response.json();
+  
+  if (!json?.data || typeof json.data.name !== 'string') {
+    throw new Error("Invalid project metadata response");
+  }
+  
+  const { data } = json as {
     data: { name: string; image: string | null };
   };
   return data;
 }
📜 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 c8b79a4 and df29258.

⛔ Files ignored due to path filters (1)
  • apps/dashboard/public/assets/pay/general-pay.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • .changeset/curly-crews-sleep.md (1 hunks)
  • apps/dashboard/src/@/utils/sdk-component-theme.ts (2 hunks)
  • apps/dashboard/src/app/pay/[id]/header.tsx (1 hunks)
  • apps/dashboard/src/app/pay/[id]/page.tsx (3 hunks)
  • apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (6 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx (3 hunks)
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsx
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.ts
  • apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx
  • apps/dashboard/src/@/utils/sdk-component-theme.ts
  • .changeset/curly-crews-sleep.md
  • packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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/pay/[id]/page.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • apps/dashboard/src/app/pay/[id]/header.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/pay/[id]/page.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • apps/dashboard/src/app/pay/[id]/header.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/pay/[id]/page.tsx
  • apps/dashboard/src/app/pay/[id]/header.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/pay/[id]/page.tsx
  • apps/dashboard/src/app/pay/[id]/header.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/pay/[id]/page.tsx
  • apps/dashboard/src/app/pay/[id]/header.tsx
packages/thirdweb/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

packages/thirdweb/**/*.{ts,tsx}: Every public symbol must have comprehensive TSDoc with at least one compiling @example and a custom tag (@beta, @internal, @experimental, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g., const { jsPDF } = await import("jspdf"))

Files:

  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
🧬 Code graph analysis (3)
apps/dashboard/src/app/pay/[id]/page.tsx (3)
apps/dashboard/src/app/pay/[id]/header.tsx (1)
  • PayIdPageHeader (12-44)
apps/dashboard/src/@/components/ui/background-patterns.tsx (1)
  • DotsBackgroundPattern (4-19)
apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsx (1)
  • PayPageWidget (16-97)
packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (2)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Text (18-34)
packages/thirdweb/src/react/web/ui/components/basic.tsx (2)
  • Container (80-193)
  • Line (70-75)
apps/dashboard/src/app/pay/[id]/header.tsx (3)
apps/playground-web/src/app/ai/components/resolveSchemeWithErrorHandler.ts (1)
  • resolveSchemeWithErrorHandler (4-21)
apps/dashboard/src/app/pay/constants.ts (1)
  • payAppThirdwebClient (59-59)
apps/dashboard/src/@/components/blocks/color-mode-toggle.tsx (1)
  • ToggleThemeButton (10-36)
⏰ 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, vite)
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (4)

100-100: Verify alignment change impact.

The alignment changed from center="y" to alignItems: "end". This shifts child elements to the bottom of the flex container instead of centering them vertically. Ensure this produces the desired visual layout for the price section.


111-111: LGTM - Typography refinement.

The font weight reduction from 600 to 500 aligns with the broader typography improvements mentioned in the PR objectives.


121-124: LGTM - Enhanced label styling.

The uppercase transformation, increased letter spacing, and reduced opacity provide better visual hierarchy for the "One-time payment" label.


131-196: LGTM - Spacing and divider refinements.

The spacer value changes (y="md+" instead of y="md", y="sm" instead of y="xs") and the switch to dashed lines improve vertical rhythm and visual separation throughout the component.

apps/dashboard/src/app/pay/[id]/page.tsx (1)

65-65: LGTM - Theme prop change.

Switching from forcedTheme to defaultTheme allows users to override the theme via system preferences or manual toggle, which aligns with the new ToggleThemeButton functionality in the header.

import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler";
import { payAppThirdwebClient } from "../constants";

export function PayIdPageHeader(props: {
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 types.

Per coding guidelines, all function declarations should have explicit return types.

As per coding guidelines

Apply this diff:

-export function PayIdPageHeader(props: {
+export function PayIdPageHeader(props: {
   projectName: string;
   projectIcon: string | undefined;
-}) {
+}): JSX.Element {

-function ToggleThemeButton(props: { className?: string }) {
+function ToggleThemeButton(props: { className?: string }): JSX.Element {

Also applies to: 46-46

🤖 Prompt for AI Agents
In apps/dashboard/src/app/pay/[id]/header.tsx around lines 12 and 46, the two
function component declarations lack explicit return types; update each function
signature to include an explicit return type (e.g., : JSX.Element or :
React.ReactElement) so they comply with the coding guidelines, and ensure any
union with null (e.g., JSX.Element | null) is used if the component can return
null.

Comment on lines +46 to +72
function ToggleThemeButton(props: { className?: string }) {
const { setTheme, theme } = useTheme();

return (
<ClientOnly
ssr={<Skeleton className="size-[36px] rounded-full border bg-accent" />}
>
<Button
aria-label="Toggle theme"
className={cn(
"h-auto w-auto rounded-full p-2 text-muted-foreground hover:text-foreground",
props.className,
)}
onClick={() => {
setTheme(theme === "dark" ? "light" : "dark");
}}
variant="ghost"
>
{theme === "light" ? (
<SunIcon className="size-5 " />
) : (
<MoonIcon className="size-5 " />
)}
</Button>
</ClientOnly>
);
}
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

Code duplication - reuse existing ToggleThemeButton.

This ToggleThemeButton implementation duplicates the existing component at apps/dashboard/src/@/components/blocks/color-mode-toggle.tsx. The only differences are minor styling adjustments (variant="ghost" vs variant="outline", and slightly different button sizes).

Consider importing and reusing the existing component:

+import { ToggleThemeButton } from "@/components/blocks/color-mode-toggle";
+
 export function PayIdPageHeader(props: {
   projectName: string;
   projectIcon: string | undefined;
 }) {
   return (
     <div className="border-b border-border/70">
       <header className="container flex max-w-7xl justify-between py-4">
         <div className="flex items-center gap-3">
           {props.projectIcon && (
             <Img
               src={
                 resolveSchemeWithErrorHandler({
                   uri: props.projectIcon,
                   client: payAppThirdwebClient,
                 }) || ""
               }
               alt=""
               className="rounded-full size-6 object-cover"
             />
           )}

           <h2 className="text-xl font-semibold tracking-tight">
             {props.projectName}
           </h2>
         </div>

         <div className="flex items-center gap-3 lg:gap-5">
-          <ToggleThemeButton />
+          <ToggleThemeButton className="h-auto w-auto p-2 text-muted-foreground hover:text-foreground" />
         </div>
       </header>
     </div>
   );
 }
-
-function ToggleThemeButton(props: { className?: string }) {
-  const { setTheme, theme } = useTheme();
-
-  return (
-    <ClientOnly
-      ssr={<Skeleton className="size-[36px] rounded-full border bg-accent" />}
-    >
-      <Button
-        aria-label="Toggle theme"
-        className={cn(
-          "h-auto w-auto rounded-full p-2 text-muted-foreground hover:text-foreground",
-          props.className,
-        )}
-        onClick={() => {
-          setTheme(theme === "dark" ? "light" : "dark");
-        }}
-        variant="ghost"
-      >
-        {theme === "light" ? (
-          <SunIcon className="size-5 " />
-        ) : (
-          <MoonIcon className="size-5 " />
-        )}
-      </Button>
-    </ClientOnly>
-  );
-}

If styling differences are needed, extend the existing component to accept additional props rather than duplicating the implementation.

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

🤖 Prompt for AI Agents
In apps/dashboard/src/app/pay/[id]/header.tsx around lines 46 to 72, this local
ToggleThemeButton duplicates the component defined at
apps/dashboard/src/@/components/blocks/color-mode-toggle.tsx; replace the
duplicate by importing and reusing the existing component (or extend the
existing component to accept props for variant, className and size overrides),
then pass the needed props (e.g., variant="ghost" and any extra className) from
this file so styling differences are applied without duplicating logic; remove
the local ToggleThemeButton implementation after switching to the shared
component and update imports accordingly.

Comment on lines +113 to +128
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/15 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

Code duplication - import existing DotsBackgroundPattern.

This DotsBackgroundPattern implementation duplicates the existing component at apps/dashboard/src/@/components/ui/background-patterns.tsx (shown in relevant code snippets). The only differences are the className values.

Import and reuse the existing component:

+import { DotsBackgroundPattern } from "@/components/ui/background-patterns";
+
 // ...

         <main className="flex justify-center py-12 w-full items-center grow overflow-hidden relative">
-          <DotsBackgroundPattern />
+          <DotsBackgroundPattern className="pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/15 hidden lg:block" />
           <PayPageWidget
             amount={paymentLink.amount ? BigInt(paymentLink.amount) : undefined}
             chainId={Number(paymentLink.destinationToken.chainId)}
             clientId={undefined}
             image={paymentLink.imageUrl}
             name={paymentLink.title}
             paymentLinkId={id}
             purchaseData={paymentLink.purchaseData}
             recipientAddress={paymentLink.receiver}
             redirectUri={redirectUri}
             token={token}
           />
         </main>
       </ThemeProvider>
     </div>
   );
 }
 
 async function getProjectMetadata(clientId: string) {
   // ...
 }
-
-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/15 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%)",
-      }}
-    />
-  );
-}

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

🤖 Prompt for AI Agents
In apps/dashboard/src/app/pay/[id]/page.tsx around lines 113 to 128, the local
DotsBackgroundPattern duplicates the component defined in
apps/dashboard/src/@/components/ui/background-patterns.tsx; remove the duplicate
function, add an import for the existing DotsBackgroundPattern from that file,
and use it in place of the local component while forwarding the className prop
(combine any local className additions with the incoming className using the
existing cn utility) so the only differences are preserved via props rather than
duplicated implementation.

…UI tweaks (#8310)

<!--

## 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 UI enhancements and minor adjustments in the `CheckoutWidget` and related components of the payment dashboard, improving styling, layout, and functionality.

### Detailed summary
- Minor UI adjustments in `CheckoutWidget`.
- Updated `formatTokenBalance.ts` to allow more flexible currency formatting.
- Added `trackingTight` prop to `Text` in `FiatValue.tsx`.
- Enhanced `PayPageWidget` with new class names for styling.
- Adjusted color values in SDK theme definitions.
- Improved layout and spacing in `WithHeader.tsx`.
- Modified text properties in `DirectPayment.tsx` for better readability.
- Created a new `PayIdPageHeader` component for improved header structure.
- Replaced complex JSX in `PayPage` with cleaner component structure, including `DotsBackgroundPattern`.

> ✨ 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**
  * Theme toggle added to Pay page headers; streamlined Pay page header and layout with decorative background.

* **Style**
  * Refined secondary/tertiary button and background colors, typography weights/letter spacing, spacing and divider styles.
  * Adjusted price and label styling, currency formatting precision, and visual spacing around branding.
  * Pay widget now uses a fallback image when no project image is provided.

* **Chores**
  * Added changelog entry documenting a patch release.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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. packages SDK Involves changes to the thirdweb SDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants