Skip to content

self-serve infra deployment: part 1 #7456

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jnsdls
Copy link
Member

@jnsdls jnsdls commented Jun 27, 2025

Add Infrastructure Section to Team Dashboard

This PR adds a new "Infrastructure" section to the team dashboard, allowing users to deploy and manage blockchain infrastructure services. Key changes include:

  • Added a new "Infrastructure" tab in the team navigation with a "New" badge
  • Created infrastructure deployment UI with a multi-step checkout flow:
    • Chain selection with filter for deprecated chains
    • Service selection for RPC, Insight, and Account Abstraction services
    • Payment frequency options with annual discount
    • Order summary with pricing calculations
  • Enhanced UpsellBannerCard component to support onClick handlers
  • Added disableDeprecated option to SingleNetworkSelector component
  • Updated Biome schema URLs from 2.0.0 to 2.0.4 across all packages

The infrastructure deployment UI includes detailed pricing information, bundle discounts, and a complete checkout experience for teams to easily deploy blockchain infrastructure services.

Summary by CodeRabbit

  • New Features

    • Introduced a "Scale" tab with a "New" badge in the team dashboard.
    • Added a multi-step infrastructure deployment flow, including chain selection, service selection (with bundle discounts), payment frequency options, and a detailed order summary.
    • Launched infrastructure overview and detail pages for teams.
    • Enabled feature access control for chain infrastructure based on team billing plans.
  • Improvements

    • Enhanced the network selector to optionally hide deprecated chains.
    • Updated the upsell banner to support both link and callback call-to-action variants.
    • Changed the skeleton loader in chain icons for improved accessibility.
  • Chores

    • Updated configuration schema versions to 2.0.4 across multiple project files.

PR-Codex overview

This PR primarily updates the $schema version in multiple biome.json files and introduces new components and features related to infrastructure management in the dashboard application, enhancing the user experience for deploying and managing services.

Detailed summary

  • Updated $schema in biome.json files from version 2.0.0 to 2.0.4 across multiple applications and packages.
  • Added InfrastructurePage component in page.tsx.
  • Implemented DeployInfrastructurePage with InfrastructureCheckout in deploy/page.tsx.
  • Enhanced NetworkSelectors to filter deprecated chains.
  • Introduced PaymentFrequencySelector and ServiceSelector components for service management.
  • Updated OrderSummary to calculate and display pricing with discounts.
  • Added InfrastructureCheckout for selecting chains and services.
  • Included new layout and upsell features in the team section of the dashboard.

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

Copy link

vercel bot commented Jun 27, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
docs-v2 ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 27, 2025 6:27am
nebula ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 27, 2025 6:27am
thirdweb_playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 27, 2025 6:27am
thirdweb-www ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 27, 2025 6:27am
wallet-ui ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 27, 2025 6:27am

Copy link

changeset-bot bot commented Jun 27, 2025

⚠️ No Changeset found

Latest commit: 4bd0809

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

This PR includes no changesets

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

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

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

Copy link
Contributor

coderabbitai bot commented Jun 27, 2025

Walkthrough

This update introduces a new "Scale" tab and a suite of React components for a blockchain infrastructure deployment and checkout flow within the dashboard's team area. It adds service selection, payment frequency options, and order summary features. Several biome.json files across the monorepo are also updated to reference schema version 2.0.4.

Changes

File(s) Change Summary
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/layout.tsx Added a layout component that gates access to chain infrastructure features based on team billing plan.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/page.tsx Added simple InfrastructurePage component for the infrastructure overview.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/[chain_id]/page.tsx Added InfrastructurePage component to display infrastructure details for a selected chain.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/page.tsx Added DeployInfrastructurePage component to render the checkout flow.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/checkout.tsx Added InfrastructureCheckout component implementing a multi-step infrastructure deployment UI.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/order-summary.tsx Added OrderSummary component for pricing, discounts, and checkout summary.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/payment-frequency-selector.tsx Added PaymentFrequencySelector component and type for billing options.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/service-selector.tsx Added ServiceSelector component and related types for selecting and upselling services.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx Added a new "Scale" tab with a "New" badge to the team layout navigation.
apps/dashboard/src/@/components/blocks/UpsellBannerCard.tsx Updated CTA prop type to support link or callback variants and made it optional.
apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx Added disableDeprecated prop to SingleNetworkSelector to filter deprecated chains.
apps/dashboard/src/@/icons/ChainIcon.tsx Changed skeleton placeholder from <div> to <span>.
biome.json and all */biome.json files across apps and packages Updated $schema reference from version 2.0.0 to 2.0.4.

Sequence Diagram(s)

Infrastructure Deployment and Checkout Flow

sequenceDiagram
    participant User
    participant Layout
    participant InfrastructureCheckout
    participant ServiceSelector
    participant PaymentFrequencySelector
    participant OrderSummary

    User->>Layout: Access /team/[team_slug]/~/scale/deploy
    Layout->>InfrastructureCheckout: Render with client prop
    InfrastructureCheckout->>ServiceSelector: Render with available services
    InfrastructureCheckout->>PaymentFrequencySelector: Render with options
    InfrastructureCheckout->>OrderSummary: Render with selected chain, services, payment frequency
    User->>ServiceSelector: Select/deselect services
    ServiceSelector-->>InfrastructureCheckout: Update selectedServices
    User->>PaymentFrequencySelector: Change payment frequency
    PaymentFrequencySelector-->>InfrastructureCheckout: Update paymentFrequency
    InfrastructureCheckout->>OrderSummary: Update summary on changes
    User->>OrderSummary: Click Checkout (if enabled)
Loading

Team Layout with "Scale" Tab

sequenceDiagram
    participant User
    participant TeamLayout
    participant Badge

    User->>TeamLayout: Access team dashboard
    TeamLayout->>Badge: Render "New" badge for "Scale" tab
    TeamLayout->>User: Display navigation with "Scale" tab and badge
Loading
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added Dashboard Involves changes to the Dashboard. Playground Changes involving the Playground codebase. Portal Involves changes to the Portal (docs) codebase. packages Ecosystem Portal Involves changes to the Ecosystem Portal SDK Involves changes to the thirdweb SDK labels Jun 27, 2025
@jnsdls jnsdls changed the title self-serve infra deployment self-serve infra deployment: part 1 Jun 27, 2025
Copy link
Member Author

jnsdls commented Jun 27, 2025


How to use the Graphite Merge Queue

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

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

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

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

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

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

Copy link
Contributor

github-actions bot commented Jun 27, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 63.17 KB (0%) 1.3 s (0%) 203 ms (+173.14% 🔺) 1.5 s
thirdweb (cjs) 351.66 KB (0%) 7.1 s (0%) 687 ms (+9.95% 🔺) 7.8 s
thirdweb (minimal + tree-shaking) 5.72 KB (0%) 115 ms (0%) 100 ms (+1552.39% 🔺) 214 ms
thirdweb/chains (tree-shaking) 530 B (0%) 11 ms (0%) 37 ms (+1811.67% 🔺) 47 ms
thirdweb/react (minimal + tree-shaking) 19.61 KB (0%) 393 ms (0%) 93 ms (+686.95% 🔺) 485 ms

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

🧹 Nitpick comments (6)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/page.tsx (1)

1-3: Consider enhancing the infrastructure overview page.

While this minimal implementation works as a placeholder, consider adding more meaningful content such as:

  • Infrastructure service status overview
  • Quick access links to deploy new services
  • Summary of existing infrastructure

This would provide better user experience compared to the current basic text display.

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/order-summary.tsx (2)

8-12: Consider exposing className prop for better composability.

Following the coding guidelines, components should expose a className prop when useful for styling flexibility.

export function OrderSummary(props: {
  selectedChainId: number;
  selectedServices: ServiceConfig[];
  paymentFrequency: PaymentFrequency;
+ className?: string;
}) {

And apply it to the root div:

-    <div className="space-y-4">
+    <div className={cn("space-y-4", props.className)}>

93-93: Consider making discount percentages configurable.

The discount percentages (15% annual, 10-15% bundle) are hardcoded, which reduces flexibility for business logic changes.

Consider extracting these into configuration constants or props:

+const DISCOUNT_CONFIG = {
+  annual: 0.15,
+  bundle: {
+    twoServices: 0.1,
+    threeServices: 0.15,
+  },
+} as const;

// Then use in calculations:
-  const annualDiscount = paymentFrequency === "annual" ? 0.15 : 0;
+  const annualDiscount = paymentFrequency === "annual" ? DISCOUNT_CONFIG.annual : 0;

Also applies to: 162-166, 169-169

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx (3)

22-26: Consider exposing className prop for better composability.

Following the coding guidelines, components should expose a className prop for styling flexibility.

export function ServiceSelector(props: {
  services: ServiceConfig[];
  selectedServices: ServiceConfig[];
  setSelectedServices: (services: ServiceConfig[]) => void;
+ className?: string;
}) {

113-116: Break down complex className for better readability.

The className string is very long and hard to read. Consider breaking it into multiple lines or extracting parts into variables.

      <Label
        className={cn(
-          "hover:bg-accent/50 flex gap-6 rounded-lg border px-6 py-4 has-[[aria-checked=true]]:border-primary has-[[aria-checked=true]]:bg-primary/10 cursor-pointer items-center",
+          "flex items-center gap-6 rounded-lg border px-6 py-4 cursor-pointer",
+          "hover:bg-accent/50",
+          "has-[[aria-checked=true]]:border-primary has-[[aria-checked=true]]:bg-primary/10",
           props.service.required && "cursor-not-allowed",
         )}
      >

146-153: Consider responsive design for feature list.

The features are completely hidden on mobile (hidden lg:grid). Consider showing a subset or using a different layout for better mobile experience.

-        <div className="grid-cols-2 gap-2 hidden lg:grid">
+        <div className="grid grid-cols-1 lg:grid-cols-2 gap-2">
           {props.service.features.map((feature) => (
             <div className="flex items-center space-x-1 text-sm" key={feature}>
               <CheckIcon className="w-3 h-3 shrink-0 text-success-text" />
               <span>{feature}</span>
             </div>
           ))}
         </div>

Or limit features shown on mobile:

+        <div className="grid grid-cols-1 lg:grid-cols-2 gap-2">
+          {props.service.features.slice(0, 2).map((feature) => (
+            <div className="flex items-center space-x-1 text-sm" key={feature}>
+              <CheckIcon className="w-3 h-3 shrink-0 text-success-text" />
+              <span>{feature}</span>
+            </div>
+          ))}
+          {props.service.features.length > 2 && (
+            <div className="text-sm text-muted-foreground lg:hidden">
+              +{props.service.features.length - 2} more features
+            </div>
+          )}
+        </div>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 277c2e2 and 71255ca.

📒 Files selected for processing (26)
  • apps/dashboard/biome.json (1 hunks)
  • apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx (2 hunks)
  • apps/dashboard/src/@/components/blocks/UpsellBannerCard.tsx (2 hunks)
  • apps/dashboard/src/@/icons/ChainIcon.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/[chain_id]/page.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/checkout.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/order-summary.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/payment-frequency-selector.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/page.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/layout.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/page.tsx (1 hunks)
  • apps/nebula/biome.json (1 hunks)
  • apps/playground-web/biome.json (1 hunks)
  • apps/portal/biome.json (1 hunks)
  • apps/wallet-ui/biome.json (1 hunks)
  • biome.json (1 hunks)
  • packages/engine/biome.json (1 hunks)
  • packages/insight/biome.json (1 hunks)
  • packages/nebula/biome.json (1 hunks)
  • packages/react-native-adapter/biome.json (1 hunks)
  • packages/service-utils/biome.json (1 hunks)
  • packages/thirdweb/biome.json (1 hunks)
  • packages/vault-sdk/biome.json (1 hunks)
  • packages/wagmi-adapter/biome.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
`apps/dashboard/*`: The dashboard app is a web-based developer console built wit...

apps/dashboard/*: The dashboard app is a web-based developer console built with Next.js and Chakra UI.
Use Tailwind CSS only for styling; no inline styles or CSS modules.
Use cn() from @/lib/utils for conditional class merging.
Use design system tokens for backgrounds (bg-card), borders (border-border), and muted text (text-muted-foreground).
Expose className prop on the root element of components for overrides.
Use NavLink for internal navigation with automatic active states.
Server components should start files with import "server-only"; client components should begin files with 'use client';.
Never import posthog-js in server components; analytics events are client-side only.

📄 Source: CodeRabbit Inference Engine (CLAUDE.md)

List of files the instruction was applied to:

  • apps/dashboard/biome.json
`packages/thirdweb/*`: Every public symbol in the SDK must have comprehensive TS...

packages/thirdweb/*: Every public symbol in the SDK must have comprehensive TSDoc with at least one @example block that compiles and custom annotation tags (@beta, @internal, @experimental).
Export everything via the exports/ directory, grouped by feature.
Place tests alongside code: foo.ts ↔ foo.test.ts.
Use real function invocations with stub data in tests; avoid brittle mocks.
Use Mock Service Worker (MSW) for fetch/HTTP call interception in tests.
Keep tests deterministic and side-effect free.

📄 Source: CodeRabbit Inference Engine (CLAUDE.md)

List of files the instruction was applied to:

  • packages/thirdweb/biome.json
`apps/wallet-ui/*`: The wallet-ui app is for wallet interface and testing.

apps/wallet-ui/*: The wallet-ui app is for wallet interface and testing.

📄 Source: CodeRabbit Inference Engine (CLAUDE.md)

List of files the instruction was applied to:

  • apps/wallet-ui/biome.json
`biome.json`: Biome is the primary linter/formatter; rules are defined in biome.json.

biome.json: Biome is the primary linter/formatter; rules are defined in biome.json.

📄 Source: CodeRabbit Inference Engine (CLAUDE.md)

List of files the instruction was applied to:

  • biome.json
`packages/wagmi-adapter/*`: Wagmi ecosystem integration is located in packages/wagmi-adapter/.

packages/wagmi-adapter/*: Wagmi ecosystem integration is located in packages/wagmi-adapter/.

📄 Source: CodeRabbit Inference Engine (CLAUDE.md)

List of files the instruction was applied to:

  • packages/wagmi-adapter/biome.json
`apps/portal/*`: The portal app is a documentation site with MDX.

apps/portal/*: The portal app is a documentation site with MDX.

📄 Source: CodeRabbit Inference Engine (CLAUDE.md)

List of files the instruction was applied to:

  • apps/portal/biome.json
`packages/react-native-adapter/*`: Mobile platform shims are located in packages/react-native-adapter/.

packages/react-native-adapter/*: Mobile platform shims are located in packages/react-native-adapter/.

📄 Source: CodeRabbit Inference Engine (CLAUDE.md)

List of files the instruction was applied to:

  • packages/react-native-adapter/biome.json
`**/icons/*`: Icons come from 'lucide-react' or the project-specific '../icons' exports – never embed raw SVG.

**/icons/*: Icons come from 'lucide-react' or the project-specific '../icons' exports – never embed raw SVG.

📄 Source: CodeRabbit Inference Engine (.cursor/rules/dashboard.mdc)

List of files the instruction was applied to:

  • apps/dashboard/src/@/icons/ChainIcon.tsx
`**/*.@(ts|tsx)`: Accept a typed 'props' object and export a named function (e.g...

**/*.@(ts|tsx): Accept a typed 'props' object and export a named function (e.g., export function MyComponent()).
Combine class names via 'cn', expose 'className' prop if useful.
Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
Local state or effects live inside; data fetching happens in hooks.
Merge class names with 'cn' from '@/lib/utils' to keep conditional logic readable.
Stick to design-tokens: background ('bg-card'), borders ('border-border'), muted text ('text-muted-foreground') etc.
Use the 'container' class with a 'max-w-7xl' cap for page width consistency.
Spacing utilities ('px-', 'py-', 'gap-*') are preferred over custom margins.
Responsive helpers follow mobile-first ('max-sm', 'md', 'lg', 'xl').
Never hard-code colors – always go through Tailwind variables.
Tailwind CSS is the styling system – avoid inline styles or CSS modules.
Prefix files with 'import "server-only";' so they never end up in the client bundle (for server-only code).

📄 Source: CodeRabbit Inference Engine (.cursor/rules/dashboard.mdc)

List of files the instruction was applied to:

  • apps/dashboard/src/@/icons/ChainIcon.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/page.tsx
  • apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/[chain_id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/payment-frequency-selector.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/checkout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/layout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/order-summary.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx
  • apps/dashboard/src/@/components/blocks/UpsellBannerCard.tsx
`apps/nebula/*`: The nebula app is for account abstraction and smart wallet management.

apps/nebula/*: The nebula app is for account abstraction and smart wallet management.

📄 Source: CodeRabbit Inference Engine (CLAUDE.md)

List of files the instruction was applied to:

  • apps/nebula/biome.json
`apps/playground-web/*`: The playground-web app is an interactive SDK testing environment.

apps/playground-web/*: The playground-web app is an interactive SDK testing environment.

📄 Source: CodeRabbit Inference Engine (CLAUDE.md)

List of files the instruction was applied to:

  • apps/playground-web/biome.json
🧠 Learnings (13)
📓 Common learnings
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:155-160
Timestamp: 2025-06-10T00:46:58.580Z
Learning: In the dashboard application, the route structure for team and project navigation is `/team/[team_slug]/[project_slug]/...` without a `/project/` segment. Contract links should be formatted as `/team/${teamSlug}/${projectSlug}/contract/${chainId}/${contractAddress}`.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
apps/dashboard/src/@/icons/ChainIcon.tsx (2)
Learnt from: jnsdls
PR: thirdweb-dev/js#7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.
Learnt from: MananTank
PR: thirdweb-dev/js#7177
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx:26-43
Timestamp: 2025-05-29T10:49:52.981Z
Learning: In React image components, conditional rendering of the entire image container (e.g., `{props.image && <Img />}`) serves a different purpose than fallback handling. The conditional prevents rendering any image UI when no image metadata exists, while the fallback prop handles cases where image metadata exists but the image fails to load. This pattern is intentional to distinguish between "no image intended" vs "image intended but failed to load".
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx (13)
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:155-160
Timestamp: 2025-06-10T00:46:58.580Z
Learning: In the dashboard application, the route structure for team and project navigation is `/team/[team_slug]/[project_slug]/...` without a `/project/` segment. Contract links should be formatted as `/team/${teamSlug}/${projectSlug}/contract/${chainId}/${contractAddress}`.
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: UI primitives should be imported from @/components/ui/*.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Always import reusable UI components from a central library (e.g., '@/components/ui/*') to ensure consistency and avoid duplication.
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.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Client components must begin with 'use client'; before imports to ensure correct rendering behavior in Next.js.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Prefer composable UI primitives (Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge) over custom markup for maintainability and design consistency.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: Client components should begin files with 'use client' and use React hooks for interactivity.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Use client components for interactive UI, components that rely on hooks, browser APIs, or require fast transitions.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Files for components should be named in PascalCase and use the '.client.tsx' suffix if interactive.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Reuse core UI primitives and avoid re-implementing common elements like buttons, cards, or modals.
Learnt from: MananTank
PR: thirdweb-dev/js#7356
File: apps/nebula/src/app/not-found.tsx:1-1
Timestamp: 2025-06-17T18:30:52.976Z
Learning: In the thirdweb/js project, the React namespace is available for type annotations (like React.FC) without needing to explicitly import React. This is project-specific configuration that differs from typical TypeScript/React setups.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx:20-20
Timestamp: 2025-05-26T16:26:58.068Z
Learning: In team/project contract pages under routes like `/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/*`, users are always logged in by design. The hardcoded `isLoggedIn={true}` prop in these pages is intentional and correct, not a bug to be fixed.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/page.tsx (5)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
Learnt from: jnsdls
PR: thirdweb-dev/js#7363
File: apps/dashboard/src/app/(app)/layout.tsx:63-74
Timestamp: 2025-06-18T02:01:06.006Z
Learning: In Next.js applications, instrumentation files (instrumentation.ts or instrumentation-client.ts) placed in the src/ directory are automatically handled by the framework and included in the client/server bundles without requiring manual imports. The framework injects these files as part of the build process.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: For new UI components, add Storybook stories (*.stories.tsx) alongside the code.
Learnt from: jnsdls
PR: thirdweb-dev/js#7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.
apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx (2)
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.
Learnt from: MananTank
PR: thirdweb-dev/js#7298
File: apps/dashboard/src/app/nebula-app/move-funds/move-funds.tsx:424-424
Timestamp: 2025-06-06T23:46:08.795Z
Learning: The thirdweb project has an ESLint rule that restricts direct usage of `defineChain`. When it's necessary to use `defineChain` directly, it's acceptable to disable the rule with `// eslint-disable-next-line no-restricted-syntax`.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/[chain_id]/page.tsx (7)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx:2-10
Timestamp: 2025-05-26T16:28:10.079Z
Learning: In Next.js 14+, the `params` object in page components is always a Promise that needs to be awaited, so the correct typing is `params: Promise<ParamsType>` rather than `params: ParamsType`.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:155-160
Timestamp: 2025-06-10T00:46:58.580Z
Learning: In the dashboard application, the route structure for team and project navigation is `/team/[team_slug]/[project_slug]/...` without a `/project/` segment. Contract links should be formatted as `/team/${teamSlug}/${projectSlug}/contract/${chainId}/${contractAddress}`.
Learnt from: jnsdls
PR: thirdweb-dev/js#7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx:20-20
Timestamp: 2025-05-26T16:26:58.068Z
Learning: In team/project contract pages under routes like `/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/*`, users are always logged in by design. The hardcoded `isLoggedIn={true}` prop in these pages is intentional and correct, not a bug to be fixed.
Learnt from: MananTank
PR: thirdweb-dev/js#7434
File: apps/dashboard/src/app/(app)/team/~/~/contract/[chain]/[contractAddress]/components/project-selector.tsx:62-76
Timestamp: 2025-06-24T21:38:03.155Z
Learning: In the project-selector.tsx component for contract imports, the addToProject.mutate() call is intentionally not awaited (fire-and-forget pattern) to allow immediate navigation to the contract page while the import happens in the background. This is a deliberate design choice to prioritize user experience.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx:41-48
Timestamp: 2025-05-26T16:28:50.772Z
Learning: The `projectMeta` prop is not required for the server-rendered `ContractTokensPage` component in the tokens shared page, unlike some other shared pages where it's needed for consistency.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/payment-frequency-selector.tsx (3)
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Files for components should be named in PascalCase and use the '.client.tsx' suffix if interactive.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: For new UI components, add Storybook stories (*.stories.tsx) alongside the code.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Prefer composable UI primitives (Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge) over custom markup for maintainability and design consistency.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/checkout.tsx (9)
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
Learnt from: jnsdls
PR: thirdweb-dev/js#7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: Client components should begin files with 'use client' and use React hooks for interactivity.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Files for components should be named in PascalCase and use the '.client.tsx' suffix if interactive.
Learnt from: MananTank
PR: thirdweb-dev/js#7434
File: apps/dashboard/src/app/(app)/team/~/~/contract/[chain]/[contractAddress]/components/project-selector.tsx:62-76
Timestamp: 2025-06-24T21:38:03.155Z
Learning: In the project-selector.tsx component for contract imports, the addToProject.mutate() call is intentionally not awaited (fire-and-forget pattern) to allow immediate navigation to the contract page while the import happens in the background. This is a deliberate design choice to prioritize user experience.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: For new UI components, add Storybook stories (*.stories.tsx) alongside the code.
Learnt from: jnsdls
PR: thirdweb-dev/js#7364
File: apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx:36-41
Timestamp: 2025-06-18T02:13:34.500Z
Learning: In the logout flow in apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx, when `doLogout()` fails, the cleanup steps (resetAnalytics(), wallet disconnect, router refresh) should NOT execute. This is intentional to maintain consistency - if server-side logout fails, client-side cleanup should not occur.
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.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/page.tsx (12)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
Learnt from: jnsdls
PR: thirdweb-dev/js#7363
File: apps/dashboard/src/app/(app)/layout.tsx:63-74
Timestamp: 2025-06-18T02:01:06.006Z
Learning: In Next.js applications, instrumentation files (instrumentation.ts or instrumentation-client.ts) placed in the src/ directory are automatically handled by the framework and included in the client/server bundles without requiring manual imports. The framework injects these files as part of the build process.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx:47-52
Timestamp: 2025-05-26T16:29:54.317Z
Learning: The `projectMeta` prop is not required for the server-rendered `ContractDirectListingsPage` component in the direct listings shared page, following the same pattern as other server components in the codebase where `projectMeta` is only needed for client components.
Learnt from: MananTank
PR: thirdweb-dev/js#7434
File: apps/dashboard/src/app/(app)/team/~/~/contract/[chain]/[contractAddress]/components/project-selector.tsx:62-76
Timestamp: 2025-06-24T21:38:03.155Z
Learning: In the project-selector.tsx component for contract imports, the addToProject.mutate() call is intentionally not awaited (fire-and-forget pattern) to allow immediate navigation to the contract page while the import happens in the background. This is a deliberate design choice to prioritize user experience.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx:41-48
Timestamp: 2025-05-26T16:28:50.772Z
Learning: The `projectMeta` prop is not required for the server-rendered `ContractTokensPage` component in the tokens shared page, unlike some other shared pages where it's needed for consistency.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Files for components should be named in PascalCase and use the '.client.tsx' suffix if interactive.
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.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Client components must begin with 'use client'; before imports to ensure correct rendering behavior in Next.js.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: Client components should begin files with 'use client' and use React hooks for interactivity.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx:33-39
Timestamp: 2025-05-26T16:30:24.965Z
Learning: In the thirdweb dashboard codebase, redirectToContractLandingPage function already handles execution termination internally (likely using Next.js redirect() which throws an exception), so no explicit return statement is needed after calling it.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx:43-49
Timestamp: 2025-05-26T16:31:02.480Z
Learning: In the thirdweb dashboard codebase, when `redirectToContractLandingPage()` is called, an explicit return statement is not required afterward because the function internally calls Next.js's `redirect()` which throws an error to halt execution.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/layout.tsx (8)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
Learnt from: jnsdls
PR: thirdweb-dev/js#7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:155-160
Timestamp: 2025-06-10T00:46:58.580Z
Learning: In the dashboard application, the route structure for team and project navigation is `/team/[team_slug]/[project_slug]/...` without a `/project/` segment. Contract links should be formatted as `/team/${teamSlug}/${projectSlug}/contract/${chainId}/${contractAddress}`.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx:2-10
Timestamp: 2025-05-26T16:28:10.079Z
Learning: In Next.js 14+, the `params` object in page components is always a Promise that needs to be awaited, so the correct typing is `params: Promise<ParamsType>` rather than `params: ParamsType`.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx:20-20
Timestamp: 2025-05-26T16:26:58.068Z
Learning: In team/project contract pages under routes like `/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/*`, users are always logged in by design. The hardcoded `isLoggedIn={true}` prop in these pages is intentional and correct, not a bug to be fixed.
Learnt from: MananTank
PR: thirdweb-dev/js#7434
File: apps/dashboard/src/app/(app)/team/~/~/contract/[chain]/[contractAddress]/components/project-selector.tsx:62-76
Timestamp: 2025-06-24T21:38:03.155Z
Learning: In the project-selector.tsx component for contract imports, the addToProject.mutate() call is intentionally not awaited (fire-and-forget pattern) to allow immediate navigation to the contract page while the import happens in the background. This is a deliberate design choice to prioritize user experience.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Client components must begin with 'use client'; before imports to ensure correct rendering behavior in Next.js.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/order-summary.tsx (2)
Learnt from: jnsdls
PR: thirdweb-dev/js#7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx (5)
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: For new UI components, add Storybook stories (*.stories.tsx) alongside the code.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Files for components should be named in PascalCase and use the '.client.tsx' suffix if interactive.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: Group feature-specific components under feature/components/* with a barrel index.ts.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Prefer composable UI primitives (Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge) over custom markup for maintainability and design consistency.
apps/dashboard/src/@/components/blocks/UpsellBannerCard.tsx (5)
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.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
Learnt from: jnsdls
PR: thirdweb-dev/js#7365
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx:16-17
Timestamp: 2025-06-18T04:30:04.326Z
Learning: Next.js Link component fully supports both internal and external URLs and works appropriately with all standard anchor attributes including target="_blank", rel="noopener noreferrer", etc. Using Link for external URLs is completely appropriate and recommended.
Learnt from: jnsdls
PR: thirdweb-dev/js#7365
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx:16-17
Timestamp: 2025-06-18T04:27:16.172Z
Learning: Next.js Link component supports external URLs without throwing errors. When used with absolute URLs (like https://...), it behaves like a regular anchor tag without client-side routing, but does not cause runtime crashes or errors as previously believed.
Learnt from: MananTank
PR: thirdweb-dev/js#7177
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx:26-43
Timestamp: 2025-05-29T10:49:52.981Z
Learning: In React image components, conditional rendering of the entire image container (e.g., `{props.image && <Img />}`) serves a different purpose than fallback handling. The conditional prevents rendering any image UI when no image metadata exists, while the fallback prop handles cases where image metadata exists but the image fails to load. This pattern is intentional to distinguish between "no image intended" vs "image intended but failed to load".
🧬 Code Graph Analysis (3)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/page.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/[chain_id]/page.tsx (1)
  • InfrastructurePage (3-12)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/payment-frequency-selector.tsx (1)
apps/dashboard/src/@/components/ui/radio-group.tsx (1)
  • RadioGroupItemButton (75-75)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/layout.tsx (2)
apps/dashboard/src/@/api/team.ts (1)
  • getTeamBySlug (13-32)
apps/dashboard/src/@/components/blocks/upsell-wrapper.tsx (1)
  • UpsellWrapper (34-74)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Build Packages
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (27)
biome.json (1)

2-2: Ensure the toolchain is upgraded to Biome 2.0.4+

The schema bump is fine, but editors/CI will complain if the locally installed @biomejs/biome CLI is still on 2.0.0.
Please verify the root package.json (or each workspace) pins @biomejs/biome ≥ 2.0.4 before this lands.

packages/insight/biome.json (1)

2-2: Same schema bump as the root file; handled by the earlier comment. No further feedback.

packages/service-utils/biome.json (1)

2-2: Same schema bump as the root file; handled by the earlier comment. No further feedback.

packages/nebula/biome.json (1)

2-2: Same schema bump as the root file; handled by the earlier comment. No further feedback.

packages/engine/biome.json (1)

2-2: Same schema bump as the root file; handled by the earlier comment. No further feedback.

apps/wallet-ui/biome.json (1)

2-2: Verify Biome CLI/tooling is on ≥ 2.0.4 before merging

The schema bump is harmless, but config validation will fail locally/CI if any environment is still pinned to 2.0.0. Double-check the version in package.json / lockfiles or CI images.

apps/portal/biome.json (1)

2-2: Confirm portal build pipeline uses Biome 2.0.4

Same note as other apps: ensure the CLI version matches the new schema to avoid lint/format errors in CI.

packages/thirdweb/biome.json (1)

2-2: SDK package also needs Biome 2.0.4 in dev-deps

Updating the schema without bumping the dev dependency may break pnpm lint for package authors. Verify the root workspace has the correct version.

apps/dashboard/biome.json (1)

2-2: Dashboard app: check Docker/CI image for Biome version drift

If the dashboard is built inside a container, ensure the image was rebuilt with Biome 2.0.4; otherwise schema validation will complain.

apps/playground-web/biome.json (1)

2-2: Playground-web: sync local VSCode extension + CI to Biome 2.0.4

Developers’ editors and CI must understand the new schema; confirm extension/update is applied.

packages/vault-sdk/biome.json (1)

2-2: Schema version bump looks good

The config now references the 2.0.4 schema, matching the rest of the repo. No further action required as long as the CI environment is already running Biome ≥ 2.0.4.

packages/wagmi-adapter/biome.json (1)

2-2: Consistent schema upgrade

Upgrade to 2.0.4 keeps the wagmi-adapter package aligned with the global tooling.

packages/react-native-adapter/biome.json (1)

2-2: LGTM – schema reference updated

Nothing else changed; integration with the React-Native adapter remains unaffected.

apps/nebula/biome.json (1)

2-2: Nebula biome.json updated correctly

The schema URL now points to 2.0.4, in sync with other apps.

apps/dashboard/src/@/icons/ChainIcon.tsx (1)

33-33: LGTM! Semantic improvement for skeleton placeholder.

The change from <div> to <span> is appropriate since spans are inline elements better suited for icon placeholders while maintaining the same styling and animation behavior.

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

155-155: LGTM! Proper prop addition.

The optional disableDeprecated prop is well-typed and follows the established pattern of other boolean filter props in this component.


173-175: LGTM! Correct filtering implementation.

The filtering logic properly excludes chains with deprecated status, using the standard filtering pattern consistent with other conditional filters in this component.


178-183: LGTM! Proper dependency array update.

The dependency array correctly includes disableDeprecated to ensure the memoized chainsToShow recalculates when the filter option changes.

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx (2)

9-9: LGTM! Proper UI primitive import.

Badge component correctly imported from the central UI library, following established coding guidelines.


90-97: LGTM! Well-structured tab addition.

The Infrastructure tab implementation follows the established pattern with proper JSX structure for the name prop containing the Badge component. The routing path is consistent with other team navigation tabs.

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/page.tsx (1)

4-8: LGTM! Proper server component pattern.

The implementation correctly follows the established server component pattern by initializing the client on the server side and passing it to the client component.

Verify team context handling.

Since this page is in the team route structure (/team/[team_slug]/...), ensure that the InfrastructureCheckout component can access the necessary team context. If team information is required, consider extracting the team_slug from params.

#!/bin/bash
# Description: Check if InfrastructureCheckout component needs team context
# Expected: Find usage of team context or team_slug in the checkout component

ast-grep --pattern $'function InfrastructureCheckout($$$) {
  $$$
}'

# Also check for any team-related props or usage
rg -A 10 -B 5 "team" apps/dashboard/src/app/\(app\)/team/\[team_slug\]/\(team\)/~/infrastructure/deploy/_components/checkout.tsx
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/[chain_id]/page.tsx (1)

3-12: LGTM! Clean implementation following Next.js 14+ patterns.

The component correctly awaits the params Promise and uses the existing getChain utility. The implementation is straightforward and follows the established patterns in the codebase.

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/layout.tsx (1)

8-46: LGTM! Well-structured layout with proper access control.

The component correctly:

  • Awaits params following Next.js 14+ patterns
  • Fetches team data and handles missing teams gracefully
  • Implements proper billing plan access control via UpsellWrapper
  • Uses consistent team route structure for the deploy button link
  • Follows the established UI component patterns
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/payment-frequency-selector.tsx (1)

4-47: LGTM! Clean and well-structured payment frequency selector.

The component effectively uses UI primitives and follows good practices:

  • Clear type definitions with PaymentFrequency export
  • Responsive grid layout for different screen sizes
  • Proper use of RadioGroup with controlled state
  • Good visual hierarchy with discount badge for annual option
  • Consistent styling patterns with data attributes
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/checkout.tsx (1)

1-206: LGTM! Comprehensive and well-structured checkout flow.

This is an excellent implementation of a multi-step infrastructure deployment checkout:

Strengths:

  • Correct use of "use client" directive and React hooks
  • Well-organized service configuration with clear pricing and features
  • Proper state management for chain, services, and payment frequency
  • Good responsive design with logical grid layout
  • Appropriate use of ClientOnly wrapper for client-side components
  • Clear step-by-step UI with badges and descriptions
  • Comprehensive order summary with chain details and fallback states
  • Follows established patterns from the codebase

Architecture:

  • Clean separation of concerns with imported child components
  • Good use of existing UI primitives (Card, Badge, etc.)
  • Proper handling of derived state with useMemo
  • RPC service correctly marked as required and pre-selected
apps/dashboard/src/@/components/blocks/UpsellBannerCard.tsx (1)

41-136: LGTM! Well-implemented discriminated union for CTA variants.

The update effectively supports both link-based and callback-based CTAs:

Good practices:

  • Clean discriminated union type definition using presence of target vs onClick
  • Proper conditional rendering logic to distinguish between variants
  • Correct security attributes (rel="noopener noreferrer") for external links
  • Consistent styling and icon handling across both variants
  • Follows established component patterns in the codebase

The type-safe approach ensures proper usage of each CTA variant while maintaining backward compatibility.

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/order-summary.tsx (1)

156-158: Add null safety for service access.

The code uses optional chaining for service?.monthlyPrice but doesn't handle the case where service itself might be null/undefined in the filter.

  const baseMonthlyTotal = selectedServices.reduce((total, service) => {
-    return total + (service?.monthlyPrice || 0);
+    return total + (service?.monthlyPrice ?? 0);
-  }, 0);
+  }, 0);

Consider filtering out null services before the reduce operation:

  const baseMonthlyTotal = selectedServices
+    .filter(Boolean)
+    .reduce((total, service) => {
-    return total + (service?.monthlyPrice || 0);
+      return total + service.monthlyPrice;
    }, 0);
⛔ Skipped due to learnings
Learnt from: MananTank
PR: thirdweb-dev/js#7177
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_hooks/useTokenPriceData.ts:49-49
Timestamp: 2025-05-27T19:55:25.056Z
Learning: In the ERC20 public pages token price data hook (`useTokenPriceData.ts`), direct array access on `json.data[0]` without optional chaining is intentionally correct and should not be changed to use safety checks.

Comment on lines 38 to 42
{service.monthlyPrice.toLocaleString("en-US", {
maximumFractionDigits: 2,
minimumFractionDigits: 2,
})}
/mo
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

Extract repeated currency formatting logic into a utility function.

The same currency formatting pattern is repeated multiple times throughout the component, making it harder to maintain and potentially inconsistent.

+const formatCurrency = (amount: number) => 
+  amount.toLocaleString("en-US", {
+    maximumFractionDigits: 2,
+    minimumFractionDigits: 2,
+  });

// Then replace all instances like:
-                  {service.monthlyPrice.toLocaleString("en-US", {
-                    maximumFractionDigits: 2,
-                    minimumFractionDigits: 2,
-                  })}
+                  {formatCurrency(service.monthlyPrice)}

Also applies to: 62-70, 80-87, 96-103, 113-117, 124-127

🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/order-summary.tsx
around lines 38 to 42 and similarly at lines 62-70, 80-87, 96-103, 113-117, and
124-127, the currency formatting logic using toLocaleString with fixed fraction
digits is repeated multiple times. Extract this repeated formatting logic into a
single reusable utility function that takes a number and returns the formatted
currency string, then replace all instances with calls to this utility function
to improve maintainability and consistency.

<div className="flex flex-col gap-8">
<div className="grid gap-4">
{props.services.map((service) => {
const isSelected = props.selectedServices.includes(service);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use ID-based comparison instead of object reference equality.

The current implementation uses includes() which relies on reference equality. This may fail if service objects are recreated with the same data but different references.

-          const isSelected = props.selectedServices.includes(service);
+          const isSelected = props.selectedServices.some(s => s.id === service.id);
📝 Committable suggestion

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

Suggested change
const isSelected = props.selectedServices.includes(service);
const isSelected = props.selectedServices.some(s => s.id === service.id);
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx
at line 53, replace the use of includes() for checking if a service is selected
with an ID-based comparison. Instead of checking if the service object is
included by reference, check if the selectedServices array contains a service
with the same unique ID as the current service. This ensures correct selection
even if service objects are recreated with identical data but different
references.

Comment on lines 84 to 90
onClick: () => {
if (nextServiceToAdd) {
props.setSelectedServices([
...props.selectedServices,
nextServiceToAdd,
]);
}
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

Remove redundant null check.

The nextServiceToAdd is already checked to be truthy in the ternary condition on line 82, making the inner null check redundant.

                onClick: () => {
-                  if (nextServiceToAdd) {
                    props.setSelectedServices([
                      ...props.selectedServices,
                      nextServiceToAdd,
                    ]);
-                  }
                },
📝 Committable suggestion

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

Suggested change
onClick: () => {
if (nextServiceToAdd) {
props.setSelectedServices([
...props.selectedServices,
nextServiceToAdd,
]);
}
onClick: () => {
props.setSelectedServices([
...props.selectedServices,
nextServiceToAdd,
]);
},
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx
around lines 84 to 90, remove the redundant null check for nextServiceToAdd
inside the onClick handler since it is already verified as truthy in the ternary
condition on line 82. Simplify the code by directly using nextServiceToAdd
without the additional if check.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx (2)

53-53: Use ID-based comparison instead of object reference equality.

The current implementation uses includes() which relies on reference equality. This may fail if service objects are recreated with the same data but different references.

-          const isSelected = props.selectedServices.includes(service);
+          const isSelected = props.selectedServices.some(s => s.id === service.id);

84-90: Remove redundant null check.

The nextServiceToAdd is already checked to be truthy in the ternary condition on line 82, making the inner null check redundant.

                onClick: () => {
-                  if (nextServiceToAdd) {
                    props.setSelectedServices([
                      ...props.selectedServices,
                      nextServiceToAdd,
                    ]);
-                  }
                },
🧹 Nitpick comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx (1)

138-138: Consider edge case handling for zero pricing.

While unlikely in this context, the pricing display doesn't handle edge cases where monthlyPrice might be 0. Consider if this scenario needs special handling or messaging.

-              ${props.service.monthlyPrice.toLocaleString()}
+              {props.service.monthlyPrice === 0 ? 'Free' : `$${props.service.monthlyPrice.toLocaleString()}`}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 71255ca and f9d44a0.

📒 Files selected for processing (26)
  • apps/dashboard/biome.json (1 hunks)
  • apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx (2 hunks)
  • apps/dashboard/src/@/components/blocks/UpsellBannerCard.tsx (2 hunks)
  • apps/dashboard/src/@/icons/ChainIcon.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/[chain_id]/page.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/checkout.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/order-summary.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/payment-frequency-selector.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/page.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/layout.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/page.tsx (1 hunks)
  • apps/nebula/biome.json (1 hunks)
  • apps/playground-web/biome.json (1 hunks)
  • apps/portal/biome.json (1 hunks)
  • apps/wallet-ui/biome.json (1 hunks)
  • biome.json (1 hunks)
  • packages/engine/biome.json (1 hunks)
  • packages/insight/biome.json (1 hunks)
  • packages/nebula/biome.json (1 hunks)
  • packages/react-native-adapter/biome.json (1 hunks)
  • packages/service-utils/biome.json (1 hunks)
  • packages/thirdweb/biome.json (1 hunks)
  • packages/vault-sdk/biome.json (1 hunks)
  • packages/wagmi-adapter/biome.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (25)
  • apps/dashboard/biome.json
  • packages/wagmi-adapter/biome.json
  • biome.json
  • apps/portal/biome.json
  • packages/service-utils/biome.json
  • packages/thirdweb/biome.json
  • packages/engine/biome.json
  • packages/insight/biome.json
  • apps/wallet-ui/biome.json
  • packages/vault-sdk/biome.json
  • packages/nebula/biome.json
  • packages/react-native-adapter/biome.json
  • apps/nebula/biome.json
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx
  • apps/playground-web/biome.json
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/page.tsx
  • apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/[chain_id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/payment-frequency-selector.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/checkout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/layout.tsx
  • apps/dashboard/src/@/icons/ChainIcon.tsx
  • apps/dashboard/src/@/components/blocks/UpsellBannerCard.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/order-summary.tsx
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.@(ts|tsx)`: Accept a typed 'props' object and export a named function (e.g...

**/*.@(ts|tsx): Accept a typed 'props' object and export a named function (e.g., export function MyComponent()).
Combine class names via 'cn', expose 'className' prop if useful.
Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
Local state or effects live inside; data fetching happens in hooks.
Merge class names with 'cn' from '@/lib/utils' to keep conditional logic readable.
Stick to design-tokens: background ('bg-card'), borders ('border-border'), muted text ('text-muted-foreground') etc.
Use the 'container' class with a 'max-w-7xl' cap for page width consistency.
Spacing utilities ('px-', 'py-', 'gap-*') are preferred over custom margins.
Responsive helpers follow mobile-first ('max-sm', 'md', 'lg', 'xl').
Never hard-code colors – always go through Tailwind variables.
Tailwind CSS is the styling system – avoid inline styles or CSS modules.
Prefix files with 'import "server-only";' so they never end up in the client bundle (for server-only code).

📄 Source: CodeRabbit Inference Engine (.cursor/rules/dashboard.mdc)

List of files the instruction was applied to:

  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx
🧠 Learnings (2)
📓 Common learnings
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:155-160
Timestamp: 2025-06-10T00:46:58.580Z
Learning: In the dashboard application, the route structure for team and project navigation is `/team/[team_slug]/[project_slug]/...` without a `/project/` segment. Contract links should be formatted as `/team/${teamSlug}/${projectSlug}/contract/${chainId}/${contractAddress}`.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx (5)
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: For new UI components, add Storybook stories (*.stories.tsx) alongside the code.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Files for components should be named in PascalCase and use the '.client.tsx' suffix if interactive.
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Prefer composable UI primitives (Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge) over custom markup for maintainability and design consistency.
🧬 Code Graph Analysis (1)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx (1)
apps/dashboard/src/@/components/blocks/UpsellBannerCard.tsx (1)
  • UpsellBannerCard (57-140)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (3)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/infrastructure/deploy/_components/service-selector.tsx (3)

9-20: Type definitions look well-structured.

The Service union type and ServiceConfig interface are properly defined and provide good type safety. The interface covers all necessary service metadata including pricing, features, and UI elements.


27-32: Good use of useMemo for performance optimization.

The nextServiceToAdd computation correctly uses ID-based comparison and is properly memoized with appropriate dependencies.


106-157: ServiceCheckboxCard component follows best practices.

The component properly:

  • Uses semantic HTML with Label for accessibility
  • Implements conditional styling with cn() utility
  • Handles required services appropriately by disabling interaction
  • Uses design system components (Checkbox, Badge)
  • Applies responsive design patterns with lg: prefixes

Copy link

codecov bot commented Jun 27, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 51.92%. Comparing base (45bb790) to head (ae2e3de).
Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7456      +/-   ##
==========================================
- Coverage   51.92%   51.92%   -0.01%     
==========================================
  Files         947      947              
  Lines       63875    63932      +57     
  Branches     4214     4219       +5     
==========================================
+ Hits        33166    33194      +28     
- Misses      30603    30632      +29     
  Partials      106      106              
Flag Coverage Δ
packages 51.92% <ø> (-0.01%) ⬇️

see 2 files with indirect coverage changes

🚀 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: 3

🧹 Nitpick comments (3)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/checkout.tsx (1)

159-162: Consider making the annual discount configurable.

The 15% discount is hardcoded here and in the description. Consider extracting this to a constant for maintainability.

+const ANNUAL_DISCOUNT_PERCENT = 15;
+
// ...
-            <PaymentFrequencySelector
-              annualDiscountPercent={15}
+            <PaymentFrequencySelector
+              annualDiscountPercent={ANNUAL_DISCOUNT_PERCENT}

Also update line 155 to use the same constant:

-              Choose your billing frequency. Save 15% with annual payment.
+              Choose your billing frequency. Save {ANNUAL_DISCOUNT_PERCENT}% with annual payment.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/service-selector.tsx (2)

84-91: Remove redundant conditional check.

The nextServiceToAdd is already checked in the ternary operator above, making the inner check redundant.

                onClick: () => {
-                  if (nextServiceToAdd) {
                    props.setSelectedServices([
                      ...props.selectedServices,
                      nextServiceToAdd,
                    ]);
-                  }
                },

22-26: Consider adding Storybook stories for the new component.

Based on the coding guidelines, new UI components should include Storybook stories for better documentation and testing.

Would you like me to generate a Storybook story file for this component to demonstrate its various states and configurations?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4bd0809 and ae2e3de.

📒 Files selected for processing (26)
  • apps/dashboard/biome.json (1 hunks)
  • apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx (2 hunks)
  • apps/dashboard/src/@/components/blocks/UpsellBannerCard.tsx (2 hunks)
  • apps/dashboard/src/@/icons/ChainIcon.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/[chain_id]/page.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/checkout.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/order-summary.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/payment-frequency-selector.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/service-selector.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/page.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/layout.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/page.tsx (1 hunks)
  • apps/nebula/biome.json (1 hunks)
  • apps/playground-web/biome.json (1 hunks)
  • apps/portal/biome.json (1 hunks)
  • apps/wallet-ui/biome.json (1 hunks)
  • biome.json (1 hunks)
  • packages/engine/biome.json (1 hunks)
  • packages/insight/biome.json (1 hunks)
  • packages/nebula/biome.json (1 hunks)
  • packages/react-native-adapter/biome.json (1 hunks)
  • packages/service-utils/biome.json (1 hunks)
  • packages/thirdweb/biome.json (1 hunks)
  • packages/vault-sdk/biome.json (1 hunks)
  • packages/wagmi-adapter/biome.json (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/page.tsx
🚧 Files skipped from review as they are similar to previous changes (18)
  • apps/wallet-ui/biome.json
  • apps/portal/biome.json
  • apps/dashboard/biome.json
  • packages/react-native-adapter/biome.json
  • packages/wagmi-adapter/biome.json
  • packages/thirdweb/biome.json
  • packages/vault-sdk/biome.json
  • packages/nebula/biome.json
  • apps/nebula/biome.json
  • biome.json
  • apps/playground-web/biome.json
  • packages/engine/biome.json
  • packages/insight/biome.json
  • packages/service-utils/biome.json
  • apps/dashboard/src/@/icons/ChainIcon.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx
  • apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx
  • apps/dashboard/src/@/components/blocks/UpsellBannerCard.tsx
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.@(ts|tsx)`: Accept a typed 'props' object and export a named function (e.g...

**/*.@(ts|tsx): Accept a typed 'props' object and export a named function (e.g., export function MyComponent()).
Combine class names via 'cn', expose 'className' prop if useful.
Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
Local state or effects live inside; data fetching happens in hooks.
Merge class names with 'cn' from '@/lib/utils' to keep conditional logic readable.
Stick to design-tokens: background ('bg-card'), borders ('border-border'), muted text ('text-muted-foreground') etc.
Use the 'container' class with a 'max-w-7xl' cap for page width consistency.
Spacing utilities ('px-', 'py-', 'gap-*') are preferred over custom margins.
Responsive helpers follow mobile-first ('max-sm', 'md', 'lg', 'xl').
Never hard-code colors – always go through Tailwind variables.
Tailwind CSS is the styling system – avoid inline styles or CSS modules.
Prefix files with 'import "server-only";' so they never end up in the client bundle (for server-only code).

📄 Source: CodeRabbit Inference Engine (.cursor/rules/dashboard.mdc)

List of files the instruction was applied to:

  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/payment-frequency-selector.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/[chain_id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/checkout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/layout.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/order-summary.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/service-selector.tsx
🧠 Learnings (7)
📓 Common learnings
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/payment-frequency-selector.tsx (1)
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Prefer composable UI primitives (Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge) over custom markup for maintainability and design consistency.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/[chain_id]/page.tsx (10)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
Learnt from: jnsdls
PR: thirdweb-dev/js#7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:155-160
Timestamp: 2025-06-10T00:46:58.580Z
Learning: In the dashboard application, the route structure for team and project navigation is `/team/[team_slug]/[project_slug]/...` without a `/project/` segment. Contract links should be formatted as `/team/${teamSlug}/${projectSlug}/contract/${chainId}/${contractAddress}`.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx:2-10
Timestamp: 2025-05-26T16:28:10.079Z
Learning: In Next.js 14+, the `params` object in page components is always a Promise that needs to be awaited, so the correct typing is `params: Promise<ParamsType>` rather than `params: ParamsType`.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx:41-48
Timestamp: 2025-05-26T16:28:50.772Z
Learning: The `projectMeta` prop is not required for the server-rendered `ContractTokensPage` component in the tokens shared page, unlike some other shared pages where it's needed for consistency.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx:20-20
Timestamp: 2025-05-26T16:26:58.068Z
Learning: In team/project contract pages under routes like `/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/*`, users are always logged in by design. The hardcoded `isLoggedIn={true}` prop in these pages is intentional and correct, not a bug to be fixed.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
Learnt from: jnsdls
PR: thirdweb-dev/js#7363
File: apps/dashboard/src/app/(app)/layout.tsx:63-74
Timestamp: 2025-06-18T02:01:06.006Z
Learning: In Next.js applications, instrumentation files (instrumentation.ts or instrumentation-client.ts) placed in the src/ directory are automatically handled by the framework and included in the client/server bundles without requiring manual imports. The framework injects these files as part of the build process.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx:47-52
Timestamp: 2025-05-26T16:29:54.317Z
Learning: The `projectMeta` prop is not required for the server-rendered `ContractDirectListingsPage` component in the direct listings shared page, following the same pattern as other server components in the codebase where `projectMeta` is only needed for client components.
Learnt from: MananTank
PR: thirdweb-dev/js#7434
File: apps/dashboard/src/app/(app)/team/~/~/contract/[chain]/[contractAddress]/components/project-selector.tsx:62-76
Timestamp: 2025-06-24T21:38:03.155Z
Learning: In the project-selector.tsx component for contract imports, the addToProject.mutate() call is intentionally not awaited (fire-and-forget pattern) to allow immediate navigation to the contract page while the import happens in the background. This is a deliberate design choice to prioritize user experience.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/checkout.tsx (11)
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
Learnt from: jnsdls
PR: thirdweb-dev/js#7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: Client components should begin files with 'use client' and use React hooks for interactivity.
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Files for components should be named in PascalCase and use the '.client.tsx' suffix if interactive.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: For new UI components, add Storybook stories (*.stories.tsx) alongside the code.
Learnt from: MananTank
PR: thirdweb-dev/js#7434
File: apps/dashboard/src/app/(app)/team/~/~/contract/[chain]/[contractAddress]/components/project-selector.tsx:62-76
Timestamp: 2025-06-24T21:38:03.155Z
Learning: In the project-selector.tsx component for contract imports, the addToProject.mutate() call is intentionally not awaited (fire-and-forget pattern) to allow immediate navigation to the contract page while the import happens in the background. This is a deliberate design choice to prioritize user experience.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Use client components for interactive UI, components that rely on hooks, browser APIs, or require fast transitions.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Client components must begin with 'use client'; before imports to ensure correct rendering behavior in Next.js.
Learnt from: jnsdls
PR: thirdweb-dev/js#7364
File: apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx:36-41
Timestamp: 2025-06-18T02:13:34.500Z
Learning: In the logout flow in apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx, when `doLogout()` fails, the cleanup steps (resetAnalytics(), wallet disconnect, router refresh) should NOT execute. This is intentional to maintain consistency - if server-side logout fails, client-side cleanup should not occur.
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.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/layout.tsx (7)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
Learnt from: jnsdls
PR: thirdweb-dev/js#7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:155-160
Timestamp: 2025-06-10T00:46:58.580Z
Learning: In the dashboard application, the route structure for team and project navigation is `/team/[team_slug]/[project_slug]/...` without a `/project/` segment. Contract links should be formatted as `/team/${teamSlug}/${projectSlug}/contract/${chainId}/${contractAddress}`.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx:20-20
Timestamp: 2025-05-26T16:26:58.068Z
Learning: In team/project contract pages under routes like `/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/*`, users are always logged in by design. The hardcoded `isLoggedIn={true}` prop in these pages is intentional and correct, not a bug to be fixed.
Learnt from: jnsdls
PR: thirdweb-dev/js#7364
File: apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx:36-41
Timestamp: 2025-06-18T02:13:34.500Z
Learning: In the logout flow in apps/dashboard/src/app/(app)/account/components/AccountHeader.tsx, when `doLogout()` fails, the cleanup steps (resetAnalytics(), wallet disconnect, router refresh) should NOT execute. This is intentional to maintain consistency - if server-side logout fails, client-side cleanup should not occur.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Client components must begin with 'use client'; before imports to ensure correct rendering behavior in Next.js.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/order-summary.tsx (2)
Learnt from: jnsdls
PR: thirdweb-dev/js#7188
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx:15-15
Timestamp: 2025-05-29T00:46:09.063Z
Learning: In the accounts component at apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-count.tsx, the 3-column grid layout (md:grid-cols-3) is intentionally maintained even when rendering only one StatCard, as part of the design structure for this component.
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/service-selector.tsx (3)
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Files for components should be named in PascalCase and use the '.client.tsx' suffix if interactive.
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-25T02:13:08.257Z
Learning: For new UI components, add Storybook stories (*.stories.tsx) alongside the code.
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-06-23T13:49:58.951Z
Learning: Prefer composable UI primitives (Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge) over custom markup for maintainability and design consistency.
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/[chain_id]/page.tsx (1)

3-12: LGTM! Clean server component implementation.

The component correctly handles async params, fetches chain data, and renders appropriately. The implementation follows Next.js server component patterns properly.

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/payment-frequency-selector.tsx (1)

4-47: LGTM! Well-structured payment frequency selector.

The component properly uses UI primitives, has clean TypeScript definitions, and follows the coding guidelines for component composition and styling.

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/checkout.tsx (1)

77-206: LGTM! Well-structured checkout component.

The component properly uses client-side hooks, manages state effectively, and composes UI components correctly. The responsive grid layout and step-by-step flow provide good UX.

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/order-summary.tsx (1)

8-191: LGTM! Comprehensive order summary with proper pricing logic.

The component handles complex pricing calculations correctly, uses proper currency formatting, and provides clear visual feedback for discounts and savings. The conditional rendering and UI composition are well implemented.

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/service-selector.tsx (1)

9-20: Overall implementation follows coding guidelines well.

The component properly:

  • Uses typed props objects and exports named functions
  • Leverages UI primitives (Checkbox, Badge, Label, UpsellBannerCard)
  • Uses cn for class name merging
  • Follows design tokens and responsive patterns
  • Implements proper spacing utilities

The service selection logic and upsell calculations are well-structured and the component provides good user experience with bundle discount incentives.

Also applies to: 22-104, 106-157

Comment on lines +40 to +45
<Button asChild>
<Link href={`/team/${params.team_slug}/~/infrastructure/deploy`}>
Deploy Infrastructure
<RocketIcon className="size-4 ml-2" />
</Link>
</Button>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the incorrect deployment route.

The link points to /team/${params.team_slug}/~/infrastructure/deploy but based on the file structure, it should be /team/${params.team_slug}/~/scale/deploy.

-              <Link href={`/team/${params.team_slug}/~/infrastructure/deploy`}>
+              <Link href={`/team/${params.team_slug}/~/scale/deploy`}>
📝 Committable suggestion

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

Suggested change
<Button asChild>
<Link href={`/team/${params.team_slug}/~/infrastructure/deploy`}>
Deploy Infrastructure
<RocketIcon className="size-4 ml-2" />
</Link>
</Button>
<Button asChild>
<Link href={`/team/${params.team_slug}/~/scale/deploy`}>
Deploy Infrastructure
<RocketIcon className="size-4 ml-2" />
</Link>
</Button>
🤖 Prompt for AI Agents
In apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/layout.tsx
between lines 40 and 45, the Link component's href incorrectly points to the
deployment route under "infrastructure" instead of "scale". Update the href to
`/team/${params.team_slug}/~/scale/deploy` to match the correct route based on
the file structure.

Comment on lines +1 to +8
import { CheckIcon } from "lucide-react";
import { useMemo } from "react";
import { UpsellBannerCard } from "@/components/blocks/UpsellBannerCard";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";

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

Consider adding 'use client' directive for interactive component.

This component uses interactive elements (Checkbox, onClick handlers) and should likely include the 'use client' directive at the top since it's not server-only code.

+import 'use client';
import { CheckIcon } from "lucide-react";

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

🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/service-selector.tsx
at the top of the file (lines 1 to 8), add the 'use client' directive as the
very first line. This is necessary because the component uses interactive
elements like Checkbox and onClick handlers, indicating it should be treated as
a client component rather than a server-only one.

Comment on lines +112 to +121
<Label
className={cn(
"hover:bg-accent/50 flex gap-6 rounded-lg border px-6 py-4 has-[[aria-checked=true]]:border-primary has-[[aria-checked=true]]:bg-primary/10 cursor-pointer items-center",
props.service.required && "cursor-not-allowed",
)}
>
<Checkbox
checked={props.isSelected}
onCheckedChange={() => props.onToggle(props.service)}
/>
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

Improve accessibility for disabled required services.

The current implementation shows cursor-not-allowed but doesn't actually disable the checkbox for required services, which could confuse users.

      <Checkbox
        checked={props.isSelected}
+        disabled={props.service.required}
        onCheckedChange={() => props.onToggle(props.service)}
      />

Also consider updating the Label styling:

      className={cn(
        "hover:bg-accent/50 flex gap-6 rounded-lg border px-6 py-4 has-[[aria-checked=true]]:border-primary has-[[aria-checked=true]]:bg-primary/10 cursor-pointer items-center",
-        props.service.required && "cursor-not-allowed",
+        props.service.required && "cursor-not-allowed opacity-60",
      )}
📝 Committable suggestion

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

Suggested change
<Label
className={cn(
"hover:bg-accent/50 flex gap-6 rounded-lg border px-6 py-4 has-[[aria-checked=true]]:border-primary has-[[aria-checked=true]]:bg-primary/10 cursor-pointer items-center",
props.service.required && "cursor-not-allowed",
)}
>
<Checkbox
checked={props.isSelected}
onCheckedChange={() => props.onToggle(props.service)}
/>
<Label
className={cn(
"hover:bg-accent/50 flex gap-6 rounded-lg border px-6 py-4 has-[[aria-checked=true]]:border-primary has-[[aria-checked=true]]:bg-primary/10 cursor-pointer items-center",
props.service.required && "cursor-not-allowed opacity-60",
)}
>
<Checkbox
checked={props.isSelected}
disabled={props.service.required}
onCheckedChange={() => props.onToggle(props.service)}
/>
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/scale/deploy/_components/service-selector.tsx
around lines 112 to 121, the checkbox for required services is not disabled,
causing accessibility issues despite showing a 'cursor-not-allowed' style. Fix
this by adding the 'disabled' attribute to the Checkbox component when the
service is required, and update the Label styling to visually indicate the
disabled state appropriately.

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. Ecosystem Portal Involves changes to the Ecosystem Portal packages Playground Changes involving the Playground codebase. Portal Involves changes to the Portal (docs) codebase. SDK Involves changes to the thirdweb SDK
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant