-
Notifications
You must be signed in to change notification settings - Fork 538
Add Contract layout in team/project #7152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThis update propagates a Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant RoutePage
participant API
participant SharedComponent
participant ContractComponent
User->>RoutePage: Access contract page (with team/project slugs)
RoutePage->>API: Fetch team/project by slug
API-->>RoutePage: Return team/project (or 404)
RoutePage->>SharedComponent: Render with contractAddress, chainIdOrSlug, projectMeta
SharedComponent->>API: Fetch contract info (with projectMeta)
API-->>SharedComponent: Return contract info
alt Contract supported
SharedComponent->>ContractComponent: Render with contract info, projectMeta
else Not supported
SharedComponent->>User: Redirect or 404
end
Suggested labels
Suggested reviewers
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #7152 +/- ##
=======================================
Coverage 55.68% 55.68%
=======================================
Files 904 904
Lines 58340 58340
Branches 4107 4107
=======================================
Hits 32484 32484
Misses 25751 25751
Partials 105 105
🚀 New features to boost your workflow:
|
size-limit report 📦
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 20
🔭 Outside diff range comments (4)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/page.tsx (1)
3-8
:⚠️ Potential issue
params
should not be typed as aPromise
Next.js’
PageProps
shape providesparams
synchronously – it is already the plain object extracted from the route, not a promise.
Typing it asPromise<…>
forces every consumer toawait
something that is never asynchronous, producing a type-error at compile time and signalling a misleading contract to future maintainers.-export default async function Page(props: { - params: Promise<{ - contractAddress: string; - chain_id: string; - }>; -}) { - const params = await props.params; +export default async function Page(props: { + params: { + contractAddress: string; + chain_id: string; + }; +}) { + const { params } = props;apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/page.tsx (1)
4-8
:⚠️ Potential issueIncorrect
Promise
typing forparams
(same issue as settings page)
params
is synchronous; typing it as a promise causes type errors and unnecessaryawait
.-export default async function Page(props: { - params: Promise<{ +export default async function Page(props: { + params: { contractAddress: string; chain_id: string; - }>; + }; }) { - const params = await props.params; + const { params } = props;apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/events-feed.tsx (1)
88-103
:⚠️ Potential issueSelecting “All” events never updates the UI
eventTypes
does not include"all"
, therefore this guard prevents both
router.push
andsetSelectedEvent
from running when the user chooses “All”.- if (eventTypes.includes(val)) { + if (val === "all" || eventTypes.includes(val)) {Without this change the dropdown appears selectable but does nothing, which is a UX bug.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx (1)
8-15
: 🛠️ Refactor suggestion
params
should not be aPromise
– mismatched Next.js typeIn Next 13/14 route segments,
Layout
receivesprops.params
as a plain object, not aPromise
.
Declaring andawait
-ing it complicates the type signature and may mask real type errors elsewhere.-export default async function Layout(props: { - params: Promise<{ +export default async function Layout(props: { + params: { contractAddress: string; chain_id: string; }; children: React.ReactNode; }) { - const params = await props.params; + const params = props.params;Recommend aligning the declaration; TS will then surface issues at compile-time instead of runtime.
♻️ Duplicate comments (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.client.tsx (1)
4-4
: Same import path concern as previous file.This file has the same deeply nested import path issue for
ProjectMeta
. Consider the same recommendation to centralize type definitions for better maintainability.
🧹 Nitpick comments (39)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/components/nfts-owned.tsx (1)
5-5
: Consider using an absolute import path for better maintainability.The relative import path is very deep (6 levels) and creates tight coupling between components. This makes the codebase fragile to directory structure changes.
Consider using an absolute import or creating a shared types file:
-import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/types/project-meta";Or create a shared types barrel export to reduce the import complexity.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/ClaimConditions.client.tsx (1)
4-4
: Consider using an absolute import path for better maintainability.The relative import path is very deep and creates tight coupling. This is the same issue present across multiple files in this PR.
Consider centralizing the
ProjectMeta
type in a shared location:-import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/types/project-meta";apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/AccountSigners.client.tsx (1)
4-4
: Consider using an absolute import path for better maintainability.This is the same deep relative import path issue seen across multiple files in this PR. Consider creating a shared types module to reduce coupling and improve maintainability.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/ContractEditModulesPage.client.tsx (1)
4-4
: Consider using a more maintainable import path.The relative import path with multiple "../" segments could be fragile if the directory structure changes. Consider using an absolute import or creating a shared types barrel export.
For better maintainability, consider:
-import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/app/types/project"; // or similar absolute pathHowever, since this pattern appears consistent across the codebase refactor, this change can be addressed in a follow-up cleanup.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/page.tsx (1)
1-19
: Good refactor, but note parameter inconsistency across shared components.The extraction to
SharedContractSourcesPage
is well-implemented and follows the same pattern as other contract pages. However, there's an architectural inconsistency worth noting: this shared component expectsteamId: undefined
while other shared components (likeSharedModulesPage
) expectprojectMeta: ProjectMeta | undefined
.Consider standardizing the parameter structure across all shared contract page components to use either
projectMeta
orteamId
consistently. This would improve maintainability and reduce confusion.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx (1)
4-4
: Consider centralizing type definitions.The deeply nested import path for
ProjectMeta
could be improved for maintainability. Consider moving shared types likeProjectMeta
to a more central location (e.g.,src/types/
or similar) to reduce coupling and improve discoverability.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/modules/page.tsx (1)
10-10
: Consider clarifying variable naming for better maintainability.The variable is named
team
but you're callinggetProject()
. Based on the usage where you accessteam.id
andteam.slug
, it appears the Project object contains team information. For clarity, consider either:
- Renaming the variable to
project
if it represents a project object containing team info- Or updating the comment to clarify that
getProject
returns team metadata- const team = await getProject(params.team_slug, params.project_slug); + const project = await getProject(params.team_slug, params.project_slug); - if (!team) { + if (!project) { - teamId: team.id, - teamSlug: team.slug, + teamId: project.teamId, // or project.team.id depending on API structure + teamSlug: project.teamSlug, // or project.team.slug depending on API structureAlso applies to: 23-24
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/events/page.tsx (1)
10-10
: Consider renaming variable for clarity.The variable is named
team
but stores the result ofgetProject()
. While the usage suggests the Project object contains team information, this naming could be confusing for future maintainers.Consider renaming for clarity:
- const team = await getProject(params.team_slug, params.project_slug); + const project = await getProject(params.team_slug, params.project_slug);And update the references accordingly:
- if (!team) { + if (!project) { notFound(); } return ( <SharedEventsPage params={{ contractAddress: params.contractAddress, chainIdOrSlug: params.chainIdOrSlug, projectMeta: { projectSlug: params.project_slug, - teamId: team.id, - teamSlug: team.slug, + teamId: project.teamId, // or project.team.id depending on structure + teamSlug: project.teamSlug, // or project.team.slug }, }} /> );apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/code/page.tsx (1)
9-10
: Consider renaming variable for clarity.The variable
team
actually contains project data fromgetProject()
. Consider renaming it toproject
for better code readability.- const team = await getProject(params.team_slug, params.project_slug); + const project = await getProject(params.team_slug, params.project_slug);And update the reference on line 23:
- teamId: team.id, + teamId: project.id,And line 24:
- teamSlug: team.slug, + teamSlug: project.slug,apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account-permissions/page.tsx (1)
3-3
: Consider using absolute imports to improve maintainability.The relative import path
../../../../../../../(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page
is very long and brittle to refactoring. Consider using absolute imports or path aliases.-import { SharedContractAccountPermissionsPage } from "../../../../../../../(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page"; +import { SharedContractAccountPermissionsPage } from "@/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page";apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx (1)
3-3
: Consider using absolute imports to improve maintainability.The relative import path is very long and brittle to refactoring. Consider using absolute imports or path aliases for better maintainability.
-import { SharedNFTPage } from "../../../../../../../(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page"; +import { SharedNFTPage } from "@/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page";apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/[tokenId]/page.tsx (2)
14-14
: Fix confusing variable namingThe variable name
team
is misleading sincegetProject()
returns a project object, not a team. This could cause confusion for future developers.- const team = await getProject(params.team_slug, params.project_slug); + const project = await getProject(params.team_slug, params.project_slug); - if (!team) { + if (!project) {Also applies to: 16-16
26-30
: Update variable reference in ProjectMeta constructionFollowing the variable naming fix above, update the reference in the
projectMeta
object.projectMeta: { projectSlug: params.project_slug, - teamId: team.id, - teamSlug: team.slug, + teamId: project.id, + teamSlug: project.slug, },apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/settings/page.tsx (1)
3-3
: Consider refactoring the long import path for maintainability.The import path
../../../../../../../(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page
is quite long and fragile. Consider using a path alias or moving shared components to a more accessible location.// Consider using a path alias like: import { SharedContractSettingsPage } from "@/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page";apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx (1)
3-3
: Same import path maintainability concern.Similar to other files in this refactor, consider using path aliases for the long relative import.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/page.tsx (2)
1-3
: Replace brittle deep-relative import with an absolute/alias pathNine “
../
” segments are easy to get wrong (and they already differ from the depth used in neighbouring pages).
Using the existing@/
alias (or introducing one) avoids future breakage when folders move.-import { SharedContractOverviewPage } from "../../../../../../(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page"; +import { SharedContractOverviewPage } from "@/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page";
16-29
: Memoise the team lookup to avoid N+1 requests across sibling pagesEvery contract sub-page repeats:
const team = await getTeamBySlug(params.team_slug);When a user navigates between pages, the same network request is made again.
WrappinggetTeamBySlug
withcache()
from React 18 (or re-exporting a cached variant) will give a free in-memory response and speed up navigation:// in @/api/team.ts -import { getAuthToken } from "./auth"; +import { getAuthToken } from "./auth"; +import { cache } from "react"; -export async function getTeamBySlug(slug: string) { +export const getTeamBySlug = cache(async (slug: string) => { ... -} +});apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/english-auctions/page.tsx (1)
6-10
: Consistent handling ofparams
Same remark as in the claim-conditions page: if
params
is not actually aPromise
here, drop theawait
and adjust the type.
Keeping the signature consistent across the new team/project pages will avoid confusion.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-conditions/page.tsx (1)
10-10
: Consider renaming the variable for clarity.The variable is named
team
but thegetProject
API call returns project data according to the function signature. Consider renaming it toproject
for consistency:- const team = await getProject(params.team_slug, params.project_slug); + const project = await getProject(params.team_slug, params.project_slug);And update the subsequent references accordingly.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/Analytics.tsx (1)
14-14
: Consider using an absolute import path.The relative import path is quite long and brittle. Consider using an absolute import if the types are commonly used across the dashboard:
-import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/types/project"; // or similar absolute pathapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/explorer/page.tsx (1)
10-10
: Consider renaming the variable for clarity.Same issue as in the claim-conditions page - the variable is named
team
but contains project data. For consistency and clarity:- const team = await getProject(params.team_slug, params.project_slug); + const project = await getProject(params.team_slug, params.project_slug);And update lines 23-24 accordingly.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-table.tsx (2)
19-19
: Extremely long relative import path – consider using a path aliasThe multi-
../
path is brittle; a single directory move will break the import and makes the location ofProjectMeta
non-obvious. Add atsconfig.json
/jest
path alias (e.g.@/types/ProjectMeta
) so consumers can import it concisely and safely.
99-107
:onRowClick
URL building duplicates routing logicHard-coding the paths in multiple components risks divergence from the canonical router helpers. Consider centralising URL creation in
useDashboardRouter
(e.g.router.toContractAccount(projectMeta, chainSlug, row.account)
) to avoid future inconsistencies and to automatically encode path params.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/page.tsx (1)
1-1
: Remove empty import – it produces an unused-import lint error
import {} from "next/navigation";
imports nothing and is unnecessary.-import {} from "next/navigation";
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
30-30
: Optimize useEffect dependencies for better performanceThe current dependency array
[router, props]
is too broad. Theprops
object reference changes on every render, causing unnecessary effect re-runs.Consider destructuring the specific props needed in the dependency array:
- }, [router, props]); + }, [router, props.contract.chain.id, props.contract.address, props.projectMeta]);This ensures the effect only runs when the actual values change, not when the props object reference changes.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx (1)
16-28
: Optimize performance with parallel data fetching.Unlike other shared components in this PR, this implementation fetches the account sequentially after contract info rather than in parallel. This could impact performance.
Consider using
Promise.all
for parallel fetching to match the pattern used in other shared components:- const info = await getContractPageParamsInfo({ - contractAddress: params.contractAddress, - chainIdOrSlug: params.chainIdOrSlug, - teamId: params.projectMeta?.teamId, - }); - - if (!info) { - notFound(); - } - - const twAccount = await getRawAccount(); + const [twAccount, info] = await Promise.all([ + getRawAccount(), + getContractPageParamsInfo({ + contractAddress: params.contractAddress, + chainIdOrSlug: params.chainIdOrSlug, + teamId: params.projectMeta?.teamId, + }), + ]); + + if (!info) { + notFound(); + }This matches the performance optimization pattern used in
shared-direct-listings-page.tsx
(lines 17-24).apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx (1)
28-28
: Use consistent variable naming across shared components.The variable
twAccount
should be namedaccount
for consistency with other shared contract components.- const twAccount = await getRawAccount(); + const account = await getRawAccount();And update the references accordingly:
- isLoggedIn={!!twAccount} + isLoggedIn={!!account}- <ContractSplitPage contract={clientContract} isLoggedIn={!!twAccount} /> + <ContractSplitPage contract={clientContract} isLoggedIn={!!account} />apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx (1)
8-21
: Parameter structure inconsistency across shared components.The parameter structure here differs from
SharedContractTokensPage
- this component takesprojectMeta
as a parameter and extractsteamId
from it, while the tokens shared page takesteamId
directly. Consider standardizing the parameter structure across all shared components for consistency.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx (2)
1-3
: Import path with nested dynamic segments is fragileThe relative path to
types.ts
walks through several dynamic route folders.
Changes in folder depth or renaming any route segment will silently break the import and TypeScript will not resolve it until build time.-import type { ProjectMeta } from "../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +// ✅ consider using the path alias already configured for app code, e.g.: +import type { ProjectMeta } from "@/app/types/project-meta";Using a ts-config path alias (e.g.
@/app/...
) improves resiliency and readability.
57-61
: Silent swallow ofPublishedBy
errors loses debugging signal
ErrorBoundary
withfallback={null}
hides all publisher-related errors without
logging, making production issues hard to trace.-<ErrorBoundary fallback={null}> +<ErrorBoundary + fallback={null} + onError={(err) => { + // eslint-disable-next-line no-console -- server-only diagnostic + console.error("[ContractOverview] PublishedBy failed:", err); + }} +>Adding a minimal
onError
callback (or Sentry capture) preserves observability without breaking the end-user experience.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx (1)
41-45
: Minor optimisation: parallelise account and metadata fetch
getAuthTokenWalletAddress
andgetRawAccount
are already parallelised, but
getContractPageMetadata
(non-localhost branch) could also be added to the
Promise.all
above to save one round-trip latency.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx (2)
28-35
: Nit: Destructuring names mismatch hampers readability
getSelectors
returns{ writeFnSelectorToName, eventSelectorToName }
but the
result is unpacked into variables with the same names; the “Record” suffix is
added only at the prop level. Consider harmonising names:- { eventSelectorToName, writeFnSelectorToName }, + { eventSelectorToName: eventSelectorToNameRecord, + writeFnSelectorToName: writeFnSelectorToNameRecord },and pass the variables with identical names.
This avoids accidental shadowing when the component grows.
53-70
: Guard against missingname
in ABI itemsSome ABI entries (e.g. fallback / receive functions) lack
name
; current code
would assignundefined
, producing a selector→undefined
mapping.- writeFnSelectorToName[toFunctionSelector(item)] = item.name; + if (item.name) { + writeFnSelectorToName[toFunctionSelector(item)] = item.name; + }The same applies to events.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/events-feed.tsx (1)
54-57
: URL construction logic duplicated & fragile – extract a helper
contractRootPath
is recomputed in multiple places (EventsFeed
,EventsFeedItem
,
MarketplaceDetails
, etc.).
Centralising this logic will:
- Prevent subtle mismatches (
/contract
vs. empty string).- Reduce boilerplate.
Example:
// utils/paths.ts export const getContractRoot = (meta?: ProjectMeta) => meta ? `/team/${meta.teamSlug}/${meta.projectSlug}/contract` : "";Then:
-const contractRootPath = projectMeta - ? `/team/${projectMeta.teamSlug}/${projectMeta.projectSlug}/contract` - : ""; +const contractRootPath = getContractRoot(projectMeta);Also applies to: 191-194
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/MarketplaceDetails.tsx (1)
300-308
: Hard-coded URL pieces – rely on extracted helperSee previous comment: replace inline interpolation with the shared
getContractRoot()
helper to keep path generation consistent.-const directListingsHref = `${contractRootPath}/${chainSlug}/${contractAddress}/direct-listings`; -const englishAuctionsHref = `${contractRootPath}/${chainSlug}/${contractAddress}/english-auctions`; +const base = `${getContractRoot(projectMeta)}/${chainSlug}/${contractAddress}`; +const directListingsHref = `${base}/direct-listings`; +const englishAuctionsHref = `${base}/english-auctions`;apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx (1)
196-210
: Minor copy edit – double space & slug vs chain-ID wordingThe fallback metadata description currently renders with two spaces (
"contract on"
) and always says “Chain ID” even when a slug such aspolygon
is supplied:description: `View tokens, transactions, balances, source code, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}`; ... description: `View tokens, transactions, balances, source code, and analytics for the smart contract on Chain ID ${params.chainIdOrSlug}`,Consider tightening the string and conditionally wording the identifier:
- description = `View tokens, transactions, balances, source code, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}`; + description = `View tokens, transactions, balances, source code, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}.`; ... - description: `View tokens, transactions, balances, source code, and analytics for the smart contract on Chain ID ${params.chainIdOrSlug}`, + description: `View tokens, transactions, balances, source code, and analytics for this smart contract on ${params.chainIdOrSlug}.`,A tiny tweak, but it improves the professionalism of SEO snippets.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx (3)
129-170
: Skip the home chain before firing 9 extra RPC calls
defaultChains
always includes the current chain, yet it is filtered after the
Promise.all
, meaning we still perform an unnecessaryeth_getCode
on the chain we
already have data for.- await Promise.all( - defaultChains.map(async (c) => { + await Promise.all( + defaultChains + .filter((c) => c !== serverContract.chain.id) // avoid redundant call + .map(async (c) => {Small change, but it saves one network round-trip per request and reduces noise in
RPC metrics.
60-68
: Suppressing all errors can hide genuine connectivity issuesThe empty
catch {}
aroundgetDeployedCloneFactoryContract
swallows
network/ABI errors that might explain missing data later on.
At minimum, log a warning withconsole.warn
(server side) or return a typed
Result
object so callers can act accordingly.
181-185
: Early return bypasses fetch-error handlingWhen
fetchPublishedContractsFromDeploy
fails we fall back to the
“NoCrossChainPrompt” without differentiating between “metadata not found”
and “network error / rate limit”. Users may mistake transient errors for an
absence of cross-chain capability.Consider distinguishing:
} catch (e) { logger.error(e); return <ErrorState message="Unable to fetch deploy metadata. Please retry." />; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (107)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/ContractDirectListingsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/NFTCards.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageSidebarLinks.ts
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/AccountSigners.client.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.client.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/components/nfts-owned.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-table.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/ClaimConditions.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/shared-code-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/data-table.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/events-feed.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/shared-events-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/shared-explorer-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/ContractEditModulesPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.client.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/TokenIdPage.client.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/token-id.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/table.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/opengraph-image.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/ContractOverviewPage.tsx
(7 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/Analytics.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/BuildYourApp.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/ContractChecklist.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/LatestEvents.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/MarketplaceDetails.tsx
(11 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/NFTDetails.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/PermissionsTable.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/contract-overview-page.client.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/ContractProposalsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/shared-sources-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/ContractSplitPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx
(3 hunks)apps/dashboard/src/app/(app)/api/lib/getAuthToken.ts
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx
(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx
(5 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/direct-listings/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/english-auctions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account-permissions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/accounts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/analytics/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-conditions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/code/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/cross-chain/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/events/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/explorer/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/modules/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/[tokenId]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/permissions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/proposals/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/settings/page.tsx
(1 hunks)
⛔ Files not processed due to max files limit (9)
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/sources/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/split/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/tokens/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/utils.ts
- apps/dashboard/src/components/contract-components/tables/cells.tsx
- apps/dashboard/src/components/contract-components/tables/contract-table.stories.tsx
- apps/dashboard/src/components/contract-components/tables/contract-table.tsx
- apps/dashboard/src/components/smart-wallets/AccountFactories/factory-contracts.tsx
🧰 Additional context used
🧠 Learnings (8)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/direct-listings/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/permissions/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/analytics/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/code/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/explorer/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
🧬 Code Graph Analysis (77)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/opengraph-image.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (1)
getContractPageParamsInfo
(8-46)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.client.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/ContractDirectListingsPage.client.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
RedirectToContractOverview
(9-33)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx (1)
SharedContractSplitPage
(9-49)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx (1)
SharedContractAccountPermissionsPage
(8-45)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/direct-listings/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/team.ts (1)
getTeamBySlug
(11-30)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx (1)
SharedDirectListingsPage
(9-54)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/ContractSplitPage.client.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
RedirectToContractOverview
(9-33)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/shared-sources-page.tsx (1)
SharedContractSourcesPage
(5-19)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/ContractEditModulesPage.client.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
RedirectToContractOverview
(9-33)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
RedirectToContractOverview
(9-33)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-conditions/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/projects.ts (1)
getProject
(29-48)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx (1)
SharedClaimConditionsPage
(10-73)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/components/nfts-owned.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/permissions/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/projects.ts (1)
getProject
(29-48)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx (1)
SharedPermissionsPage
(9-54)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx (1)
SharedPermissionsPage
(9-54)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx (1)
SharedClaimConditionsPage
(10-73)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/ContractProposalsPage.client.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
RedirectToContractOverview
(9-33)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account-permissions/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/team.ts (1)
getTeamBySlug
(11-30)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx (1)
SharedContractAccountPermissionsPage
(8-45)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/BuildYourApp.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx (1)
SharedContractSettingsPage
(10-56)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/TokenIdPage.client.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
RedirectToContractOverview
(9-33)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.client.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
RedirectToContractOverview
(9-33)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.tsx (1)
AccountsPage
(17-52)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx (1)
SharedNFTPage
(10-62)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx (1)
SharedModulesPage
(10-55)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.client.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
RedirectToContractOverview
(9-33)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx (1)
SharedAccountsPage
(9-57)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/AccountSigners.client.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
RedirectToContractOverview
(9-33)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page.tsx (1)
SharedContractAccountPage
(9-59)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/shared-sources-page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (1)
getContractPageParamsInfo
(8-46)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx (1)
SharedContractOverviewPage
(10-64)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx (1)
SharedContractProposalsPage
(9-48)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-table.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.client.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
RedirectToContractOverview
(9-33)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/events/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/projects.ts (1)
getProject
(29-48)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/shared-events-page.tsx (1)
SharedEventsPage
(6-30)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx (1)
SharedNFTTokenPage
(11-79)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/PermissionsTable.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/ClaimConditions.client.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
RedirectToContractOverview
(9-33)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/proposals/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/team.ts (1)
getTeamBySlug
(11-30)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx (1)
SharedContractProposalsPage
(9-48)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/english-auctions/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/team.ts (1)
getTeamBySlug
(11-30)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx (1)
SharedEnglishAuctionsPage
(9-53)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/team.ts (1)
getTeamBySlug
(11-30)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx (1)
SharedContractOverviewPage
(10-64)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/shared-events-page.tsx (1)
SharedEventsPage
(6-30)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/shared-code-page.tsx (1)
SharedCodePage
(8-47)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/table.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (1)
getContractPageParamsInfo
(8-46)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/ContractProposalsPage.client.tsx (1)
ContractProposalsPageClient
(10-40)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageMetadata.ts (1)
getContractPageMetadata
(30-32)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/shared-explorer-page.tsx (1)
SharedExplorerPage
(9-53)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx (4)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (1)
getContractPageParamsInfo
(8-46)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/AccountSigners.client.tsx (1)
AccountSignersClient
(10-34)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageMetadata.ts (1)
getContractPageMetadata
(30-32)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/analytics/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/projects.ts (1)
getProject
(29-48)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx (1)
SharedAnalyticsPage
(10-51)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx (1)
SharedDirectListingsPage
(9-54)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/code/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/projects.ts (1)
getProject
(29-48)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/shared-code-page.tsx (1)
SharedCodePage
(8-47)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/data-table.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/api/lib/getAuthToken.ts (1)
apps/dashboard/src/@/constants/thirdweb-client.client.ts (1)
getClientThirdwebClient
(3-11)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/contract-overview-page.client.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/modules/page.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx (1)
SharedModulesPage
(10-55)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (1)
apps/dashboard/src/app/(app)/api/lib/getAuthToken.ts (1)
getUserThirdwebClient
(32-51)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/NFTDetails.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx (1)
SharedContractTokensPage
(12-50)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/components/nfts-owned.tsx (1)
NftsOwned
(14-51)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/LatestEvents.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/@3rdweb-sdk/react/hooks/useActivity.ts (1)
useActivity
(16-55)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx (6)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (1)
getContractPageParamsInfo
(8-46)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/ContractEditModulesPage.client.tsx (1)
ContractEditModulesPageClient
(10-40)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageMetadata.ts (1)
getContractPageMetadata
(30-32)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/utils.ts (1)
redirectToContractLandingPage
(5-18)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx (1)
SharedEnglishAuctionsPage
(9-53)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/[tokenId]/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/projects.ts (1)
getProject
(29-48)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx (1)
SharedNFTTokenPage
(11-79)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx (4)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (1)
getContractPageParamsInfo
(8-46)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageMetadata.ts (1)
getContractPageMetadata
(30-32)apps/dashboard/src/constants/addresses.ts (1)
DEFAULT_FEE_RECIPIENT
(7-8)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/token-id.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageSidebarLinks.ts (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/team.ts (1)
getTeamBySlug
(11-30)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page.tsx (1)
SharedContractAccountPage
(9-59)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/ContractChecklist.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/Analytics.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/accounts/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectContractPageParams
(1-6)apps/dashboard/src/@/api/team.ts (1)
getTeamBySlug
(11-30)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx (1)
SharedAccountsPage
(9-57)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (1)
getContractPageParamsInfo
(8-46)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/ContractSplitPage.client.tsx (1)
ContractSplitPageClient
(10-40)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageMetadata.ts (1)
getContractPageMetadata
(30-32)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/MarketplaceDetails.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (1)
getContractPageParamsInfo
(8-46)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx (1)
ContractEnglishAuctionsPageClient
(10-41)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageMetadata.ts (1)
getContractPageMetadata
(30-32)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx (6)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (1)
getContractPageParamsInfo
(8-46)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageMetadata.ts (1)
getContractPageMetadata
(30-32)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/ClaimConditions.client.tsx (1)
ClaimConditionsClient
(10-48)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/utils.ts (1)
redirectToContractLandingPage
(5-18)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/NFTCards.tsx (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts (1)
ProjectMeta
(8-12)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (146)
apps/dashboard/src/app/(app)/api/lib/getAuthToken.ts (1)
32-51
: LGTM! Good API design improvement.The function signature change to accept a parameter object with optional
teamId
follows good practices and aligns well with the project-scoped functionality being introduced. The prioritization logic correctly handles explicitteamId
parameters while preserving the existing cookie-based fallback behavior.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.client.tsx (2)
5-5
: LGTM! Proper type import.The import of
ProjectMeta
type uses the correct relative path and follows TypeScript best practices.
14-14
: LGTM! Clean prop threading.The addition of the optional
projectMeta
prop and its pass-through to the child component is implemented correctly and follows the established pattern for project-scoped functionality.Also applies to: 28-28
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx (1)
45-46
: LGTM! Proper prop addition.The addition of
teamSlug
andprojectSlug
props toDeployedContractsPage
correctly uses the already available parameters and follows the established pattern for project-scoped functionality.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/opengraph-image.tsx (1)
24-28
: LGTM! Correct function signature update.The update to explicitly construct the parameter object with
chainIdOrSlug
andteamId: undefined
correctly matches the new function signature shown in the relevant code snippets. SettingteamId
toundefined
is appropriate for this route context which doesn't have project scope.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/components/nfts-owned.tsx (1)
11-11
: LGTM! Consistent project metadata integration.The addition of the optional
projectMeta
prop and its propagation toNFTCards
follows the established pattern for project-scoped routing support. The type safety is maintained with proper TypeScript annotations.Also applies to: 17-17, 30-30
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/ClaimConditions.client.tsx (1)
13-13
: LGTM! Proper project metadata propagation.The addition of the
projectMeta
prop and its forwarding toRedirectToContractOverview
enables project-scoped routing when claim conditions are unsupported. The conditional rendering logic correctly maintains the redirect behavior while adding project context.Also applies to: 32-37
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/AccountSigners.client.tsx (1)
12-12
: LGTM! Consistent project metadata integration.The
projectMeta
prop addition and its propagation toRedirectToContractOverview
maintains consistency with the broader architectural pattern. The conditional rendering logic correctly handles unsupported account permissions while preserving project context during redirects.Also applies to: 25-30
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/ContractSplitPage.client.tsx (2)
13-13
: LGTM! Consistent project metadata integration.The
projectMeta
prop addition and its propagation toRedirectToContractOverview
follows the established pattern. The conditional rendering correctly handles unsupported split contracts while maintaining project context.Also applies to: 26-31
34-39
:❌ Incorrect review comment
Consider passing projectMeta to ContractSplitPage if needed.
The
ContractSplitPage
component doesn't receive theprojectMeta
prop. If this component contains links or navigation that should be project-scoped, it may need the project context.Please verify if
ContractSplitPage
needs project context for any internal navigation or links:
🏁 Script executed:
#!/bin/bash # Description: Check if ContractSplitPage component uses any navigation or links that might benefit from project context # Search for navigation-related patterns in ContractSplitPage ast-grep --pattern 'export $_ ContractSplitPage($_) { $$$ }' # Also search for Link components or router usage rg -A 10 -B 5 "Link|router|href" apps/dashboard/src/app/\(app\)/\(dashboard\)/\(chain\)/\[chain_id\]/\[contractAddress\]/split/ContractSplitPage.tsx || echo "ContractSplitPage.tsx not found at expected location" # Search for any file with ContractSplitPage fd ContractSplitPage.tsxLength of output: 455
🏁 Script executed:
#!/bin/bash # Locate ContractSplitPage.tsx and inspect for navigation-related code FILE=$(fd ContractSplitPage.tsx | head -n1) echo "Inspecting file: $FILE" echo "- Checking for Link imports" rg -n "import.*Link" "$FILE" || echo "No Link imports found" echo "- Checking for next/link imports" rg -n "import.*next/link" "$FILE" || echo "No next/link imports found" echo "- Checking for href attributes" rg -n "href=" "$FILE" || echo "No href attributes found" echo "- Checking for router usage" rg -n "router\." "$FILE" || echo "No router usage found"Length of output: 1429
Ignore passing
projectMeta
to ContractSplitPage
No link, router or navigation logic exists inContractSplitPage.tsx
, so there’s currently no need for a project context prop.Likely an incorrect or invalid review comment.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/ContractEditModulesPage.client.tsx (2)
13-13
: Well-implemented prop addition.The optional
projectMeta
prop is properly typed and aligns with the component's dual usage in both project-scoped and legacy routing contexts.
26-31
: Correct implementation of project-aware redirect.The
projectMeta
prop is properly passed toRedirectToContractOverview
, enabling project-scoped URL generation when redirecting non-modular core contracts. The conditional logic flow remains intact while adding the necessary project context.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/ContractDirectListingsPage.client.tsx (2)
4-4
: Consistent implementation with project metadata support.The import and prop addition follow the same pattern as other components in this refactor, maintaining consistency across the codebase. The optional
projectMeta
typing is appropriate for dual-context usage.Also applies to: 13-13
26-31
: Proper project-aware redirect for unsupported direct listings.The redirect logic correctly passes
projectMeta
to enable project-scoped URL generation when direct listings are not supported. The conditional check usingisDirectListingSupported
is appropriate for this marketplace component.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/page.tsx (2)
1-1
: Excellent page simplification through shared component delegation.The refactoring to use
SharedContractSplitPage
effectively centralizes complex contract handling logic while simplifying the page component. This approach reduces code duplication and improves maintainability across the contract dashboard.Also applies to: 11-17
15-15
: Appropriate explicitprojectMeta
handling for legacy route.Setting
projectMeta: undefined
is correct for this legacy route context, clearly indicating that this page operates without project scope. This explicit handling helps maintain clarity between legacy and project-scoped routing paths.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/page.tsx (1)
1-1
: Consistent page simplification following established pattern.The refactoring matches the pattern established in other contract pages, delegating complex logic to
SharedContractAccountPermissionsPage
while maintaining appropriate parameter mapping and explicitprojectMeta: undefined
for the legacy route context.Also applies to: 10-18
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/ContractProposalsPage.client.tsx (3)
4-4
: LGTM: Import path is correct for ProjectMeta type.The relative import path correctly references the ProjectMeta type definition from the team/project contract types.
13-13
: LGTM: Optional projectMeta prop follows the established pattern.The addition of the optional
projectMeta
prop is consistent with the broader refactoring effort to support project-scoped routing throughout the dashboard.
26-31
: LGTM: Proper propagation of projectMeta to child component.The
projectMeta
prop is correctly passed to theRedirectToContractOverview
component, ensuring consistent project context for URL construction and navigation.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/BuildYourApp.tsx (3)
4-4
: LGTM: Import path is correct for ProjectMeta type.The relative import path correctly references the ProjectMeta type definition.
10-14
: LGTM: Clean implementation of project-scoped URL construction.The conditional logic properly constructs the
contractRootPath
whenprojectMeta
is available, enabling project-scoped URLs while maintaining backward compatibility.
26-26
: LGTM: Proper usage of contractRootPath in href construction.The
contractRootPath
is correctly prepended to the URL, enabling proper navigation within the team/project context when available.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx (3)
9-9
: LGTM: Import path is correct for ProjectMeta type.The relative import path correctly references the ProjectMeta type definition.
20-20
: LGTM: Clean addition of projectMeta prop.The
projectMeta
prop is properly added to the component interface and destructured, following the established pattern for project-scoped routing support.Also applies to: 35-35
50-50
: LGTM: Improved prop passing to PrimaryDashboardButton.The changes correctly:
- Add
projectMeta
prop for project context- Use
contract.client
instead of a separate client prop, which is cleaner and more consistentAlso applies to: 59-59
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/TokenIdPage.client.tsx (3)
4-4
: LGTM: Import path is correct for ProjectMeta type.The relative import path correctly references the ProjectMeta type definition from the team/project contract types.
15-15
: LGTM: Optional projectMeta prop follows the established pattern.The addition of the optional
projectMeta
prop is consistent with the broader refactoring effort to support project-scoped routing throughout the dashboard.
31-36
: LGTM: Proper propagation of projectMeta to child components.The
projectMeta
prop is correctly passed to both:
RedirectToContractOverview
for proper URL construction during redirectsTokenIdPage
for consistent project context throughout the component treeAlso applies to: 46-46
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/page.tsx (1)
1-19
: LGTM! Clean refactor to shared component pattern.The refactor successfully extracts complex contract fetching and validation logic to
SharedModulesPage
, making this page component much simpler and more maintainable. The parameter mapping fromchain_id
tochainIdOrSlug
is consistent with the shared component's interface.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx (3)
5-7
: Clean type import updates for project-scoped routing.The import changes correctly replace the
ThirdwebClient
dependency withProjectMeta
to support team/project-scoped navigation.
19-19
: Props updated to support project metadata.The prop change from
client: ThirdwebClient
toprojectMeta: ProjectMeta | undefined
aligns with the project-scoped routing refactor across the dashboard.
43-43
: Correct integration with sidebar link generation.Passing
projectMeta
togetContractPageSidebarLinks
ensures that sidebar navigation URLs are properly prefixed with team/project context when available.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/shared-events-page.tsx (1)
1-31
: Well-implemented shared component following established patterns.The
SharedEventsPage
component correctly implements the shared component pattern with proper error handling and parameter structure. It usesprojectMeta
parameter (consistent withSharedModulesPage
), handles the not-found case appropriately, and passes the necessary props toEventsFeed
.The component properly extracts
teamId
fromprojectMeta
when callinggetContractPageParamsInfo
, ensuring team-scoped contract resolution works correctly.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/proposals/page.tsx (1)
1-29
: LGTM! Clean implementation following the established pattern.This page component correctly implements the team/project-scoped contract proposals functionality by:
- Properly awaiting the params Promise (consistent with Next.js server components)
- Fetching team data and handling not found cases appropriately
- Constructing the projectMeta object with the correct team and project information
- Delegating rendering to the shared component
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.client.tsx (1)
5-5
: LGTM! Proper prop threading for project-scoped functionality.The changes correctly implement support for the optional
projectMeta
prop by:
- Adding the appropriate import for the
ProjectMeta
type- Including the prop in the component interface as optional
- Passing it through to both
RedirectToContractOverview
andAccountPage
componentsThis follows the consistent pattern established across other similar client components in the dashboard.
Also applies to: 15-15, 28-33, 42-42
apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx (1)
15-16
: LGTM! Clean prop threading for team/project context.The addition of
teamSlug
andprojectSlug
props is implemented correctly:
- Props are consistently added to both the main and async component interfaces
- They are properly passed through to the
ContractTable
component- No breaking changes introduced
This enables the component to work within the team/project-scoped routing structure.
Also applies to: 44-45, 63-64
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/page.tsx (1)
1-19
: LGTM! Clean refactoring following separation of concerns.This refactoring successfully delegates all contract-specific logic to the
SharedNFTPage
component, simplifying the page component to focus only on parameter extraction. The pattern of passingprojectMeta: undefined
is consistent with the dashboard routes not having project context yet, while the shared component can handle both scenarios.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx (2)
10-14
: LGTM! Proper addition of projectMeta prop.The
projectMeta
prop is correctly typed as optional and follows the established pattern for enabling project-scoped routing.
26-31
: LGTM! Correct prop forwarding for project-scoped redirects.The
RedirectToContractOverview
component now receives theprojectMeta
prop, enabling it to redirect to the appropriate project-scoped URL when applicable.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/page.tsx (1)
1-19
: LGTM! Consistent refactoring pattern.This change follows the same clean refactoring pattern as other contract pages, successfully delegating complex logic to the
SharedCodePage
component while maintaining proper parameter passing. TheprojectMeta: undefined
is appropriate for dashboard routes.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.client.tsx (2)
10-14
: LGTM! Consistent prop addition pattern.The
projectMeta
prop addition follows the established pattern and is properly typed as optional.
28-33
: LGTM! Complete prop forwarding for project-scoped functionality.Both the
RedirectToContractOverview
andContractNFTPage
components now correctly receive theprojectMeta
prop, enabling proper project-scoped routing and UI context throughout the NFT page flow.Also applies to: 36-44
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/contract-overview-page.client.tsx (1)
4-4
: LGTM! Clean implementation of project metadata propagation.The changes properly introduce the
ProjectMeta
prop with correct typing, optional handling, and clean prop threading through the component hierarchy.Also applies to: 12-12, 14-14, 30-30
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.tsx (1)
4-4
: LGTM! Consistent implementation pattern.The changes follow the same clean pattern as other components, properly integrating project metadata into the NFT page with correct typing and prop propagation.
Also applies to: 20-20, 28-28, 113-113
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.client.tsx (1)
4-4
: LGTM! Proper prop threading to child components.The implementation correctly passes the
projectMeta
to both the redirect and main page components, maintaining consistency with the overall refactoring pattern.Also applies to: 13-13, 26-31, 35-40
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/modules/page.tsx (1)
6-14
: LGTM! Proper async handling and error management.The implementation correctly handles the async params, fetches project data, and uses
notFound()
for missing resources, which is the appropriate 404 handling pattern for Next.js.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/shared-sources-page.tsx (1)
1-19
: Clean shared component implementation following established patterns.This shared server component correctly implements the pattern seen across the PR:
- Proper contract info fetching with error handling
- Clean separation between data fetching and rendering logic
- Consistent parameter structure with optional team context
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/events/page.tsx (1)
6-29
: Good implementation of project-scoped page pattern.The implementation correctly:
- Awaits the params Promise (consistent with Next.js behavior noted in learnings)
- Implements proper error handling for missing projects
- Follows the established pattern for passing projectMeta to shared components
- Maintains consistency with other project-scoped pages in the PR
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/page.tsx (1)
1-19
: Excellent refactoring to centralize logic in shared components.This simplification successfully:
- Delegates complex contract info fetching and validation to SharedAnalyticsPage
- Maintains the same page interface while reducing duplication
- Correctly passes undefined for projectMeta in non-project context
- Follows the consistent pattern established across other contract pages
This refactor improves maintainability by centralizing the complex analytics logic.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/direct-listings/page.tsx (1)
6-29
: Consistent implementation with clear variable naming.This project-scoped page correctly:
- Uses appropriate API call (
getTeamBySlug
) for fetching team data- Maintains clear variable naming (
team
for team data)- Implements consistent error handling and parameter passing patterns
- Properly awaits the params Promise as expected in Next.js
The implementation is consistent with the established pattern across other project-scoped pages in this PR.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/page.tsx (1)
1-20
: LGTM! Clean refactoring to shared component pattern.The simplification of this page by delegating logic to
SharedContractTokensPage
is a good architectural improvement. The async/await pattern for params is correct for Next.js server components, and passingundefined
forteamId
is appropriate for the non-team scoped route.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (2)
8-12
: LGTM! Parameter updates support team-scoped functionality.The renaming of
chain_id
tochainIdOrSlug
improves consistency, and the addition of the optionalteamId
parameter correctly supports the team-scoped contract functionality.
35-37
: LGTM! Correct usage of updated getUserThirdwebClient API.The function call correctly passes the
teamId
parameter in the expected object format, matching the updatedgetUserThirdwebClient
function signature.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/code/page.tsx (2)
12-14
: LGTM! Proper error handling for missing projects.The
notFound()
call correctly handles cases where the project doesn't exist or the user doesn't have access.
17-27
: LGTM! Correct projectMeta construction and prop passing.The
projectMeta
object is properly constructed with all required fields and correctly passed to theSharedCodePage
component, enabling team/project-scoped functionality.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.tsx (3)
6-6
: LGTM! Correct import of ProjectMeta type.The import path correctly references the ProjectMeta type definition from the team/project contract types.
16-16
: LGTM! Appropriate addition of projectMeta prop.The optional
projectMeta
prop addition enables team/project-scoped functionality while maintaining backward compatibility.
50-54
: LGTM! Correct prop forwarding to NftsOwned component.The
projectMeta
prop is properly passed to theNftsOwned
component, enabling project-scoped NFT functionality as shown in the relevant code snippets.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.tsx (2)
8-8
: LGTM: Clean import of ProjectMeta type.The import path correctly references the types file for the project-scoped contract pages.
16-16
: LGTM: Proper projectMeta prop integration.The implementation correctly:
- Adds optional projectMeta prop to the interface
- Constructs contractRootPath conditionally based on projectMeta presence
- Defaults to empty string when projectMeta is undefined
- Uses the path consistently in explorerHref construction
This follows the expected pattern for enabling project-scoped URLs.
Also applies to: 21-30
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account-permissions/page.tsx (1)
1-1
:✅ Verification successful
Inconsistent data fetching approach compared to similar pages.
This page uses
getTeamBySlug
to fetch team data, but the route structure suggests it should be fetching project-specific data. Compare with the NFTs page which usesgetProject(params.team_slug, params.project_slug)
for the same route pattern.Let me verify the correct API to use for project-scoped pages:
Also applies to: 10-10
🏁 Script executed:
#!/bin/bash # Check which API function is used in other similar project-scoped contract pages rg -A 5 "getTeamBySlug|getProject" apps/dashboard/src/app/\(app\)/team/\[team_slug\]/\[project_slug\]/contract/Length of output: 42668
No change needed for data fetching approach
The account-permissions page aligns with a group of contract subpages (split, tokens, sources, proposals, settings, account, accounts, english-auctions, direct-listings) that intentionally use
getTeamBySlug
. Pages that require project-scoped metadata (events, permissions, NFTs, modules, explorer, cross-chain, code, analytics, claim-conditions) usegetProject
. This split is by design, so no update is required here.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/page.tsx (1)
1-1
: LGTM: Clean architectural improvement.The simplification to delegate to
SharedExplorerPage
is a good architectural change that centralizes complex contract data fetching and conditional rendering logic. SettingprojectMeta: undefined
is appropriate for the non-project-scoped route.Also applies to: 11-17
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx (1)
68-69
: LGTM: Clean propagation of team/project contextThe changes correctly propagate
teamSlug
andprojectSlug
through the component hierarchy to enable team/project-scoped URLs in theContractTable
component. The implementation is clean and follows the established pattern.Also applies to: 97-98, 116-117
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/NFTDetails.tsx (1)
10-10
: LGTM: Correct implementation of conditional URL constructionThe changes properly implement team/project context support by:
- Adding optional
projectMeta
prop with correct typing- Conditionally constructing URLs with team/project prefix when context is available
- Maintaining backward compatibility by falling back to original behavior
- Correctly propagating the context to child components
Also applies to: 18-18, 26-26, 28-32, 68-68
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/[tokenId]/page.tsx (1)
1-34
: LGTM: Follows established pattern correctlyThe page component correctly implements the pattern of:
- Fetching project data using the API
- Handling missing projects with 404 responses
- Delegating rendering to shared components with enriched metadata
- Constructing proper
ProjectMeta
object for team/project contextapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/PermissionsTable.tsx (1)
22-22
: LGTM: Consistent implementation of project contextThe changes correctly follow the established pattern by:
- Adding optional
projectMeta
prop with proper typing- Conditionally constructing the base path for permissions URLs
- Maintaining backward compatibility when project context is not available
- Using the constructed path consistently in the component
The implementation is consistent with similar changes in other overview components.
Also applies to: 28-28, 30-32, 62-62
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/settings/page.tsx (1)
1-25
: LGTM! Clean implementation following the new pattern.The implementation correctly follows the bridge pattern for team/project scoped routing:
- Properly awaits params (following Next.js best practices)
- Fetches team data with appropriate error handling
- Delegates to shared component with correct projectMeta construction
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx (1)
1-29
: LGTM! Consistent implementation following the established pattern.This implementation is consistent with the settings page and correctly follows the bridge pattern for team/project scoped routing.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.tsx (1)
6-6
: LGTM! Clean addition of projectMeta support.The changes correctly add
projectMeta
prop support to enable team/project scoped routing. The implementation is minimal, well-typed, and follows the established pattern.Also applies to: 14-14, 20-20, 49-49
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/page.tsx (1)
6-10
: Good call on awaitingprops.params
This matches the quirky Next.js behaviour we learnt previously (params occasionally arrive as a
Promise
).
No action needed.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/page.tsx (1)
4-8
: Double-check whetherparams
really needs to be awaited on this routeUnlike the
team/...
routes, this file hasn’t introduced a custom segment that triggers the params-as-Promise quirk.
Awaiting an object that’s already synchronous is harmless, but it does hide potential type mismatches and can confuse future maintainers.Please verify with:
export default function Page({ params }: { params: { /* … */ } }) {If it compiles, prefer the synchronous version; otherwise keep the
await
and add a short comment explaining the rationale.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/cross-chain/page.tsx (1)
1-29
: LGTM! Clean implementation of the project-scoped contract page pattern.The implementation correctly follows the established pattern:
- Properly extracts and awaits route parameters
- Fetches project data with appropriate error handling via
notFound()
- Delegates rendering to the shared component with well-structured
projectMeta
- Maintains type safety with
ProjectContractPageParams
The long relative import path for
SharedCrossChainPage
is consistent with the established file structure, though it could benefit from path mapping in the future.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx (1)
53-54
: Good prop propagation for project-scoped routing.The addition of
teamSlug
andprojectSlug
props follows a clean pattern:
- Props are consistently extracted from the fetched team/project objects
- Proper threading through the component hierarchy to
FactoryContracts
- Maintains backward compatibility while enabling project-scoped URL construction
This aligns well with the broader refactor to support team/project context in contract-related pages.
Also applies to: 65-66, 105-106, 117-118, 151-152
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx (1)
1-19
: Excellent refactor to shared component pattern.The simplification effectively centralizes complex logic in
SharedAccountsPage
while maintaining the same functionality:
- Proper delegation to the shared component with correct parameter mapping
projectMeta: undefined
appropriately indicates this is a non-project-scoped route- Parameter rename from
chain_id
tochainIdOrSlug
improves consistency across the codebaseThe shared component handles all the previously embedded logic including contract fetching, account validation, and conditional rendering based on chain type and contract capabilities.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx (1)
1-19
: Consistent implementation of the shared component pattern.This refactor follows the same excellent pattern as the accounts page:
- Clean delegation to
SharedDirectListingsPage
with proper parameter mapping- Correct use of
projectMeta: undefined
for non-project-scoped routes- Consistent parameter naming with
chainIdOrSlug
The shared component encapsulates all the complex logic including account fetching, contract validation, marketplace capability checks, and conditional rendering that was previously embedded in this page.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-conditions/page.tsx (1)
6-29
: LGTM! Well-structured server component implementation.The page follows a clean pattern of parameter resolution, data fetching, error handling, and delegation to a shared component. The async/await handling and 404 error responses are implemented correctly.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/Analytics.tsx (1)
25-38
: LGTM! Clean implementation of project-scoped URL generation.The conditional
contractRootPath
logic correctly builds team/project-prefixed URLs whenprojectMeta
is available, enabling proper navigation within project contexts.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/page.tsx (1)
10-18
: LGTM! Excellent refactoring that centralizes logic.The simplified implementation that delegates contract data fetching and validation to
SharedEventsPage
is a good architectural decision. SettingprojectMeta: undefined
is correct for this non-project context.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/explorer/page.tsx (1)
6-29
: LGTM! Consistent implementation following established patterns.The page correctly implements the pattern established across other contract pages: parameter resolution, project data fetching, error handling, and delegation to shared components. The async/await handling is proper per Next.js server component requirements.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/page.tsx (2)
3-9
: Remove unnecessary Promise wrapper aroundparams
params
is synchronously injected by Next.js and is not aPromise
.
Typing it asPromise<…>
and awaiting it:
- introduces an avoidable
async
render path,- forces the whole component to be
async
,- makes the call-site contract inaccurate (Next.js will pass an object, not a promise).
A small refactor simplifies the file and removes the superfluous
await
.-export default async function Page(props: { - params: Promise<{ - contractAddress: string; - chain_id: string; - }>; -}) { - const params = await props.params; +export default function Page(props: { + params: { + contractAddress: string; + chain_id: string; + }; +}) { + const { params } = props;If you still need the function to be
async
for other reasons (e.g. headers, cookies) you can keepasync
while dropping thePromise
type.
[ suggest_essential_refactor ]
14-16
: Consider normalising thechain_id
keyInternally you map
chain_id → chainIdOrSlug
.
If possible, expose the canonical name (chainIdOrSlug
) at the route level to avoid this translation step and reduce chances of a typo drifting between files.
If changing the route segment is not feasible, at least add a comment here explaining the mismatch for future readers.
[ suggest_nitpick ]apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/page.tsx (2)
3-9
: Sameparams
Promise issue as aboveThe
NFT
token page repeats the Promise pattern.
Please apply the same refactor as suggested for the overview page to keep the codebase consistent and accurate.
[ duplicate_comment ]
14-18
: Guard against missingprojectMeta
to avoid prop churnYou explicitly pass
projectMeta: undefined
.
Because the property is already optional in the shared component, omitting it entirely keeps the call-site cleaner and prevents ESLint/TS from propagating “possibly undefined” checks downstream.- tokenId: params.tokenId, - projectMeta: undefined, + tokenId: params.tokenId,[ suggest_nitpick ]
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/NFTCards.tsx (4)
6-6
: Brittle deep-relative import forProjectMeta
The import path climbs six directories and reaches into a route-specific folder:
import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types";This is highly fragile:
- a single folder rename will break every consumer,
- it creates an accidental dependency on a page-layer file from a shared component, risking circular builds.
Move
ProjectMeta
to a centraltypes
(e.g.@/types/project
) and reference it via a path alias to improve stability.-import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/types/project";[ suggest_essential_refactor ]
33-34
: Prop should be optionalThe prop is declared as
projectMeta: ProjectMeta | undefined;
but not marked optional (?
).
Marking it optional improves DX and matches usage patterns.-interface NFTCardsProps { +interface NFTCardsProps { ... - projectMeta: ProjectMeta | undefined; + projectMeta?: ProjectMeta; }[ suggest_nitpick ]
49-52
: Avoid manual string concatenation for routesBuilding URLs with template literals is error-prone and duplicates knowledge of routing rules.
Consider a helper:import { buildContractPath } from "@/lib/paths"; ... const href = buildContractPath({ projectMeta, chainId: token.chainId, contractAddress: token.contractAddress, slug: `nfts/${tokenId}`, });Centralising route logic prevents drift when path patterns evolve (e.g., moving from
/team
to/t
).
[ suggest_optional_refactor ]
95-98
: Missing leading slash whenprojectMeta
is defined
contractRootPath
already starts with a/
.
WhenprojectMeta
is not defined, the final URL correctly starts with/
.
WhenprojectMeta
is defined, the concatenation yields
/team/.../contract/<chain>/<address>/nfts/<id>
— ✅
Just sanity-checked: there is no double slash, so nothing breaks here.
[ approve_code_changes ]apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/accounts/page.tsx (1)
1-29
: LGTM! Clean implementation following established patterns.This page component follows the established pattern for team/project-scoped contract pages:
- Proper async/await usage with Next.js App Router
- Appropriate error handling with
notFound()
for missing teams- Clean delegation to shared component logic
- Correctly constructed
projectMeta
object matching theProjectMeta
typeThe implementation is consistent with other similar pages in the codebase.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/LatestEvents.tsx (2)
31-43
: LGTM! Clean conditional URL construction.The implementation correctly:
- Maintains backward compatibility with
undefined
projectMeta- Constructs project-scoped URLs when projectMeta is available
- Uses the constructed path to build the events link
This follows the established pattern for project-aware routing.
25-25
:✅ Verification successful
Verify import path consistency.
The import uses a relative path with many directory traversals. Consider whether this could be simplified with a path alias or if it matches the pattern used in other similar imports across the codebase.
🏁 Script executed:
#!/bin/bash # Check if there's a consistent pattern for ProjectMeta imports across the codebase rg -A 2 -B 2 "import.*ProjectMeta" --type tsx --type tsLength of output: 85
To verify consistency of
ProjectMeta
imports and check for any path aliases:
🏁 Script executed:
#!/bin/bash # 1. Find all imports of ProjectMeta in .ts/.tsx files rg "import.*ProjectMeta" --glob "*.ts" --glob "*.tsx" -nLength of output: 14250
🏁 Script executed:
#!/bin/bash # 2. Inspect tsconfig.json for configured path aliases grep -R '"paths"' -n tsconfig.json && sed -n '/"paths"\s*:/,/\]/p' tsconfig.jsonLength of output: 83
Import path consistency confirmed
All
ProjectMeta
imports in the dashboard use the same deep-relative path pattern and there’s no path alias configuration in the repo (notsconfig.json
definingpaths
was found). This matches other components—no changes needed.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/ContractChecklist.tsx (3)
24-59
: LGTM! Comprehensive URL construction with proper dependencies.The implementation correctly:
- Adds projectMeta to component props interface
- Constructs conditional URL paths for all navigation links
- Maintains backward compatibility when projectMeta is undefined
- Uses the constructed paths consistently throughout the component
The approach is thorough and follows the established pattern.
347-367
: Excellent dependency management in useMemo.Good practice including all the href variables in the useMemo dependency array. This ensures the steps are recalculated when the URL paths change based on project context.
15-15
:✅ Verification successful
Verify import path consistency.
Similar to the previous file, this uses a deeply nested relative import path. Ensure this pattern is consistent across the codebase.
🏁 Script executed:
#!/bin/bash # Check for consistent ProjectMeta import patterns rg "import.*ProjectMeta.*from.*team.*project_slug.*types" --type tsx --type tsLength of output: 108
🏁 Script executed:
#!/bin/bash # Search for all ProjectMeta imports across TS and TSX files without type filters rg "import.*ProjectMeta.*from" -g "*.ts" -g "*.tsx"Length of output: 14117
Import path consistency verified.
The
ProjectMeta
import uses the appropriate number of../
across all files relative to their directory depth, matching the pattern in other components. No changes needed.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx (1)
1-54
: LGTM! Well-structured shared component with excellent async patterns.This implementation demonstrates several best practices:
- Efficient data fetching: Uses
Promise.all
to concurrently fetch contract info and auth token- Proper error handling: Returns
notFound()
when contract info is missing- Clean separation of concerns: Delegates to appropriate components based on chain type
- Type safety: Properly typed parameters including optional
projectMeta
- Consistent patterns: Follows the established pattern for shared contract page components
The component successfully centralizes the async logic while maintaining flexibility for different rendering contexts.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (3)
6-6
: LGTM: Proper type import for ProjectMetaThe import correctly references the ProjectMeta type from the team/project types file.
10-11
: LGTM: Interface updated to include projectMetaThe addition of the optional
projectMeta
prop with correct typing aligns with the broader refactor pattern across the dashboard.
22-30
: LGTM: Conditional URL construction logic is correctThe conditional logic properly handles both scenarios:
- Without projectMeta: uses legacy URL format
/{chainId}/{contractAddress}
- With projectMeta: uses project-scoped format
/team/{teamSlug}/{projectSlug}/contract/{chainId}/{contractAddress}
The destructuring of
teamSlug
andprojectSlug
is safe since the conditional check ensuresprojectMeta
is defined.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/page.tsx (2)
1-1
: LGTM: Proper delegation to shared componentThe import of
SharedPermissionsPage
follows the established pattern for this refactor.
11-17
: LGTM: Clean parameter mapping and delegationThe page component is correctly simplified to delegate all logic to
SharedPermissionsPage
. Key improvements:
- Parameter mapping:
chain_id
→chainIdOrSlug
aligns with the shared component's interface- Explicit projectMeta: Setting to
undefined
clearly indicates this is a non-project route- Logic delegation: Complex contract fetching, validation, and conditional rendering is now handled by the shared component
This pattern improves maintainability and consistency across the codebase.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/token-id.tsx (5)
31-31
: LGTM: Correct type importThe import properly references the ProjectMeta type from the team/project types file.
57-57
: LGTM: Interface updated with projectMetaThe addition of the optional
projectMeta
prop maintains backward compatibility while enabling project-scoped functionality.
68-68
: LGTM: Component parameter updatedThe component correctly accepts the new
projectMeta
parameter for use in path construction.
74-76
: LGTM: Conditional path constructionThe
contractRootPath
logic correctly handles both scenarios:
- With projectMeta: constructs
/team/{teamSlug}/{projectSlug}/contract
prefix- Without projectMeta: uses empty string (maintains existing behavior)
This pattern aligns with the broader refactor across the dashboard.
139-144
: LGTM: Breadcrumb navigation updated consistentlyThe breadcrumb link correctly uses the
contractRootPath
for both thehref
and therouter.push
call, ensuring consistent navigation behavior in project-scoped and legacy contexts.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/page.tsx (2)
1-1
: LGTM: Consistent delegation patternThe import of
SharedContractAccountPage
follows the established refactor pattern across the dashboard.
11-17
: LGTM: Effective simplification with proper delegationThe page component successfully delegates all complex logic to
SharedContractAccountPage
. This refactor provides several benefits:
- Consistency: Follows the same pattern as other contract pages (permissions, direct-listings, etc.)
- Maintainability: Complex logic is centralized in the shared component
- Clear intent: Explicit
projectMeta: undefined
indicates non-project context- Parameter mapping:
chain_id
→chainIdOrSlug
aligns with shared component interfaceThe previous complex logic for contract info fetching, localhost handling, and conditional rendering is now properly encapsulated in the shared component.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx (2)
17-25
: Good use of parallel data fetching.The parallel fetching of contract info and account data using
Promise.all
is an efficient approach that reduces the overall loading time.
45-51
: Proper validation and redirect handling.The ERC standard validation and redirect to the contract landing page for unsupported contracts follows good defensive programming practices.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageSidebarLinks.ts (1)
15-17
: Clean implementation of project-scoped URL construction.The conditional
layoutPrefix
construction properly handles both project-scoped and legacy URL patterns, maintaining backward compatibility while enabling the new functionality.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx (1)
11-17
: Excellent refactoring to shared component pattern.The simplification of this page component by delegating to
SharedEnglishAuctionsPage
reduces code duplication and centralizes the contract page logic. The parameter mapping and explicitprojectMeta: undefined
are appropriate for this non-project-scoped route.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx (2)
53-55
: Consistent implementation of project-scoped URL construction.The
contractRootPath
construction follows the same pattern established in the sidebar links utility, ensuring consistent URL handling across the dashboard.
67-67
: Proper integration of project-scoped path in code snippets link.The code snippets button correctly uses the constructed
contractRootPath
to maintain URL consistency within project contexts.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/data-table.tsx (4)
61-61
: LGTM: Correct import of ProjectMeta type.The import path correctly references the ProjectMeta type definition from the team/project contract types.
95-95
: LGTM: Proper prop interface integration.The
projectMeta
prop is correctly added as optional to both the function signature and props interface, maintaining backward compatibility.Also applies to: 105-105
246-250
: LGTM: Correct conditional URL construction for network links.The URL construction properly handles both project-scoped and non-project-scoped routing by conditionally prefixing with team and project slugs when
projectMeta
is available.
417-421
: LGTM: Consistent URL construction for deploy status modal.The view contract link construction follows the same conditional pattern as the network links, ensuring consistent navigation behavior throughout the component.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/ContractOverviewPage.tsx (3)
2-2
: LGTM: Correct import of ProjectMeta type.The import correctly references the ProjectMeta type definition for use in the component props.
24-24
: LGTM: Proper prop interface and component integration.The
projectMeta
prop is correctly added as optional to the interface and component props, maintaining consistency with other components in the refactor.Also applies to: 41-41
53-53
: LGTM: Consistent prop propagation to child components.All relevant child components (
ContractChecklist
,ContractAnalyticsOverviewCard
,MarketplaceDetails
,NFTDetails
,LatestEvents
,PermissionsTable
, andBuildYourApp
) properly receive theprojectMeta
prop, enabling project-scoped behavior throughout the component tree.Also applies to: 62-62, 69-69, 83-83, 93-93, 101-101, 109-109
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/table.tsx (2)
44-44
: LGTM: Correct import of ProjectMeta type.The import correctly references the ProjectMeta type definition with proper relative path resolution.
50-50
: LGTM: Proper prop interface integration.The
projectMeta
prop is correctly added as optional to both the interface and component props.Also applies to: 56-56
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/shared-code-page.tsx (5)
1-7
: LGTM: Proper imports and dependencies.All necessary imports are correctly included, including the ProjectMeta type, utility functions, and components needed for the server component.
8-14
: LGTM: Well-structured component interface.The props interface is properly typed with clear parameter structure including the optional
projectMeta
for team/project context.
16-24
: LGTM: Proper data fetching and error handling.The component correctly calls
getContractPageParamsInfo
with the teamId from projectMeta and properly handles the 404 case when no contract information is found.
29-36
: LGTM: Appropriate conditional rendering for localhost chains.The component correctly handles localhost chains by rendering the client-side component, which is necessary for chains that may not have server-side contract resolution capabilities.
38-46
: LGTM: Robust ABI resolution with error handling.The ABI resolution includes proper error handling with
.catch(() => undefined)
, ensuring the component doesn't crash if ABI resolution fails, and gracefully passes undefined to the server component.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/shared-explorer-page.tsx (1)
9-53
: Well-structured shared component with good performance patterns.This component effectively centralizes the explorer page logic with several good practices:
- Parallel data fetching using
Promise.all
for optimal performance- Graceful error handling for ABI resolution failures
- Clean conditional rendering based on chain type
- Proper 404 handling for missing contract information
The architecture promotes code reuse while maintaining type safety with the optional
ProjectMeta
parameter.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx (1)
10-56
: Excellent implementation with robust fee configuration handling.The component demonstrates several best practices:
- Efficient parallel data fetching with
Promise.all
- Robust platform fee checking with proper error handling (lines 42-46)
- Correct case-insensitive address comparison for fee recipient validation
- Consistent error handling pattern with
notFound()
for missing contract infoThe fee configuration logic gracefully handles contracts that don't support platform fees by catching exceptions and defaulting to
true
.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx (1)
9-54
: Consistent implementation following established patterns.This component maintains the architectural consistency seen across other shared pages:
- Efficient parallel data fetching for account and contract information
- Proper feature validation (direct listing support) before rendering
- Correct error handling with
notFound()
for unsupported features- Clean separation between localhost and production chain handling
The
projectMeta
propagation to client components enables proper project-scoped routing.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx (1)
29-53
: Clean feature validation and rendering logic.The remaining implementation is excellent:
- Proper feature support validation for English auctions
- Consistent error handling with
notFound()
for unsupported features- Correct prop propagation including
projectMeta
for project-scoped routing- Clean separation between client and server rendering paths
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx (3)
1-15
: LGTM! Clean component structure and imports.The component follows the consistent pattern established for shared contract components, with proper imports and TypeScript typing.
16-28
: Correct contract info fetching and error handling.The component properly fetches contract information using the team context and handles the 404 case appropriately.
29-37
: Localhost rendering implemented correctly.The client component receives all necessary props including projectMeta for proper navigation handling.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx (1)
1-27
: Well-structured shared component following established pattern.The component correctly implements the contract info fetching, error handling, and conditional rendering logic consistent with other shared contract components.
Also applies to: 30-45
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx (2)
29-34
: Excellent use of concurrent fetching for performance.The Promise.all implementation with conditional metadata fetching for non-localhost chains is a good performance optimization.
50-56
: Good consistency in projectMeta prop passing.Unlike some other shared components, this correctly passes
projectMeta
to both client and server components for consistent behavior.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page.tsx (1)
1-59
: Excellent implementation following best practices.This shared component demonstrates the most consistent implementation of the established pattern:
- Proper variable naming (
account
instead of variations)- Consistent
projectMeta
passing to both client and server components- Includes
chainMetadata
where needed- Clean error handling and conditional rendering
This serves as a good reference for the other shared components.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx (1)
1-50
: LGTM! Well-structured shared component with proper error handling.This shared component follows an excellent pattern by centralizing contract token page logic with proper error handling and conditional rendering. The implementation correctly:
- Fetches contract information with appropriate error handling
- Separates localhost and remote chain rendering paths
- Uses ERC20 feature detection via function selectors
- Passes the correct props to child components
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx (1)
37-44
: Good feature validation with appropriate error handling.The component properly validates that the contract supports account permissions before rendering, and returns a 404 if not supported. This provides a better user experience than showing an error page.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/page.tsx (1)
11-17
: Clean refactor that delegates logic to shared component.This simplification effectively moves complex cross-chain logic into the shared component while maintaining the same functionality. Setting
projectMeta: undefined
is appropriate for non-project-scoped routes.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx (1)
42-50
: Good feature validation with proper redirect handling.The component correctly validates modular core support and redirects to the contract landing page when not supported, properly passing through the project metadata for consistent navigation.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/layout.tsx (2)
28-30
: Missingaccount
null-check before render
getValidAccount
might returnundefined
, yetaccount
is passed to
<TeamHeaderLoggedIn>
which expects a valid object.
Add a guard to avoid runtime crashes:if (!account) { redirect("/login"); }
16-22
:⚠️ Potential issue
params
should not be declared as aPromise
Next.js injects
params
synchronously (Record<string,string>
).
Typing it asPromise<...>
forces you toawait
something that is not a thenable,
silently widening the type and hiding real compiler errors.-export default async function ContractLayout(props: { - children: React.ReactNode; - params: Promise<ProjectContractPageParams>; -}) { - const params = await props.params; +export default async function ContractLayout(props: { + children: React.ReactNode; + params: ProjectContractPageParams; +}) { + const params = props.params;⛔ Skipped due to learnings
Learnt from: jnsdls PR: thirdweb-dev/js#6929 File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19 Timestamp: 2025-05-21T05:17:31.283Z Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx (1)
131-159
: 🛠️ Refactor suggestionParallelise inner
getProjects
calls to avoid N×M latency
Promise.all
already gathers the outer promises concurrently, but each async mapper awaitsgetProjects
inside the callback, forcing thegetProjects
calls to execute sequentially (one per team).
You can shave seconds off the dashboard load time for users that belong to many teams by starting all project-fetch requests at once:- const teamsAndProjects: MinimalTeamsAndProjects = await Promise.all( - teams.map(async (team) => ({ - team: { - id: team.id, - name: team.name, - slug: team.slug, - image: team.image, - }, - projects: (await getProjects(team.slug)).map((x) => ({ - id: x.id, - name: x.name, - image: x.image, - })), - })), - ); + const teamsAndProjects: MinimalTeamsAndProjects = await Promise.all( + teams.map(async (team) => { + const projects = await getProjects(team.slug); // kick off in parallel + return { + team: { + id: team.id, + name: team.name, + slug: team.slug, + image: team.image, + }, + projects: projects.map((p) => ({ + id: p.id, + name: p.name, + image: p.image, + })), + }; + }), + );(The key change is removing the immediate
await
insidemap
.)
For large organisations this reduces total wait time to the slowest single request instead of the sum of all requests.Likely an incorrect or invalid review comment.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx (1)
28-34
: Confirm props signature aligns with Next.js routing
projectMeta
is injected intoparams
, butparams
normally only contains
path segments provided by the framework.
Ensure every page that calls<SharedCrossChainPage>
manually passes
projectMeta
inside theparams
object; otherwise this will always beundefined
,
breaking team/project scoping.If this was meant to be a separate prop, consider:
export async function SharedCrossChainPage({ params, projectMeta, }: { params: { contractAddress: string; chainIdOrSlug: string }; projectMeta?: ProjectMeta; }) { … }
...pp/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/ContractSplitPage.client.tsx
Show resolved
Hide resolved
...eam/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/analytics/page.tsx
Outdated
Show resolved
Hide resolved
...eam/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/analytics/page.tsx
Outdated
Show resolved
Hide resolved
...pp)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx
Outdated
Show resolved
Hide resolved
...m/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/permissions/page.tsx
Outdated
Show resolved
Hide resolved
.../(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/layout.tsx
Show resolved
Hide resolved
.../(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/layout.tsx
Show resolved
Hide resolved
...oard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx
Outdated
Show resolved
Hide resolved
...oard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx
Outdated
Show resolved
Hide resolved
...pp)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx
Show resolved
Hide resolved
1f6e73a
to
fbfe157
Compare
|
fbfe157
to
abf343e
Compare
abf343e
to
139648c
Compare
dc995cc
to
3f5b1f2
Compare
3f5b1f2
to
5f65eea
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 14
🔭 Outside diff range comments (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/events-feed.tsx (1)
89-105
:⚠️ Potential issue“All” option never triggers navigation – broaden the guard
When the user switches back to “All”,
eventTypes.includes("all")
isfalse
, therefore the router does not update the URL and the state stays stale.- if (eventTypes.includes(val)) { + if (val === "all" || eventTypes.includes(val)) {This restores the old behaviour and keeps the UI/URL in sync.
@@ - if (eventTypes.includes(val)) { + if (val === "all" || eventTypes.includes(val)) { const path = buildContractPagePath({ projectMeta, chainIdOrSlug: chainSlug.toString(), contractAddress: contract.address, subpath: e.target.value === "all" ? "/events" : `/events?event=${val}`, }); router.push(path); setSelectedEvent(val); }apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx (1)
22-27
: 🛠️ Refactor suggestion
params
is not a Promise – drop theawait
and fix the typeNext.js supplies
params
synchronously. Typing it asPromise<…>
and awaiting works at runtime (sinceawait
on a non-promise is a no-op) but misleads type-checking and future maintainers.-export default async function Page(props: { - params: Promise<{ team_slug: string; project_slug: string }>; -}) { - const params = await props.params; +export default async function Page(props: { + params: { team_slug: string; project_slug: string }; +}) { + const { params } = props;This also eliminates an unnecessary micro-task hop.
After applying, no other lines need changes becauseparams
is still an in-scope constant.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx (1)
15-18
:⚠️ Potential issue
params
should not be typed asPromise
next/router
passesparams
synchronously. Declaring it asPromise<…>
forces an unnecessaryawait
, hides type-checking errors, and allows accidental misuse elsewhere.-export default async function Page(props: { - params: Promise<{ team_slug: string; project_slug: string }>; -}) { - const params = await props.params; +export default async function Page(props: { + params: { team_slug: string; project_slug: string }; +}) { + const { params } = props;After the change, drop
await
whereverprops.params
was previously awaited.
♻️ Duplicate comments (23)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/ContractSplitPage.client.tsx (1)
4-4
: Deep relative import path issue (duplicate concern)This is a duplicate of the previously flagged maintainability concern about deep relative import paths for the
ProjectMeta
type.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/ContractEditModulesPage.client.tsx (1)
4-4
: Deep relative import path issue (duplicate concern)This is a duplicate of the previously flagged maintainability concern about deep relative import paths for the
ProjectMeta
type.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/components/nfts-owned.tsx (1)
5-5
: Even deeper relative import path creates maintainability risksThis file uses an even deeper relative import path (7 levels up) for the
ProjectMeta
type, which is worse than the previously flagged 6-level imports. This creates significant maintainability overhead and tight coupling.Consider centralizing this type import:
-import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/types/project-meta";apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.client.tsx (1)
5-5
: Deep relative import path issue (duplicate concern)This is a duplicate of the previously flagged maintainability concern about deep relative import paths for the
ProjectMeta
type.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/MarketplaceDetails.tsx (1)
136-141
: Same remark as above – centralise base path creationRepeating the call here invites drift. See previous comment.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/page.tsx (1)
5-7
: Align with Next JS page prop conventionsSame as in
modules/page.tsx
,props.params
should be a plain object, not a promise. This type misuse leaks into every consumer ofPublicContractPageParams
.[same reasoning → please fix across the board]
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/page.tsx (1)
6-8
: Incorrect param typing (promise vs value) repeats hereFollow the fix recommended in
modules/page.tsx
to keep consistency with Next JS expectations.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/page.tsx (1)
4-8
: Same signature mismatch as in Explorer pageSee the comment in
explorer/page.tsx
: theparams
prop should not be typed asPromise<>
. Apply the same fix here for consistency and to remove the superfluousawait
.
(Leaving a danglingawait
will compile, but add an unnecessary micro-tick to every request.)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/page.tsx (1)
5-9
: Drop thePromise
wrapper forparams
here as wellReplicate the fix suggested for the Explorer & Events pages to keep the typing consistent and avoid the unnecessary
await
.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/page.tsx (2)
5-8
: SamePromise
misuse forparams
as in settings pageThe issue described in the previous file recurs here. Adopt the same correction pattern to keep typings accurate and avoid redundant
await
s.
10-14
: Drop unnecessaryprojectMeta={undefined}
propSee previous justification; omit the prop for cleaner JSX.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/page.tsx (2)
5-8
: Incorrect asynchronous typing ofparams
Replicates the
Promise
-typing problem outlined earlier; adjust the signature andawait
usage accordingly.
10-14
: Remove explicitundefined
for optionalprojectMeta
Consistent with prior pages, drop the prop for brevity.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/accounts/page.tsx (1)
25-25
: Consider making the login status dynamic (same issue as claim-conditions page).Similar to the claim-conditions page, the
isLoggedIn
prop is hardcoded totrue
. Consider fetching the actual authentication state for consistency.This is the same issue identified in the claim-conditions page. Consider applying a similar fix to make the authentication status dynamic rather than hardcoded.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx (1)
47-50
: Fix projectMeta inconsistency between client and server components.The server component
ContractSplitPage
doesn't receive theprojectMeta
prop while the client component does. This creates inconsistent behavior between localhost and non-localhost environments.Apply this diff to maintain consistency:
return ( <ContractSplitPage contract={clientContract} isLoggedIn={props.isLoggedIn} + projectMeta={props.projectMeta} /> );
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx (1)
48-52
: 🛠️ Refactor suggestionConsider passing projectMeta to server component for consistency.
Similar to other shared components, the server component doesn't receive
projectMeta
while the client version does, which could lead to inconsistent navigation behavior.Consider adding projectMeta to maintain consistency:
return ( <ContractEditModulesPage contract={clientContract} isLoggedIn={props.isLoggedIn} + projectMeta={props.projectMeta} /> );
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx (1)
46-51
: Server component missing projectMeta prop for consistency.The server component
ContractProposalsPage
doesn't receive theprojectMeta
prop, while the client version does. This could lead to inconsistent navigation behavior between localhost and production environments.Consider updating to include projectMeta:
return ( <ContractProposalsPage contract={clientContract} isLoggedIn={props.isLoggedIn} + projectMeta={props.projectMeta} /> );
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx (1)
37-56
: Guard againstsupportedERCs
being undefinedThe previous review already highlighted this; the crash pathway is still present:
isERC20={supportedERCs.isERC20}
getContractPageMetadata
can returnsupportedERCs === undefined
on failure -> runtimeTypeError
.
Add a nullish check or default fallback before property access.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/layout.tsx (3)
4-4
: Duplicate issue: Avoid invoking code from.client
modules inside a Server ComponentThis import violates React Server Component rules as previously identified. The
getClientThirdwebClient
function is imported from a.client
module which should not be used directly in server components.
40-50
: Duplicate issue: N + 1 fetch pattern – fetch only the current team's projectsThis code fetches projects for every team but only uses projects from the matching team, creating unnecessary database load and latency as previously identified.
56-60
:⚠️ Potential issueCritical RSC violation will cause build failure
Using
getClientThirdwebClient
from a.client
module inside this server component will cause a build-time error. This violates React Server Component architecture.Move the client creation to a server-safe location or wrap this in a client component:
- import { getClientThirdwebClient } from "@/constants/thirdweb-client.client"; + import { getClientThirdwebClient } from "@/constants/thirdweb-client.server";apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx (1)
32-41
: Duplicate issue: Over-restrictive token-ID validation blocks legitimate NFTsThe
isOnlyNumbers
function only accepts decimal-numeric IDs, which will block valid hex or string token IDs used by many ERC-721/ERC-1155 contracts as previously identified.Also applies to: 78-80
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx (1)
227-232
: Duplicate issue: Off-by-one bug causes modules list to be dropped when it is the first argThe
findIndex
returns0
when the matching parameter is first, but the ternary treats0
as falsy, incorrectly settingmodules
toundefined
as previously identified.
🧹 Nitpick comments (48)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.client.tsx (1)
5-5
: Consider optimizing the import path.The deep relative import path with many "../" segments could be brittle and hard to maintain if the file structure changes.
Consider using a path alias or barrel export to simplify the import:
-import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/types/contract"; // or similar aliasapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/ContractProposalsPage.client.tsx (1)
4-4
: Consider optimizing the import path.Same issue as in other files - the deep relative import path could be brittle. Consider using a path alias for better maintainability.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/ClaimConditions.client.tsx (1)
4-4
: Consider optimizing the import path.The deep relative import path follows the same pattern as other files in this PR. Consider establishing a consistent import alias strategy across the project for better maintainability.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/PermissionsTable.tsx (1)
31-37
: Consider memoisingpermissionsHref
to avoid redundant recomputations
buildContractPagePath
is executed on every render even though its inputs rarely change. Wrapping it inuseMemo
prevents unnecessary string building and keeps the dependency graph explicit.- const permissionsHref = buildContractPagePath({ - projectMeta: props.projectMeta, - chainIdOrSlug: props.chainSlug, - contractAddress: props.contract.address, - subpath: "/permissions", - }); + const permissionsHref = useMemo( + () => + buildContractPagePath({ + projectMeta: props.projectMeta, + chainIdOrSlug: props.chainSlug, + contractAddress: props.contract.address, + subpath: "/permissions", + }), + [props.projectMeta, props.chainSlug, props.contract.address], + );(The file already imports
useMemo
, so no additional imports are needed.)
Impact is minor, hence purely a micro-optimisation.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx (1)
55-61
: Lazy-computecodePagePath
to avoid unnecessary work
codePagePath
is computed even in branches where it will never be used (e.g., when the component immediately returnsnull
). Wrapping the calculation inuseMemo
defers the work until needed and makes dependencies explicit.- const codePagePath = buildContractPagePath({ - projectMeta, - chainIdOrSlug: contractInfo.chainSlug, - contractAddress: contractAddress, - subpath: "/code", - }); + const codePagePath = useMemo( + () => + buildContractPagePath({ + projectMeta, + chainIdOrSlug: contractInfo.chainSlug, + contractAddress: contractAddress, + subpath: "/code", + }), + [projectMeta, contractInfo.chainSlug, contractAddress], + );Remember to import
useMemo
at the top of the file:-import { useState } from "react"; +import { useState, useMemo } from "react";apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/events-feed.tsx (1)
36-38
: Extremely long relative import path – consider an alias to improve maintainability
../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types
is very fragile.
A single folder move will break many files that copy-paste this path. Adding a TS path alias (e.g.@contract/types
) keeps the import stable and the codebase readable.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/MarketplaceDetails.tsx (3)
55-61
: Duplicated path-building logic – extract to a helper
DirectListingCards
andEnglishAuctionCards
build their section root with an identicalbuildContractPagePath
invocation.
Creatingconst contractBase = buildContractPagePath({ … })
once in the parent (or a custom hook) avoids duplication and guarantees both sections stay in sync when the path rules evolve.
307-318
: Trailing slash ambiguity in derived URLs
const contractLayout = buildContractPagePath({ … })
is later concatenated with"/direct-listings"
and"/english-auctions"
.
If the util ever returns a path with a trailing slash, the final URL will contain a double slash. Safeguard by usingjoin
semantics orcontractLayout.replace(/\/$/, "")
.
312-312
: Mutating prop argumentlistings
violates React best practices
listings = isPending ? … : listings.slice(0,3)
reassigns the prop variable.
Prefer a new local:const visibleListings = isPending ? Array.from({ length: 3 }).map((_, idx) => dummyMetadata(idx)) : listings.slice(0, 3);This avoids accidental side-effects if the array reference is used elsewhere.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/ContractDirectListingsPage.client.tsx (3)
4-5
: Alias or barrel export recommended for sharedProjectMeta
typeThe deeply nested relative path is hard to maintain. Exposing
ProjectMeta
from a central barrel (e.g.@types/project
) keeps import statements short and robust.
13-14
: Props interface should be declared once for clarityInline object types scale poorly as the prop list grows. Declare an interface:
interface ContractDirectListingsPageClientProps { contract: ThirdwebContract; isLoggedIn: boolean; projectMeta?: ProjectMeta; }and use it in both the function and elsewhere to stay DRY.
27-31
: ForwardingprojectMeta
is good – consider also forwardingisLoggedIn
for consistency
RedirectToContractOverview
might eventually need login state to decide between public/project scopes. Passing it now future-proofs the call.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/AccountSigners.client.tsx (1)
4-4
: Prefer path alias over deep relative importThe 6-level relative path is fragile and hurts readability. Consider introducing a TS/webpack alias such as
@/app/team/.../types
(or re-exportProjectMeta
from a central barrel) to shorten the import and make future moves/renames safer.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/BuildYourApp.tsx (1)
4-6
: Same alias remark appliesDeep relative imports for both
ProjectMeta
andbuildContractPagePath
could be replaced with an alias to improve maintainability.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/page.tsx (1)
14-16
: Double-checkprojectMeta={undefined}
If the shared page expects
ProjectMeta | undefined
, this is fine. Otherwise, passprojectMeta={null}
or omit the prop to avoid unnecessary explicitundefined
.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/page.tsx (2)
2-3
: Avoid importing types and values from different directory levels in the same block
PublicContractPageParams
lives next totypes.ts
, whereasSharedModulesPage
is under the localmodules
sub-folder. Importing them in a single group blurs the distinction between external/public types and local implementation files.-import type { PublicContractPageParams } from "../types"; -import { SharedModulesPage } from "./shared-modules-page"; +import type { PublicContractPageParams } from "../types"; // public contract route types + +// local module implementation +import { SharedModulesPage } from "./shared-modules-page";[nitpick]
10-15
: Pass optional props as truly optionalIf
projectMeta
is declared optional inSharedModulesPageProps
, sendingundefined
is redundant; omitting the prop tightens the contract and avoids| undefined
noise through the component tree.- <SharedModulesPage - contractAddress={params.contractAddress} - chainIdOrSlug={params.chain_id} - projectMeta={undefined} - isLoggedIn={!!account} - /> + <SharedModulesPage + contractAddress={params.contractAddress} + chainIdOrSlug={params.chain_id} + isLoggedIn={!!account} + />apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/page.tsx (1)
9-13
: Omitundefined
optional propIf
projectMeta
is optional inSharedContractSourcesPage
, leave it out for clarity.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/page.tsx (1)
11-15
: Pass only the necessary propsSame redundant
projectMeta={undefined}
issue as above; remove it to simplify the API surface.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx (1)
1-5
: Consider simplifying complex import paths.The deeply nested relative import paths (e.g.,
../../../../../../../
) are fragile and hard to maintain. Consider using absolute imports or path aliases for better maintainability.Example using path aliases:
-import { SharedContractAccountPage } from "../../../../../../../(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page"; -import { getProject } from "../../../../../../../../../@/api/projects"; +import { SharedContractAccountPage } from "@/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page"; +import { getProject } from "@/api/projects";apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/direct-listings/page.tsx (1)
1-4
: Consider simplifying complex import paths.Similar to the other files, the deeply nested relative import paths could be simplified using absolute imports or path aliases for better maintainability.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/page.tsx (1)
12-14
: Normalise naming – prefer one param key (chainIdOrSlug
) throughoutHere we transform
params.chain_id
→chainIdOrSlug={…}
.
Mixing snake_case and camelCase in the same statement increases the mental load and is error-prone.Consider renaming the dynamic segment in the route folder to
[chainIdOrSlug]
(matching the project-scoped routes) or introduce a small mapper:const chainIdOrSlug = params.chain_id;before passing it further.
Consistency here will prevent subtle typos when copying code between routes.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/page.tsx (1)
9-14
: Prop naming / consistency nitSame snake ↔ camel naming issue (
params.chain_id
⇒chainIdOrSlug
).
Recommend the same normalisation strategy as above.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/events/page.tsx (1)
20-24
: Leverage existing slug instead of re-deriving it
params.project_slug
is already validated by the router and matches the requested URL.
Passingproject.slug
(fetched value) back intoprojectMeta
means a misconfigured API could silently diverge from the URL the user is on.- projectMeta={{ - projectSlug: project.slug, + projectMeta={{ + projectSlug: params.project_slug,Keeps the UI fully driven by the route and avoids accidental inconsistencies.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/page.tsx (1)
10-13
: Naming consistency again (chain_id
vschainIdOrSlug
)Unify the parameter naming or create an alias variable before passing it to
SharedCodePage
.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.tsx (1)
28-33
: Excellent refactoring to use centralized URL building.The change from hardcoded URL construction to using the
buildContractPagePath
utility is a great improvement. This centralizes URL logic and ensures consistency across the application.This pattern should be applied consistently across all contract pages for maintainability.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/explorer/page.tsx (1)
6-14
: Consistent pattern with modules page.The parameter handling and project fetching logic is identical to the modules page, which is good for consistency.
Consider extracting the common project fetching and validation logic into a shared utility function to reduce duplication:
// utils/project-page-wrapper.ts export async function getProjectFromParams(params: ProjectContractPageParams) { const project = await getProject(params.team_slug, params.project_slug); if (!project) { notFound(); } return project; }This could be used in both modules and explorer pages.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/page.tsx (1)
11-14
: Avoid explicitundefined
for optional propsPassing
projectMeta={undefined}
clutters the JSX and provides no extra information. Omit the prop entirely:-<SharedContractSettingsPage - contractAddress={params.contractAddress} - chainIdOrSlug={params.chain_id} - projectMeta={undefined} - isLoggedIn={!!account} -/> +<SharedContractSettingsPage + contractAddress={params.contractAddress} + chainIdOrSlug={params.chain_id} + isLoggedIn={!!account} />apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-conditions/page.tsx (1)
25-25
: Consider making the login status dynamic rather than hardcoded.The
isLoggedIn
prop is hardcoded totrue
, which may not reflect the actual authentication state. Consider fetching the account status similar to how it's done in the public contract pages.Apply this diff to make the login status dynamic:
+import { getRawAccount } from "../../../../../../../../account/settings/getAccount"; export default async function Page(props: { params: Promise<ProjectContractPageParams>; }) { - const params = await props.params; - const project = await getProject(params.team_slug, params.project_slug); + const [params, account] = await Promise.all([ + props.params, + getRawAccount() + ]); + const project = await getProject(params.team_slug, params.project_slug); if (!project) { notFound(); } return ( <SharedClaimConditionsPage contractAddress={params.contractAddress} chainIdOrSlug={params.chainIdOrSlug} projectMeta={{ projectSlug: project.slug, teamId: project.teamId, teamSlug: params.team_slug, }} - isLoggedIn={true} + isLoggedIn={!!account} /> ); }apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/page.tsx (1)
11-16
:projectMeta={undefined}
is redundant
projectMeta
is optional inSharedContractProposalsPage
, so passingundefined
adds noise without value. Dropping it improves readability:- <SharedContractProposalsPage - contractAddress={params.contractAddress} - chainIdOrSlug={params.chain_id} - projectMeta={undefined} - isLoggedIn={!!account} - /> + <SharedContractProposalsPage + contractAddress={params.contractAddress} + chainIdOrSlug={params.chain_id} + isLoggedIn={!!account} + />apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx (1)
10-16
: Drop explicitundefined
forprojectMeta
– idem to proposals page.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageSidebarLinks.ts (2)
2-4
: Import path leaks feature-folder knowledge
ProjectMeta
is imported from a deeply nested route path:import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types";Coupling a utility to the route hierarchy hurts re-usability. Prefer re-exporting
ProjectMeta
from a central domain module (e.g.contracts/types
) and import from there.
14-21
: Variable naming drift (chainSlug
vschainIdOrSlug
)
buildContractPagePath
expectschainIdOrSlug
, but the wrapper still useschainSlug
. Mixing terms makes the API harder to follow.- chainSlug: string; + chainIdOrSlug: string; ... - chainIdOrSlug: data.chainSlug, + chainIdOrSlug: data.chainIdOrSlug,Aligning the names avoids accidental misuse.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx (2)
6-7
: Prefer root-alias import over brittle deep relative pathThe 5-level
../../../../../…
path is fragile – a single folder rename or move will silently break the import.
Using a root alias (e.g.@/app/(app)/team/...
) or placing common types in a shared package keeps the path stable and improves readability.-import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types";
18-31
: Effect dependency could be narrowed to avoid unnecessary executions
useEffect
depends on the fullprops
object.
Parents often pass a new object on every render, which will re-trigger the effect (it’s guarded byredirected.current
, but the hook still wakes up).
Depending only on the handful of primitives used keeps React DevTools noise down and avoids redundant work:-}, [router, props]); +}, [ + router, + props.contract.address, + props.contract.chain.id, + props.projectMeta?.teamId, // if used inside buildContractPagePath +]);apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx (1)
1-4
: Replace deep relative import with alias for maintainabilitySame concern as earlier: the 5-level climb is brittle. Prefer an alias or expose
ProjectMeta
from a central package.-import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types";apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/contract-page-path.ts (1)
1-1
: Prefer path alias over deep relative importA 6-level relative path is fragile and becomes painful to maintain when files are moved. The rest of the dashboard codebase already uses the
@/…
alias – consider adding one forapps/dashboard/src/app
(e.g.@dashboard/…
) and importingimport type { ProjectMeta } from "@dashboard/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types";This keeps imports readable and avoids breakage on refactors.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/page.tsx (1)
11-14
: Consider passing realprojectMeta
when available
projectMeta={undefined}
works for the public dashboard, but if this page ever lives under a team/project route, links generated by child components may break. If the caller has the information, forward it here to preserve URL consistency.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/shared-explorer-page.tsx (1)
37-44
: Consider caching the ABI resolution to avoid redundant network calls
resolveContractAbi
is executed on every request for non-localhost chains. For popular public contracts this can become an expensive hot-path.
If the ABI is immutable, wrap the call inunstable_cache
(Next.js) or your in-house cache util with a sensible revalidation time.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx (1)
39-45
: Add an explicitreturn
after redirect for readability & type-safety
redirectToContractLandingPage
presumably ends the response (callsredirect
).
Addingreturn
makes the control flow obvious to readers and silences potential lint rules complaining about “function continues after redirect”.redirectToContractLandingPage({ chainIdOrSlug: props.chainIdOrSlug, contractAddress: props.contractAddress, projectMeta: props.projectMeta, }); + return null; // unreachable – satisfies TS / ESLint
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx (1)
37-39
: Cache heavy metadata look-upsSimilar to the explorer page,
getContractPageMetadata
can be expensive. Wrapping it in a cache layer (or passing a cached result down from a higher level) will reduce latency for frequently visited token pages.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx (1)
53-62
: Improve error handling in checkDefaultFeeConfig function.The empty catch block silently swallows all errors, which could hide important issues like network failures or contract interaction errors. Consider logging the error or handling specific error types.
async function checkDefaultFeeConfig(contract: ThirdwebContract) { let hasDefaultFeeConfig = true; try { const feeInfo = await getPlatformFeeInfo({ contract }); hasDefaultFeeConfig = feeInfo[0].toLowerCase() === DEFAULT_FEE_RECIPIENT.toLowerCase(); - } catch {} + } catch (error) { + console.warn("Failed to check default fee config:", error); + // Assume default config on error + } return hasDefaultFeeConfig; }apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx (1)
50-73
: Consider adding an explicit return type togetSelectors
Typing the helper improves IntelliSense for callers and prevents accidental shape changes:
-async function getSelectors(contract: ThirdwebContract) { +async function getSelectors( + contract: ThirdwebContract, +): Promise<{ + writeFnSelectorToName: Record<string, string>; + eventSelectorToName: Record<string, string>; +}> {Not mandatory but a low-effort win for maintainability.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx (2)
125-165
: Consider making default chains configurableThe hardcoded list of default chains is comprehensive but may need updates as new chains are supported. Consider making this configurable or fetching from a centralized source.
- const defaultChains = [ - 1, 137, 8453, 10, 42161, 11155111, 84532, 11155420, 421614, - ]; + const defaultChains = await getSupportedChainIds(); // or from config
213-216
: Consider type safety for decoded function dataThe
decodedData
is typed asany
which bypasses type safety. Consider using proper typing or at least add runtime validation.- // biome-ignore lint/suspicious/noExplicitAny: FIXME - const decodedData: any = await decodeFunctionData({ + const decodedData: unknown = await decodeFunctionData({ contract: serverContract, data: initializeData, });apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx (2)
1-21
: Consider organizing imports and using path aliases for better maintainability.The imports are functional but could be better organized. The import on line 13 is particularly long and could benefit from path aliasing.
Consider grouping imports by source (external libraries, internal utilities, components) and using path aliases:
+// External libraries import type { Metadata } from "next"; import { notFound } from "next/navigation"; import { getContractMetadata } from "thirdweb/extensions/common"; import { isAddress, isContractDeployed } from "thirdweb/utils"; + +// API and utilities import { getProjects } from "@/api/projects"; import { getTeams } from "@/api/team"; +import { getAuthTokenWalletAddress } from "@/api/lib/getAuthToken"; import { resolveFunctionSelectors } from "lib/selectors"; import { shortenIfAddress } from "utils/usedapp-external"; + +// Types import type { MinimalTeamsAndProjects } from "components/contract-components/contract-deploy-form/add-to-project-card"; -import type { ProjectMeta } from "../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; + +// Components and layout utilities import { NebulaChatButton } from "../../../../../nebula-app/(app)/components/FloatingChat/FloatingChat"; import { examplePrompts } from "../../../../../nebula-app/(app)/data/examplePrompts"; -import { getAuthTokenWalletAddress } from "../../../../api/lib/getAuthToken";
186-206
: Consider refactoring the contract type detection and description generation.The logic for determining contract types and generating descriptions could be more maintainable with a cleaner structure.
+const generateContractDescription = ( + contractDisplayName: string, + cleanedChainName: string, + contractTypes: { isERC721: boolean; isERC1155: boolean; isERC20: boolean } +) => { + const baseText = `View tokens, source code, transactions, balances, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}`; + + if (contractTypes.isERC721 || contractTypes.isERC1155) { + return `View tokens, source code, transactions, balances, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}.`; + } else if (contractTypes.isERC20) { + return `View ERC20 tokens, transactions, balances, source code, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}`; + } else { + return `View tokens, transactions, balances, source code, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}`; + } +}; const { isERC1155, isERC20, isERC721 } = supportedERCs(functionSelectors); const contractDisplayName = `${contractMetadata.name}${ contractMetadata.symbol ? ` (${contractMetadata.symbol})` : "" }`; const cleanedChainName = info?.chainMetadata?.name .replace("Mainnet", "") .replace("Testnet", "") .trim(); const title = `${contractDisplayName} | ${cleanedChainName} Smart Contract`; - let description = ""; - - if (isERC721 || isERC1155) { - description = `View tokens, source code, transactions, balances, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}.`; - } else if (isERC20) { - description = `View ERC20 tokens, transactions, balances, source code, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}`; - } else { - description = `View tokens, transactions, balances, source code, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}`; - } + const description = generateContractDescription(contractDisplayName, cleanedChainName, { isERC721, isERC1155, isERC20 });apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/TokenIdPage.client.tsx (1)
4-4
: Consider using a more maintainable import path.The current import path for
ProjectMeta
is very long and brittle. Consider creating a barrel export or alias to improve maintainability.-import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/app/(app)/(dashboard)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types";Or create a shared types file closer to the consuming components.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (107)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/ContractDirectListingsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/NFTCards.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/contract-page-path.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageSidebarLinks.ts
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/AccountSigners.client.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.client.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/components/nfts-owned.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-table.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/ClaimConditions.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/shared-code-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/data-table.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/events-feed.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/shared-events-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/shared-explorer-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/ContractEditModulesPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.client.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/TokenIdPage.client.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/token-id.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/table.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/opengraph-image.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/ContractOverviewPage.tsx
(7 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/Analytics.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/BuildYourApp.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/ContractChecklist.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/LatestEvents.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/MarketplaceDetails.tsx
(11 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/NFTDetails.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/PermissionsTable.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/contract-overview-page.client.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/ContractProposalsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/shared-sources-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/ContractSplitPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/types.ts
(1 hunks)apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx
(3 hunks)apps/dashboard/src/app/(app)/api/lib/getAuthToken.ts
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx
(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx
(5 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/direct-listings/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/english-auctions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account-permissions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/accounts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/analytics/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-conditions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/code/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/cross-chain/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/events/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/explorer/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/modules/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/[tokenId]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/permissions/page.tsx
(1 hunks)
⛔ Files not processed due to max files limit (11)
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/proposals/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/settings/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/sources/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/split/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/tokens/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/utils.ts
- apps/dashboard/src/components/contract-components/tables/cells.tsx
- apps/dashboard/src/components/contract-components/tables/contract-table.stories.tsx
- apps/dashboard/src/components/contract-components/tables/contract-table.tsx
- apps/dashboard/src/components/smart-wallets/AccountFactories/factory-contracts.tsx
✅ Files skipped from review due to trivial changes (2)
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/types.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/opengraph-image.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/code/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/shared-events-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/analytics/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/shared-sources-page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/english-auctions/page.tsx
🧰 Additional context used
🧠 Learnings (4)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/explorer/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx (1)
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
🔇 Additional comments (129)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/ContractSplitPage.client.tsx (1)
13-13
: LGTM: Correct implementation of projectMeta prop propagationThe component correctly accepts the new
projectMeta
prop and passes it to theRedirectToContractOverview
component when split functionality is not supported. This aligns with the PR objectives of incorporating project context throughout the contract pages.Also applies to: 26-31
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/ContractEditModulesPage.client.tsx (1)
13-13
: LGTM: Correct implementation of projectMeta prop propagationThe component correctly accepts the new
projectMeta
prop and passes it to theRedirectToContractOverview
component when the contract is not a modular core. This follows the consistent pattern of propagating project context throughout the application.Also applies to: 26-31
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/components/nfts-owned.tsx (1)
11-11
: LGTM: Proper prop threading for project contextThe component correctly extends its interface to accept
projectMeta
, properly destructures it from props, and passes it down to theNFTCards
component. This enables project-aware URL generation and navigation throughout the NFT display functionality.Also applies to: 17-17, 30-30
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.client.tsx (1)
14-14
: LGTM: Clean integration of project contextThe component correctly accepts the
projectMeta
prop and passes it to theContractPermissionsPage
component. This enables the permissions page to generate project-aware URLs and maintain consistent navigation within the team/project context.Also applies to: 28-28
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.client.tsx (1)
15-15
: LGTM! Consistent prop threading pattern.The addition of
projectMeta
prop and its propagation to child components follows a consistent pattern across the codebase. The optional typing (ProjectMeta | undefined
) maintains backward compatibility.Also applies to: 28-33, 42-42
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx (1)
45-46
: LGTM! Proper context propagation.Adding
teamSlug
andprojectSlug
props toDeployedContractsPage
provides necessary team/project context for the component. The values are correctly sourced from the already destructuredparams
object.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/ContractProposalsPage.client.tsx (1)
13-13
: LGTM! Consistent pattern implementation.The addition of
projectMeta
prop and its usage in the redirect scenario maintains consistency with the broader refactoring effort.Also applies to: 26-31
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/ClaimConditions.client.tsx (1)
13-13
: LGTM! Proper conditional rendering with context.The implementation correctly passes
projectMeta
toRedirectToContractOverview
when claim conditions are not supported, maintaining consistency with the overall refactoring pattern.Also applies to: 32-37
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-table.tsx (4)
19-20
: LGTM! Consistent import pattern for project metadata.The imports for
ProjectMeta
type andbuildContractPagePath
utility follow the established pattern across the codebase.
41-44
: LGTM! Proper prop interface extension.The addition of the optional
projectMeta
prop to the interface is correctly typed and follows the established pattern.
46-49
: LGTM! Clean component signature update.The component destructuring properly includes the new
projectMeta
prop while maintaining readability.
101-107
: Excellent improvement to URL generation consistency.The replacement of manual URL construction with
buildContractPagePath
centralizes route generation logic and ensures consistent URL patterns across the application. This improves maintainability and reduces the risk of URL inconsistencies.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/Analytics.tsx (3)
14-15
: LGTM! Consistent import pattern.The imports for
ProjectMeta
type andbuildContractPagePath
utility maintain consistency with other components in the refactor.
26-26
: LGTM! Proper prop addition.The
projectMeta
prop is correctly typed and follows the established optional pattern.
91-96
: Excellent centralized URL generation.The use of
buildContractPagePath
with the/analytics
subpath maintains consistency with the routing pattern and improves maintainability by centralizing URL generation logic.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/NFTDetails.tsx (5)
10-12
: LGTM! Consistent import pattern.The imports for
ProjectMeta
type andbuildContractPagePath
utility maintain consistency across the refactor.
19-19
: LGTM! Proper interface extension.The addition of the optional
projectMeta
prop toNFTDetailsProps
follows the established typing pattern.
27-27
: LGTM! Clean component signature.The component destructuring properly includes the new
projectMeta
prop.
29-34
: Excellent centralized URL generation.The replacement of manual URL construction with
buildContractPagePath
ensures consistent routing patterns and improves maintainability.
70-70
: LGTM! Proper prop threading.The
projectMeta
prop is correctly passed down to theNFTCards
component, maintaining the context flow throughout the component hierarchy.apps/dashboard/src/app/(app)/api/lib/getAuthToken.ts (1)
32-42
: Excellent API improvement for team context flexibility.The modification to accept an optional
teamId
parameter provides better control over team context while maintaining backward compatibility through the cookie fallback. The conditional logic properly prioritizes the explicit parameter over the stored cookie value.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.tsx (1)
6-6
: LGTM! Clean integration of projectMeta propThe changes correctly extend the component to accept and propagate the
projectMeta
prop. The type is properly imported, the interface is updated appropriately, and the prop is correctly passed down to theAccountsTable
component.Also applies to: 14-14, 20-20, 49-49
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/ContractChecklist.tsx (2)
15-16
: LGTM! Proper integration of projectMeta propThe addition of
projectMeta
prop and corresponding import are correctly implemented, following the established pattern throughout the codebase.Also applies to: 25-25, 50-50
54-63
: Excellent refactoring to centralized URL generationReplacing hardcoded URL construction with the
buildContractPagePath
utility is a great improvement. This approach:
- Centralizes URL logic for better maintainability
- Ensures consistent URL structure across components
- Properly handles project metadata for dynamic routing
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/LatestEvents.tsx (1)
25-26
: LGTM! Consistent implementation of dynamic URL generationThe changes properly integrate the
projectMeta
prop and utilize thebuildContractPagePath
utility for dynamic URL construction. The implementation:
- Correctly imports required types and utilities
- Follows the established pattern from other components
- Maintains clean separation between logic and UI components
Also applies to: 32-32, 37-42, 48-48
apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx (1)
15-16
: LGTM! Proper propagation of team and project contextThe changes correctly add
teamSlug
andprojectSlug
props to both the main component and async function, then properly forward them to theContractTable
component. While this approach uses separate string props instead of aProjectMeta
object (as seen in other files), it achieves the same goal of propagating team/project context through the component hierarchy.Also applies to: 44-45, 63-64
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/events-feed.tsx (2)
41-48
:projectMeta
should be explicitly optional in runtime as wellAlthough the prop is typed as
ProjectMeta | undefined
, later code passes it straight intobuildContractPagePath
.
If a parent forgets the prop, the builder may receiveundefined
and still try to dereference fields, causing a runtime error.Consider:
- projectMeta, + projectMeta ?? null, // or handle inside buildContractPagePathor assert inside
buildContractPagePath
thatprojectMeta
is defined wheneverteamSlug/projectSlug
-style URLs are generated.
264-272
: Potential double slashes in composed paths
subpath
already starts with/events…
;buildContractPagePath
presumably returns/…/contract
without a trailing slash.
Please confirm the util never appends a trailing/
, otherwise${basePath}/events
will render as…//events
.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/AccountSigners.client.tsx (1)
24-30
: Prop-plumbing looks correct
projectMeta
is forwarded toRedirectToContractOverview
, preserving the new routing context while keeping the existing logic intact.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/BuildYourApp.tsx (2)
13-18
: Guard against double slashes incodePath
subpath
is passed as"/code"
(leading slash). IfbuildContractPagePath
naïvely concatenates strings, the resulting URL could contain a double//
. Please ensure the helper normalises slashes or pass"code"
here.
30-31
: Good replacement of hard-coded pathUsing
buildContractPagePath
centralises URL logic and prevents future drift. Nice!apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/page.tsx (1)
5-9
:⚠️ Potential issueType mismatch:
params
should not be aPromise
Next.js supplies
params
as a plain object, not a promise. Declaring it asPromise<…>
compiles but will break type-safety and may confuse future readers.-export default async function Page(props: { - params: Promise<PublicContractPageParams>; -}) { - const [params, account] = await Promise.all([props.params, getRawAccount()]); +export default async function Page(props: { + params: PublicContractPageParams; +}) { + const params = props.params; + const account = await getRawAccount();⛔ Skipped due to learnings
Learnt from: jnsdls PR: thirdweb-dev/js#6929 File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19 Timestamp: 2025-05-21T05:17:31.283Z Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/page.tsx (1)
1-15
: LGTM! Clean refactoring to shared component architecture.This refactoring effectively centralizes the complex contract page logic into
SharedContractAccountPermissionsPage
, making the route handler much cleaner and more maintainable. The pattern of passingprojectMeta
asundefined
is appropriate for public contract pages that exist outside of a project context.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx (3)
7-9
: Improved import organization.Good refactoring to replace
ThirdwebClient
import withProjectMeta
import, reflecting the actual prop requirements of the component.
20-20
: Better prop interface design.Replacing the redundant
client
prop withprojectMeta
makes the interface cleaner since the client is already available throughcontract.client
.
50-60
: Consistent prop usage improvements.The changes correctly:
- Pass
projectMeta
to enable project-aware functionality- Use
contract.client
instead of the redundant separateclient
propThis eliminates prop duplication while adding the necessary project context.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.client.tsx (4)
4-4
: Consistent type import pattern.The
ProjectMeta
import follows the same pattern established across other contract client components.
13-13
: Proper optional prop addition.Adding
projectMeta
as an optional prop maintains backward compatibility while enabling project-aware functionality.
28-33
: Correct prop propagation for redirects.Ensuring
RedirectToContractOverview
receivesprojectMeta
enables proper project-aware URL generation during redirects.
42-42
: Complete prop forwarding.The
projectMeta
prop is correctly passed toContractNFTPage
, completing the data flow through the component hierarchy.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx (1)
1-18
: LGTM! Good architectural refactoring.The refactoring successfully moves complex logic to a shared component (
SharedDirectListingsPage
) while maintaining the same functionality. The simplified page component now only handles data fetching and delegates rendering logic to the shared component. Type usage withPublicContractPageParams
is correct and prop passing is consistent.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx (2)
5-7
: LGTM! Consistent type imports for project context.The import changes correctly replace
ThirdwebClient
withProjectMeta
to support the new project-aware routing architecture.
19-19
: LGTM! Proper prop threading for project metadata.The prop type change from
client: ThirdwebClient
toprojectMeta: ProjectMeta | undefined
and its usage ingetContractPageSidebarLinks
correctly propagates project context for URL generation and navigation.Also applies to: 43-43
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx (2)
9-14
: LGTM! Proper variable naming and error handling.The variable naming correctly uses
project
instead ofteam
(addressing past review feedback), and the 404 handling for missing projects is appropriate.
21-25
:❓ Verification inconclusive
Verify projectMeta field mappings.
The
projectMeta
object mixes data sources (project object and params). Please verify thatproject.teamId
is the correct field and that the mapping is consistent with other similar pages.
🏁 Script executed:
#!/bin/bash # Check the Project type definition and teamId field usage ast-grep --pattern 'interface Project { $$$ teamId: $_ $$$ }' # Check how projectMeta is constructed in other team/project pages rg -A 5 "projectMeta.*{" --type tsLength of output: 198
🏁 Script executed:
#!/bin/bash # Locate the Project interface declaration to confirm the exact field name rg "interface Project\\b" -A5 # Find how projectMeta is assembled elsewhere in TSX pages to verify consistency rg "projectMeta\\s*[:=]\\s*\\{" -A5 --type tsxLength of output: 104
Confirm projectMeta mapping consistency
I couldn’t locate a definitive
Project
type declaration or otherprojectMeta
usages in the repo, so please verify the following:
- In your
Project
interface (e.g. insrc/lib/types.ts
), ensureteamId
is the intended identifier and there isn’t ateamSlug
property on theproject
object.- Across other pages that build a
projectMeta
object, confirm they map the same fields (project.teamId
→teamId
,params.team_slug
→teamSlug
, etc.).- If any pages use
project.teamSlug
instead or source these values differently, update the snippet in
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx
(lines 21–25) to match the agreed mapping.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.tsx (1)
4-4
: LGTM! Consistent project metadata propagation.The addition of
ProjectMeta
prop and its propagation through the component hierarchy is well-implemented. The optional type (ProjectMeta | undefined
) correctly handles both public and project-scoped contract pages.Also applies to: 20-20, 28-28, 113-113
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/page.tsx (1)
5-8
: 🛠️ Refactor suggestion
⚠️ Potential issue
params
should not be typed asPromise<…>
Next JS passes
props.params
synchronously; wrapping it inPromise
breaks the contract with the framework, forces a superfluousawait
, and may trigger type-narrowing issues elsewhere (e.g. when re-exported).-export default async function Page(props: { - params: Promise<PublicContractPageParams>; -}) { - const [params, account] = await Promise.all([props.params, getRawAccount()]); +export default async function Page(props: { + params: PublicContractPageParams; +}) { + const [account] = await Promise.all([getRawAccount()]); + const { contractAddress, chain_id } = props.params;You still keep the concurrency benefit while respecting the official signature.
⛔ Skipped due to learnings
Learnt from: jnsdls PR: thirdweb-dev/js#6929 File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19 Timestamp: 2025-05-21T05:17:31.283Z Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/cross-chain/page.tsx (1)
1-27
: LGTM! Clean implementation following established patterns.The page component correctly implements the project-specific contract route pattern:
- Proper async parameter handling
- Project validation with 404 fallback
- Consistent projectMeta structure passed to shared component
The implementation follows the same pattern as other project-specific contract pages, ensuring consistency across the codebase.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account-permissions/page.tsx (1)
1-27
: LGTM! Consistent implementation with cross-chain page.The implementation follows the established pattern perfectly:
- Proper error handling with
notFound()
for missing projects- Consistent
projectMeta
structure (teamId, projectSlug, teamSlug)- Clean separation of concerns with shared component delegation
One minor observation: The
projectMeta
object property order differs slightly from the cross-chain page (teamId first vs projectSlug first), but this doesn't affect functionality.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx (3)
2-3
: LGTM! Good use of shared component pattern.The refactor successfully moves complex business logic to the shared component while maintaining the correct parameter types (
PublicContractPageParams
) for the public contract route.
8-8
: Efficient concurrent data fetching.Good use of
Promise.all()
to fetch parameters and account data concurrently, improving page load performance.
11-16
: Correct projectMeta handling for public routes.Setting
projectMeta={undefined}
is appropriate for public contract routes that don't operate within a specific project context. This maintains consistency with the shared component interface while clearly indicating the route type.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx (3)
4-4
: Correct import path for ProjectMeta type.The import path correctly references the project-specific contract types, ensuring type consistency across the project-aware components.
10-14
: Proper prop interface extension.The addition of the optional
projectMeta
prop maintains backward compatibility while enabling project-aware functionality. The type definition correctly allows for undefined values.
26-31
: Consistent prop threading to redirect component.The
projectMeta
prop is correctly passed through toRedirectToContractOverview
, enabling project-aware redirects when English auctions are not supported. This maintains the component's existing redirect logic while adding project context.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts (2)
8-12
: LGTM! Function signature updated correctly for team/project context.The parameter renaming from
chain_id
tochainIdOrSlug
aligns with the routing changes, and adding the optionalteamId
parameter enables team-aware client initialization.
35-37
: Team context properly passed to client initialization.The
teamId
is correctly passed togetUserThirdwebClient
to ensure the client has the appropriate team context for authentication and permissions.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/page.tsx (2)
6-14
: Proper async parameter handling and error handling.The implementation correctly awaits the params Promise (as noted in the retrieved learning) and handles the case where the project is not found with
notFound()
.
20-24
: ProjectMeta object construction is correct.The projectMeta object properly maps the project data and route parameters to provide team and project context to the shared component.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx (1)
25-25
: Hardcoded isLoggedIn value is appropriate.Setting
isLoggedIn={true}
is correct for team/project pages since users must be authenticated to access these routes.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/page.tsx (1)
5-9
:❌ Incorrect review comment
Avoid wrapping
params
in aPromise
– keep the signature aligned with Next JS conventions
params
is synchronously provided by the routing layer ({ [segment: string]: string }
).
Typing it asPromise<…>
forces every consumer toawait
a non-thenable object, produces confusing IntelliSense, and hides genuine async work inside the component.-export default async function Page(props: { - params: Promise<PublicContractPageParams>; -}) { - const params = await props.params; +export default function Page(props: { + params: PublicContractPageParams; +}) { + const { params } = props;This change:
- Removes an unnecessary
await
.- Keeps the component a React server component (it can still be
async
if additional awaits are required later).Follow-up: update the type in
PublicContractPageParams
consumers across the codebase.
🏁 Script executed:
#!/bin/bash # Search for Page components and their props signature rg -n "export default async function Page" -A 5 rg -n "params: Promise" -A 3Length of output: 66199
Keep
params
as aPromise
—this matches our existing conventions
The codebase consistently types and awaitsprops.params
(andprops.searchParams
) asPromise<…>
across all App-Router pages to handle cases where Next.js provides these as thenables (see prior fix ininsight/webhooks/page.tsx
). Removing thePromise
wrapper here would break that pattern and risk runtime errors. No change needed.Likely an incorrect or invalid review comment.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/events/page.tsx (1)
10-15
:⚠️ Potential issueDifferentiate “not found” from upstream errors
getProject
might throw (network, DB, auth). Treating every thrown error asnotFound()
will incorrectly surface 404s for 5xx situations and make debugging harder.-const project = await getProject(params.team_slug, params.project_slug); - -if (!project) { - notFound(); -} +let project; +try { + project = await getProject(params.team_slug, params.project_slug); + if (!project) { + notFound(); + return; // unreachable but satisfies TS + } +} catch (err) { + // re-throw and let the Next.js error boundary convert to 500 + throw err; +}This preserves correct HTTP semantics.
Likely an incorrect or invalid review comment.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/modules/page.tsx (2)
6-14
: LGTM! Proper async parameter handling and error handling.The component correctly awaits the params Promise (consistent with Next.js patterns) and properly handles the case where project data is not found by triggering a 404 response.
16-27
: Clean projectMeta construction and component usage.The projectMeta object is constructed with consistent naming and structure, passing all necessary context to the SharedModulesPage component. The hardcoded
isLoggedIn={true}
follows the pattern seen in other similar pages.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/contract-overview-page.client.tsx (3)
12-14
: Good prop threading pattern.The component properly accepts the optional projectMeta prop and destructures it for clean usage.
28-30
: Consistent prop forwarding.The projectMeta is correctly passed down to the ContractOverviewPage component, maintaining the data flow chain.
4-4
:✅ Verification successful
Verify the import path for ProjectMeta type.
The import path
../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types
seems quite deep and might be fragile to file structure changes.
🏁 Script executed:
#!/bin/bash # Verify the ProjectMeta type definition exists at the imported path fd -t f "types.ts" apps/dashboard/src/app | grep "team.*project_slug.*contract" | head -5 # Check if there's a more centralized type definition rg -A 5 "type ProjectMeta" apps/dashboard/srcLength of output: 907
ProjectMeta import path is valid
Verified that
ProjectMeta
is defined in
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts
and there’s no centralized export for it. No changes required.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.tsx (2)
7-8
: Good imports for type safety and URL utility.The imports for ProjectMeta type and buildContractPagePath utility support the refactoring to centralized URL building.
16-16
: Proper optional prop typing.The projectMeta prop is correctly typed as optional, maintaining backward compatibility.
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/explorer/page.tsx (1)
16-27
: LGTM! Clean component usage with proper projectMeta construction.The SharedExplorerPage is called with all necessary props and the projectMeta object follows the established pattern.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/page.tsx (1)
5-8
:⚠️ Potential issue
params
should not be typed/handled as aPromise
in a route page componentNext.js (>=13) injects
params
synchronously. Typing it asPromise<…>
and awaiting it:params: Promise<PublicContractPageParams>; … const [params, account] = await Promise.all([props.params, getRawAccount()]);① Produces an incorrect type that will compile only because of
await
abuse, masking errors at call-sites.
② Adds an unnecessary micro-task tick (Promise.resolve
) even if the object is already available.
③ Breaks the contract with Next.js – in runtime,props.params
will be a plain object, not a promise; accidental double‐awaits can lead to subtle bugs when the object contains getters (e.g. edge runtimes).Suggested fix:
-export default async function Page(props: { - params: Promise<PublicContractPageParams>; -}) { - const [params, account] = await Promise.all([props.params, getRawAccount()]); +export default async function Page({ + params, +}: { + params: PublicContractPageParams; +}) { + const account = await getRawAccount();⛔ Skipped due to learnings
Learnt from: jnsdls PR: thirdweb-dev/js#6929 File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19 Timestamp: 2025-05-21T05:17:31.283Z Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/NFTCards.tsx (1)
6-7
: LGTM! Good refactor to use centralized URL generation.The changes correctly implement the projectMeta prop pattern and replace hardcoded URL construction with the buildContractPagePath utility. This improves consistency and maintainability across the dashboard.
Also applies to: 34-34, 42-42, 94-99
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/permissions/page.tsx (1)
10-10
:✅ Verification successful
Verify that project.teamId contains the correct team ID.
The variable naming has been improved from previous versions, but I need to verify that
project.teamId
actually contains the team ID rather than the project ID, given past review concerns about this data structure.Also applies to: 21-25
🏁 Script executed:
#!/bin/bash # Description: Verify the Project type structure and teamId field # Expected: project.teamId should contain the team ID, not project ID # Search for Project type/interface definitions rg -A 10 -B 2 "^(export )?(type|interface) Project\b" --type ts --type tsx # Search for getProject function signature and return type rg -A 5 "export.*function getProject" --type ts --type tsx # Look for Project usage in similar files to verify teamId usage pattern rg -B 2 -A 2 "project\.teamId" --type ts --type tsxLength of output: 275
🏁 Script executed:
#!/bin/bash # Search for Project type/interface definitions in TS and TSX files rg -A 10 -B 2 '^(export )?(type|interface) Project\b' -g '*.ts*' # Search for getProject function signature and return type rg -A 5 -B 2 'getProject' -g '*.ts*' # Search for project.teamId usage across the codebase rg -B 2 -A 2 'project\.teamId' -g '*.ts*'Length of output: 69637
🏁 Script executed:
#!/bin/bash echo "---- apps/dashboard/src/@/api/projects.ts (first 200 lines) ----" sed -n '1,200p' apps/dashboard/src/@/api/projects.ts echo echo "---- Searching for ProjectResponse type definitions ----" rg -A 5 -B 2 'type ProjectResponse' -g '*.ts*'Length of output: 2004
Confirmed:
project.teamId
is the correct team identifier
TheProject
type aliasesProjectResponse
(packages/service-utils/src/core/api.ts), whereteamId: string
refers to the Team ID. No changes needed.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/shared-code-page.tsx (1)
8-44
: LGTM! Well-structured shared component with proper error handling.The implementation follows best practices:
- Proper error handling with
notFound()
for missing contract info- Graceful ABI resolution error handling
- Clean separation between localhost and remote chain rendering
- Consistent with the broader refactoring pattern for shared components
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/ContractOverviewPage.tsx (1)
2-2
: LGTM! Clean implementation of projectMeta propagation.The changes correctly add and propagate the optional projectMeta prop through the component tree, enabling all child components to generate project-aware URLs. The implementation is consistent with the broader refactoring pattern.
Also applies to: 24-24, 41-41, 53-53, 62-62, 69-69, 83-83, 93-93, 101-101, 109-109
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-conditions/page.tsx (1)
6-28
: LGTM! Clean implementation with proper error handling.The component follows Next.js app router conventions correctly with async parameter handling and appropriate 404 error handling when the project is not found.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/page.tsx (1)
8-17
: Excellent refactoring! Simplified logic with performance optimization.The refactoring successfully consolidates complex conditional rendering into a single shared component while maintaining functionality. The use of
Promise.all
for parallel fetching is a good performance optimization, and explicitly settingprojectMeta
toundefined
clearly indicates this is for public (non-project-scoped) contract access.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.client.tsx (3)
4-4
: Good type import organization.Importing the
ProjectMeta
type from the correct location maintains proper module boundaries.
10-13
: Proper prop interface extension.The addition of the optional
projectMeta
prop correctly supports both project-scoped and public contract contexts.
26-40
: Consistent projectMeta propagation.The
projectMeta
prop is correctly passed down to both theRedirectToContractOverview
andAccountsPage
components, maintaining consistency in the component hierarchy.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/accounts/page.tsx (1)
6-28
: LGTM! Consistent implementation pattern.The component follows the same clean pattern as other team/project contract pages with proper async parameter handling and error handling.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/page.tsx (1)
2-9
:⚠️ Potential issue
props.params
should not be typed as aPromise
In a Next JS route segment
params
is synchronously provided as an object.
Typing it asPromise<PublicContractPageParams>
will:
- Break type-safety – the framework will supply a
PublicContractPageParams
, not aPromise
.- Force an unnecessary
Promise.all
wrapper (the spread is already awaited whengetRawAccount()
resolves).A minimal fix:
-export default async function Page(props: { - params: Promise<PublicContractPageParams>; -}) { - const [params, account] = await Promise.all([props.params, getRawAccount()]); +export default async function Page(props: { + params: PublicContractPageParams; +}) { + const [account] = await Promise.all([getRawAccount()]); + const params = props.params; // already resolvedThis also removes an unneeded micro-task and keeps the function signature aligned with other pages.
⛔ Skipped due to learnings
Learnt from: jnsdls PR: thirdweb-dev/js#6929 File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19 Timestamp: 2025-05-21T05:17:31.283Z Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageSidebarLinks.ts (1)
16-20
: Potential double-slash whenprojectMeta
is absentIf
buildContractPagePath
returns/${chain}/${address}
(no trailing slash) the later template strings (${layoutPrefix}/modules
, …) are safe.
Verify the helper never inserts a trailing slash to avoid URLs like/0x123///modules
.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/page.tsx (2)
4-8
:params
should not be wrapped in aPromise
for Next App Router pages
props.params
is synchronously supplied by Next.js, so typing it asPromise<…>
andawait
-ing it is unnecessary and may confuse future readers or tooling (e.g. ESLint rules that rely on the official types).-export default async function Page(props: { - params: Promise<PublicContractPageParams>; -}) { - const params = await props.params; +export default function Page({ params }: { params: PublicContractPageParams }) {If the whole component is not otherwise
async
, theasync
keyword can also be dropped.
[ suggest_essential_refactor ]
10-12
: Parameter name mismatch can break project-aware routing
SharedContractOverviewPage
expectschainIdOrSlug
, but we are passingparams.chain_id
, notparams.chainIdOrSlug
.
IfPublicContractPageParams
only containschain_id
, downstream code that assumes a slug may misbehave (e.g. wrong breadcrumbs).Please verify the shape of
PublicContractPageParams
and either:- chainIdOrSlug={params.chain_id} + chainIdOrSlug={params.chainIdOrSlug ?? params.chain_id}or rename the field in the type so that it is unambiguous.
[ request_verification ]apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/token-id.tsx (2)
30-32
: Avoid deep relative import for sharedProjectMeta
typeImporting a type through a 7-level relative path couples unrelated route trees and risks circular-dependency headaches at build time.
Consider hoistingProjectMeta
to a root-leveltypes
(or@/types
) module:-import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import type { ProjectMeta } from "@/types/project";This also improves IntelliSense and future refactors.
[ suggest_optional_refactor ]
118-124
: Double-slash risk inbuildContractPagePath
subpath: "/nfts"
already starts with a slash.
IfbuildContractPagePath
concatenates with/
(common), the final URL will contain//nfts
.- subpath: "/nfts", + subpath: "nfts",Please run a quick check (unit test or
console.log
) to ensure the generated path is correct.
[ request_verification ]apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/[tokenId]/page.tsx (2)
24-27
:isLoggedIn
hard-coded totrue
may expose privileged UI/actions
SharedNFTTokenPage
likely shows mint/burn buttons or owner-only data whenisLoggedIn
istrue
.
Hard-coding this value means unauthenticated users can see or attempt actions they shouldn’t.Retrieve the actual auth state (session/token) instead:
- isLoggedIn={true} + isLoggedIn={Boolean(await getAuthToken())}(or pass it down from a higher layout where auth is already resolved).
[ raise_critical_issue ]
6-13
: SamePromise<…>
pattern as above – reconsiderAs noted in the public-route file,
params
is delivered synchronously. UsingPromise<…>
is non-idiomatic and should be removed unless you have a custom loader that actually returns a promise.
[ duplicate_comment ]apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx (1)
151-153
: Forwarding new slug props looks good
FactoryContracts
now receivesteamSlug
/projectSlug
; this propagates context required by downstream pages without altering existing logic. 👍apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx (1)
14-19
: Consider forwardingprojectId
alongsideteamId
getContractPageParamsInfo
receives onlyteamId
.
Other shared pages pass bothteamId
andprojectId
, enabling stricter project-scoped look-ups. If that helper expects or benefits fromprojectId
, this omission could surface as subtle auth/visibility bugs.Please double-check the helper’s signature and include
projectId: props.projectMeta?.projectId
when applicable.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx (3)
68-70
: Prop drilling looks okay, but watch for duplication
teamSlug
/projectSlug
are now forwarded toAssetsPageAsync
. Make sure the child component (and any further descendants) actually declare these props; otherwise TypeScript will silently allow the extra fields but they will be unused.
97-99
: Same observation forAssetsPageAsync
signatureThe async helper now accepts the two new slug props – good. Verify that callers other than this file were updated; otherwise they will fail type-checking.
116-118
: Propagation intoContractTable
looks correct
ContractTable
now receives both IDs and slugs, enabling it to construct project-aware links. Nice incremental improvement.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/page.tsx (1)
5-9
:⚠️ Potential issueIncorrect Promise typing on
params
As in the assets page,
params
is synchronously provided by Next 13/14. Typing it asPromise<…>
forces unnecessaryawait
logic and could mask real typing errors.-export default async function Page(props: { - params: Promise<PublicContractPageParams>; -}) { - const [params, account] = await Promise.all([props.params, getRawAccount()]); +export default async function Page(props: { + params: PublicContractPageParams; +}) { + const [account] = await Promise.all([getRawAccount()]); + const { params } = props;Adjust the destructuring accordingly.
⛔ Skipped due to learnings
Learnt from: jnsdls PR: thirdweb-dev/js#6929 File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19 Timestamp: 2025-05-21T05:17:31.283Z Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/page.tsx (1)
5-23
: LGTM! Clean refactoring to shared component pattern.The simplification to delegate to
SharedNFTTokenPage
follows the established architectural pattern. The hardcodedprojectMeta={undefined}
is appropriate for this non-team/project scoped route.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx (1)
29-33
: LGTM! ProjectMeta is correctly implemented.The client component correctly receives
projectMeta
from props, resolving any previous TODO concerns.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx (1)
9-53
: LGTM! Well-structured shared component following established patterns.The component correctly handles contract info fetching, localhost detection, metadata validation, and conditional rendering/redirection.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx (1)
11-51
: Well-structured shared component with good separation of concerns.The component follows React server component best practices with proper data fetching, error handling via
notFound()
, and conditional rendering based on chain type. The concurrent fetching pattern withPromise.all
is efficient.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx (1)
9-54
: Correctly implemented shared accounts page component.The component properly handles contract info fetching, localhost rendering, and factory support validation. The previous issue with
projectMeta={undefined}
has been correctly fixed - line 32 now passesprops.projectMeta
as expected.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page.tsx (1)
9-57
: Well-implemented shared account page component.The component correctly follows the established pattern with proper data fetching, localhost handling, account validation, and conditional rendering. The props are appropriately passed to child components including
chainMetadata
andprojectMeta
.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx (2)
46-46
: 💡 Verification agent🧩 Analysis chain
Inconsistent projectMeta prop passing between client and server components.
The server-side
AccountSigners
component (line 46) doesn't receive theprojectMeta
prop, while the client-sideAccountSignersClient
(lines 28-32) does. This inconsistency may affect navigation behavior between localhost and remote chains.
🏁 Script executed:
#!/bin/bash # Check if AccountSigners component accepts projectMeta prop ast-grep --pattern 'function AccountSigners($$$) { $$$ }' # Check the component's prop interface rg -A 10 -B 2 "AccountSigners.*props" apps/dashboard/src/app/\(app\)/\(dashboard\)/\(chain\)Length of output: 2673
🏁 Script executed:
#!/bin/bash # Locate server-side AccountSigners file (excluding the client variant) SERVER_FILE=$(find apps/dashboard/src/app/\(app\)/\(dashboard\)/\(chain\) -type f -name "account-signers.tsx" ! -name "*client.tsx") echo "Server component file: $SERVER_FILE" # Show the top of the file to inspect its prop signature head -n 50 "$SERVER_FILE"Length of output: 2282
Remove or forward the unused projectMeta prop in AccountSignersClient
The
AccountSignersClient
component declares aprojectMeta
prop but never uses or forwards it toAccountSigners
. To avoid confusion and possible bugs, either:
Remove
projectMeta
from theAccountSignersClient
props interface, since it isn’t consumed;OR ‑
If downstream code needs it, update both components to accept and pass it through:
// AccountSigners.client.tsx export function AccountSignersClient(props: { contract: ThirdwebContract; - projectMeta: ProjectMeta | undefined; }) { const metadataQuery = useContractPageMetadata(props.contract); … - return <AccountSigners contract={props.contract} />; + return ( + <AccountSigners + contract={props.contract} + projectMeta={props.projectMeta} + /> + ); }And in
components/account-signers.tsx
, extendAccountSignersProps
accordingly.Locations to update:
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/AccountSigners.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/components/account-signers.tsx
Likely an incorrect or invalid review comment.
9-13
:❌ Incorrect review comment
Verify missing isLoggedIn prop in component signature.
This component's props interface lacks the
isLoggedIn
prop that other similar shared components include (e.g.,SharedContractSettingsPage
,SharedAccountsPage
). Ensure this omission is intentional.
🏁 Script executed:
#!/bin/bash # Check if AccountSigners or AccountSignersClient components expect isLoggedIn prop ast-grep --pattern 'function AccountSigners($$$) { $$$ }' ast-grep --pattern 'function AccountSignersClient($$$) { $$$ }' # Check other shared components for isLoggedIn prop pattern rg -A 3 "isLoggedIn.*boolean" apps/dashboard/src/app/\(app\)/\(dashboard\)/\(chain\)Length of output: 66713
--- 🏁 Script executed: ```shell #!/bin/bash set -e echo "Files in account-permissions directory:" ls "apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions" echo echo "----- shared-account-permissions-page.tsx (lines 1-200) -----" sed -n '1,200p' "apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx" echo echo "----- Searching for AccountSigners definitions -----" grep -R -n "AccountSigners" "apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions"
Length of output: 4087
Ignore missing
isLoggedIn
andprojectMeta
prop suggestions for SharedContractAccountPermissionsPageBoth flagged inconsistencies are false positives:
- The server-side
SharedContractAccountPermissionsPage
intentionally only acceptscontractAddress
,chainIdOrSlug
, andprojectMeta
— it does not need anisLoggedIn
prop at this layer.- The client component
AccountSignersClient
takesprojectMeta
, but the inner<AccountSigners>
component’s props interface only declares acontract
field. PassingprojectMeta
there would be a no-op.No changes are required.
Likely an incorrect or invalid review comment.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/data-table.tsx (4)
61-62
: LGTM! Proper imports for project context support.The imports for
ProjectMeta
type andbuildContractPagePath
utility are correctly added to support the new project-aware URL generation functionality.
96-106
: LGTM! Component signature properly updated.The
DataTable
component signature correctly adds the optionalprojectMeta
prop, maintaining backward compatibility while enabling project-aware navigation.
242-252
: LGTM! Consistent URL generation in network links.The network column links now use
buildContractPagePath
to generate URLs that include project metadata when available, replacing the previous hardcoded approach. This ensures consistent navigation behavior across the dashboard.
420-427
: LGTM! Post-deployment contract links use centralized URL generation.The post-deployment contract view link correctly uses
buildContractPagePath
to generate project-aware URLs, ensuring users are directed to the appropriate project-scoped contract page after successful deployment.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx (3)
9-14
: LGTM! Well-structured component interface.The component signature properly accepts all necessary props including
projectMeta
for project-aware navigation andisLoggedIn
for authentication state.
15-23
: LGTM! Proper contract validation and error handling.The component correctly uses
getContractPageParamsInfo
to validate contract parameters and properly handles the case where contract info is not found by triggering a 404 response.
26-34
: LGTM! Client component receives project context.The localhost branch correctly passes
projectMeta
to the client component, enabling project-aware navigation in development environments.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx (4)
10-14
: LGTM! Consistent component interface.The component signature follows the established pattern and properly includes
projectMeta
for project-aware navigation.
15-23
: LGTM! Proper contract validation and error handling.The component correctly validates contract parameters and handles missing contract info with appropriate 404 response.
27-35
: LGTM! Client component properly configured.The localhost branch correctly passes all necessary props including
projectMeta
,chainMetadata
, andcontract
to the client component.
39-60
: LGTM! Comprehensive server component configuration.The server component receives extensive metadata and properly includes
projectMeta
for consistent navigation behavior. TheErrorBoundary
wrapper aroundPublishedBy
provides good fault tolerance.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/page.tsx (2)
1-2
: LGTM! Proper imports for simplified implementation.The imports are correctly updated to use
PublicContractPageParams
type and the newSharedCrossChainPage
component.
5-15
: LGTM! Clean simplification with proper prop passing.The page implementation is correctly simplified to use the shared component pattern. Passing
undefined
forprojectMeta
is appropriate for public contract pages that don't have project context.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx (1)
46-53
:✅ Verification successful
Verify projectMeta propagation in client component
The
projectMeta
prop is now correctly passed toTokenIdPageClient
. Ensure the client component properly handles and forwards this metadata for consistent navigation.
🏁 Script executed:
#!/bin/bash # Verify TokenIdPageClient accepts and uses projectMeta prop ast-grep --pattern 'function TokenIdPageClient($$$) { $$$ }'Length of output: 5754
projectMeta correctly propagated in TokenIdPageClient
Verified thatTokenIdPageClient
accepts aprojectMeta
prop and forwards it to both<RedirectToContractOverview>
and<TokenIdPage>
. No further changes required.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx (2)
16-23
: Excellent refactor: Logic centralized in shared componentsThis simplification moves complex validation, data fetching, and conditional rendering logic to
SharedContractLayout
, improving maintainability and reducing code duplication across contract pages.
33-37
: Clean delegation to shared metadata generationThe metadata generation is now properly delegated to
generateContractLayoutMetadata
, removing duplicate logic and ensuring consistency across contract layouts.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx (1)
28-37
: Good contract validation patternThe component properly fetches contract info with team context and handles the not found case appropriately.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx (6)
29-31
: LGTM! Proper address validation with early return.The address validation using
isAddress
with early return vianotFound()
is a good security practice that prevents invalid addresses from being processed further.
33-41
: Excellent use of Promise.all for parallel data fetching.The parallel execution of independent async operations optimizes performance by reducing total execution time compared to sequential await calls.
67-75
: Good error handling in contract validation Promise.all.The
.catch(() => false)
on line 72 properly handles potential deployment check failures by defaulting to false, which will trigger the 404 handling below.
130-158
: Good error handling and performance optimization in teams/projects fetching.The function properly handles authentication failures by returning
undefined
and usesPromise.all
to parallelize project fetching for each team. The try-catch ensures graceful degradation when user data is unavailable.
175-180
: LGTM! Parallel execution optimizes metadata generation.Using
Promise.all
to fetch function selectors and contract metadata concurrently improves performance while maintaining proper error handling.
212-217
: Good fallback metadata handling for error cases.The fallback logic properly handles cases where contract metadata cannot be retrieved, providing sensible defaults using the address and chain information.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/TokenIdPage.client.tsx (3)
15-15
: Good addition of optional projectMeta prop.Adding
projectMeta
as an optional prop maintains backward compatibility while enabling the new team/project context functionality.
31-36
: Proper context propagation in redirect flow.The updated
RedirectToContractOverview
call correctly passes theprojectMeta
to maintain team/project context when redirecting users for unsupported ERC standards.
46-46
: Consistent prop forwarding to child component.The
projectMeta
prop is properly forwarded to theTokenIdPage
component, maintaining the data flow pattern established throughout this refactor.
...ard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/table.tsx
Show resolved
Hide resolved
...pp)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx
Show resolved
Hide resolved
...ject_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/direct-listings/page.tsx
Show resolved
Hide resolved
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx
Show resolved
Hide resolved
.../src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/contract-page-path.ts
Show resolved
Hide resolved
...p/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx
Show resolved
Hide resolved
...[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx
Show resolved
Hide resolved
...oard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx
Show resolved
Hide resolved
...oard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx
Show resolved
Hide resolved
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
Show resolved
Hide resolved
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 introduces enhancements to the handling of contract pages, adding new types for parameters and project metadata, while refactoring existing components to incorporate team and project-specific data. ### Detailed summary - Added `PublicContractPageParams` and `ProjectContractPageParams` types. - Introduced `ProjectMeta` type for project metadata. - Refactored components to accept `teamSlug`, `projectSlug`, and `projectMeta`. - Updated routing and links to include project-specific paths. - Enhanced handling of contract page data retrieval and UI rendering. > The following files were skipped due to too many changes: `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.client.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/TokenIdPage.client.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.client.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/shared-explorer-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/ContractChecklist.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/data-table.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/token-id.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/ContractOverviewPage.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/events-feed.tsx`, `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/layout.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/MarketplaceDetails.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx` > ✨ 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** - Enhanced routing to include project and team slugs, enabling project-aware navigation for contract, NFT, marketplace, analytics, permissions, and proposal pages. - Passed project metadata (team and project info) throughout various pages and components for contextual consistency. - Introduced shared layout and page components for contract overview, NFTs, analytics, permissions, and settings, streamlining the user experience. - **Refactor** - Removed internal data fetching, validation, and conditional rendering from pages, delegating logic to shared components. - Updated navigation links and breadcrumbs to dynamically incorporate project and team slugs when available. - Centralized metadata and layout generation into utility functions to reduce duplication. - **Bug Fixes** - Improved handling of missing or invalid project/team data by triggering notFound responses appropriately. - **Chores** - Extended component props and interfaces to accept projectMeta objects. - Simplified page components to directly render shared components with minimal logic. - Updated URL construction to utilize utility functions for project-aware paths. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
5f65eea
to
1247502
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx (1)
94-99
: Extract the hardcoded AI prompt prefix to improve maintainability.The contractPromptPrefix is quite long and hardcoded within the component, making it difficult to maintain and test. Consider extracting it to a separate constant or utility function.
+// At the top of the file or in a separate utils file +const createContractPromptPrefix = (contractAddress: string, chainName: string, chainId: number) => + `A user is viewing the contract address ${contractAddress} on ${chainName} (Chain ID: ${chainId}). Provide a concise summary of this contract's functionalities, such as token minting, staking, or governance mechanisms. Focus on what the contract enables users to do, avoiding transaction execution details unless requested. +Users may be interested in how to interact with the contract. Outline common interaction patterns, such as claiming rewards, participating in governance, or transferring assets. Emphasize the contract's capabilities without guiding through transaction processes unless asked. +Provide insights into how the contract is being used. Share information on user engagement, transaction volumes, or integration with other dApps, focusing on the contract's role within the broader ecosystem. +Users may be considering integrating the contract into their applications. Discuss how this contract's functionalities can be leveraged within different types of dApps, highlighting potential use cases and benefits. + +The following is the user's message:`; - const contractPromptPrefix = `A user is viewing the contract address ${contractAddress} on ${chainName} (Chain ID: ${chainId}). Provide a concise summary of this contract's functionalities, such as token minting, staking, or governance mechanisms. Focus on what the contract enables users to do, avoiding transaction execution details unless requested. -Users may be interested in how to interact with the contract. Outline common interaction patterns, such as claiming rewards, participating in governance, or transferring assets. Emphasize the contract's capabilities without guiding through transaction processes unless asked. -Provide insights into how the contract is being used. Share information on user engagement, transaction volumes, or integration with other dApps, focusing on the contract's role within the broader ecosystem. -Users may be considering integrating the contract into their applications. Discuss how this contract's functionalities can be leveraged within different types of dApps, highlighting potential use cases and benefits. - -The following is the user's message:`; + const contractPromptPrefix = createContractPromptPrefix(contractAddress, chainName, chainId);apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx (1)
227-231
:⚠️ Potential issueCritical bug: Fix the off-by-one error in module index check.
This issue was previously identified but remains unfixed. When
findIndex
returns0
(indicating the modules parameter is the first argument), the current ternary checkmoduleIndex ?
evaluates tofalse
, incorrectly settingmodules
toundefined
.Apply this fix:
-modules = moduleIndex ? decodedData[moduleIndex] : undefined; +modules = moduleIndex !== -1 ? decodedData[moduleIndex] : undefined;
🧹 Nitpick comments (6)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx (2)
203-203
: Fix missing semicolon in description string.The description string is missing a semicolon at the end for consistency with other description strings.
- description = `View ERC20 tokens, transactions, balances, source code, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}` + description = `View ERC20 tokens, transactions, balances, source code, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}.`;
205-205
: Fix double space in description string.There's an extra space between "contract" and "on" in the description string.
- description = `View tokens, transactions, balances, source code, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}`; + description = `View tokens, transactions, balances, source code, and analytics for the ${contractDisplayName} smart contract on ${cleanedChainName}.`;apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx (4)
125-127
: Extract hardcoded chain IDs to a constant.The default chains list should be extracted to a named constant for better maintainability and reusability.
+const DEFAULT_CROSS_CHAIN_IDS = [ + 1, 137, 8453, 10, 42161, 11155111, 84532, 11155420, 421614, +] as const; -const defaultChains = [ - 1, 137, 8453, 10, 42161, 11155111, 84532, 11155420, 421614, -]; +const defaultChains = DEFAULT_CROSS_CHAIN_IDS;
99-101
: Extract hardcoded address to a named constant.The CREATE2 factory address should be extracted to a named constant for clarity and maintainability.
+const CREATE2_FACTORY_ADDRESS = "0x4e59b44847b379578588920cA78FbF26c0B4956C"; isDirectDeploy = creationTx.to?.toLowerCase() === - "0x4e59b44847b379578588920cA78FbF26c0B4956C".toLowerCase(); + CREATE2_FACTORY_ADDRESS.toLowerCase();
80-105
: Improve error handling specificity.The current catch block uses a generic
console.debug(e)
which may not provide sufficient information for debugging deployment issues.} catch (e) { - console.debug(e); + console.debug("Failed to fetch contract creation data:", e); }
129-165
: Consider performance optimization for chain deployment checks.The current implementation checks all chains sequentially with
Promise.all
, but this could be optimized by implementing request timeouts and potentially batching requests.Consider adding timeout handling:
const chainsDeployedOn = ( await Promise.all( defaultChains.map(async (c) => { + const timeoutPromise = new Promise((_, reject) => + setTimeout(() => reject(new Error('Timeout')), 5000) + ); + + return Promise.race([ + (async () => { // eslint-disable-next-line no-restricted-syntax const chain = defineChain(c); // ... existing logic + })(), + timeoutPromise + ]).catch(() => ({ + id: c, + network: "", + chainId: c, + status: "NOT_DEPLOYED" as const, + })); }), ) ).filter((c) => c.chainId !== serverContract.chain.id);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (107)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/ContractDirectListingsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/NFTCards.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/contract-page-path.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageSidebarLinks.ts
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/AccountSigners.client.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.client.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/components/nfts-owned.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-table.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/ClaimConditions.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/shared-code-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/data-table.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/events-feed.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/shared-events-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/shared-explorer-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/ContractEditModulesPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.client.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/TokenIdPage.client.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/token-id.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/table.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/opengraph-image.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/ContractOverviewPage.tsx
(7 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/Analytics.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/BuildYourApp.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/ContractChecklist.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/LatestEvents.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/MarketplaceDetails.tsx
(11 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/NFTDetails.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/PermissionsTable.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/contract-overview-page.client.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/ContractProposalsPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/shared-sources-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/ContractSplitPage.client.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/types.ts
(1 hunks)apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx
(3 hunks)apps/dashboard/src/app/(app)/api/lib/getAuthToken.ts
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx
(3 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx
(5 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/direct-listings/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/english-auctions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account-permissions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/accounts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/analytics/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-conditions/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/code/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/cross-chain/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/events/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/explorer/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/modules/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/[tokenId]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/permissions/page.tsx
(1 hunks)
⛔ Files not processed due to max files limit (11)
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/proposals/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/settings/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/sources/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/split/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/tokens/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/utils.ts
- apps/dashboard/src/components/contract-components/tables/cells.tsx
- apps/dashboard/src/components/contract-components/tables/contract-table.stories.tsx
- apps/dashboard/src/components/contract-components/tables/contract-table.tsx
- apps/dashboard/src/components/smart-wallets/AccountFactories/factory-contracts.tsx
✅ Files skipped from review due to trivial changes (1)
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/types.ts
🚧 Files skipped from review as they are similar to previous changes (95)
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/opengraph-image.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/ContractSplitPage.client.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/contracts/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/AccountSigners.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/ContractEditModulesPage.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/components/nfts-owned.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/ContractProposalsPage.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/BuildYourApp.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/ClaimConditions.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/analytics/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/code/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/Analytics.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/shared-events-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/explorer/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/modules/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account-permissions/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/shared-sources-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/TokenIdPage.client.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/cross-chain/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/events/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/components/accounts-table.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/page.tsx
- apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/contract-overview-page.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/PermissionsTable.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/english-auctions/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/AccountsPage.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractPageSidebarLinks.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/accounts/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/ContractOverviewPage.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-conditions/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/ContractDirectListingsPage.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/LatestEvents.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/shared-code-page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/permissions/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/[tokenId]/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/direct-listings/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/NFTDetails.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/layout.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/NFTCards.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx
- apps/dashboard/src/app/(app)/api/lib/getAuthToken.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/shared-explorer-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/ContractChecklist.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/events-feed.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/table.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/data-table.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/token-id.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/MarketplaceDetails.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/contract-page-path.ts
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx:41-48
Timestamp: 2025-05-26T16:28:50.737Z
Learning: The `projectMeta` prop is not required for the server-rendered `ContractTokensPage` component in the tokens shared page, unlike some other shared pages where it's needed for consistency.
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx:47-52
Timestamp: 2025-05-26T16:29:54.299Z
Learning: The `projectMeta` prop is not required for the server-rendered `ContractDirectListingsPage` component in the direct listings shared page, following the same pattern as other server components in the codebase where `projectMeta` is only needed for client components.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx (2)
Learnt from: MananTank
PR: thirdweb-dev/js#7152
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx:2-10
Timestamp: 2025-05-26T16:28:10.059Z
Learning: In Next.js 14+, the `params` object in page components is always a Promise that needs to be awaited, so the correct typing is `params: Promise<ParamsType>` rather than `params: ParamsType`.
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
🧬 Code Graph Analysis (7)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/page.tsx (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/types.ts (1)
PublicContractPageParams
(1-4)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx (1)
SharedContractSettingsPage
(11-51)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/page.tsx (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/types.ts (1)
PublicContractPageParams
(1-4)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx (1)
SharedNFTPage
(9-56)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/types.ts (1)
PublicContractPageParams
(1-4)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx (1)
SharedDirectListingsPage
(9-53)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/page.tsx (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/types.ts (1)
PublicContractPageParams
(1-4)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx (1)
SharedClaimConditionsPage
(9-59)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/page.tsx (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/types.ts (1)
PublicContractPageParams
(1-4)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx (1)
SharedNFTTokenPage
(11-76)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx (4)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/page.tsx (1)
Page
(4-15)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/types.ts (1)
PublicContractPageParams
(1-4)apps/dashboard/src/app/(app)/account/settings/getAccount.ts (1)
getRawAccount
(11-38)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx (1)
SharedAccountsPage
(9-54)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx (2)
SharedContractLayout
(23-128)generateContractLayoutMetadata
(160-218)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx (1)
generateMetadata
(34-54)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (34)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/page.tsx (4)
2-3
: LGTM: Clean import structureThe imports are well-organized and follow the established pattern seen across other contract pages in the codebase.
6-6
: LGTM: Correct Next.js 13+ app router patternUsing
Promise<PublicContractPageParams>
aligns with the Next.js 13+ app router where params are promises. This is consistent with the pattern used across other contract pages.
8-8
: LGTM: Efficient parallel data fetchingUsing
Promise.all
to fetch params and account data in parallel is a good performance optimization since these are independent operations.
10-16
: LGTM: Proper delegation to shared componentThe component correctly delegates to
SharedClaimConditionsPage
with all required props. The explicitprojectMeta: undefined
is consistent with the pattern for server components as noted in the retrieved learnings. This architectural change successfully moves complex logic (contract validation, metadata checking, conditional rendering) to the shared component, improving maintainability.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx (4)
1-3
: LGTM! Clean import structure.The imports are well-organized and follow the established patterns. The
PublicContractPageParams
type import andSharedDirectListingsPage
component import are appropriate for the refactored architecture.
5-7
: Good use of Promise-based params.The function signature correctly uses
Promise<PublicContractPageParams>
which aligns with Next.js App Router patterns for async route parameters.
8-8
: Excellent concurrent data fetching.Using
Promise.all
to fetch bothparams
andgetRawAccount()
concurrently is a performance optimization that reduces the overall loading time.
10-17
: Clean delegation to shared component.The simplified rendering pattern effectively delegates complex logic to
SharedDirectListingsPage
. SettingprojectMeta={undefined}
is appropriate for server components based on the retrieved learnings, and the props match the expected interface from the shared component.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/page.tsx (4)
2-3
: LGTM: Clean import structure following the new pattern.The imports correctly reference the new type definitions and shared component, aligning with the refactored architecture.
6-6
: LGTM: Proper Next.js 15 pattern with Promise-wrapped params.The component correctly handles the new Next.js 15 pattern where route parameters are wrapped in a Promise, ensuring compatibility with the latest framework conventions.
8-8
: LGTM: Efficient concurrent data fetching.Using
Promise.all
to fetch both params and account data concurrently is a performance optimization that reduces the overall loading time.
11-17
: LGTM: Simplified component following the new architectural pattern.The component correctly delegates complex logic to
SharedNFTPage
while maintaining the required props structure. SettingprojectMeta
toundefined
is consistent with the pattern for server components as noted in the retrieved learnings.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/page.tsx (3)
2-3
: Clean import structure for the refactored architecture.Good use of type imports and the shared component pattern. This follows the established architectural approach across other contract pages in the codebase.
6-8
: Excellent use of concurrent data fetching and proper TypeScript types.The Promise.all approach for fetching both params and account data concurrently is a performance optimization over sequential fetching. The Promise-wrapped params type correctly handles the new parameter structure.
11-17
: Well-structured delegation to shared component.This approach successfully:
- Centralizes complex contract logic in
SharedContractSettingsPage
- Maintains clean separation of concerns
- Correctly sets
projectMeta={undefined}
for this public route (consistent with learned patterns for server-rendered components)- Passes all necessary props for proper rendering
The refactoring improves maintainability while supporting the new team/project context features.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx (3)
2-3
: LGTM! Clean import structure for the refactored implementation.The new imports properly support the simplified page structure by bringing in the required type and shared component.
5-7
: Correct params typing for Next.js 14+.The function signature correctly types
params
asPromise<PublicContractPageParams>
, which aligns with Next.js 14+ behavior where params are always promises.
8-16
: Excellent refactoring that centralizes contract page logic.This implementation follows the established pattern across contract pages:
- Concurrently awaits both
params
and user account data for optimal performance- Delegates all complex logic (contract info fetching, validation, redirects) to
SharedAccountsPage
- Correctly passes
projectMeta
asundefined
for public routes- Converts account to boolean for the
isLoggedIn
propThis refactoring improves maintainability by eliminating code duplication and centralizing contract page behavior.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/page.tsx (3)
1-2
: LGTM! Clean import structure for the refactored analytics page.The imports correctly reference the new type definitions and shared component, aligning with the broader refactoring to centralize contract logic.
4-6
: Good use of proper TypeScript typing.The updated parameter type
PublicContractPageParams
correctly reflects that this is a public contract page (not within a team/project context), which explains whyprojectMeta
will be undefined.
9-13
:✅ Verification successful
Excellent refactoring - complexity moved to shared component.
This is a clean implementation of the refactoring pattern described in the PR objectives. The page now focuses solely on prop passing while the
SharedAnalyticsPage
handles all the complex contract validation, data fetching, and conditional rendering logic that was previously in this file.Setting
projectMeta={undefined}
is appropriate for public contract pages and follows the established pattern from the retrieved learnings.Let me verify that the shared component properly handles the delegated logic:
🏁 Script executed:
#!/bin/bash # Description: Verify the SharedAnalyticsPage component handles the moved contract logic # Expected: The shared component should contain contract validation, data fetching, and error handling cat "apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx"Length of output: 2615
✅ Verification complete: SharedAnalyticsPage correctly handles contract validation, data fetching, and error handling. Approving code changes.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/page.tsx (4)
2-3
: LGTM! Clean import structure for the refactored implementation.The new imports properly support the architectural shift to using shared components and centralized type definitions.
5-11
: Correct implementation of Next.js 15 async params pattern.The Promise wrapper around params properly handles the async nature of route parameters in Next.js 15, and the type intersection correctly extends
PublicContractPageParams
with thetokenId
field.
12-12
: Excellent use of concurrent data fetching.Using
Promise.all
to fetch params and account data concurrently is an optimal performance improvement since these operations are independent.
14-23
: Well-structured delegation to shared component.The implementation correctly:
- Passes all required props to
SharedNFTTokenPage
- Sets
projectMeta
toundefined
(consistent with server component patterns per retrieved learnings)- Uses proper boolean conversion for
isLoggedIn
flag- Follows the established pattern of delegating complex contract logic to shared components
This clean separation of concerns improves maintainability and code reuse across the dashboard.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx (2)
16-23
: LGTM! Clean delegation to shared layout component.The simplified layout effectively delegates complex contract validation, data fetching, and rendering logic to the
SharedContractLayout
component. SettingprojectMeta={undefined}
correctly indicates this route is not within a project context.
33-37
: LGTM! Proper metadata generation delegation.The metadata generation correctly delegates to the shared
generateContractLayoutMetadata
utility, maintaining consistency across different contract page routes.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx (4)
29-31
: LGTM! Proper address validation.The early validation using
isAddress
andnotFound()
correctly handles invalid contract addresses at the entry point.
33-41
: LGTM! Efficient parallel data fetching.The use of
Promise.all
to fetch contract info, authentication status, and teams/projects data in parallel is efficient and follows best practices.
67-75
: LGTM! Well-structured metadata fetching.The parallel fetching of contract validation, page metadata, and header data is efficient and properly structured.
130-158
: LGTM! Robust teams and projects fetching.The helper function properly handles authentication checks, parallel fetching of team projects, and graceful error handling by returning
undefined
on failures.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/page.tsx (1)
1-15
: LGTM! Clean refactor following the established pattern.The implementation correctly follows the refactor pattern mentioned in the PR objectives, where complex contract page logic has been moved to shared components. The page properly awaits route parameters and delegates rendering to
SharedCrossChainPage
with appropriate props.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx (2)
28-32
: LGTM! Well-structured component interface.The component props interface is clean and properly typed with optional
projectMeta
to support both public and project-scoped contract pages.
257-281
: LGTM! Clean component structure and prop passing.The JSX structure is well-organized with clear section separation and proper prop forwarding to the
DataTable
component.
// biome-ignore lint/suspicious/noExplicitAny: FIXME | ||
const decodedData: any = await decodeFunctionData({ | ||
contract: serverContract, | ||
data: initializeData, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove or properly type the any annotation.
The decodedData: any
violates TypeScript best practices. Consider using proper typing or a more specific type assertion.
-// biome-ignore lint/suspicious/noExplicitAny: FIXME
-const decodedData: any = await decodeFunctionData({
+const decodedData: unknown[] = await decodeFunctionData({
contract: serverContract,
data: initializeData,
});
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// biome-ignore lint/suspicious/noExplicitAny: FIXME | |
const decodedData: any = await decodeFunctionData({ | |
contract: serverContract, | |
data: initializeData, | |
}); | |
const decodedData: unknown[] = await decodeFunctionData({ | |
contract: serverContract, | |
data: initializeData, | |
}); |
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx
around lines 212 to 216, the variable decodedData is typed as any, which
violates TypeScript best practices. Replace the any type with a more specific
type that matches the expected structure returned by decodeFunctionData, or
define an appropriate interface/type for decodedData to ensure type safety and
clarity.
PR-Codex overview
This PR focuses on enhancing the contract page functionality by introducing
teamSlug
andprojectSlug
parameters across various components, improving the organization of contract-related pages, and ensuring better integration with team projects.Detailed summary
PublicContractPageParams
andProjectContractPageParams
types.teamSlug
andprojectSlug
.Summary by CodeRabbit
New Features
Refactor
Bug Fixes
Chores