Skip to content

Conversation

@MananTank
Copy link
Member

@MananTank MananTank commented Sep 26, 2025


PR-Codex overview

This PR focuses on refactoring and enhancing components related to chain metadata and SEO within the dashboard application. It includes updates to function names, UI adjustments, and the introduction of a new FAQ section.

Detailed summary

  • Renamed getChainMetadata to getCustomChainMetadata.
  • Updated UI styles for various components, including ChainOverviewSection and SupportedProductsSection.
  • Added a new FaqSection component for displaying FAQs.
  • Integrated fetchChainSeo to improve SEO handling.
  • Adjusted metadata fetching in ChainPageLayout and Page components.
  • Changed how chain metadata is accessed in multiple components to use the new custom function.

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

Summary by CodeRabbit

  • New Features

    • Chain pages now show an interactive FAQ section when SEO data includes FAQs.
    • SEO data is fetched and cached to provide richer titles, descriptions, and OpenGraph/Twitter previews.
  • Bug Fixes / Behavior

    • Metadata generation now depends on external SEO data and may be unavailable, affecting preview availability and link consistency.
    • Chain header images and gas-sponsored indicators now source from the updated metadata.
  • Style

    • More compact Supported Products cards, adjusted overview spacing/corner radius, and lighter explorer/info-item typography.

@linear
Copy link

linear bot commented Sep 26, 2025

@vercel
Copy link

vercel bot commented Sep 26, 2025

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

Project Deployment Preview Comments Updated (UTC)
thirdweb-www Ready Ready Preview Comment Sep 26, 2025 10:17pm
4 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
docs-v2 Skipped Skipped Sep 26, 2025 10:17pm
nebula Skipped Skipped Sep 26, 2025 10:17pm
thirdweb_playground Skipped Skipped Sep 26, 2025 10:17pm
wallet-ui Skipped Skipped Sep 26, 2025 10:17pm

@vercel vercel bot temporarily deployed to Preview – thirdweb_playground September 26, 2025 18:00 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui September 26, 2025 18:00 Inactive
@changeset-bot
Copy link

changeset-bot bot commented Sep 26, 2025

⚠️ No Changeset found

Latest commit: 64f5e47

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

This PR includes no changesets

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

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

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

@vercel vercel bot temporarily deployed to Preview – nebula September 26, 2025 18:00 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 September 26, 2025 18:00 Inactive
@MananTank MananTank marked this pull request as ready for review September 26, 2025 18:01
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 26, 2025

Walkthrough

Adds a cached server API (fetchChainSeo + ChainSeo type), integrates fetched SEO into chain page metadata and rendering (including FAQs), refactors getChainMetadata → synchronous getCustomChainMetadata and updates callers, converts some server components from async to sync, and applies minor UI styling tweaks across chain-related components.

Changes

Cohort / File(s) Summary
SEO fetch API
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts
Adds server-only ChainSeo type and exported fetchChainSeo(chainId) wrapped with unstable_cache (24h revalidate); constructs external SEO URL, fetches JSON, returns parsed payload or undefined.
Metadata & layout integration
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
Replaces getChainMetadata with getCustomChainMetadata; generateMetadata now calls fetchChainSeo and may return undefined; OpenGraph/Twitter, title/description, header image and gas sponsorship checks now use SEO or custom metadata.
Page + FAQ
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx, apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
Imports fetchChainSeo; renders new client-side FaqSection when SEO includes FAQs; adds FaqSection export and interactive FaqItem internals; introduces Props type alias for the page.
Custom chain metadata (sync) refactor
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts, .../chainlist/components/server/chainlist-card.tsx, .../chainlist/components/server/chainlist-row.tsx
Renames/export changes: getChainMetadata → synchronous getCustomChainMetadata; updated callers to use synchronous return; ChainListCard and ChainListRow converted from async exports to synchronous functions.
UI styling tweaks
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx, .../ChainOverviewSection.tsx, .../explorer-section.tsx, .../primary-info-item.tsx
Minor visual/layout adjustments: className changes (rounded-lg → rounded-xl, gap adjustments), icon removal and layout simplification, typography weight tweaks; no behavioral changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User as User
  participant Router as Next.js App Router
  participant Meta as generateMetadata
  participant SEO as fetchChainSeo
  participant Layout as ChainPageLayout
  participant Utils as getCustomChainMetadata

  User->>Router: Navigate to /chain/[chain_id]
  Router->>Meta: generateMetadata(params)
  Meta->>SEO: fetchChainSeo(chainId)
  SEO-->>Meta: ChainSeo | undefined
  alt SEO available
    Meta-->>Router: Metadata (from ChainSeo)
  else SEO missing
    Meta-->>Router: undefined
  end

  Router->>Layout: render page
  Layout->>Utils: getCustomChainMetadata(chainId)
  Utils-->>Layout: customChainMetadata | null
  Layout->>SEO: fetchChainSeo(chainId)
  SEO-->>Layout: ChainSeo | undefined
  alt ChainSeo contains FAQs
    Layout-->>Router: Render page including FaqSection
  else
    Layout-->>Router: Render page without FAQs
  end

  Router-->>User: HTML (OG tags from SEO, optional FAQs)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The pull request includes extensive UI style modifications and refactors—such as layout class adjustments in ChainOverviewSection, SupportedProductsSection, explorer-section, primary-info-item, and renames of getChainMetadata to getCustomChainMetadata and related chainlist components—that are unrelated to the linked issue’s focus on SEO metadata updates and adding an FAQ section. Please isolate unrelated UI and metadata function renaming changes into a separate pull request or provide justification for their inclusion to keep this PR focused on the SEO and FAQ objectives.
Description Check ⚠️ Warning The pull request description contains only the commented template and an autogenerated PR-Codex overview but lacks the required filled sections for title, notes for reviewer, and testing instructions as specified in the repository template. Please populate the template by providing a concise PR title, detailed notes for the reviewer outlining the changes, and clear instructions on how to test the changes.
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly reflects the main changes by specifying updating SEO metadata and adding the FAQ section and references the issue tag, which concisely conveys the scope of the pull request without unrelated details.
Linked Issues Check ✅ Passed The changes implement the SEO API fetch via fetchChainSeo, integrate the returned title, description, and OG/Twitter tags in generateMetadata, and add the FaqSection component with collapsible items sourced from the API, matching the objectives in MNY-216 for updating SEO metadata and adding an FAQ section from the provided API.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mny-216

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

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

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

@MananTank MananTank requested review from a team as code owners September 26, 2025 18:01
@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Sep 26, 2025
Copy link
Member Author

MananTank commented Sep 26, 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.

@codecov
Copy link

codecov bot commented Sep 26, 2025

Codecov Report

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

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8135   +/-   ##
=======================================
  Coverage   56.28%   56.28%           
=======================================
  Files         906      906           
  Lines       59192    59192           
  Branches     4174     4174           
=======================================
  Hits        33316    33316           
  Misses      25771    25771           
  Partials      105      105           
Flag Coverage Δ
packages 56.28% <ø> (ø)
🚀 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.

@github-actions
Copy link
Contributor

github-actions bot commented Sep 26, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.09 KB (0%) 1.3 s (0%) 1.6 s (+8.73% 🔺) 2.8 s
thirdweb (cjs) 361.63 KB (0%) 7.3 s (0%) 13.5 s (-1.59% 🔽) 20.7 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 154 ms (+118.16% 🔺) 269 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 46 ms (+39.02% 🔺) 56 ms
thirdweb/react (minimal + tree-shaking) 19.14 KB (0%) 383 ms (0%) 83 ms (+30.58% 🔺) 466 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: 5

🧹 Nitpick comments (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx (1)

14-16: Align Page props type with Next.js API.

Next.js always passes params synchronously; typing it as Promise obscures the real shape and invites accidental misuse. Please restore the plain object type.

-type Props = {
-  params: Promise<{ chain_id: string }>;
-};
+type Props = {
+  params: { chain_id: string };
+};
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b888413 and ce330ea.

📒 Files selected for processing (11)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx (3 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
apps/{dashboard,playground}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Expose a className prop on the root element of every component

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
🧠 Learnings (6)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{ts,tsx} : Export default async functions without `'use client';` – they run on the Node edge.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
📚 Learning: 2025-05-29T00:46:09.063Z
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.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
📚 Learning: 2025-08-29T23:44:47.512Z
Learnt from: MananTank
PR: thirdweb-dev/js#7951
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx:38-38
Timestamp: 2025-08-29T23:44:47.512Z
Learning: The ContractPageLayout component in apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx is not the root layout - it's nested within the dashboard layout which already handles footer positioning with min-h-dvh and AppFooter placement. The ContractPageLayout needs flex flex-col grow to properly participate in the parent's flex layout.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/layout.tsx : Building layout shells (`layout.tsx`) and top-level pages that mainly assemble data.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
🧬 Code graph analysis (5)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts (1)
  • ChainSeo (4-29)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (2)
  • getChain (102-125)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts (1)
  • fetchChainSeo (31-50)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (2)
  • getChain (102-125)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts (1)
  • fetchChainSeo (31-50)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx (1)
  • FaqSection (9-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (6)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx (1)

20-22: Typography adjustment looks good

The lighter weight aligns with the updated dashboard headings while preserving hierarchy. No issues spotted.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx (1)

14-14: Consistent spacing with updated chain cards

The rounded-xl + gap adjustments line up with the rest of the refreshed chain UI while keeping the content grid intact.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx (1)

9-9: Typography update aligns with new overview styling

Dropping the medium weight matches the lighter section headings introduced elsewhere and keeps emphasis on the value content.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx (1)

29-40: Synchronous metadata access keeps server row lightweight

Using getCustomChainMetadata inline removes the async boundary and still exposes the optional flags the row needs.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx (1)

21-32: Card now relies on shared custom metadata helper

Switching the card to the shared synchronous helper keeps the metadata story consistent between list views without extra awaits.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1)

917-919: Helper rename lands cleanly

The renamed helper returns the same memoized data without the async wrapper, matching the new call sites.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ce330ea and 3c75b50.

📒 Files selected for processing (11)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx (3 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
apps/{dashboard,playground}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Expose a className prop on the root element of every component

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
🧠 Learnings (10)
📚 Learning: 2025-08-29T23:44:47.512Z
Learnt from: MananTank
PR: thirdweb-dev/js#7951
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx:38-38
Timestamp: 2025-08-29T23:44:47.512Z
Learning: The ContractPageLayout component in apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx is not the root layout - it's nested within the dashboard layout which already handles footer positioning with min-h-dvh and AppFooter placement. The ContractPageLayout needs flex flex-col grow to properly participate in the parent's flex layout.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/layout.tsx : Building layout shells (`layout.tsx`) and top-level pages that mainly assemble data.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

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

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Never hard-code colors – always go through Tailwind variables.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
📚 Learning: 2025-05-29T00:46:09.063Z
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.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use the `container` class with a `max-w-7xl` cap for page width consistency.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
📚 Learning: 2025-05-26T16:27:26.443Z
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/table.tsx:304-313
Timestamp: 2025-05-26T16:27:26.443Z
Learning: The `useChainSlug` hook returns `string | number`, not `string | undefined` as previously assumed. It does not return undefined values.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
🧬 Code graph analysis (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (2)
  • getChain (102-125)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts (1)
  • fetchChainSeo (31-50)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (2)
  • getChain (102-125)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts (1)
  • fetchChainSeo (31-50)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx (1)
  • FaqSection (9-29)
🔇 Additional comments (6)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx (1)

20-22: Typography adjustment looks good

The shift to font-medium matches the updated visual language elsewhere and keeps the explorer cards consistent. 👍

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx (1)

14-14: Rounded-xl & gap adjustments look good

The tighter large-screen gap and softer radius align well with the dashboard design language.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx (1)

21-24: Use the resolved chainId when fetching custom metadata

Casting params.chain_id to a number returns NaN on slug routes (e.g. /chain/base), so every custom CTA silently disappears. Use the canonical chain.chainId you just fetched instead.

-  const customChainMetadata = getCustomChainMetadata(Number(params.chain_id));
+  const customChainMetadata = getCustomChainMetadata(chain.chainId);
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx (1)

9-9: Typographic tweak aligns with the updated hierarchy

Dropping the extra weight keeps this subheading consistent with the lighter typography used elsewhere in the refreshed chain page. Looks good.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx (1)

26-38: Revised card layout reads cleanly

Appreciate the tightened card styling—using the bordered avatar for product icons plus the font-medium headline keeps the entry visually balanced while staying on design tokens. Nicely done.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx (1)

29-40: Synchronous metadata lookup simplifies the row component

Switching to getCustomChainMetadata and shedding the async wrapper keeps the render path lean while preserving the existing feature checks. 👍

@vercel vercel bot temporarily deployed to Preview – wallet-ui September 26, 2025 19:56 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground September 26, 2025 19:56 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula September 26, 2025 19:56 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (4)

25-26: Mark this layout as server-only

Add the server-only marker to prevent accidental client bundling.

As per coding guidelines

+import "server-only";
 import { ChevronDownIcon, TicketCheckIcon } from "lucide-react";

31-36: Do not type params as a Promise; remove unnecessary awaits

Next.js passes params as a plain object; modeling it as a Promise is misleading and unnecessary.

-type Params = Promise<{ chain_id: string }>;
+type Params = { chain_id: string };
 
 export async function generateMetadata(props: {
-  params: Params;
-}): Promise<Metadata | undefined> {
-  const params = await props.params;
+  params: Params;
+}): Promise<Metadata | undefined> {
+  const { params } = props;
 export default async function ChainPageLayout(props: {
   children: React.ReactNode;
   params: Params;
 }) {
-  const params = await props.params;
+  const { params } = props;

Also applies to: 67-73


38-40: Avoid redundant Number() conversion

chain.chainId is already a number; drop the cast.

-  const chainSeo = await fetchChainSeo(Number(chain.chainId)).catch(
+  const chainSeo = await fetchChainSeo(chain.chainId).catch(
     () => undefined,
   );

47-56: Set OpenGraph URL to the chain page URL (not site root)

Improves share previews by pointing OG/Twitter to the actual chain page.

-    metadataBase: new URL("https://thirdweb.com"),
+    metadataBase: new URL("https://thirdweb.com"),
     openGraph: {
       title: chainSeo.og.title,
       description: chainSeo.og.description,
       siteName: "thirdweb",
       type: "website",
-      url: "https://thirdweb.com",
+      url: `https://thirdweb.com/${chain.slug}`,
     },
     twitter: {
       title: chainSeo.og.title,
       description: chainSeo.og.description,
       card: "summary_large_image",
       creator: "@thirdweb",
       site: "@thirdweb",
     },

Also applies to: 57-63

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between cfba49f and c2e5f65.

📒 Files selected for processing (11)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx (3 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
apps/{dashboard,playground}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Expose a className prop on the root element of every component

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
🧠 Learnings (8)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

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

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Never hard-code colors – always go through Tailwind variables.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
📚 Learning: 2025-05-29T00:46:09.063Z
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.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
📚 Learning: 2025-08-29T23:44:47.512Z
Learnt from: MananTank
PR: thirdweb-dev/js#7951
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx:38-38
Timestamp: 2025-08-29T23:44:47.512Z
Learning: The ContractPageLayout component in apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx is not the root layout - it's nested within the dashboard layout which already handles footer positioning with min-h-dvh and AppFooter placement. The ContractPageLayout needs flex flex-col grow to properly participate in the parent's flex layout.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Use the `container` class with a `max-w-7xl` cap for page width consistency.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/layout.tsx : Building layout shells (`layout.tsx`) and top-level pages that mainly assemble data.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
🧬 Code graph analysis (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (2)
  • getChain (102-125)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts (1)
  • fetchChainSeo (31-50)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1)
  • getCustomChainMetadata (917-928)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (11)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx (1)

20-20: Typography tweak looks consistent

The lighter heading weight still keeps hierarchy clear and aligns with the rest of the refreshed section styling.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx (1)

14-49: Adjustment keeps overview grid consistent with the new card radius/spacing spec.

The tighter lg:gap-6 and larger radius line up with the refreshed design tokens used elsewhere in the chain page—looks good.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx (1)

26-49: Card/CTA refinements look solid.

The bordered tile + centered icon treatment reads cleaner, and restoring font-medium on the link resolves the earlier Tailwind issue while keeping the overlay affordance.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx (1)

21-109: Switch to synchronous metadata integration is ✅.

Pulling getCustomChainMetadata directly keeps the card render simple and preserves the gas-sponsored badge logic without the extra async hop.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1)

917-928: Renamed helper aligns with its actual behavior.

Making the function synchronous under the getCustomChainMetadata name matches its usage pattern throughout the stack.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx (1)

29-99: Row update tracks the new metadata utility nicely.

Dropping the async signature and reusing getCustomChainMetadata keeps the table render tight while preserving the gas-sponsored badge.

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (5)

51-52: OG title mapping fix looks good

openGraph/twitter titles now correctly use chainSeo.og.title.

Also applies to: 58-59


140-140: Header image source change LGTM

Using customChainMetadata.headerImgUrl is appropriate.


148-148: Gas Sponsored gating LGTM

Conditioning on customChainMetadata.gasSponsored is correct.

Also applies to: 170-170


178-180: Description fallback LGTM

Gracefully prefers custom copy with SEO fallback.


82-86: Guard SEO fetch to avoid layout crash on API errors

This call can throw and take down the layout; mirror the try/catch used in generateMetadata.

-  const chainSeo = await fetchChainSeo(chain.chainId);
+  const chainSeo = await fetchChainSeo(chain.chainId).catch(() => undefined);
   const client = getClientThirdwebClient(undefined);
   const description = customChainMetadata?.about || chainSeo?.description;

@graphite-app
Copy link
Contributor

graphite-app bot commented Sep 26, 2025

Merge activity

<!--

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

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

## Notes for the reviewer

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

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring and enhancing the codebase for better readability and functionality. It primarily involves renaming functions, updating component styles, and implementing a new SEO fetching mechanism.

### Detailed summary
- Renamed `getChainMetadata` to `getCustomChainMetadata`.
- Updated styles in several components for consistency.
- Added `fetchChainSeo` function for improved SEO handling.
- Replaced `chainMetadata` with `customChainMetadata` in various components.
- Introduced `FaqSection` component for displaying FAQs.
- Adjusted metadata generation to utilize fetched SEO data.

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

<!-- end pr-codex -->

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

- New Features
  - Chain pages now show an interactive FAQ section when SEO data includes FAQs.
  - SEO data is fetched and cached externally to provide richer titles, descriptions, and OpenGraph/Twitter previews.

- Bug Fixes / Behavior
  - Metadata generation now depends on external SEO (may be unavailable), affecting preview availability and link consistency.
  - Chain header images and gas-sponsored indicators now use the updated metadata source.

- Style
  - More compact Supported Products cards, adjusted overview spacing/corner radius, lighter explorer/info-item typography, and refined link styling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@vercel vercel bot temporarily deployed to Preview – wallet-ui September 26, 2025 22:09 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground September 26, 2025 22:09 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula September 26, 2025 22:09 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 September 26, 2025 22:09 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx (1)

1-8: Add server-only directive, explicit return type, and className support on root

  • Server component should start with import "server-only";.
  • Add an explicit return type.
  • Expose a className prop on the root element per dashboard guideline and merge via cn().

As per coding guidelines

Example update:

import "server-only";
import Link from "next/link";
import type { ChainMetadataWithServices } from "@/types/chain";
import { cn } from "@/lib/utils";

export function SupportedProductsSection(props: {
  services: ChainMetadataWithServices["services"];
  className?: string;
}): JSX.Element | null {
  const { services, className } = props;
  // ...
  return (
    <section className={cn(className)}>
      {/* ... */}
    </section>
  );
}
🧹 Nitpick comments (13)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx (2)

26-26: Add focus-visible ring to support the stretched-link pattern

The link’s ::before covers the card. Add a visible focus state on the card for keyboard users.

As per coding guidelines

-              className="relative rounded-xl border bg-card p-4 hover:border-active-border"
+              className="relative rounded-xl border bg-card p-4 hover:border-active-border focus-within:ring-2 focus-within:ring-ring"

29-33: Hide decorative icon from screen readers

Mark the product icon as decorative to avoid redundant announcements.

-                  <product.icon className="size-4 text-muted-foreground" />
+                  <product.icon aria-hidden="true" className="size-4 text-muted-foreground" />
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx (1)

1-15: Add server-only directive, className prop, and explicit return type

Aligns with dashboard server-component guidelines and improves composability.

As per coding guidelines

+import "server-only";
+import type { JSX } from "react";
+import { cn } from "@/lib/utils";
-export function PrimaryInfoItem(props: {
-  title: string;
-  titleIcon?: React.ReactNode;
-  children: React.ReactNode;
-}) {
+export function PrimaryInfoItem(props: {
+  title: string;
+  titleIcon?: React.ReactNode;
+  children: React.ReactNode;
+  className?: string;
+}): JSX.Element {
   return (
-    <div>
+    <div className={cn(props.className)}>
       <div className="flex items-center gap-2">
         <h3 className="text-base text-muted-foreground">{props.title}</h3>
         {props.titleIcon}
       </div>
       {props.children}
     </div>
   );
 }
apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx (1)

1-9: Mark as server-only, expose className, and add explicit return type

Improves typing and adherence to dashboard component conventions.

As per coding guidelines

+import "server-only";
 import { CircleAlertIcon, TicketCheckIcon } from "lucide-react";
 import Link from "next/link";
 import type { JSX } from "react";
 import { CopyTextButton } from "@/components/ui/CopyTextButton";
 import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
 import type { ChainSupportedService } from "@/types/chain";
 import { ChainIcon } from "../../../components/server/chain-icon";
 import { getCustomChainMetadata } from "../../../utils";
+import { cn } from "@/lib/utils";
 
 type ChainListCardProps = {
   favoriteButton: JSX.Element | undefined;
   chainId: number;
   chainSlug: string;
   chainName: string;
   enabledServices: ChainSupportedService[];
   currencySymbol: string;
   isDeprecated: boolean;
   iconUrl?: string;
+  className?: string;
 };
 
-export function ChainListCard({
+export function ChainListCard({
   isDeprecated,
   chainId,
   chainName,
   chainSlug,
   currencySymbol,
   enabledServices,
   favoriteButton,
   iconUrl,
-}: ChainListCardProps) {
+  className,
+}: ChainListCardProps): JSX.Element {
   const customChainMetadata = getCustomChainMetadata(chainId);
 
   return (
-    <div className="relative h-full">
+    <div className={cn("relative h-full", className)}>
       <Card className="h-full w-full transition-colors hover:border-active-border">

Also applies to: 10-19, 21-31, 34-35

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx (1)

1-6: Use correct Props shape for Next.js params and mark server-only

params is not a Promise; also add explicit return type and server-only directive.

As per coding guidelines

+import "server-only";
 import { CircleAlertIcon } from "lucide-react";
 import { getRawAccount } from "@/api/account/get-account";
 import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
 import { getChain, getCustomChainMetadata } from "../../utils";
 import { fetchChainSeo } from "./apis/chain-seo";
+import type { JSX } from "react";
@@
-type Props = {
-  params: Promise<{ chain_id: string }>;
-};
+type Props = { params: { chain_id: string } };
 
-export default async function Page(props: Props) {
-  const params = await props.params;
+export default async function Page(props: Props): Promise<JSX.Element> {
+  const { params } = props;

Also applies to: 14-19

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx (3)

9-16: Expose className on FaqSection and add explicit return types

Improves composability and typings across dashboard components.

As per coding guidelines

-export function FaqSection(props: { faqs: ChainSeo["faqs"] }) {
+export function FaqSection(props: {
+  faqs: ChainSeo["faqs"];
+  className?: string;
+}): JSX.Element {
   return (
-    <div className="py-10">
+    <div className={cn("py-10", props.className)}>
@@
-function FaqItem(props: {
+function FaqItem(props: {
   title: string;
   description: string;
   className?: string;
-}) {
+}): JSX.Element {

Also applies to: 31-35


42-52: Prevent accidental form submission

Set Button type="button" to avoid submit behavior if nested in a form.

-          <Button
+          <Button
+            type="button"
             variant="ghost"
             onClick={() => setIsOpen(!isOpen)}
             aria-controls={contentId}
             aria-expanded={isOpen}

17-24: Stabilize list keys

Titles may collide; include index to avoid React key warnings.

-          {props.faqs.map((faq, faqIndex) => (
+          {props.faqs.map((faq, faqIndex) => (
             <FaqItem
-              key={faq.title}
+              key={`${faq.title}-${faqIndex}`}
               title={faq.title}
               description={faq.description}
               className={cn(faqIndex === props.faqs.length - 1 && "border-b-0")}
             />
           ))}
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (5)

1-1: Mark this layout as a Server Component

Add the server-only marker at the top to prevent accidental client imports and align with our dashboard server component guidelines.

As per coding guidelines

+import "server-only";
 import { ChevronDownIcon, TicketCheckIcon } from "lucide-react";

31-31: Nit: Clarify the Params alias (and consider avoiding Promise-typed params)

The generic name makes tracing harder, and Next normally passes params synchronously. Consider a more specific alias (e.g., ChainPageParams) and decoupling from Promise for future compatibility.


42-44: Prefer a minimal fallback over returning undefined metadata

Returning undefined drops all metadata. Provide a minimal canonical fallback so pages still have reasonable titles when SEO data is unavailable.

-  if (!chainSeo) {
-    return undefined;
-  }
+  if (!chainSeo) {
+    return {
+      title: chain.name,
+      metadataBase: new URL("https://thirdweb.com"),
+    };
+  }

47-63: Set canonical per-chain URL and include images in OG/Twitter

Use the specific chain URL for OG previews and wire through image(s) if provided by the SEO API.

   return {
     title: chainSeo.title,
     description: chainSeo.description,
     metadataBase: new URL("https://thirdweb.com"),
+    // Optional but recommended for SEO
+    alternates: {
+      canonical: `/chain/${chain.slug}`,
+    },
     openGraph: {
       title: chainSeo.og.title,
       description: chainSeo.og.description,
       siteName: "thirdweb",
       type: "website",
-      url: "https://thirdweb.com",
+      url: `https://thirdweb.com/chain/${chain.slug}`,
+      images: chainSeo.og?.image ? [chainSeo.og.image] : undefined,
     },
     twitter: {
       title: chainSeo.og.title,
       description: chainSeo.og.description,
       card: "summary_large_image",
       creator: "@thirdweb",
       site: "@thirdweb",
+      images: chainSeo.og?.image ? [chainSeo.og.image] : undefined,
     },
   };

If you’d rather avoid alternates, at least update openGraph.url as above. Based on learnings


212-218: Use design tokens instead of raw HSL colors

Replace hard-coded HSL with our design tokens (e.g., bg-accent and text-accent-foreground) for theme consistency and dark mode support.

As per coding guidelines

-  return (
-    <div className="flex items-center gap-2 rounded-full bg-[hsla(335,57%,51%,0.2)] px-2.5 py-1 text-[hsl(334,81.12%,69.65%)]">
+  return (
+    <div className="flex items-center gap-2 rounded-full bg-accent px-2.5 py-1 text-accent-foreground">
       <TicketCheckIcon className="size-4" />
       <span className="font-medium text-xs">Gas Sponsored</span>
     </div>
   );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c2e5f65 and 64f5e47.

📒 Files selected for processing (11)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx (3 hunks)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-row.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/ChainOverviewSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/explorer-section.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
apps/{dashboard,playground}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Expose a className prop on the root element of every component

Files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/primary-info-item.tsx
  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx
🧠 Learnings (9)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

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

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Never hard-code colors – always go through Tailwind variables.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx
📚 Learning: 2025-08-29T23:44:47.512Z
Learnt from: MananTank
PR: thirdweb-dev/js#7951
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx:38-38
Timestamp: 2025-08-29T23:44:47.512Z
Learning: The ContractPageLayout component in apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx is not the root layout - it's nested within the dashboard layout which already handles footer positioning with min-h-dvh and AppFooter placement. The ContractPageLayout needs flex flex-col grow to properly participate in the parent's flex layout.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Keep `queryKey` stable and descriptive for cache hits.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use descriptive, stable `queryKeys` for React Query cache hits

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/layout.tsx : Building layout shells (`layout.tsx`) and top-level pages that mainly assemble data.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
📚 Learning: 2025-05-26T16:27:26.443Z
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/table.tsx:304-313
Timestamp: 2025-05-26T16:27:26.443Z
Learning: The `useChainSlug` hook returns `string | number`, not `string | undefined` as previously assumed. It does not return undefined values.

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx
🧬 Code graph analysis (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/chainlist/components/server/chainlist-card.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (1)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx (1)
  • generateMetadata (28-39)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (2)
  • getChain (102-125)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/utils.ts (2)
  • getChain (102-125)
  • getCustomChainMetadata (917-928)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx (1)
  • FaqSection (9-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Build Packages
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (11)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/SupportedProductsSection.tsx (1)

35-41: Resolved: invalid Tailwind class; also verify external vs internal link

  • The previous “text-medium” issue is fixed by using font-medium. LGTM.
  • If product.link is internal, use NavLink per dashboard guideline; if external, consider a plain <a> over next/link.

As per coding guidelines

#!/bin/bash
# Inspect product links to confirm internal vs external usage.
set -euo pipefail

# Find the products definition and show link fields
rg -nP -C2 'export\s+const\s+products\b|link\s*:' --type=ts --type=tsx

# If most links start with "/", prefer NavLink. If they start with http(s), <a> is fine.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/apis/chain-seo.ts (1)

31-47: Handle SEO API network failures gracefully

Wrap in try/catch to avoid taking down the page when upstream hiccups; return undefined on errors.

 export const fetchChainSeo = unstable_cache(
   async (chainId: number) => {
-    const url = new URL(
-      `https://seo-pages-generator-5814.zeet-nftlabs.zeet.app/chain/${chainId}`,
-    );
-    const res = await fetch(url, {
-      headers: {
-        "Content-Type": "application/json",
-      },
-    });
-
-    if (!res.ok) {
-      return undefined;
-    }
-
-    return res.json() as Promise<ChainSeo>;
+    try {
+      const url = new URL(
+        `https://seo-pages-generator-5814.zeet-nftlabs.zeet.app/chain/${chainId}`,
+      );
+      const res = await fetch(url, {
+        headers: { "Content-Type": "application/json" },
+      });
+      if (!res.ok) {
+        return undefined;
+      }
+      return (await res.json()) as ChainSeo;
+    } catch {
+      return undefined;
+    }
   },
   ["chain-seo"],
   { revalidate: 60 * 60 * 24 }, // 24 hours
 );
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx (1)

21-23: Fix custom metadata lookup for slug routes

Use the canonical chainId from getChain; Number(params.chain_id) is NaN on slug URLs.

-  const customChainMetadata = getCustomChainMetadata(Number(params.chain_id));
+  const customChainMetadata = getCustomChainMetadata(Number(chain.chainId));
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/faq-section.tsx (1)

36-46: Fix setter name typo

Rename to setIsOpen for clarity; update the onClick to match.

-  const [isOpen, setIsOpenn] = useState(false);
+  const [isOpen, setIsOpen] = useState(false);
@@
-          <Button
+          <Button
             variant="ghost"
-            onClick={() => setIsOpenn(!isOpen)}
+            onClick={() => setIsOpen(!isOpen)}
             aria-controls={contentId}
             aria-expanded={isOpen}
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (7)

25-26: Imports refactor looks good

Switch to getCustomChainMetadata and using fetchChainSeo is appropriate here.


38-40: Good: SEO fetch is guarded in generateMetadata

Catching failures avoids metadata generation crashes on SEO API outages.


51-56: OG title mapping fix is correct

Mapping openGraph.title to chainSeo.og.title resolves the prior bug.


85-85: Description fallback logic is good

Preferring customChainMetadata.about over SEO description aligns with the objectives.


140-141: Header image source switch looks right

Passing customChainMetadata?.headerImgUrl into ChainHeader is consistent with the refactor.


178-181: Description rendering LGTM

Whitespace handling and responsive typography look good.


83-85: Guard fetchChainSeo in layout to avoid runtime crashes on SEO API outages

Unlike generateMetadata, this call isn’t caught. A thrown fetch will crash the layout render.

-  const chainSeo = await fetchChainSeo(chain.chainId);
+  const chainSeo = await fetchChainSeo(chain.chainId).catch(() => undefined);

@graphite-app graphite-app bot merged commit 64f5e47 into main Sep 26, 2025
25 checks passed
@graphite-app graphite-app bot deleted the mny-216 branch September 26, 2025 22:18
@vercel vercel bot temporarily deployed to Production – wallet-ui September 26, 2025 22:18 Inactive
@vercel vercel bot temporarily deployed to Production – thirdweb_playground September 26, 2025 22:18 Inactive
@vercel vercel bot temporarily deployed to Production – nebula September 26, 2025 22:18 Inactive
@vercel vercel bot temporarily deployed to Production – docs-v2 September 26, 2025 22:18 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dashboard Involves changes to the Dashboard.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants