-
Notifications
You must be signed in to change notification settings - Fork 613
Dashboard: /pay/<id> page UI improvements, SDK: CheckoutWidget minor UI tweaks #8310
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 23cb3bd The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
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 |
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
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. |
WalkthroughAdds 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
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30–40 minutes Points to review:
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro Disabled knowledge base sources:
⛔ Files ignored due to path filters (1)
📒 Files selected for processing (9)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (5)
🧰 Additional context used📓 Path-based instructions (5)**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
apps/{dashboard,playground-web}/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
apps/{dashboard,playground}/**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
apps/{dashboard,playground}/**/*.tsx📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (3)📚 Learning: 2025-08-29T15:37:38.513ZApplied to files:
📚 Learning: 2025-07-18T19:19:55.613ZApplied to files:
📚 Learning: 2025-07-18T19:20:32.530ZApplied to files:
🧬 Code graph analysis (2)apps/dashboard/src/app/pay/[id]/header.tsx (3)
apps/dashboard/src/app/pay/[id]/page.tsx (3)
⏰ 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)
🔇 Additional comments (2)
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
Comment |
size-limit report 📦
|
Codecov Report❌ Patch coverage is 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
🚀 New features to boost your workflow:
|
There was a problem hiding this 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 as20pxin the design system). However, the price text at line 147 should usefontFamily: "monospace"for consistency with similar payment/token displays inPaymentOverview.tsx,TransactionPayment.tsx, andPaymentReceipt.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: MissingclassNameprop on root element.Per coding guidelines for dashboard apps, components should expose a
classNameprop 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
resolveSchemeWithErrorHandlerreturnsundefineddue to an error, the fallback|| ""sets an empty string as thesrc, which may result in a broken image indicator. Consider either:
- Not rendering the
Imgcomponent when resolution fails- 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
ToggleThemeButtonexists inapps/dashboard/src/@/components/blocks/color-mode-toggle.tsxwith 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
DotsBackgroundPatterncomponent exists inapps/dashboard/src/@/components/ui/background-patterns.tsx(lines 3-18). While this version has slightly different styling (negative insets, hidden on small screens), consider:
- Consolidating into a single component with variants
- If keeping separate, the component should properly utilize the
classNameprop parameterIf 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
classNameprop is already being merged withcn(), 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.
⛔ Files ignored due to path filters (1)
apps/dashboard/public/assets/pay/general-pay.pngis 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 inpackages/*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@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless 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@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless 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.tspackages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsxapps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsxapps/dashboard/src/app/pay/[id]/header.tsxapps/dashboard/src/@/utils/sdk-component-theme.tspackages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsxpackages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsxapps/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.tspackages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsxapps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsxapps/dashboard/src/app/pay/[id]/header.tsxapps/dashboard/src/@/utils/sdk-component-theme.tspackages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsxpackages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsxapps/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@exampleand 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.tspackages/thirdweb/src/react/web/ui/Bridge/common/WithHeader.tsxpackages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsxpackages/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
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsxapps/dashboard/src/app/pay/[id]/header.tsxapps/dashboard/src/@/utils/sdk-component-theme.tsapps/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)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsxapps/dashboard/src/app/pay/[id]/header.tsxapps/dashboard/src/@/utils/sdk-component-theme.tsapps/dashboard/src/app/pay/[id]/page.tsx
apps/{dashboard,playground}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Expose a
classNameprop on the root element of every component
Files:
apps/dashboard/src/app/pay/components/client/PayPageWidget.client.tsxapps/dashboard/src/app/pay/[id]/header.tsxapps/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
trackingTightimproves 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-imageclass 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
trackingTightcreates 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
metadataexport provides proper SEO and Open Graph tags for the Pay page.
52-55: LGTM! Efficient parallel data fetching.Using
Promise.allfor 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
forcedThemetodefaultThemeenables 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.pngis present and will correctly resolve to/assets/pay/general-pay.pngin 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 theformatMoney()function, which is exclusively used for formatting fiat currency amounts (viaformatCurrencyAmount()). Fiat currencies typically use 0-2 decimals, so 5 is a conservative and appropriate maximum.Token amounts are formatted separately through
formatTokenBalance()andformatTokenAmount(), both of which accept customizabledecimals/decimalsToShowparameters. 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 ifformatTokenBalance.tsis 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.tswith new parameters (maximumFractionDigits,minimumFractionDigits). If this function is exported as public API, this would warrant a "minor" bump instead of "patch."If
formatTokenBalance.tsis internal-only or only has internal callers updated, the "patch" bump is appropriate. Otherwise, please adjust to "minor."
Merge activity
|
…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 -->
c8b79a4 to
df29258
Compare
There was a problem hiding this 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
resolveSchemeWithErrorHandlerreturnsundefined, thesrcbecomes an empty string"". TheImgcomponent may not handle this gracefully.Consider conditionally rendering the
Imgonly 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 hasp-2(8px padding on all sides) plus asize-5icon (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
datafield 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.
⛔ Files ignored due to path filters (1)
apps/dashboard/public/assets/pay/general-pay.pngis 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@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless 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@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless 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.tsxpackages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsxapps/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.tsxpackages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsxapps/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
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/app/pay/[id]/page.tsxapps/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)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/pay/[id]/page.tsxapps/dashboard/src/app/pay/[id]/header.tsx
apps/{dashboard,playground}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Expose a
classNameprop on the root element of every component
Files:
apps/dashboard/src/app/pay/[id]/page.tsxapps/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@exampleand 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"toalignItems: "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 ofy="md",y="sm"instead ofy="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
forcedThemetodefaultThemeallows users to override the theme via system preferences or manual toggle, which aligns with the newToggleThemeButtonfunctionality in the header.
| import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler"; | ||
| import { payAppThirdwebClient } from "../constants"; | ||
|
|
||
| export function PayIdPageHeader(props: { |
There was a problem hiding this comment.
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.
| 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> | ||
| ); | ||
| } |
There was a problem hiding this comment.
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.
| 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%)", | ||
| }} | ||
| /> | ||
| ); | ||
| } |
There was a problem hiding this comment.
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 -->
df29258 to
23cb3bd
Compare

PR-Codex overview
This PR focuses on UI improvements and minor adjustments in various components of the
thirdwebapplication, enhancing the user experience in payment-related features.Detailed summary
maximumFractionDigitsandminimumFractionDigitstoformatTokenBalance.FiatValuecomponent to includetrackingTight.PayPageWidgetwith additional class names and default image.WithHeadercomponent styles, including margin and text weight.DirectPaymentcomponent for improved layout and styling.PayIdPageHeaderto include project icon and name.DotsBackgroundPatternfor background design inPayPage.Summary by CodeRabbit