-
Notifications
You must be signed in to change notification settings - Fork 559
[TOOL-4802] NFT Asset Page #7332
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 ↗︎
|
🦋 Changeset detectedLatest commit: 913ea98 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
## Walkthrough
This update introduces a comprehensive NFT Asset Page supporting both NFT Drop Claim (ERC-721) and Edition Drop Claim (ERC-1155). It adds public NFT pages, paginated grid views, token viewers, claim/buy flows, and related UI components. The implementation includes new hooks, utilities, and refactors for displaying pricing, supply progress, and responsive layouts, as well as storybook stories for new components.
## Changes
| Files/Paths (grouped) | Change Summary |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx, .../overview/nfts-grid.tsx, .../overview/tabs.tsx, .../overview/buy-nft-drop/buy-nft-drop-card.client.tsx, .../buy-nft-drop-card.server.tsx, .../buy-nft-drop-ui.client.tsx, .../buy-nft-drop.client.tsx, .../buy-edition-drop/buy-edition-drop.client.tsx, .../token-viewer/token-viewer.tsx, .../nft-page-layout.tsx, .../utils.ts, .../client-utils.ts, .../format.ts | Added and integrated NFT public page components: main page, paginated grid, tabbed navigation, buy/claim flows for ERC-721/1155, token viewer dialog, layout, hooks, utilities, and formatting. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.tsx, .../supply-claimed-progress.stories.tsx | Added supply claimed progress component and Storybook stories. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.stories.tsx | Added Storybook stories for BuyNFTDropUI with multiple claim and pricing scenarios. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop.client.tsx | Added BuyNFTDrop client component, claim logic, and helper functions/types. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.server.tsx | Added server-side logic for buy NFT drop card and claim parameter fetching. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-edition-drop/buy-edition-drop.client.tsx | Added BuyEditionDrop client component for ERC-1155 claims. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx | Added TokenViewerSheet and PageLoadTokenViewerSheet components for token details. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page-layout.tsx | Added NFTPublicPageLayout for consistent layout of NFT public pages. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts | Added utility to get total NFT count for ERC-721/1155. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/client-utils.ts | Added hook for ERC-1155 claim condition and pricing. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/format.ts | Added supplyFormatter for compact number formatting. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx | Added TokenPrice component for displaying formatted price. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx | Refactored: renamed ClaimTokenCardUI to TokenDropClaim, removed local price/supply components, used new TokenPrice and SupplyClaimedProgress. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.stories.tsx, .../erc20.tsx | Updated to use TokenDropClaim instead of ClaimTokenCardUI. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx | Added imageClassName prop for image styling customization. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.stories.tsx | Added Storybook story for supply claimed progress component. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PageHeader.tsx | Added containerClassName prop for header container styling. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts | Refactored public page type detection to support erc721/erc1155, updated type. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx, .../nfts/[tokenId]/shared-nfts-token-page.tsx, .../shared-overview-page.tsx | Integrated new NFT public page logic and routing. |
| apps/dashboard/src/@/components/Responsive.tsx | Added ResponsiveLayout component for device-specific rendering. |
| apps/dashboard/src/@/components/blocks/media-renderer.tsx | Added CustomMediaRenderer component with loading skeleton. |
| apps/dashboard/src/@/components/pagination-buttons.tsx | Enhanced pagination: added className prop, special case for 2 pages. |
| apps/dashboard/src/@/components/blocks/wallet-address.tsx | Added preventOpenOnFocus prop to WalletAddress component. |
| apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx, .../add-to-project-card.stories.tsx | Updated MinimalProject type and story data to include slug property. |
| apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx | Updated contract view link logic to use team/project slugs when available. |
| apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx, .../published-contract/components/uri-based-deploy.tsx | Added slug property to project objects in teamsAndProjects data. |
| packages/thirdweb/src/utils/nft/parseNft.ts | Broadened NFTMetadata properties/attributes fields to allow arrays or objects. |
| apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/cards.tsx | Refactored CardLink tracking and keyboard event logic for consistency. |
| apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/_common/tracking.ts | Changed contractType tracking to "NFTCollection", added ercType field. |
## Sequence Diagram(s)
```mermaid
sequenceDiagram
participant User
participant NFTPublicPage
participant NFTsGrid
participant BuyNFTDropCard
participant BuyNFTDrop
participant TokenViewerSheet
participant ThirdwebContract
User->>NFTPublicPage: Visit NFT asset page
NFTPublicPage->>ThirdwebContract: Fetch metadata, selectors, NFT count
NFTPublicPage->>NFTsGrid: Render NFT grid with contract/type
NFTPublicPage->>BuyNFTDropCard: Render buy/claim UI if available
User->>NFTsGrid: Browse NFTs, select token
NFTsGrid->>TokenViewerSheet: Open token viewer modal
TokenViewerSheet->>ThirdwebContract: Fetch token metadata/details
User->>BuyNFTDropCard: Initiate NFT claim/purchase
BuyNFTDropCard->>BuyNFTDrop: Render claim UI
BuyNFTDrop->>ThirdwebContract: Prepare claim transaction, check approval
BuyNFTDrop->>ThirdwebContract: Execute claim transaction
BuyNFTDrop->>NFTPublicPage: On success, refresh data Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested reviewers
|
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. |
size-limit report 📦
|
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #7332 +/- ##
=======================================
Coverage 55.58% 55.58%
=======================================
Files 909 909
Lines 58683 58683
Branches 4158 4163 +5
=======================================
Hits 32617 32617
Misses 25959 25959
Partials 107 107
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 16
🧹 Nitpick comments (19)
packages/thirdweb/src/utils/nft/parseNft.ts (2)
20-22
: Update accompanying JSDoc / TODO
properties
can now be either a record or an array, but the comment at line 19 (“// TODO check if we truly need both of these?”) still refers to the old single-record assumption.
Consider updating the TODO (or removing it) and expanding the inline docs so future readers know why both shapes are accepted.
32-33
: Add note aboutattributes
shape in documentationThe new union type for
attributes
mirrorsproperties
, but the file-level doc-block doesn’t mention it. A short description (and maybe an example) would prevent confusion for integrators parsing the metadata.apps/dashboard/src/@/components/pagination-buttons.tsx (2)
22-23
: Prop should be documented on the component signature
className
is a welcome addition, but there’s no TSDoc comment explaining what gets applied. A one-liner keeps the public API self-documenting.
74-75
: Avoid duplicatingprops.className
logic
className={props.className}
is repeated in three branches. Consider extracting arootClass = props.className
variable (or just spreading{ ...props }
) to keep all branches consistent.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx (1)
70-83
: Missingalt
attribute on the<Img>
elementScreen-readers will announce this image as an unnamed graphic. Passing an
alt
prop (even an empty string when the image is purely decorative) is considered an accessibility baseline.<Img className={cn( "size-20 shrink-0 rounded-full border bg-muted", props.imageClassName, )} + alt={props.name} src={ ... } ... />
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-embed.client.tsx (1)
5-16
: Stabilise theonSuccess
handlerEvery render recreates the arrow function, causing a prop change on
NFTDropClaimUI
and a potential unnecessary re-render. Wrap it inuseCallback
.-import { useDashboardRouter } from "../../../../../../../../../@/lib/DashboardRouter"; +import { useCallback } from "react"; +import { useDashboardRouter } from "../../../../../../../../../@/lib/DashboardRouter"; ... const router = useDashboardRouter(); + const handleSuccess = useCallback(() => router.refresh(), [router]); ... - <NFTDropClaimUI {...props} onSuccess={() => router.refresh()} /> + <NFTDropClaimUI {...props} onSuccess={handleSuccess} />apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/tabs.tsx (1)
14-30
: Guard againstbuyPage
removal after mountIf
buyPage
becomesnull
after the tab is already set to"buy"
, the component will render nothing.
Consider auto-resetting the tab whenbuyPage
toggles to falsy.-const [tab, setTab] = useState<"nfts" | "buy">("nfts"); +const [tab, setTab] = useState<"nfts" | "buy">( + props.buyPage ? "nfts" : "nfts", +); ... useEffect(() => { if (!props.buyPage && tab === "buy") { setTab("nfts"); } }, [props.buyPage, tab]);apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx (2)
17-21
:loadedData
could leak very large numbers to the UI
compactNumberFormatter
is configured withmaximumFractionDigits: 10
, but no upper bound is set onpriceInTokens
. If the contract returns a value with a very large magnitude (e.g.1e24
wei formatted to tokens), the compact formatter will happily display something like “1e21 ETH”, which is not a usable price for end-users and may break layouts.- : `${compactNumberFormatter.format(props.data.priceInTokens)} ${props.data.symbol}` + : `${compactNumberFormatter.format( + Math.min(props.data.priceInTokens, 1_000_000_000), + )} ${props.data.symbol}`Clamp or round the value (or fall back to scientific notation) before calling
.format
so the UI remains predictable.
36-39
: Reuse a shared formatter instead of recreating it per bundle
Intl.NumberFormat
carries non-trivial instantiation overhead. Consider exporting a singleton from autils/format
module so every price/text component can reuse it instead of creating its own copy.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx (1)
415-432
: Total price calculation is vulnerable to FP roundingMultiplying two JS
Number
s that originated from bigints may introduce floating-point error (e.g.0.1 * 3
=0.30000000000000004
).
Use bigint arithmetic up to the final UI formatting step.- priceInTokens: - Number(toTokens(claimParamsData.pricePerTokenWei, claimParamsData.decimals)) * - Number(quantity), + priceInTokens: Number( + ( + BigInt(claimParamsData.pricePerTokenWei) * + BigInt(quantity) + ).toString() / + 10n ** BigInt(claimParamsData.decimals), + ),Alternatively leverage
ethers.js
formatUnits
&parseUnits
.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts (1)
23-41
: Extension feature gates can be merged for readabilityThree nested
if
s duplicate the same pattern (ERC check +isGetNFTsSupported
).
Consider factoring into a helper to make future additions easier.- if (_supportedERCs.isERC1155 && ERC1155Ext.isGetNFTsSupported(functionSelectors)) { - return { type: "erc1155" }; - } - if (_supportedERCs.isERC721 && ERC721Ext.isGetNFTsSupported(functionSelectors)) { - return { type: "erc721" }; - } + const ercChecks: Array<[boolean, () => boolean, NewPublicPageType]> = [ + [_supportedERCs.isERC1155, () => ERC1155Ext.isGetNFTsSupported(functionSelectors), "erc1155"], + [_supportedERCs.isERC721, () => ERC721Ext.isGetNFTsSupported(functionSelectors), "erc721"], + ]; + for (const [supported, guard, type] of ercChecks) { + if (supported && guard()) return { type }; + }No functional change, but the intent becomes clearer.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/edition-drop-claim.tsx (1)
351-355
:decimals
prop is unused
SupplyRemaining
receivesdecimals
but never references it, creating dead-code noise and misleading callers.Either remove the parameter or implement formatting that actually needs it.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nft-drop-claim.tsx (1)
512-516
: Unuseddecimals
parameter inSupplyRemaining
The component never touches
decimals
; drop the prop to keep the API minimal.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts (1)
92-99
: Minor:publicPrice
can reuse the fetched meta data
claimConditionQuery.data
already containsdecimals
andsymbol
; cloning those fields intopublicPrice
is fine but costs an unnecessary object allocation every render.
Consider memoising or just re-exportingclaimConditionQuery.data
to keep the hook light.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-embed.tsx (1)
11-24
:async
keyword is redundant here
NFTDropClaimEmbed
never awaits, so the function always returns a resolvedPromise<JSX.Element>
.
Unless you intentionally rely on React’s Server Components to stream the result, you can drop theasync
keyword to avoid an unnecessary micro-task and type widening.-export async function NFTDropClaimEmbed(props: { /* … */ }) { +export function NFTDropClaimEmbed(props: { /* … */ }) {apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx (2)
150-167
: Extractattributes
withuseMemo
to avoid repeated parsing
getAttributes
is called on every render – even while the dialog is open but nothing changes.
Parsing large metadata arrays repeatedly can be surprisingly expensive on mobile devices.- const attributes = props.data ? getAttributes(props.data) : []; + const attributes = useMemo( + () => (props.data ? getAttributes(props.data) : []), + [props.data], + );
109-122
: Error message conflates “not found” with all other errors
nftQuery.isError
fires for network errors, RPC issues, and user-rejected requests, yet the dialog always says “No NFT found”.
Consider inspectingnftQuery.error
and showing a generic fallback or the actual error message.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx (2)
170-176
: Loading skeleton count drifts frompageSize
NFTGridSkeleton
renders 50 placeholders while the actual page size is 48.
Keeping them in sync prevents layout shifts.- {Array.from({ length: 50 }).map((_, idx) => ( + {Array.from({ length: pageSize }).map((_, idx) => (
318-327
:supplyClaimed
may beundefined
during skeleton renderWhen data hasn’t arrived yet the JSX prints “undefined of … tokens bought”.
Guard the value or fall back to a skeleton placeholder.- {claimConditionQuery.data?.supplyClaimed} of{" "} + {(claimConditionQuery.data?.supplyClaimed ?? "—")} of{" "}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
apps/dashboard/src/@/components/Responsive.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/wallet-address.tsx
(2 hunks)apps/dashboard/src/@/components/pagination-buttons.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PageHeader.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-embed.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-embed.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/edition-drop-claim.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nft-drop-claim.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/tabs.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts
(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
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/uri-based-deploy.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx
(1 hunks)packages/thirdweb/src/utils/nft/parseNft.ts
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (10)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts (1)
shouldRenderNewPublicPage
(9-53)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/utils.ts (1)
redirectToContractLandingPage
(6-18)
apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx (1)
apps/dashboard/src/@/api/projects.ts (1)
Project
(6-6)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx (1)
NFTPublicPage
(19-138)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts (1)
shouldRenderNewPublicPage
(9-53)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx (1)
NFTPublicPage
(19-138)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/tabs.tsx (1)
apps/dashboard/src/@/components/ui/tabs.tsx (1)
TabButtons
(85-159)
apps/dashboard/src/@/components/Responsive.tsx (1)
apps/dashboard/src/components/ClientOnly/ClientOnly.tsx (1)
ClientOnly
(18-43)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_utils/getCurrencyMeta.ts (1)
getCurrencyMeta
(8-44)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx (1)
TokenPrice
(3-34)packages/thirdweb/src/exports/thirdweb.ts (1)
toTokens
(190-190)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/edition-drop-claim.tsx (6)
packages/thirdweb/src/exports/thirdweb.ts (2)
ThirdwebContract
(71-71)toTokens
(190-190)apps/dashboard/src/hooks/analytics/useTrack.ts (1)
useTrack
(13-45)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts (2)
useERC1155ClaimCondition
(46-153)ASSET_PAGE_ERC1155_QUERIES_ROOT_KEY
(44-44)apps/dashboard/src/utils/errorParser.tsx (1)
parseError
(29-69)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx (1)
TokenPrice
(3-34)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PublicPageConnectButton.tsx (1)
PublicPageConnectButton
(11-40)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-embed.tsx (3)
packages/thirdweb/src/exports/thirdweb.ts (1)
ThirdwebContract
(71-71)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-embed.client.tsx (1)
NFTDropClaimEmbedUI
(5-16)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_utils/getCurrencyMeta.ts (1)
getCurrencyMeta
(8-44)
⏰ Context from checks skipped due to timeout of 90000ms (8)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: Unit Tests
- GitHub Check: Build Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (16)
apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx (1)
46-51
:slug
addition looks correct – thanks for keeping the stub in sync
No functional issues spotted.apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/uri-based-deploy.tsx (1)
42-47
: Verify thatgetProjects()
always returnsslug
slug: x.slug
assumes the REST/GraphQL response already contains this field. If any existing environment still omitsslug
, this will explode at runtime withundefined
paths.- slug: x.slug, + slug: x.slug ?? "", // defensive defaultor add a runtime guard / type-level guarantee.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx (1)
170-175
: Same runtime guarantee concern forslug
Ifx.slug
can benull
/undefined
, links further downstream will render/team/foo//contract/...
, breaking navigation.Consider asserting presence early or filtering out projects lacking a slug.
apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx (1)
22-24
: Type extension approved
MinimalProject
now mirrors the backend contract. Good catch keeping the pick list in one place.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx (1)
6-6
: Import path checkThe helper lives in
../_utils/newPublicPage
, but we already import other helpers from the same folder using the same pattern. Good catch keeping paths consistent.apps/dashboard/src/@/components/blocks/wallet-address.tsx (2)
27-28
: Nice quality-of-life prop
preventOpenOnFocus
solves the common UX annoyance when tabbing through the page—good addition.
68-71
: Consider forwarding the prop downstreamEven with
tabIndex={-1}
, the nested<Button>
is still focusable and may reopen the card on key events depending on Radix behaviour.
If that proves noisy, you might need to forward the prop toHoverCard
’sopenDelay
or addonFocus={(e)=>e.preventDefault()}
at the trigger layer.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PageHeader.tsx (2)
7-17
: LGTM – flexible container classesAllowing
containerClassName
gives downstream layouts breathing room without cloning this component. Implementation looks correct.
20-21
: Minor visual tweak acknowledgedLogo height change from
h-6
toh-5
is non-breaking and keeps vertical rhythm tighter.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx (1)
44-45
: Prop addition looks goodIntroducing
imageClassName
as an optional prop keeps the component backwards-compatible while allowing style overrides.
No issues spotted.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx (1)
104-115
: Support for ERC-721 / ERC-1155 public pages added correctlyThe new switch branch cleanly re-uses
NFTPublicPage
; type-safety is preserved andtokenId
is sensibly set toundefined
.
No further action required.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx (1)
45-59
: Public token page routing logic is solidThe additional branch neatly defers to
NFTPublicPage
for ERC-721/1155 contracts when no project metadata is present. Good defensive check onshouldRenderNewPublicPage
.apps/dashboard/src/@/components/Responsive.tsx (1)
18-23
: Potential double evaluation ofuseIsMobile
useIsMobile()
runs before we know whether we are on the client (because it is outsideClientOnly
).
If the hook internally toucheswindow
during SSR, hydration warnings or runtime exceptions may surface.Verify that
useIsMobile
is SSR-safe (i.e. guards everywindow
/matchMedia
access with atypeof window !== "undefined"
check).apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx (1)
126-133
: GuardBigInt
parsing oftokenId
BigInt(props.tokenId)
will throw iftokenId
is not a valid integer (e.g. query param tampering).Add a safe parse with try/catch or pre-validate via
/^\d+$/
.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-embed.tsx (1)
52-66
: Verify the meaning oferc721NextTokenIdToClaim
erc721NextTokenIdToClaim
is populated withERC721Ext.getTotalClaimedSupply
.
If the intention is to surface the next token id (often ≙ claimed supply, but not always, e.g. when tokens are burned), consider switching toERC721Ext.nextTokenIdToClaim
for clarity:- ERC721Ext.getTotalClaimedSupply({ + ERC721Ext.nextTokenIdToClaim({Please double-check the SDK semantics to ensure the UI shows an accurate next-id.
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx (1)
51-52
: Potential overflow convertingBigInt
toNumber
Math.ceil(Number(props.totalNFTCount) / pageSize)
silently loses precision for collections larger than ≈9 quadrillion tokens.
While unlikely, usingBigInt
throughout avoids foot-guns:- const totalPages = Math.ceil(Number(props.totalNFTCount) / pageSize); + const totalPages = Number( + (props.totalNFTCount + BigInt(pageSize) - 1n) / BigInt(pageSize), + );
apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx
Show resolved
Hide resolved
...ard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
Show resolved
Hide resolved
...pp)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PageHeader.tsx
Outdated
Show resolved
Hide resolved
...dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nft-drop-claim.tsx
Outdated
Show resolved
Hide resolved
...ard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts
Outdated
Show resolved
Hide resolved
...ard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts
Outdated
Show resolved
Hide resolved
...shboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx
Outdated
Show resolved
Hide resolved
...pp)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx
Show resolved
Hide resolved
1c2a044
to
324a08e
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: 0
♻️ Duplicate comments (7)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts (2)
54-61
: 🛠️ Refactor suggestionUnstable React-Query cache keys — still embedding full contract objects
Prior review already covered this.
params.contract
is still stored inside both query keys, making the key identity change whenever a new signer recreates the SDK instance and blowing away the cache.
Use a stable primitive (address and optionally chain id) instead.- { - contract: params.contract, + { + contractAddress: params.contract.address,Apply the same change to the
claimParamsQuery
key (lines 102-110).Also applies to: 102-110
101-139
: 🛠️ Refactor suggestion
claimParamsQuery
still fires unconditionallyThe query is mounted even when
params.enabled
is false or whileclaimConditionQuery
is still loading, causing an avoidable extra RPC round-trip.
Prior review already highlighted this – add anenabled
guard that mirrors the first query:const claimParamsQuery = useQuery({ queryKey: [/* … */], queryFn: async () => { /* … */ }, - }); + enabled: params.enabled && (!!publicPrice || !!account), + });apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx (1)
284-286
:⚠️ Potential issueDuplicate React keys risk runtime warnings & incorrect diffing
Using only
attribute.trait_type
as a React key will collide when multiple traits share the same name (e.g. two “color” traits).
Generate a stable per-element key.- {attributes.map((attribute) => ( - <TraitCard key={attribute.trait_type} {...attribute} /> - ))} + {attributes.map((attribute, idx) => ( + <TraitCard key={`${attribute.trait_type}-${idx}`} {...attribute} /> + ))}apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/edition-drop-claim.tsx (2)
94-98
:⚠️ Potential issueIncorrect
contractType
sent to analytics – still hard-coded
contractType
is hard-coded as"DropERC20"
but this component handles an ERC-1155 Edition Drop. Analytics will be mis-categorised.- contractType: "DropERC20", + contractType: "EditionDrop",
149-160
:⚠️ Potential issueAbort flow on failed approval
If
approveTxPromise
rejects, execution still proceeds to the claim transaction, almost guaranteeing a revert and double toast noise.
Return early (or wrap claim inside the sametry
) after tracking the error.} catch (err) { const errorMessage = parseError(err); trackAssetBuy({ type: "error", errorMessage: typeof errorMessage === "string" ? errorMessage : "Unknown error", }); + return; // stop – approval failed }
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nft-drop-claim.tsx (2)
173-178
:⚠️ Potential issueAnalytics mis-categorisation
contractType
again reports"DropERC20"
inside an ERC-721 drop component. Use the proper type ("NFTDrop"
or similar) so downstream dashboards remain accurate.- contractType: "DropERC20", + contractType: "NFTDrop",
234-244
:⚠️ Potential issueContinue-on-error after failed approval
Same logical flaw as in the ERC-1155 component: if approval fails, the claim still fires. Insert an early
return
.} catch (err) { const errorMessage = parseError(err); trackAssetBuy({ type: "error", errorMessage: typeof errorMessage === "string" ? errorMessage : "Unknown error", }); + return; // abort – approval failed }
🧹 Nitpick comments (4)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts (4)
3-6
: Avoid star-imports from large extension packages to reduce bundle size
import * as ERC721Ext
andERC1155Ext
will pull every export from the extension packages into the bundle, even though you only needisGetNFTsSupported
. Tree-shaking of* as
namespaces is unreliable with some bundlers.-import * as ERC721Ext from "thirdweb/extensions/erc721"; -import * as ERC1155Ext from "thirdweb/extensions/erc1155"; +import { isGetNFTsSupported as isERC721GetNFTsSupported } from "thirdweb/extensions/erc721"; +import { isGetNFTsSupported as isERC1155GetNFTsSupported } from "thirdweb/extensions/erc1155";Update the usages accordingly:
- _supportedERCs.isERC1155 && ERC1155Ext.isGetNFTsSupported(functionSelectors) + _supportedERCs.isERC1155 && isERC1155GetNFTsSupported(functionSelectors)and
- _supportedERCs.isERC721 && ERC721Ext.isGetNFTsSupported(functionSelectors) + _supportedERCs.isERC721 && isERC721GetNFTsSupported(functionSelectors)
7-8
: Add a default/never
branch to future-proof the union type
NewPublicPageType
is now a closed union. Consider adding an exhaustive check (e.g. in aswitch
) or anever
fallback wherever you consume this type so TypeScript will alert you when a new token standard is added.
21-22
: Drop the leading underscore for consistencyLocal variables are camel-cased elsewhere in the codebase (
functionSelectors
). Renaming_supportedERCs
tosupported
(or similar) keeps naming conventions consistent and removes the unused private-like prefix.
43-47
: Minor: guard clause can exit earlierFor slight readability, consider converting the final ERC-20 check into a guard clause at the top (after computing
supportedERCs
) so the positive paths are short-circuited and the defaultreturn false
sits at the bottom without nestedif
s.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
apps/dashboard/src/@/components/Responsive.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/wallet-address.tsx
(2 hunks)apps/dashboard/src/@/components/pagination-buttons.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PageHeader.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx
(4 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-embed.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-embed.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/edition-drop-claim.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nft-drop-claim.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/tabs.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts
(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
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/uri-based-deploy.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx
(1 hunks)packages/thirdweb/src/utils/nft/parseNft.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (22)
- apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx
- apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/uri-based-deploy.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]/shared-layout.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]/public-pages/_components/PageHeader.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.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]/public-pages/nft/overview/buy-nft-embed.client.tsx
- apps/dashboard/src/@/components/blocks/wallet-address.tsx
- apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx
- apps/dashboard/src/@/components/pagination-buttons.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/tabs.tsx
- apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx
- apps/dashboard/src/@/components/Responsive.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page-layout.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-embed.tsx
- packages/thirdweb/src/utils/nft/parseNft.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/edition-drop-claim.tsx (6)
packages/thirdweb/src/exports/thirdweb.ts (2)
ThirdwebContract
(71-71)toTokens
(190-190)apps/dashboard/src/hooks/analytics/useTrack.ts (1)
useTrack
(13-45)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts (2)
useERC1155ClaimCondition
(46-153)ASSET_PAGE_ERC1155_QUERIES_ROOT_KEY
(44-44)apps/dashboard/src/utils/errorParser.tsx (1)
parseError
(29-69)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx (1)
TokenPrice
(3-34)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PublicPageConnectButton.tsx (1)
PublicPageConnectButton
(11-40)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts (2)
packages/thirdweb/src/exports/thirdweb.ts (1)
ThirdwebContract
(71-71)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_utils/getCurrencyMeta.ts (1)
getCurrencyMeta
(8-44)
⏰ Context from checks skipped due to timeout of 90000ms (8)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Unit Tests
- GitHub Check: Build Packages
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts (1)
23-41
: Verify behaviour when a contract advertises multiple standardsA single contract can technically expose both ERC-721 and ERC-1155 interfaces (e.g. multi-token wrappers). With the current ordering, such a contract will always be treated as
erc1155
because that check appears first.Please confirm that this precedence is intentional; otherwise, add explicit disambiguation logic or allow the caller to decide.
if (_supportedERCs.isERC1155 && _supportedERCs.isERC721) { // decide which page to show or surface a selector to the user }
324a08e
to
b8c6679
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
🧹 Nitpick comments (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx (2)
320-326
: Still possible to generate duplicate React keysUsing
trait_type
andvalue
drastically reduces the likelihood of clashes, yet duplicates are still possible whenever an NFT has the same trait/value pair repeated (seen in some collections that encode rarity weight).
Relying on deterministic data for keys can silently break React reconciliation.- {attributes.map((attribute) => ( - <TraitCard - key={`${attribute.trait_type}-${attribute.value}`} - ... - ))} + {attributes.map((attribute, idx) => ( + <TraitCard + key={`${attribute.trait_type}-${attribute.value}-${idx}`} + ... + ))}
157-164
: Recompute-heavy values not memoised
attributes
andisClaimable
are recalculated on every re-render. Wrapping them inuseMemo
(anduseMemo
on the BigInt comparison) will avoid unnecessary work when parent state toggles (e.g. during claim mutations).Not critical but improves perf in large grids.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (40)
.changeset/red-cooks-juggle.md
(1 hunks)apps/dashboard/src/@/components/Responsive.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/media-renderer.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/wallet-address.tsx
(2 hunks)apps/dashboard/src/@/components/pagination-buttons.tsx
(3 hunks)apps/dashboard/src/@/constants/server-envs.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PageHeader.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.stories.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.stories.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/client-utils.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/format.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-edition-drop/buy-edition-drop.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.server.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.stories.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/tabs.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts
(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
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/uri-based-deploy.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/cards.tsx
(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/_common/tracking.ts
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx
(1 hunks)packages/thirdweb/src/utils/nft/parseNft.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (39)
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/format.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
- apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/uri-based-deploy.tsx
- apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx
- apps/dashboard/src/@/constants/server-envs.ts
- .changeset/red-cooks-juggle.md
- packages/thirdweb/src/utils/nft/parseNft.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/_common/tracking.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.stories.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]/public-pages/_components/PageHeader.tsx
- apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/tabs.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/cards.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx
- apps/dashboard/src/@/components/blocks/wallet-address.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.stories.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page-layout.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/client-utils.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx
- apps/dashboard/src/@/components/Responsive.tsx
- apps/dashboard/src/@/components/blocks/media-renderer.tsx
- apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx
- apps/dashboard/src/@/components/pagination-buttons.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-edition-drop/buy-edition-drop.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.server.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.stories.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx
⏰ Context from checks skipped due to timeout of 90000ms (8)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Build Packages
- GitHub Check: Lint Packages
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx (1)
165-169
:Available For Purchase
message may be misleading for ERC-721
isClaimable
logic only applies to ERC-1155. For ERC-721 the UI labels every ownerless token as “Available For Purchase”, even though the contract may not implement marketplace/sale logic. Consider:
- Querying a sales module / marketplace extension when present.
- Hiding the banner unless price or listing information can be fetched.
This prevents confusing users with a CTA that might not exist.
Also applies to: 251-269
...shboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx
Show resolved
Hide resolved
417b970
to
a50d520
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: 0
♻️ Duplicate comments (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/client-utils.ts (1)
19-26
: React-Query key still embeds the wholecontract
objectNon-serialisable objects in a query key break referential equality and will miss cache hits between renders. Pass stable primitives (address + chain id) instead.
- { - contract: params.contract, - tokenId: params.tokenId.toString(), - }, + { + contractAddress: params.contract.address, + chainId: params.contract.chain.id, + tokenId: params.tokenId.toString(), + },Also applies to: 67-75
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx (2)
55-55
:Number(totalNFTCount)
can lose precision for big collectionsBigints beyond 2^53-1 silently truncate. Keep the maths in bigint and cast only the final page count.
200-215
:role="button"
declared even when card isn’t clickableScreen readers announce every card as a button, but without
onClick
it’s not operable—accessibility mismatch. Makerole
conditional liketabIndex
.
🧹 Nitpick comments (2)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/client-utils.ts (2)
57-65
: Duplicate price-mapping logic – extract helper
publicPriceData
is built twice with identical code. Consolidating this in a small util (or at least auseMemo
) removes repetition and keeps future refactors DRY.Also applies to: 107-114
66-76
: SkipclaimParamsQuery
when no connected wallet
enabled
ignoresaccount
, so the query fires (and instantly returnsnull
) on every rerender until a wallet connects—unnecessary work and noise in React-Query DevTools.-enabled: params.enabled, +enabled: params.enabled && !!account,Also applies to: 77-80, 104-105
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (40)
.changeset/red-cooks-juggle.md
(1 hunks)apps/dashboard/src/@/components/Responsive.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/media-renderer.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/wallet-address.tsx
(2 hunks)apps/dashboard/src/@/components/pagination-buttons.tsx
(3 hunks)apps/dashboard/src/@/constants/server-envs.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PageHeader.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.stories.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.stories.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/client-utils.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/format.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-edition-drop/buy-edition-drop.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.server.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.stories.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/tabs.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts
(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
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/uri-based-deploy.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/cards.tsx
(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/_common/tracking.ts
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx
(1 hunks)packages/thirdweb/src/utils/nft/parseNft.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (38)
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
- .changeset/red-cooks-juggle.md
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.stories.tsx
- apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/uri-based-deploy.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.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]/public-pages/nft/format.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/_common/tracking.ts
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/cards.tsx
- apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx
- packages/thirdweb/src/utils/nft/parseNft.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PageHeader.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx
- apps/dashboard/src/@/components/pagination-buttons.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/tabs.tsx
- apps/dashboard/src/@/components/blocks/wallet-address.tsx
- apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx
- apps/dashboard/src/@/components/blocks/media-renderer.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page-layout.tsx
- apps/dashboard/src/@/components/Responsive.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-edition-drop/buy-edition-drop.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx
- apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.stories.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx
- apps/dashboard/src/@/constants/server-envs.ts
- 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]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.stories.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.server.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx
🧰 Additional context used
🧠 Learnings (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx (2)
Learnt from: MananTank
PR: thirdweb-dev/js#7332
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx:347-351
Timestamp: 2025-06-13T21:59:58.910Z
Learning: Intl.NumberFormat.prototype.format supports bigint values in modern JavaScript (ES2020+), so bigint values can be passed directly to formatter.format() without conversion to number.
Learnt from: MananTank
PR: thirdweb-dev/js#7332
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx:347-351
Timestamp: 2025-06-13T21:59:58.910Z
Learning: Intl.NumberFormat.prototype.format supports bigint values in modern JavaScript (ES2020+), so bigint values can be passed directly to formatter.format() without conversion to number.
⏰ Context from checks skipped due to timeout of 90000ms (7)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Size
- GitHub Check: Unit Tests
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
Merge activity
|
<!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on enhancing the handling of NFTs and contract components within the application, including updates to types, UI components, and functionality related to NFT collections and claims. ### Detailed summary - Updated `NFTMetadata` type to include `slug`. - Added `slug` property in various components. - Introduced `supplyFormatter` for better NFT supply formatting. - Changed contract type handling to `NFTCollection`. - Enhanced `MinimalProject` type to include `slug`. - Updated UI components for better user interaction. - Improved pagination and NFT display logic. - Added new utilities for NFT claim conditions and total counts. - Refactored claim token UI to utilize new components and structures. - Implemented responsive layouts for better mobile support. > The following files were skipped due to too many changes: `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.client.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.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** - Introduced public NFT pages for ERC-721 and ERC-1155 contracts with responsive layouts, NFT grids, token viewer dialogs, and buy functionality. - Added components for token price display, supply claimed progress, and enhanced pagination controls. - Enabled NFT purchases from drops with dedicated UI and transaction handling for ERC-721 and ERC-1155 standards. - Added tabbed navigation for public NFT pages and improved media rendering with loading placeholders. - Introduced a responsive layout component for device-specific rendering and customizable wallet address focus behavior. - Added new components for buying NFTs and editions with form validation, pricing display, and transaction feedback. - Added a token price component with loading skeleton and strikethrough styling. - Added a supply claimed progress bar with detailed percentage display. - Introduced a token viewer dialog with dynamic data fetching and rich metadata display. - Added a paginated NFT grid with detailed claim condition info for ERC-1155 tokens. - Added buy NFT drop card components with server and client rendering support. - Added a custom media renderer component with loading state management. - **Enhancements** - Improved contract and page header components with customizable styling options. - Expanded project and team data structures to include project slugs for better navigation. - Updated wallet address and pagination components with additional props for accessibility and styling. - Refined tracking of click and keyboard events for asset cards. - Simplified purchase UI code by delegating price and supply display to shared components. - Enhanced pagination to handle two-page scenarios with simplified controls. - Updated public page rendering logic to support multiple ERC standards with unified detection. - Improved purchase flows with analytics tracking and toast notifications. - Added support for special user pricing and dynamic claim condition fetching. - **Bug Fixes** - Fixed conditional rendering and redirection logic for public NFT pages based on contract type and metadata presence. - **Documentation** - Added Storybook stories for new UI components including supply claimed progress and NFT drop purchase flows. - **Refactor** - Delegated price and supply display logic to shared components for consistency. - Updated types and props to support new features and improve maintainability. - **Chores** - Broadened NFT metadata field types for improved compatibility with diverse data formats. - Added fallback for React experimental API to prevent errors in unsupported environments. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
a50d520
to
913ea98
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 (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx (1)
377-414
: Numeric/boolean attribute values are still silently skippedThe safeguard keeps the exact logic that was previously flagged and therefore continues to ignore non-string
value
s coming from on-chain metadata (numbers, booleans, nullables), so those traits never appear in the UI.
Convert everything toString(attribute.value)
(array branch) /String(nft.metadata.attributes[key])
(object branch) instead of filtering them out.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/client-utils.ts (2)
19-26
: Avoid embedding non-serialisable objects in React-Query keys
params.contract
is a live object; a new instance is passed on every render, breaking referential equality and cache hits. Use stable primitives such asparams.contract.address
andparams.contract.chain.id
instead.- { - contract: params.contract, - tokenId: params.tokenId.toString(), - }, + { + contractAddress: params.contract.address, + chainId: params.contract.chain.id, + tokenId: params.tokenId.toString(), + },
67-75
: Same key-stability issue as above forERC1155_getClaimParams
queryPlease apply the same primitive-only pattern here to keep cache behaviour predictable.
🧹 Nitpick comments (3)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx (2)
320-327
: React key may still collide for duplicate traits
key={
${attribute.trait_type}-${attribute.value}}
reduces the risk but does not remove it – duplicate metadata entries with identicaltrait_type
andvalue
will still clash. The safest low-cost fix is to suffix theindex
:- {attributes.map((attribute) => ( - <TraitCard - key={`${attribute.trait_type}-${attribute.value}`} - ... - /> - ))} + {attributes.map((attribute, idx) => ( + <TraitCard + key={`${attribute.trait_type}-${attribute.value}-${idx}`} + ... + /> + ))}
157-164
: Repeated re-parsing of attributes on every render
getAttributes
is called on each render ofTokenInfoUI
, even whennft
hasn’t changed. Wrapping the call inuseMemo
keyed byprops.data
keeps renders cheap, especially for NFTs with many traits.- const attributes = props.data ? getAttributes(props.data) : []; + const attributes = React.useMemo( + () => (props.data ? getAttributes(props.data) : []), + [props.data], + );apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/client-utils.ts (1)
57-65
: Duplicate price-mapping logic – factor out to a helperThe blocks that map
claimConditionQuery.data
into{ pricePerTokenWei, … }
are duplicated. Consolidating them into a small helper will reduce maintenance overhead and the risk of inconsistent changes.Also applies to: 107-114
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (40)
.changeset/red-cooks-juggle.md
(1 hunks)apps/dashboard/src/@/components/Responsive.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/media-renderer.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/wallet-address.tsx
(2 hunks)apps/dashboard/src/@/components/pagination-buttons.tsx
(3 hunks)apps/dashboard/src/@/constants/server-envs.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PageHeader.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.stories.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.stories.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx
(5 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/client-utils.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/format.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-edition-drop/buy-edition-drop.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.server.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.stories.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop.client.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/tabs.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/token-viewer/token-viewer.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts
(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
(2 hunks)apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/uri-based-deploy.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/cards.tsx
(2 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/_common/tracking.ts
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx
(1 hunks)apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx
(1 hunks)packages/thirdweb/src/utils/nft/parseNft.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (38)
- apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.stories.tsx
- .changeset/red-cooks-juggle.md
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/format.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.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]/nfts/shared-nfts-page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/_common/tracking.ts
- apps/dashboard/src/components/contract-components/contract-deploy-form/add-to-project-card.tsx
- packages/thirdweb/src/utils/nft/parseNft.ts
- apps/dashboard/src/@/constants/server-envs.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.stories.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/PageHeader.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]/public-pages/erc20/_components/ContractHeader.tsx
- apps/dashboard/src/@/components/blocks/wallet-address.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page-layout.tsx
- apps/dashboard/src/@/components/pagination-buttons.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/published-contract/components/uri-based-deploy.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/token-price.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/_components/supply-claimed-progress.stories.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/utils.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/tabs.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/cards.tsx
- apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/newPublicPage.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.client.tsx
- apps/dashboard/src/@/components/blocks/media-renderer.tsx
- apps/dashboard/src/@/components/Responsive.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-ui.stories.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/nft-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop-card.server.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-nft-drop/buy-nft-drop.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/buy-edition-drop/buy-edition-drop.client.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nfts-grid.tsx
⏰ Context from checks skipped due to timeout of 90000ms (8)
- GitHub Check: Build Packages
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Lint Packages
- GitHub Check: Unit Tests
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Analyze (javascript)
PR-Codex overview
This PR focuses on enhancing the NFT and ERC20 functionalities within the dashboard, improving type definitions, and refining components for better usability and integration.
Detailed summary
NFTMetadata
type to includeslug
.slug
property in several components.supplyFormatter
for consistent supply formatting.BuyNFTDrop
andTokenDropClaim
components for better NFT purchase handling.ClaimTokenCardUI
to useSupplyClaimedProgress
andTokenPrice
.NFTPublicPage
and layout components for better organization.Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Documentation
Refactor
Chores