@medialane/ui 0.306.0 → 0.308.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/asset-card.cjs +3 -0
- package/dist/components/asset-card.cjs.map +1 -1
- package/dist/components/asset-card.d.cts +2 -1
- package/dist/components/asset-card.d.ts +2 -1
- package/dist/components/asset-card.js +3 -0
- package/dist/components/asset-card.js.map +1 -1
- package/dist/components/asset-page.cjs +2 -10
- package/dist/components/asset-page.cjs.map +1 -1
- package/dist/components/asset-page.js +2 -10
- package/dist/components/asset-page.js.map +1 -1
- package/dist/components/collection-page.cjs +5 -3
- package/dist/components/collection-page.cjs.map +1 -1
- package/dist/components/collection-page.js +5 -3
- package/dist/components/collection-page.js.map +1 -1
- package/dist/components/launchpad/single-edition-mint.cjs +14 -4
- package/dist/components/launchpad/single-edition-mint.cjs.map +1 -1
- package/dist/components/launchpad/single-edition-mint.js +14 -4
- package/dist/components/launchpad/single-edition-mint.js.map +1 -1
- package/dist/components/soulbound-card.cjs +24 -17
- package/dist/components/soulbound-card.cjs.map +1 -1
- package/dist/components/soulbound-card.d.cts +4 -5
- package/dist/components/soulbound-card.d.ts +4 -5
- package/dist/components/soulbound-card.js +25 -19
- package/dist/components/soulbound-card.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/collection-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState, type ComponentType, type ReactNode } from \"react\";\nimport { Inbox, Lock, Sparkles, Ticket } from \"lucide-react\";\nimport { assetHref, getService, type ApiCollection, type ApiOrder, type ApiToken, type Chain, type CollectionTokensSort } from \"@medialane/sdk\";\nimport Link from \"./link.js\";\nimport { AssetCard, AssetCardSkeleton } from \"./asset-card.js\";\nimport { CollectionHeader } from \"./collection-header.js\";\nimport { CollectionFiltersDialog, CollectionActiveFilters } from \"./collection-filters-dialog.js\";\nimport { MoreMenu } from \"./more-menu.js\";\nimport { EXPLORER_URL } from \"../utils/explorer-url.js\";\nimport { CollectionProvenanceTab } from \"./collection-provenance-tab.js\";\nimport { ClubOwnerActions } from \"./club-owner-actions.js\";\nimport { OwnerSetupPanel } from \"./owner-setup-panel.js\";\nimport { TransferCollectionOwnership } from \"./transfer-collection-ownership.js\";\nimport { HiddenContentBanner } from \"./hidden-content-banner.js\";\nimport { ListingCard, ListingCardSkeleton } from \"./listing-card.js\";\nimport { ListingCardMenu } from \"./listing-card-menu.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { MakeOfferPicker } from \"./make-offer-picker.js\";\nimport { OrderSortControl, sortOrders, type OrderSort } from \"./order-sort-control.js\";\nimport { GatedContentHero, GatedContentPanel, type GatedContentState } from \"./gated-content.js\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"./tabs.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { ReportDialog } from \"./report-dialog.js\";\nimport { useCollection, useCollectionTokens } from \"../utils/use-collections.js\";\nimport { useOrders } from \"../utils/use-orders.js\";\nimport { useCollectionProfile } from \"../utils/use-profiles.js\";\nimport { useUsdPrices, usdPriceFor } from \"../utils/use-usd-prices.js\";\nimport { formatUsd } from \"../utils/format.js\";\nimport { isSameAddress } from \"../utils/same-address.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\n\nexport interface CollectionMarketActions {\n buy: (order: ApiOrder) => void;\n offer: (token: ApiToken) => void;\n dialogs: ReactNode;\n}\n\nexport interface CollectionPageSlots {\n useMarketActions: () => CollectionMarketActions;\n useGatedContent: (contract: string | undefined) => GatedContentState;\n ServiceAction: ComponentType<{ service: string | null | undefined; contractAddress: string }>;\n}\n\nconst PAGE_SIZE = 24;\nconst GRID = \"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-3 sm:gap-4\";\n\nconst MINT_HREFS: Partial<Record<string, (contract: string) => string>> = {\n \"mip-erc721\": () => \"/launchpad/single-editions\",\n \"mip-erc1155\": (c) => `/launchpad/nfteditions/${c}/mint`,\n \"ip-tickets\": (c) => `/launchpad/tickets/${c}/mint`,\n \"ip-club\": (c) => `/launchpad/club/${c}/mint`,\n};\n\n/** Ownership transfer exists from the audited v3 collection registry (2026-05-14) on. */\nexport function canTransferCollectionOwnership(collection: ApiCollection): boolean {\n return !!collection.collectionId && collection.standard === \"ERC721\" && collection.createdAt >= \"2026-05-14\";\n}\n\nfunction usdFor(order: ApiOrder | undefined, prices: ReturnType<typeof useUsdPrices>): string | null {\n const currency = order?.price?.currency?.toUpperCase();\n const amount = order?.price?.formatted ? parseFloat(order.price.formatted) : NaN;\n const rate = currency ? usdPriceFor(prices, currency) : undefined;\n return rate == null || isNaN(amount) ? null : formatUsd(amount * rate);\n}\n\nfunction EmptyState({ title, body, action }: { title: string; body: string; action?: { href: string; label: string } }) {\n return (\n <div className=\"py-20 flex flex-col items-center gap-3 text-center\">\n <Inbox className=\"h-10 w-10 text-muted-foreground/40\" />\n <p className=\"text-sm font-medium text-muted-foreground\">{title}</p>\n <p className=\"text-xs text-muted-foreground/70 max-w-xs\">{body}</p>\n {action ? (\n <Link href={action.href} className=\"mt-2 inline-flex items-center gap-1.5 h-9 px-4 rounded-lg text-sm font-semibold bg-foreground text-background hover:opacity-90 transition\">\n <Sparkles className=\"h-3.5 w-3.5\" />\n {action.label}\n </Link>\n ) : null}\n </div>\n );\n}\n\nfunction useCollectionItems(contract: string) {\n const [page, setPage] = useState(1);\n const [sort, setSort] = useState<CollectionTokensSort>(\"recent\");\n const [allTokens, setAllTokens] = useState<ApiToken[]>([]);\n const [selectedFilters, setSelectedFilters] = useState<Record<string, string[]>>({});\n const { tokens, meta, isLoading } = useCollectionTokens(contract, page, PAGE_SIZE, sort);\n\n const handleSortChange = (next: CollectionTokensSort) => {\n setSort(next);\n setPage(1);\n setAllTokens([]);\n };\n\n useEffect(() => {\n if (tokens.length === 0) return;\n setAllTokens((prev) => {\n const ids = new Set(prev.map((t) => `${t.contractAddress}-${t.tokenId}`));\n return page === 1 ? tokens : [...prev, ...tokens.filter((t) => !ids.has(`${t.contractAddress}-${t.tokenId}`))];\n });\n }, [tokens, page]);\n\n return { meta, isLoading, setPage, sort, handleSortChange, allTokens, selectedFilters, setSelectedFilters };\n}\n\ntype CollectionItemsState = ReturnType<typeof useCollectionItems>;\n\nfunction CollectionItems({ items, activeListings, mintHref }: { items: CollectionItemsState; activeListings: ApiOrder[]; mintHref: string | null }) {\n const { meta, isLoading, setPage, sort, handleSortChange, allTokens, selectedFilters, setSelectedFilters } = items;\n const usdPrices = useUsdPrices();\n\n const listingByTokenId = useMemo(() => new Map(activeListings.filter((o) => o.nftTokenId).map((o) => [o.nftTokenId!, o])), [activeListings]);\n\n const visibleTokens = useMemo(() => {\n const filters = Object.entries(selectedFilters);\n return allTokens.filter((token) => {\n if (filters.length === 0) return true;\n const attrs = Array.isArray(token.metadata?.attributes) ? (token.metadata.attributes as { trait_type?: string; value?: string }[]) : [];\n return filters.every(([traitType, values]) => attrs.some((a) => a.trait_type === traitType && values.includes(String(a.value))));\n });\n }, [allTokens, selectedFilters]);\n\n if (isLoading && allTokens.length === 0) {\n return <div className={GRID}>{Array.from({ length: 8 }).map((_, i) => <AssetCardSkeleton key={i} />)}</div>;\n }\n\n if (allTokens.length === 0) {\n return mintHref ? (\n <EmptyState title=\"Ready for your first work\" body=\"Mint into this collection and it appears here.\" action={{ href: mintHref, label: \"Mint your first work\" }} />\n ) : (\n <EmptyState title=\"No items yet\" body=\"Tokens in this collection will appear here once indexed.\" />\n );\n }\n\n return (\n <div className=\"space-y-3\">\n <CollectionActiveFilters tokens={allTokens} selected={selectedFilters} onChange={setSelectedFilters} sort={sort} onSortChange={handleSortChange} />\n {visibleTokens.length === 0 ? (\n <EmptyState title=\"No items match these filters\" body=\"Try removing some filters to see more results.\" />\n ) : (\n <div className={GRID}>\n {visibleTokens.map((t) => {\n const listing =\n t.activeOrders?.find((o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\") ?? listingByTokenId.get(t.tokenId);\n return (\n <AssetCard\n key={`${t.contractAddress}-${t.tokenId}`}\n href={assetHref(t.chain as Chain, t.contractAddress, t.tokenId)}\n name={t.metadata?.name || `Token #${t.tokenId}`}\n image={t.metadata?.image}\n animationUrl={t.metadata?.animationUrl}\n live={isLivingRenderCollection(t.chain as Chain, t.contractAddress)}\n ipType={t.metadata?.ipType}\n price={listing ? { ...listing.price, usdValue: usdFor(listing, usdPrices) } : null}\n fallbackId={t.tokenId}\n indexing={t.metadataStatus === \"PENDING\" || t.metadataStatus === \"FETCHING\"}\n />\n );\n })}\n </div>\n )}\n <LoadMoreSentinel hasMore={meta ? allTokens.length < (meta.total ?? 0) : false} isLoading={isLoading} onLoadMore={() => setPage((p) => p + 1)} />\n </div>\n );\n}\n\nfunction OwnerActions({ collection }: { collection: ApiCollection }) {\n const service = getService(collection.service)?.id;\n const contract = collection.contractAddress;\n if (service === \"ip-tickets\") {\n return (\n <Link href={`/launchpad/tickets/${contract}/mint`} className=\"flex w-fit items-center gap-1.5 h-8 px-3 rounded-lg text-xs font-semibold text-white bg-brand-blue hover:brightness-110 active:scale-[0.98] transition\">\n <Ticket className=\"h-3.5 w-3.5\" />\n Mint tickets\n </Link>\n );\n }\n if (service === \"ip-club\") return <ClubOwnerActions contractAddress={contract} isOwner />;\n return null;\n}\n\nexport interface CollectionPageProps {\n contract: string;\n slots: CollectionPageSlots;\n}\n\nexport function CollectionPage({ contract, slots }: CollectionPageProps) {\n const { walletAddress } = useMedialaneApp();\n const { collection, isLoading: collectionLoading } = useCollection(contract);\n const { profile } = useCollectionProfile(contract);\n const gatedState = slots.useGatedContent(profile?.hasGatedContent ? contract : undefined);\n const market = slots.useMarketActions();\n const { orders, isLoading: ordersLoading } = useOrders({ collection: contract, status: \"ACTIVE\", sort: \"recent\", limit: 100 });\n\n const [reportOpen, setReportOpen] = useState(false);\n const [activeTab, setActiveTab] = useState(\"assets\");\n const [marketTab, setMarketTab] = useState<\"listings\" | \"offers\">(\"listings\");\n const [listingsSort, setListingsSort] = useState<OrderSort>(\"recent\");\n const [offersSort, setOffersSort] = useState<OrderSort>(\"recent\");\n const usdPrices = useUsdPrices();\n const items = useCollectionItems(contract);\n\n const activeListings = orders.filter((o) => o.status === \"ACTIVE\" && (o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"));\n const activeBids = orders.filter((o) => o.status === \"ACTIVE\" && o.offer.itemType === \"ERC20\");\n const isOwner = !!collection?.owner && !!walletAddress && isSameAddress(collection.owner, walletAddress);\n const mintHref = isOwner && collection ? MINT_HREFS[getService(collection.service)?.id ?? \"\"]?.(contract) ?? null : null;\n const { ServiceAction } = slots;\n\n const listingGrid = (items: ApiOrder[], sort: OrderSort, buyable: boolean) => (\n <div className={GRID}>\n {sortOrders(items, sort).map((o) => (\n <ListingCard\n key={o.orderHash}\n order={o}\n onBuy={buyable && !isSameAddress(o.offerer, walletAddress) ? market.buy : undefined}\n usdValue={usdFor(o, usdPrices)}\n overflowMenu={<ListingCardMenu order={o} />}\n />\n ))}\n </div>\n );\n const loadingGrid = <div className={GRID}>{Array.from({ length: 8 }).map((_, i) => <ListingCardSkeleton key={i} />)}</div>;\n\n return (\n <div className=\"relative z-0 min-h-screen\">\n {(collection as { isHidden?: boolean } | null | undefined)?.isHidden ? <HiddenContentBanner /> : null}\n\n <div className=\"px-4 sm:px-6 pt-20 pb-6 space-y-4\">\n <CollectionHeader collection={collection} loading={collectionLoading}>\n {collection && isOwner ? <OwnerActions collection={collection} /> : null}\n {collection ? <ServiceAction service={collection.service} contractAddress={collection.contractAddress} /> : null}\n </CollectionHeader>\n {collection && profile ? <GatedContentHero profile={profile} state={gatedState} onViewExclusive={() => setActiveTab(\"exclusive\")} /> : null}\n </div>\n\n <div className=\"px-4 sm:px-6 pb-12\">\n <Tabs value={activeTab} onValueChange={setActiveTab}>\n <div className=\"sticky top-0 z-10 flex items-center gap-2 pt-3 pb-1\">\n <TabsList className=\"min-w-0 flex-1 justify-start overflow-x-auto sm:flex-none\">\n <TabsTrigger value=\"assets\" className=\"flex-1 sm:flex-none\">\n Assets{collection?.totalSupply ? ` (${collection.totalSupply.toLocaleString()})` : \"\"}\n </TabsTrigger>\n <TabsTrigger value=\"market\" className=\"flex-1 sm:flex-none\">\n Market{!ordersLoading && activeListings.length + activeBids.length > 0 && ` (${activeListings.length + activeBids.length})`}\n </TabsTrigger>\n <TabsTrigger value=\"provenance\" className=\"flex-1 sm:flex-none\">Provenance</TabsTrigger>\n {profile?.hasGatedContent ? (\n <TabsTrigger value=\"exclusive\" className=\"flex-1 sm:flex-none gap-1.5\">\n <Lock className=\"h-3.5 w-3.5\" />\n Exclusive\n </TabsTrigger>\n ) : null}\n </TabsList>\n <div className=\"ml-auto flex shrink-0 items-center gap-2\">\n {activeTab === \"assets\" && items.allTokens.length > 0 ? (\n <CollectionFiltersDialog tokens={items.allTokens} selected={items.selectedFilters} onChange={items.setSelectedFilters} sort={items.sort} onSortChange={items.handleSortChange} chips={false} />\n ) : null}\n {collection ? (\n <MoreMenu\n explorerHref={`${EXPLORER_URL}/contract/${collection.contractAddress}`}\n shareTitle={collection.name ?? \"Collection\"}\n onReport={() => setReportOpen(true)}\n />\n ) : null}\n </div>\n </div>\n\n <TabsContent value=\"assets\" className=\"mt-4\">\n {collection ? <CollectionItems items={items} activeListings={activeListings} mintHref={mintHref} /> : null}\n </TabsContent>\n\n <TabsContent value=\"market\" className=\"mt-4\">\n <Tabs value={marketTab} onValueChange={(v) => setMarketTab(v as \"listings\" | \"offers\")}>\n <TabsList className=\"h-9\">\n <TabsTrigger value=\"listings\" className=\"text-xs px-3 py-1\">\n Listings{!ordersLoading && activeListings.length > 0 && ` (${activeListings.length})`}\n </TabsTrigger>\n <TabsTrigger value=\"offers\" className=\"text-xs px-3 py-1\">\n Offers{!ordersLoading && activeBids.length > 0 && ` (${activeBids.length})`}\n </TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"listings\" className=\"mt-4\">\n {ordersLoading ? loadingGrid : activeListings.length === 0 ? (\n <EmptyState title=\"No active listings\" body=\"When items in this collection are listed for sale, they'll appear here.\" />\n ) : (\n <div className=\"space-y-3\">\n <div className=\"flex justify-end\">\n <OrderSortControl value={listingsSort} onChange={setListingsSort} />\n </div>\n {listingGrid(activeListings, listingsSort, true)}\n </div>\n )}\n </TabsContent>\n\n <TabsContent value=\"offers\" className=\"mt-4\">\n <div className=\"flex justify-end items-center gap-2 mb-3\">\n {!ordersLoading && activeBids.length > 0 ? <OrderSortControl value={offersSort} onChange={setOffersSort} /> : null}\n <MakeOfferPicker contract={contract} onPick={market.offer} />\n </div>\n {ordersLoading ? loadingGrid : activeBids.length === 0 ? (\n <EmptyState title=\"No active offers\" body=\"Make the first offer, or check back when collectors start bidding.\" />\n ) : (\n listingGrid(activeBids, offersSort, false)\n )}\n </TabsContent>\n </Tabs>\n </TabsContent>\n\n <TabsContent value=\"provenance\" className=\"mt-4\">\n <CollectionProvenanceTab contract={contract} />\n </TabsContent>\n\n {profile?.hasGatedContent ? (\n <TabsContent value=\"exclusive\" className=\"mt-4\">\n <GatedContentPanel state={gatedState} onBrowseListings={() => { setMarketTab(\"listings\"); setActiveTab(\"market\"); }} />\n </TabsContent>\n ) : null}\n </Tabs>\n </div>\n\n {collection && isOwner ? (\n <div className=\"px-4 sm:px-6 pb-8 space-y-4\">\n <OwnerSetupPanel contract={contract} profile={profile ?? null} />\n {canTransferCollectionOwnership(collection) ? (\n <div className=\"flex justify-end\">\n <TransferCollectionOwnership collectionId={collection.collectionId!} currentOwner={collection.owner!} collectionName={collection.name} />\n </div>\n ) : null}\n </div>\n ) : null}\n\n {collection ? (\n <ReportDialog open={reportOpen} onOpenChange={setReportOpen} target={{ type: \"COLLECTION\", contract: collection.contractAddress, name: collection.name ?? undefined }} />\n ) : null}\n {market.dialogs}\n </div>\n );\n}\n"],"mappings":"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","names":["Link","items"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/collection-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState, type ComponentType, type ReactNode } from \"react\";\nimport { Inbox, Lock, Sparkles, Ticket } from \"lucide-react\";\nimport { assetHref, getService, type ApiCollection, type ApiOrder, type ApiToken, type Chain, type CollectionTokensSort } from \"@medialane/sdk\";\nimport Link from \"./link.js\";\nimport { AssetCard, AssetCardSkeleton } from \"./asset-card.js\";\nimport { detectAssetKind } from \"./asset-page.js\";\nimport { CollectionHeader } from \"./collection-header.js\";\nimport { CollectionFiltersDialog, CollectionActiveFilters } from \"./collection-filters-dialog.js\";\nimport { MoreMenu } from \"./more-menu.js\";\nimport { EXPLORER_URL } from \"../utils/explorer-url.js\";\nimport { CollectionProvenanceTab } from \"./collection-provenance-tab.js\";\nimport { ClubOwnerActions } from \"./club-owner-actions.js\";\nimport { OwnerSetupPanel } from \"./owner-setup-panel.js\";\nimport { TransferCollectionOwnership } from \"./transfer-collection-ownership.js\";\nimport { HiddenContentBanner } from \"./hidden-content-banner.js\";\nimport { ListingCard, ListingCardSkeleton } from \"./listing-card.js\";\nimport { ListingCardMenu } from \"./listing-card-menu.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { MakeOfferPicker } from \"./make-offer-picker.js\";\nimport { OrderSortControl, sortOrders, type OrderSort } from \"./order-sort-control.js\";\nimport { GatedContentHero, GatedContentPanel, type GatedContentState } from \"./gated-content.js\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"./tabs.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { ReportDialog } from \"./report-dialog.js\";\nimport { useCollection, useCollectionTokens } from \"../utils/use-collections.js\";\nimport { useOrders } from \"../utils/use-orders.js\";\nimport { useCollectionProfile } from \"../utils/use-profiles.js\";\nimport { useUsdPrices, usdPriceFor } from \"../utils/use-usd-prices.js\";\nimport { formatUsd } from \"../utils/format.js\";\nimport { isSameAddress } from \"../utils/same-address.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\n\nexport interface CollectionMarketActions {\n buy: (order: ApiOrder) => void;\n offer: (token: ApiToken) => void;\n dialogs: ReactNode;\n}\n\nexport interface CollectionPageSlots {\n useMarketActions: () => CollectionMarketActions;\n useGatedContent: (contract: string | undefined) => GatedContentState;\n ServiceAction: ComponentType<{ service: string | null | undefined; contractAddress: string }>;\n}\n\nconst PAGE_SIZE = 24;\nconst GRID = \"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-3 sm:gap-4\";\n\nconst MINT_HREFS: Partial<Record<string, (contract: string) => string>> = {\n \"mip-erc721\": () => \"/launchpad/single-editions\",\n \"mip-erc1155\": (c) => `/launchpad/nfteditions/${c}/mint`,\n \"ip-tickets\": (c) => `/launchpad/tickets/${c}/mint`,\n \"ip-club\": (c) => `/launchpad/club/${c}/mint`,\n};\n\n/** Ownership transfer exists from the audited v3 collection registry (2026-05-14) on. */\nexport function canTransferCollectionOwnership(collection: ApiCollection): boolean {\n return !!collection.collectionId && collection.standard === \"ERC721\" && collection.createdAt >= \"2026-05-14\";\n}\n\nfunction usdFor(order: ApiOrder | undefined, prices: ReturnType<typeof useUsdPrices>): string | null {\n const currency = order?.price?.currency?.toUpperCase();\n const amount = order?.price?.formatted ? parseFloat(order.price.formatted) : NaN;\n const rate = currency ? usdPriceFor(prices, currency) : undefined;\n return rate == null || isNaN(amount) ? null : formatUsd(amount * rate);\n}\n\nfunction EmptyState({ title, body, action }: { title: string; body: string; action?: { href: string; label: string } }) {\n return (\n <div className=\"py-20 flex flex-col items-center gap-3 text-center\">\n <Inbox className=\"h-10 w-10 text-muted-foreground/40\" />\n <p className=\"text-sm font-medium text-muted-foreground\">{title}</p>\n <p className=\"text-xs text-muted-foreground/70 max-w-xs\">{body}</p>\n {action ? (\n <Link href={action.href} className=\"mt-2 inline-flex items-center gap-1.5 h-9 px-4 rounded-lg text-sm font-semibold bg-foreground text-background hover:opacity-90 transition\">\n <Sparkles className=\"h-3.5 w-3.5\" />\n {action.label}\n </Link>\n ) : null}\n </div>\n );\n}\n\nfunction useCollectionItems(contract: string) {\n const [page, setPage] = useState(1);\n const [sort, setSort] = useState<CollectionTokensSort>(\"recent\");\n const [allTokens, setAllTokens] = useState<ApiToken[]>([]);\n const [selectedFilters, setSelectedFilters] = useState<Record<string, string[]>>({});\n const { tokens, meta, isLoading } = useCollectionTokens(contract, page, PAGE_SIZE, sort);\n\n const handleSortChange = (next: CollectionTokensSort) => {\n setSort(next);\n setPage(1);\n setAllTokens([]);\n };\n\n useEffect(() => {\n if (tokens.length === 0) return;\n setAllTokens((prev) => {\n const ids = new Set(prev.map((t) => `${t.contractAddress}-${t.tokenId}`));\n return page === 1 ? tokens : [...prev, ...tokens.filter((t) => !ids.has(`${t.contractAddress}-${t.tokenId}`))];\n });\n }, [tokens, page]);\n\n return { meta, isLoading, setPage, sort, handleSortChange, allTokens, selectedFilters, setSelectedFilters };\n}\n\ntype CollectionItemsState = ReturnType<typeof useCollectionItems>;\n\nfunction CollectionItems({ items, activeListings, mintHref, soulbound }: { items: CollectionItemsState; activeListings: ApiOrder[]; mintHref: string | null; soulbound: boolean }) {\n const { meta, isLoading, setPage, sort, handleSortChange, allTokens, selectedFilters, setSelectedFilters } = items;\n const usdPrices = useUsdPrices();\n\n const listingByTokenId = useMemo(() => new Map(activeListings.filter((o) => o.nftTokenId).map((o) => [o.nftTokenId!, o])), [activeListings]);\n\n const visibleTokens = useMemo(() => {\n const filters = Object.entries(selectedFilters);\n return allTokens.filter((token) => {\n if (filters.length === 0) return true;\n const attrs = Array.isArray(token.metadata?.attributes) ? (token.metadata.attributes as { trait_type?: string; value?: string }[]) : [];\n return filters.every(([traitType, values]) => attrs.some((a) => a.trait_type === traitType && values.includes(String(a.value))));\n });\n }, [allTokens, selectedFilters]);\n\n if (isLoading && allTokens.length === 0) {\n return <div className={GRID}>{Array.from({ length: 8 }).map((_, i) => <AssetCardSkeleton key={i} />)}</div>;\n }\n\n if (allTokens.length === 0) {\n return mintHref ? (\n <EmptyState title=\"Ready for your first work\" body=\"Mint into this collection and it appears here.\" action={{ href: mintHref, label: \"Mint your first work\" }} />\n ) : (\n <EmptyState title=\"No items yet\" body=\"Tokens in this collection will appear here once indexed.\" />\n );\n }\n\n return (\n <div className=\"space-y-3\">\n <CollectionActiveFilters tokens={allTokens} selected={selectedFilters} onChange={setSelectedFilters} sort={sort} onSortChange={handleSortChange} />\n {visibleTokens.length === 0 ? (\n <EmptyState title=\"No items match these filters\" body=\"Try removing some filters to see more results.\" />\n ) : (\n <div className={GRID}>\n {visibleTokens.map((t) => {\n const listing =\n t.activeOrders?.find((o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\") ?? listingByTokenId.get(t.tokenId);\n return (\n <AssetCard\n key={`${t.contractAddress}-${t.tokenId}`}\n href={assetHref(t.chain as Chain, t.contractAddress, t.tokenId)}\n name={t.metadata?.name || `Token #${t.tokenId}`}\n image={t.metadata?.image}\n animationUrl={t.metadata?.animationUrl}\n live={isLivingRenderCollection(t.chain as Chain, t.contractAddress)}\n ipType={t.metadata?.ipType}\n price={listing ? { ...listing.price, usdValue: usdFor(listing, usdPrices) } : null}\n fallbackId={t.tokenId}\n indexing={t.metadataStatus === \"PENDING\" || t.metadataStatus === \"FETCHING\"}\n soulbound={soulbound}\n />\n );\n })}\n </div>\n )}\n <LoadMoreSentinel hasMore={meta ? allTokens.length < (meta.total ?? 0) : false} isLoading={isLoading} onLoadMore={() => setPage((p) => p + 1)} />\n </div>\n );\n}\n\nfunction OwnerActions({ collection }: { collection: ApiCollection }) {\n const service = getService(collection.service)?.id;\n const contract = collection.contractAddress;\n if (service === \"ip-tickets\") {\n return (\n <Link href={`/launchpad/tickets/${contract}/mint`} className=\"flex w-fit items-center gap-1.5 h-8 px-3 rounded-lg text-xs font-semibold text-white bg-brand-blue hover:brightness-110 active:scale-[0.98] transition\">\n <Ticket className=\"h-3.5 w-3.5\" />\n Mint tickets\n </Link>\n );\n }\n if (service === \"ip-club\") return <ClubOwnerActions contractAddress={contract} isOwner />;\n return null;\n}\n\nexport interface CollectionPageProps {\n contract: string;\n slots: CollectionPageSlots;\n}\n\nexport function CollectionPage({ contract, slots }: CollectionPageProps) {\n const { walletAddress } = useMedialaneApp();\n const { collection, isLoading: collectionLoading } = useCollection(contract);\n const { profile } = useCollectionProfile(contract);\n const gatedState = slots.useGatedContent(profile?.hasGatedContent ? contract : undefined);\n const market = slots.useMarketActions();\n const { orders, isLoading: ordersLoading } = useOrders({ collection: contract, status: \"ACTIVE\", sort: \"recent\", limit: 100 });\n\n const [reportOpen, setReportOpen] = useState(false);\n const [activeTab, setActiveTab] = useState(\"assets\");\n const [marketTab, setMarketTab] = useState<\"listings\" | \"offers\">(\"listings\");\n const [listingsSort, setListingsSort] = useState<OrderSort>(\"recent\");\n const [offersSort, setOffersSort] = useState<OrderSort>(\"recent\");\n const usdPrices = useUsdPrices();\n const items = useCollectionItems(contract);\n\n const activeListings = orders.filter((o) => o.status === \"ACTIVE\" && (o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"));\n const activeBids = orders.filter((o) => o.status === \"ACTIVE\" && o.offer.itemType === \"ERC20\");\n const isOwner = !!collection?.owner && !!walletAddress && isSameAddress(collection.owner, walletAddress);\n const mintHref = isOwner && collection ? MINT_HREFS[getService(collection.service)?.id ?? \"\"]?.(contract) ?? null : null;\n const { ServiceAction } = slots;\n\n const listingGrid = (items: ApiOrder[], sort: OrderSort, buyable: boolean) => (\n <div className={GRID}>\n {sortOrders(items, sort).map((o) => (\n <ListingCard\n key={o.orderHash}\n order={o}\n onBuy={buyable && !isSameAddress(o.offerer, walletAddress) ? market.buy : undefined}\n usdValue={usdFor(o, usdPrices)}\n overflowMenu={<ListingCardMenu order={o} />}\n />\n ))}\n </div>\n );\n const loadingGrid = <div className={GRID}>{Array.from({ length: 8 }).map((_, i) => <ListingCardSkeleton key={i} />)}</div>;\n\n return (\n <div className=\"relative z-0 min-h-screen\">\n {(collection as { isHidden?: boolean } | null | undefined)?.isHidden ? <HiddenContentBanner /> : null}\n\n <div className=\"px-4 sm:px-6 pt-20 pb-6 space-y-4\">\n <CollectionHeader collection={collection} loading={collectionLoading}>\n {collection && isOwner ? <OwnerActions collection={collection} /> : null}\n {collection ? <ServiceAction service={collection.service} contractAddress={collection.contractAddress} /> : null}\n </CollectionHeader>\n {collection && profile ? <GatedContentHero profile={profile} state={gatedState} onViewExclusive={() => setActiveTab(\"exclusive\")} /> : null}\n </div>\n\n <div className=\"px-4 sm:px-6 pb-12\">\n <Tabs value={activeTab} onValueChange={setActiveTab}>\n <div className=\"sticky top-0 z-10 flex items-center gap-2 pt-3 pb-1\">\n <TabsList className=\"min-w-0 flex-1 justify-start overflow-x-auto sm:flex-none\">\n <TabsTrigger value=\"assets\" className=\"flex-1 sm:flex-none\">\n Assets{collection?.totalSupply ? ` (${collection.totalSupply.toLocaleString()})` : \"\"}\n </TabsTrigger>\n <TabsTrigger value=\"market\" className=\"flex-1 sm:flex-none\">\n Market{!ordersLoading && activeListings.length + activeBids.length > 0 && ` (${activeListings.length + activeBids.length})`}\n </TabsTrigger>\n <TabsTrigger value=\"provenance\" className=\"flex-1 sm:flex-none\">Provenance</TabsTrigger>\n {profile?.hasGatedContent ? (\n <TabsTrigger value=\"exclusive\" className=\"flex-1 sm:flex-none gap-1.5\">\n <Lock className=\"h-3.5 w-3.5\" />\n Exclusive\n </TabsTrigger>\n ) : null}\n </TabsList>\n <div className=\"ml-auto flex shrink-0 items-center gap-2\">\n {activeTab === \"assets\" && items.allTokens.length > 0 ? (\n <CollectionFiltersDialog tokens={items.allTokens} selected={items.selectedFilters} onChange={items.setSelectedFilters} sort={items.sort} onSortChange={items.handleSortChange} chips={false} />\n ) : null}\n {collection ? (\n <MoreMenu\n explorerHref={`${EXPLORER_URL}/contract/${collection.contractAddress}`}\n shareTitle={collection.name ?? \"Collection\"}\n onReport={() => setReportOpen(true)}\n />\n ) : null}\n </div>\n </div>\n\n <TabsContent value=\"assets\" className=\"mt-4\">\n {collection ? <CollectionItems items={items} activeListings={activeListings} mintHref={mintHref} soulbound={detectAssetKind(collection.service, collection.standard) === \"pop\"} /> : null}\n </TabsContent>\n\n <TabsContent value=\"market\" className=\"mt-4\">\n <Tabs value={marketTab} onValueChange={(v) => setMarketTab(v as \"listings\" | \"offers\")}>\n <TabsList className=\"h-9\">\n <TabsTrigger value=\"listings\" className=\"text-xs px-3 py-1\">\n Listings{!ordersLoading && activeListings.length > 0 && ` (${activeListings.length})`}\n </TabsTrigger>\n <TabsTrigger value=\"offers\" className=\"text-xs px-3 py-1\">\n Offers{!ordersLoading && activeBids.length > 0 && ` (${activeBids.length})`}\n </TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"listings\" className=\"mt-4\">\n {ordersLoading ? loadingGrid : activeListings.length === 0 ? (\n <EmptyState title=\"No active listings\" body=\"When items in this collection are listed for sale, they'll appear here.\" />\n ) : (\n <div className=\"space-y-3\">\n <div className=\"flex justify-end\">\n <OrderSortControl value={listingsSort} onChange={setListingsSort} />\n </div>\n {listingGrid(activeListings, listingsSort, true)}\n </div>\n )}\n </TabsContent>\n\n <TabsContent value=\"offers\" className=\"mt-4\">\n <div className=\"flex justify-end items-center gap-2 mb-3\">\n {!ordersLoading && activeBids.length > 0 ? <OrderSortControl value={offersSort} onChange={setOffersSort} /> : null}\n <MakeOfferPicker contract={contract} onPick={market.offer} />\n </div>\n {ordersLoading ? loadingGrid : activeBids.length === 0 ? (\n <EmptyState title=\"No active offers\" body=\"Make the first offer, or check back when collectors start bidding.\" />\n ) : (\n listingGrid(activeBids, offersSort, false)\n )}\n </TabsContent>\n </Tabs>\n </TabsContent>\n\n <TabsContent value=\"provenance\" className=\"mt-4\">\n <CollectionProvenanceTab contract={contract} />\n </TabsContent>\n\n {profile?.hasGatedContent ? (\n <TabsContent value=\"exclusive\" className=\"mt-4\">\n <GatedContentPanel state={gatedState} onBrowseListings={() => { setMarketTab(\"listings\"); setActiveTab(\"market\"); }} />\n </TabsContent>\n ) : null}\n </Tabs>\n </div>\n\n {collection && isOwner ? (\n <div className=\"px-4 sm:px-6 pb-8 space-y-4\">\n <OwnerSetupPanel contract={contract} profile={profile ?? null} />\n {canTransferCollectionOwnership(collection) ? (\n <div className=\"flex justify-end\">\n <TransferCollectionOwnership collectionId={collection.collectionId!} currentOwner={collection.owner!} collectionName={collection.name} />\n </div>\n ) : null}\n </div>\n ) : null}\n\n {collection ? (\n <ReportDialog open={reportOpen} onOpenChange={setReportOpen} target={{ type: \"COLLECTION\", contract: collection.contractAddress, name: collection.name ?? undefined }} />\n ) : null}\n {market.dialogs}\n </div>\n );\n}\n"],"mappings":"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","names":["Link","items"]}
|
|
@@ -5,6 +5,7 @@ import { Inbox, Lock, Sparkles, Ticket } from "lucide-react";
|
|
|
5
5
|
import { assetHref, getService } from "@medialane/sdk";
|
|
6
6
|
import Link from "./link.js";
|
|
7
7
|
import { AssetCard, AssetCardSkeleton } from "./asset-card.js";
|
|
8
|
+
import { detectAssetKind } from "./asset-page.js";
|
|
8
9
|
import { CollectionHeader } from "./collection-header.js";
|
|
9
10
|
import { CollectionFiltersDialog, CollectionActiveFilters } from "./collection-filters-dialog.js";
|
|
10
11
|
import { MoreMenu } from "./more-menu.js";
|
|
@@ -78,7 +79,7 @@ function useCollectionItems(contract) {
|
|
|
78
79
|
}, [tokens, page]);
|
|
79
80
|
return { meta, isLoading, setPage, sort, handleSortChange, allTokens, selectedFilters, setSelectedFilters };
|
|
80
81
|
}
|
|
81
|
-
function CollectionItems({ items, activeListings, mintHref }) {
|
|
82
|
+
function CollectionItems({ items, activeListings, mintHref, soulbound }) {
|
|
82
83
|
const { meta, isLoading, setPage, sort, handleSortChange, allTokens, selectedFilters, setSelectedFilters } = items;
|
|
83
84
|
const usdPrices = useUsdPrices();
|
|
84
85
|
const listingByTokenId = useMemo(() => new Map(activeListings.filter((o) => o.nftTokenId).map((o) => [o.nftTokenId, o])), [activeListings]);
|
|
@@ -111,7 +112,8 @@ function CollectionItems({ items, activeListings, mintHref }) {
|
|
|
111
112
|
ipType: t.metadata?.ipType,
|
|
112
113
|
price: listing ? { ...listing.price, usdValue: usdFor(listing, usdPrices) } : null,
|
|
113
114
|
fallbackId: t.tokenId,
|
|
114
|
-
indexing: t.metadataStatus === "PENDING" || t.metadataStatus === "FETCHING"
|
|
115
|
+
indexing: t.metadataStatus === "PENDING" || t.metadataStatus === "FETCHING",
|
|
116
|
+
soulbound
|
|
115
117
|
},
|
|
116
118
|
`${t.contractAddress}-${t.tokenId}`
|
|
117
119
|
);
|
|
@@ -199,7 +201,7 @@ function CollectionPage({ contract, slots }) {
|
|
|
199
201
|
) : null
|
|
200
202
|
] })
|
|
201
203
|
] }),
|
|
202
|
-
/* @__PURE__ */ jsx(TabsContent, { value: "assets", className: "mt-4", children: collection ? /* @__PURE__ */ jsx(CollectionItems, { items, activeListings, mintHref }) : null }),
|
|
204
|
+
/* @__PURE__ */ jsx(TabsContent, { value: "assets", className: "mt-4", children: collection ? /* @__PURE__ */ jsx(CollectionItems, { items, activeListings, mintHref, soulbound: detectAssetKind(collection.service, collection.standard) === "pop" }) : null }),
|
|
203
205
|
/* @__PURE__ */ jsx(TabsContent, { value: "market", className: "mt-4", children: /* @__PURE__ */ jsxs(Tabs, { value: marketTab, onValueChange: (v) => setMarketTab(v), children: [
|
|
204
206
|
/* @__PURE__ */ jsxs(TabsList, { className: "h-9", children: [
|
|
205
207
|
/* @__PURE__ */ jsxs(TabsTrigger, { value: "listings", className: "text-xs px-3 py-1", children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/collection-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState, type ComponentType, type ReactNode } from \"react\";\nimport { Inbox, Lock, Sparkles, Ticket } from \"lucide-react\";\nimport { assetHref, getService, type ApiCollection, type ApiOrder, type ApiToken, type Chain, type CollectionTokensSort } from \"@medialane/sdk\";\nimport Link from \"./link.js\";\nimport { AssetCard, AssetCardSkeleton } from \"./asset-card.js\";\nimport { CollectionHeader } from \"./collection-header.js\";\nimport { CollectionFiltersDialog, CollectionActiveFilters } from \"./collection-filters-dialog.js\";\nimport { MoreMenu } from \"./more-menu.js\";\nimport { EXPLORER_URL } from \"../utils/explorer-url.js\";\nimport { CollectionProvenanceTab } from \"./collection-provenance-tab.js\";\nimport { ClubOwnerActions } from \"./club-owner-actions.js\";\nimport { OwnerSetupPanel } from \"./owner-setup-panel.js\";\nimport { TransferCollectionOwnership } from \"./transfer-collection-ownership.js\";\nimport { HiddenContentBanner } from \"./hidden-content-banner.js\";\nimport { ListingCard, ListingCardSkeleton } from \"./listing-card.js\";\nimport { ListingCardMenu } from \"./listing-card-menu.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { MakeOfferPicker } from \"./make-offer-picker.js\";\nimport { OrderSortControl, sortOrders, type OrderSort } from \"./order-sort-control.js\";\nimport { GatedContentHero, GatedContentPanel, type GatedContentState } from \"./gated-content.js\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"./tabs.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { ReportDialog } from \"./report-dialog.js\";\nimport { useCollection, useCollectionTokens } from \"../utils/use-collections.js\";\nimport { useOrders } from \"../utils/use-orders.js\";\nimport { useCollectionProfile } from \"../utils/use-profiles.js\";\nimport { useUsdPrices, usdPriceFor } from \"../utils/use-usd-prices.js\";\nimport { formatUsd } from \"../utils/format.js\";\nimport { isSameAddress } from \"../utils/same-address.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\n\nexport interface CollectionMarketActions {\n buy: (order: ApiOrder) => void;\n offer: (token: ApiToken) => void;\n dialogs: ReactNode;\n}\n\nexport interface CollectionPageSlots {\n useMarketActions: () => CollectionMarketActions;\n useGatedContent: (contract: string | undefined) => GatedContentState;\n ServiceAction: ComponentType<{ service: string | null | undefined; contractAddress: string }>;\n}\n\nconst PAGE_SIZE = 24;\nconst GRID = \"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-3 sm:gap-4\";\n\nconst MINT_HREFS: Partial<Record<string, (contract: string) => string>> = {\n \"mip-erc721\": () => \"/launchpad/single-editions\",\n \"mip-erc1155\": (c) => `/launchpad/nfteditions/${c}/mint`,\n \"ip-tickets\": (c) => `/launchpad/tickets/${c}/mint`,\n \"ip-club\": (c) => `/launchpad/club/${c}/mint`,\n};\n\n/** Ownership transfer exists from the audited v3 collection registry (2026-05-14) on. */\nexport function canTransferCollectionOwnership(collection: ApiCollection): boolean {\n return !!collection.collectionId && collection.standard === \"ERC721\" && collection.createdAt >= \"2026-05-14\";\n}\n\nfunction usdFor(order: ApiOrder | undefined, prices: ReturnType<typeof useUsdPrices>): string | null {\n const currency = order?.price?.currency?.toUpperCase();\n const amount = order?.price?.formatted ? parseFloat(order.price.formatted) : NaN;\n const rate = currency ? usdPriceFor(prices, currency) : undefined;\n return rate == null || isNaN(amount) ? null : formatUsd(amount * rate);\n}\n\nfunction EmptyState({ title, body, action }: { title: string; body: string; action?: { href: string; label: string } }) {\n return (\n <div className=\"py-20 flex flex-col items-center gap-3 text-center\">\n <Inbox className=\"h-10 w-10 text-muted-foreground/40\" />\n <p className=\"text-sm font-medium text-muted-foreground\">{title}</p>\n <p className=\"text-xs text-muted-foreground/70 max-w-xs\">{body}</p>\n {action ? (\n <Link href={action.href} className=\"mt-2 inline-flex items-center gap-1.5 h-9 px-4 rounded-lg text-sm font-semibold bg-foreground text-background hover:opacity-90 transition\">\n <Sparkles className=\"h-3.5 w-3.5\" />\n {action.label}\n </Link>\n ) : null}\n </div>\n );\n}\n\nfunction useCollectionItems(contract: string) {\n const [page, setPage] = useState(1);\n const [sort, setSort] = useState<CollectionTokensSort>(\"recent\");\n const [allTokens, setAllTokens] = useState<ApiToken[]>([]);\n const [selectedFilters, setSelectedFilters] = useState<Record<string, string[]>>({});\n const { tokens, meta, isLoading } = useCollectionTokens(contract, page, PAGE_SIZE, sort);\n\n const handleSortChange = (next: CollectionTokensSort) => {\n setSort(next);\n setPage(1);\n setAllTokens([]);\n };\n\n useEffect(() => {\n if (tokens.length === 0) return;\n setAllTokens((prev) => {\n const ids = new Set(prev.map((t) => `${t.contractAddress}-${t.tokenId}`));\n return page === 1 ? tokens : [...prev, ...tokens.filter((t) => !ids.has(`${t.contractAddress}-${t.tokenId}`))];\n });\n }, [tokens, page]);\n\n return { meta, isLoading, setPage, sort, handleSortChange, allTokens, selectedFilters, setSelectedFilters };\n}\n\ntype CollectionItemsState = ReturnType<typeof useCollectionItems>;\n\nfunction CollectionItems({ items, activeListings, mintHref }: { items: CollectionItemsState; activeListings: ApiOrder[]; mintHref: string | null }) {\n const { meta, isLoading, setPage, sort, handleSortChange, allTokens, selectedFilters, setSelectedFilters } = items;\n const usdPrices = useUsdPrices();\n\n const listingByTokenId = useMemo(() => new Map(activeListings.filter((o) => o.nftTokenId).map((o) => [o.nftTokenId!, o])), [activeListings]);\n\n const visibleTokens = useMemo(() => {\n const filters = Object.entries(selectedFilters);\n return allTokens.filter((token) => {\n if (filters.length === 0) return true;\n const attrs = Array.isArray(token.metadata?.attributes) ? (token.metadata.attributes as { trait_type?: string; value?: string }[]) : [];\n return filters.every(([traitType, values]) => attrs.some((a) => a.trait_type === traitType && values.includes(String(a.value))));\n });\n }, [allTokens, selectedFilters]);\n\n if (isLoading && allTokens.length === 0) {\n return <div className={GRID}>{Array.from({ length: 8 }).map((_, i) => <AssetCardSkeleton key={i} />)}</div>;\n }\n\n if (allTokens.length === 0) {\n return mintHref ? (\n <EmptyState title=\"Ready for your first work\" body=\"Mint into this collection and it appears here.\" action={{ href: mintHref, label: \"Mint your first work\" }} />\n ) : (\n <EmptyState title=\"No items yet\" body=\"Tokens in this collection will appear here once indexed.\" />\n );\n }\n\n return (\n <div className=\"space-y-3\">\n <CollectionActiveFilters tokens={allTokens} selected={selectedFilters} onChange={setSelectedFilters} sort={sort} onSortChange={handleSortChange} />\n {visibleTokens.length === 0 ? (\n <EmptyState title=\"No items match these filters\" body=\"Try removing some filters to see more results.\" />\n ) : (\n <div className={GRID}>\n {visibleTokens.map((t) => {\n const listing =\n t.activeOrders?.find((o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\") ?? listingByTokenId.get(t.tokenId);\n return (\n <AssetCard\n key={`${t.contractAddress}-${t.tokenId}`}\n href={assetHref(t.chain as Chain, t.contractAddress, t.tokenId)}\n name={t.metadata?.name || `Token #${t.tokenId}`}\n image={t.metadata?.image}\n animationUrl={t.metadata?.animationUrl}\n live={isLivingRenderCollection(t.chain as Chain, t.contractAddress)}\n ipType={t.metadata?.ipType}\n price={listing ? { ...listing.price, usdValue: usdFor(listing, usdPrices) } : null}\n fallbackId={t.tokenId}\n indexing={t.metadataStatus === \"PENDING\" || t.metadataStatus === \"FETCHING\"}\n />\n );\n })}\n </div>\n )}\n <LoadMoreSentinel hasMore={meta ? allTokens.length < (meta.total ?? 0) : false} isLoading={isLoading} onLoadMore={() => setPage((p) => p + 1)} />\n </div>\n );\n}\n\nfunction OwnerActions({ collection }: { collection: ApiCollection }) {\n const service = getService(collection.service)?.id;\n const contract = collection.contractAddress;\n if (service === \"ip-tickets\") {\n return (\n <Link href={`/launchpad/tickets/${contract}/mint`} className=\"flex w-fit items-center gap-1.5 h-8 px-3 rounded-lg text-xs font-semibold text-white bg-brand-blue hover:brightness-110 active:scale-[0.98] transition\">\n <Ticket className=\"h-3.5 w-3.5\" />\n Mint tickets\n </Link>\n );\n }\n if (service === \"ip-club\") return <ClubOwnerActions contractAddress={contract} isOwner />;\n return null;\n}\n\nexport interface CollectionPageProps {\n contract: string;\n slots: CollectionPageSlots;\n}\n\nexport function CollectionPage({ contract, slots }: CollectionPageProps) {\n const { walletAddress } = useMedialaneApp();\n const { collection, isLoading: collectionLoading } = useCollection(contract);\n const { profile } = useCollectionProfile(contract);\n const gatedState = slots.useGatedContent(profile?.hasGatedContent ? contract : undefined);\n const market = slots.useMarketActions();\n const { orders, isLoading: ordersLoading } = useOrders({ collection: contract, status: \"ACTIVE\", sort: \"recent\", limit: 100 });\n\n const [reportOpen, setReportOpen] = useState(false);\n const [activeTab, setActiveTab] = useState(\"assets\");\n const [marketTab, setMarketTab] = useState<\"listings\" | \"offers\">(\"listings\");\n const [listingsSort, setListingsSort] = useState<OrderSort>(\"recent\");\n const [offersSort, setOffersSort] = useState<OrderSort>(\"recent\");\n const usdPrices = useUsdPrices();\n const items = useCollectionItems(contract);\n\n const activeListings = orders.filter((o) => o.status === \"ACTIVE\" && (o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"));\n const activeBids = orders.filter((o) => o.status === \"ACTIVE\" && o.offer.itemType === \"ERC20\");\n const isOwner = !!collection?.owner && !!walletAddress && isSameAddress(collection.owner, walletAddress);\n const mintHref = isOwner && collection ? MINT_HREFS[getService(collection.service)?.id ?? \"\"]?.(contract) ?? null : null;\n const { ServiceAction } = slots;\n\n const listingGrid = (items: ApiOrder[], sort: OrderSort, buyable: boolean) => (\n <div className={GRID}>\n {sortOrders(items, sort).map((o) => (\n <ListingCard\n key={o.orderHash}\n order={o}\n onBuy={buyable && !isSameAddress(o.offerer, walletAddress) ? market.buy : undefined}\n usdValue={usdFor(o, usdPrices)}\n overflowMenu={<ListingCardMenu order={o} />}\n />\n ))}\n </div>\n );\n const loadingGrid = <div className={GRID}>{Array.from({ length: 8 }).map((_, i) => <ListingCardSkeleton key={i} />)}</div>;\n\n return (\n <div className=\"relative z-0 min-h-screen\">\n {(collection as { isHidden?: boolean } | null | undefined)?.isHidden ? <HiddenContentBanner /> : null}\n\n <div className=\"px-4 sm:px-6 pt-20 pb-6 space-y-4\">\n <CollectionHeader collection={collection} loading={collectionLoading}>\n {collection && isOwner ? <OwnerActions collection={collection} /> : null}\n {collection ? <ServiceAction service={collection.service} contractAddress={collection.contractAddress} /> : null}\n </CollectionHeader>\n {collection && profile ? <GatedContentHero profile={profile} state={gatedState} onViewExclusive={() => setActiveTab(\"exclusive\")} /> : null}\n </div>\n\n <div className=\"px-4 sm:px-6 pb-12\">\n <Tabs value={activeTab} onValueChange={setActiveTab}>\n <div className=\"sticky top-0 z-10 flex items-center gap-2 pt-3 pb-1\">\n <TabsList className=\"min-w-0 flex-1 justify-start overflow-x-auto sm:flex-none\">\n <TabsTrigger value=\"assets\" className=\"flex-1 sm:flex-none\">\n Assets{collection?.totalSupply ? ` (${collection.totalSupply.toLocaleString()})` : \"\"}\n </TabsTrigger>\n <TabsTrigger value=\"market\" className=\"flex-1 sm:flex-none\">\n Market{!ordersLoading && activeListings.length + activeBids.length > 0 && ` (${activeListings.length + activeBids.length})`}\n </TabsTrigger>\n <TabsTrigger value=\"provenance\" className=\"flex-1 sm:flex-none\">Provenance</TabsTrigger>\n {profile?.hasGatedContent ? (\n <TabsTrigger value=\"exclusive\" className=\"flex-1 sm:flex-none gap-1.5\">\n <Lock className=\"h-3.5 w-3.5\" />\n Exclusive\n </TabsTrigger>\n ) : null}\n </TabsList>\n <div className=\"ml-auto flex shrink-0 items-center gap-2\">\n {activeTab === \"assets\" && items.allTokens.length > 0 ? (\n <CollectionFiltersDialog tokens={items.allTokens} selected={items.selectedFilters} onChange={items.setSelectedFilters} sort={items.sort} onSortChange={items.handleSortChange} chips={false} />\n ) : null}\n {collection ? (\n <MoreMenu\n explorerHref={`${EXPLORER_URL}/contract/${collection.contractAddress}`}\n shareTitle={collection.name ?? \"Collection\"}\n onReport={() => setReportOpen(true)}\n />\n ) : null}\n </div>\n </div>\n\n <TabsContent value=\"assets\" className=\"mt-4\">\n {collection ? <CollectionItems items={items} activeListings={activeListings} mintHref={mintHref} /> : null}\n </TabsContent>\n\n <TabsContent value=\"market\" className=\"mt-4\">\n <Tabs value={marketTab} onValueChange={(v) => setMarketTab(v as \"listings\" | \"offers\")}>\n <TabsList className=\"h-9\">\n <TabsTrigger value=\"listings\" className=\"text-xs px-3 py-1\">\n Listings{!ordersLoading && activeListings.length > 0 && ` (${activeListings.length})`}\n </TabsTrigger>\n <TabsTrigger value=\"offers\" className=\"text-xs px-3 py-1\">\n Offers{!ordersLoading && activeBids.length > 0 && ` (${activeBids.length})`}\n </TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"listings\" className=\"mt-4\">\n {ordersLoading ? loadingGrid : activeListings.length === 0 ? (\n <EmptyState title=\"No active listings\" body=\"When items in this collection are listed for sale, they'll appear here.\" />\n ) : (\n <div className=\"space-y-3\">\n <div className=\"flex justify-end\">\n <OrderSortControl value={listingsSort} onChange={setListingsSort} />\n </div>\n {listingGrid(activeListings, listingsSort, true)}\n </div>\n )}\n </TabsContent>\n\n <TabsContent value=\"offers\" className=\"mt-4\">\n <div className=\"flex justify-end items-center gap-2 mb-3\">\n {!ordersLoading && activeBids.length > 0 ? <OrderSortControl value={offersSort} onChange={setOffersSort} /> : null}\n <MakeOfferPicker contract={contract} onPick={market.offer} />\n </div>\n {ordersLoading ? loadingGrid : activeBids.length === 0 ? (\n <EmptyState title=\"No active offers\" body=\"Make the first offer, or check back when collectors start bidding.\" />\n ) : (\n listingGrid(activeBids, offersSort, false)\n )}\n </TabsContent>\n </Tabs>\n </TabsContent>\n\n <TabsContent value=\"provenance\" className=\"mt-4\">\n <CollectionProvenanceTab contract={contract} />\n </TabsContent>\n\n {profile?.hasGatedContent ? (\n <TabsContent value=\"exclusive\" className=\"mt-4\">\n <GatedContentPanel state={gatedState} onBrowseListings={() => { setMarketTab(\"listings\"); setActiveTab(\"market\"); }} />\n </TabsContent>\n ) : null}\n </Tabs>\n </div>\n\n {collection && isOwner ? (\n <div className=\"px-4 sm:px-6 pb-8 space-y-4\">\n <OwnerSetupPanel contract={contract} profile={profile ?? null} />\n {canTransferCollectionOwnership(collection) ? (\n <div className=\"flex justify-end\">\n <TransferCollectionOwnership collectionId={collection.collectionId!} currentOwner={collection.owner!} collectionName={collection.name} />\n </div>\n ) : null}\n </div>\n ) : null}\n\n {collection ? (\n <ReportDialog open={reportOpen} onOpenChange={setReportOpen} target={{ type: \"COLLECTION\", contract: collection.contractAddress, name: collection.name ?? undefined }} />\n ) : null}\n {market.dialogs}\n </div>\n );\n}\n"],"mappings":"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","names":["items"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/collection-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState, type ComponentType, type ReactNode } from \"react\";\nimport { Inbox, Lock, Sparkles, Ticket } from \"lucide-react\";\nimport { assetHref, getService, type ApiCollection, type ApiOrder, type ApiToken, type Chain, type CollectionTokensSort } from \"@medialane/sdk\";\nimport Link from \"./link.js\";\nimport { AssetCard, AssetCardSkeleton } from \"./asset-card.js\";\nimport { detectAssetKind } from \"./asset-page.js\";\nimport { CollectionHeader } from \"./collection-header.js\";\nimport { CollectionFiltersDialog, CollectionActiveFilters } from \"./collection-filters-dialog.js\";\nimport { MoreMenu } from \"./more-menu.js\";\nimport { EXPLORER_URL } from \"../utils/explorer-url.js\";\nimport { CollectionProvenanceTab } from \"./collection-provenance-tab.js\";\nimport { ClubOwnerActions } from \"./club-owner-actions.js\";\nimport { OwnerSetupPanel } from \"./owner-setup-panel.js\";\nimport { TransferCollectionOwnership } from \"./transfer-collection-ownership.js\";\nimport { HiddenContentBanner } from \"./hidden-content-banner.js\";\nimport { ListingCard, ListingCardSkeleton } from \"./listing-card.js\";\nimport { ListingCardMenu } from \"./listing-card-menu.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { MakeOfferPicker } from \"./make-offer-picker.js\";\nimport { OrderSortControl, sortOrders, type OrderSort } from \"./order-sort-control.js\";\nimport { GatedContentHero, GatedContentPanel, type GatedContentState } from \"./gated-content.js\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"./tabs.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { ReportDialog } from \"./report-dialog.js\";\nimport { useCollection, useCollectionTokens } from \"../utils/use-collections.js\";\nimport { useOrders } from \"../utils/use-orders.js\";\nimport { useCollectionProfile } from \"../utils/use-profiles.js\";\nimport { useUsdPrices, usdPriceFor } from \"../utils/use-usd-prices.js\";\nimport { formatUsd } from \"../utils/format.js\";\nimport { isSameAddress } from \"../utils/same-address.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\n\nexport interface CollectionMarketActions {\n buy: (order: ApiOrder) => void;\n offer: (token: ApiToken) => void;\n dialogs: ReactNode;\n}\n\nexport interface CollectionPageSlots {\n useMarketActions: () => CollectionMarketActions;\n useGatedContent: (contract: string | undefined) => GatedContentState;\n ServiceAction: ComponentType<{ service: string | null | undefined; contractAddress: string }>;\n}\n\nconst PAGE_SIZE = 24;\nconst GRID = \"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-3 sm:gap-4\";\n\nconst MINT_HREFS: Partial<Record<string, (contract: string) => string>> = {\n \"mip-erc721\": () => \"/launchpad/single-editions\",\n \"mip-erc1155\": (c) => `/launchpad/nfteditions/${c}/mint`,\n \"ip-tickets\": (c) => `/launchpad/tickets/${c}/mint`,\n \"ip-club\": (c) => `/launchpad/club/${c}/mint`,\n};\n\n/** Ownership transfer exists from the audited v3 collection registry (2026-05-14) on. */\nexport function canTransferCollectionOwnership(collection: ApiCollection): boolean {\n return !!collection.collectionId && collection.standard === \"ERC721\" && collection.createdAt >= \"2026-05-14\";\n}\n\nfunction usdFor(order: ApiOrder | undefined, prices: ReturnType<typeof useUsdPrices>): string | null {\n const currency = order?.price?.currency?.toUpperCase();\n const amount = order?.price?.formatted ? parseFloat(order.price.formatted) : NaN;\n const rate = currency ? usdPriceFor(prices, currency) : undefined;\n return rate == null || isNaN(amount) ? null : formatUsd(amount * rate);\n}\n\nfunction EmptyState({ title, body, action }: { title: string; body: string; action?: { href: string; label: string } }) {\n return (\n <div className=\"py-20 flex flex-col items-center gap-3 text-center\">\n <Inbox className=\"h-10 w-10 text-muted-foreground/40\" />\n <p className=\"text-sm font-medium text-muted-foreground\">{title}</p>\n <p className=\"text-xs text-muted-foreground/70 max-w-xs\">{body}</p>\n {action ? (\n <Link href={action.href} className=\"mt-2 inline-flex items-center gap-1.5 h-9 px-4 rounded-lg text-sm font-semibold bg-foreground text-background hover:opacity-90 transition\">\n <Sparkles className=\"h-3.5 w-3.5\" />\n {action.label}\n </Link>\n ) : null}\n </div>\n );\n}\n\nfunction useCollectionItems(contract: string) {\n const [page, setPage] = useState(1);\n const [sort, setSort] = useState<CollectionTokensSort>(\"recent\");\n const [allTokens, setAllTokens] = useState<ApiToken[]>([]);\n const [selectedFilters, setSelectedFilters] = useState<Record<string, string[]>>({});\n const { tokens, meta, isLoading } = useCollectionTokens(contract, page, PAGE_SIZE, sort);\n\n const handleSortChange = (next: CollectionTokensSort) => {\n setSort(next);\n setPage(1);\n setAllTokens([]);\n };\n\n useEffect(() => {\n if (tokens.length === 0) return;\n setAllTokens((prev) => {\n const ids = new Set(prev.map((t) => `${t.contractAddress}-${t.tokenId}`));\n return page === 1 ? tokens : [...prev, ...tokens.filter((t) => !ids.has(`${t.contractAddress}-${t.tokenId}`))];\n });\n }, [tokens, page]);\n\n return { meta, isLoading, setPage, sort, handleSortChange, allTokens, selectedFilters, setSelectedFilters };\n}\n\ntype CollectionItemsState = ReturnType<typeof useCollectionItems>;\n\nfunction CollectionItems({ items, activeListings, mintHref, soulbound }: { items: CollectionItemsState; activeListings: ApiOrder[]; mintHref: string | null; soulbound: boolean }) {\n const { meta, isLoading, setPage, sort, handleSortChange, allTokens, selectedFilters, setSelectedFilters } = items;\n const usdPrices = useUsdPrices();\n\n const listingByTokenId = useMemo(() => new Map(activeListings.filter((o) => o.nftTokenId).map((o) => [o.nftTokenId!, o])), [activeListings]);\n\n const visibleTokens = useMemo(() => {\n const filters = Object.entries(selectedFilters);\n return allTokens.filter((token) => {\n if (filters.length === 0) return true;\n const attrs = Array.isArray(token.metadata?.attributes) ? (token.metadata.attributes as { trait_type?: string; value?: string }[]) : [];\n return filters.every(([traitType, values]) => attrs.some((a) => a.trait_type === traitType && values.includes(String(a.value))));\n });\n }, [allTokens, selectedFilters]);\n\n if (isLoading && allTokens.length === 0) {\n return <div className={GRID}>{Array.from({ length: 8 }).map((_, i) => <AssetCardSkeleton key={i} />)}</div>;\n }\n\n if (allTokens.length === 0) {\n return mintHref ? (\n <EmptyState title=\"Ready for your first work\" body=\"Mint into this collection and it appears here.\" action={{ href: mintHref, label: \"Mint your first work\" }} />\n ) : (\n <EmptyState title=\"No items yet\" body=\"Tokens in this collection will appear here once indexed.\" />\n );\n }\n\n return (\n <div className=\"space-y-3\">\n <CollectionActiveFilters tokens={allTokens} selected={selectedFilters} onChange={setSelectedFilters} sort={sort} onSortChange={handleSortChange} />\n {visibleTokens.length === 0 ? (\n <EmptyState title=\"No items match these filters\" body=\"Try removing some filters to see more results.\" />\n ) : (\n <div className={GRID}>\n {visibleTokens.map((t) => {\n const listing =\n t.activeOrders?.find((o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\") ?? listingByTokenId.get(t.tokenId);\n return (\n <AssetCard\n key={`${t.contractAddress}-${t.tokenId}`}\n href={assetHref(t.chain as Chain, t.contractAddress, t.tokenId)}\n name={t.metadata?.name || `Token #${t.tokenId}`}\n image={t.metadata?.image}\n animationUrl={t.metadata?.animationUrl}\n live={isLivingRenderCollection(t.chain as Chain, t.contractAddress)}\n ipType={t.metadata?.ipType}\n price={listing ? { ...listing.price, usdValue: usdFor(listing, usdPrices) } : null}\n fallbackId={t.tokenId}\n indexing={t.metadataStatus === \"PENDING\" || t.metadataStatus === \"FETCHING\"}\n soulbound={soulbound}\n />\n );\n })}\n </div>\n )}\n <LoadMoreSentinel hasMore={meta ? allTokens.length < (meta.total ?? 0) : false} isLoading={isLoading} onLoadMore={() => setPage((p) => p + 1)} />\n </div>\n );\n}\n\nfunction OwnerActions({ collection }: { collection: ApiCollection }) {\n const service = getService(collection.service)?.id;\n const contract = collection.contractAddress;\n if (service === \"ip-tickets\") {\n return (\n <Link href={`/launchpad/tickets/${contract}/mint`} className=\"flex w-fit items-center gap-1.5 h-8 px-3 rounded-lg text-xs font-semibold text-white bg-brand-blue hover:brightness-110 active:scale-[0.98] transition\">\n <Ticket className=\"h-3.5 w-3.5\" />\n Mint tickets\n </Link>\n );\n }\n if (service === \"ip-club\") return <ClubOwnerActions contractAddress={contract} isOwner />;\n return null;\n}\n\nexport interface CollectionPageProps {\n contract: string;\n slots: CollectionPageSlots;\n}\n\nexport function CollectionPage({ contract, slots }: CollectionPageProps) {\n const { walletAddress } = useMedialaneApp();\n const { collection, isLoading: collectionLoading } = useCollection(contract);\n const { profile } = useCollectionProfile(contract);\n const gatedState = slots.useGatedContent(profile?.hasGatedContent ? contract : undefined);\n const market = slots.useMarketActions();\n const { orders, isLoading: ordersLoading } = useOrders({ collection: contract, status: \"ACTIVE\", sort: \"recent\", limit: 100 });\n\n const [reportOpen, setReportOpen] = useState(false);\n const [activeTab, setActiveTab] = useState(\"assets\");\n const [marketTab, setMarketTab] = useState<\"listings\" | \"offers\">(\"listings\");\n const [listingsSort, setListingsSort] = useState<OrderSort>(\"recent\");\n const [offersSort, setOffersSort] = useState<OrderSort>(\"recent\");\n const usdPrices = useUsdPrices();\n const items = useCollectionItems(contract);\n\n const activeListings = orders.filter((o) => o.status === \"ACTIVE\" && (o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"));\n const activeBids = orders.filter((o) => o.status === \"ACTIVE\" && o.offer.itemType === \"ERC20\");\n const isOwner = !!collection?.owner && !!walletAddress && isSameAddress(collection.owner, walletAddress);\n const mintHref = isOwner && collection ? MINT_HREFS[getService(collection.service)?.id ?? \"\"]?.(contract) ?? null : null;\n const { ServiceAction } = slots;\n\n const listingGrid = (items: ApiOrder[], sort: OrderSort, buyable: boolean) => (\n <div className={GRID}>\n {sortOrders(items, sort).map((o) => (\n <ListingCard\n key={o.orderHash}\n order={o}\n onBuy={buyable && !isSameAddress(o.offerer, walletAddress) ? market.buy : undefined}\n usdValue={usdFor(o, usdPrices)}\n overflowMenu={<ListingCardMenu order={o} />}\n />\n ))}\n </div>\n );\n const loadingGrid = <div className={GRID}>{Array.from({ length: 8 }).map((_, i) => <ListingCardSkeleton key={i} />)}</div>;\n\n return (\n <div className=\"relative z-0 min-h-screen\">\n {(collection as { isHidden?: boolean } | null | undefined)?.isHidden ? <HiddenContentBanner /> : null}\n\n <div className=\"px-4 sm:px-6 pt-20 pb-6 space-y-4\">\n <CollectionHeader collection={collection} loading={collectionLoading}>\n {collection && isOwner ? <OwnerActions collection={collection} /> : null}\n {collection ? <ServiceAction service={collection.service} contractAddress={collection.contractAddress} /> : null}\n </CollectionHeader>\n {collection && profile ? <GatedContentHero profile={profile} state={gatedState} onViewExclusive={() => setActiveTab(\"exclusive\")} /> : null}\n </div>\n\n <div className=\"px-4 sm:px-6 pb-12\">\n <Tabs value={activeTab} onValueChange={setActiveTab}>\n <div className=\"sticky top-0 z-10 flex items-center gap-2 pt-3 pb-1\">\n <TabsList className=\"min-w-0 flex-1 justify-start overflow-x-auto sm:flex-none\">\n <TabsTrigger value=\"assets\" className=\"flex-1 sm:flex-none\">\n Assets{collection?.totalSupply ? ` (${collection.totalSupply.toLocaleString()})` : \"\"}\n </TabsTrigger>\n <TabsTrigger value=\"market\" className=\"flex-1 sm:flex-none\">\n Market{!ordersLoading && activeListings.length + activeBids.length > 0 && ` (${activeListings.length + activeBids.length})`}\n </TabsTrigger>\n <TabsTrigger value=\"provenance\" className=\"flex-1 sm:flex-none\">Provenance</TabsTrigger>\n {profile?.hasGatedContent ? (\n <TabsTrigger value=\"exclusive\" className=\"flex-1 sm:flex-none gap-1.5\">\n <Lock className=\"h-3.5 w-3.5\" />\n Exclusive\n </TabsTrigger>\n ) : null}\n </TabsList>\n <div className=\"ml-auto flex shrink-0 items-center gap-2\">\n {activeTab === \"assets\" && items.allTokens.length > 0 ? (\n <CollectionFiltersDialog tokens={items.allTokens} selected={items.selectedFilters} onChange={items.setSelectedFilters} sort={items.sort} onSortChange={items.handleSortChange} chips={false} />\n ) : null}\n {collection ? (\n <MoreMenu\n explorerHref={`${EXPLORER_URL}/contract/${collection.contractAddress}`}\n shareTitle={collection.name ?? \"Collection\"}\n onReport={() => setReportOpen(true)}\n />\n ) : null}\n </div>\n </div>\n\n <TabsContent value=\"assets\" className=\"mt-4\">\n {collection ? <CollectionItems items={items} activeListings={activeListings} mintHref={mintHref} soulbound={detectAssetKind(collection.service, collection.standard) === \"pop\"} /> : null}\n </TabsContent>\n\n <TabsContent value=\"market\" className=\"mt-4\">\n <Tabs value={marketTab} onValueChange={(v) => setMarketTab(v as \"listings\" | \"offers\")}>\n <TabsList className=\"h-9\">\n <TabsTrigger value=\"listings\" className=\"text-xs px-3 py-1\">\n Listings{!ordersLoading && activeListings.length > 0 && ` (${activeListings.length})`}\n </TabsTrigger>\n <TabsTrigger value=\"offers\" className=\"text-xs px-3 py-1\">\n Offers{!ordersLoading && activeBids.length > 0 && ` (${activeBids.length})`}\n </TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"listings\" className=\"mt-4\">\n {ordersLoading ? loadingGrid : activeListings.length === 0 ? (\n <EmptyState title=\"No active listings\" body=\"When items in this collection are listed for sale, they'll appear here.\" />\n ) : (\n <div className=\"space-y-3\">\n <div className=\"flex justify-end\">\n <OrderSortControl value={listingsSort} onChange={setListingsSort} />\n </div>\n {listingGrid(activeListings, listingsSort, true)}\n </div>\n )}\n </TabsContent>\n\n <TabsContent value=\"offers\" className=\"mt-4\">\n <div className=\"flex justify-end items-center gap-2 mb-3\">\n {!ordersLoading && activeBids.length > 0 ? <OrderSortControl value={offersSort} onChange={setOffersSort} /> : null}\n <MakeOfferPicker contract={contract} onPick={market.offer} />\n </div>\n {ordersLoading ? loadingGrid : activeBids.length === 0 ? (\n <EmptyState title=\"No active offers\" body=\"Make the first offer, or check back when collectors start bidding.\" />\n ) : (\n listingGrid(activeBids, offersSort, false)\n )}\n </TabsContent>\n </Tabs>\n </TabsContent>\n\n <TabsContent value=\"provenance\" className=\"mt-4\">\n <CollectionProvenanceTab contract={contract} />\n </TabsContent>\n\n {profile?.hasGatedContent ? (\n <TabsContent value=\"exclusive\" className=\"mt-4\">\n <GatedContentPanel state={gatedState} onBrowseListings={() => { setMarketTab(\"listings\"); setActiveTab(\"market\"); }} />\n </TabsContent>\n ) : null}\n </Tabs>\n </div>\n\n {collection && isOwner ? (\n <div className=\"px-4 sm:px-6 pb-8 space-y-4\">\n <OwnerSetupPanel contract={contract} profile={profile ?? null} />\n {canTransferCollectionOwnership(collection) ? (\n <div className=\"flex justify-end\">\n <TransferCollectionOwnership collectionId={collection.collectionId!} currentOwner={collection.owner!} collectionName={collection.name} />\n </div>\n ) : null}\n </div>\n ) : null}\n\n {collection ? (\n <ReportDialog open={reportOpen} onOpenChange={setReportOpen} target={{ type: \"COLLECTION\", contract: collection.contractAddress, name: collection.name ?? undefined }} />\n ) : null}\n {market.dialogs}\n </div>\n );\n}\n"],"mappings":";AAuEM,cAIE,YAJF;AArEN,SAAS,WAAW,SAAS,gBAAoD;AACjF,SAAS,OAAO,MAAM,UAAU,cAAc;AAC9C,SAAS,WAAW,kBAA2G;AAC/H,OAAO,UAAU;AACjB,SAAS,WAAW,yBAAyB;AAC7C,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,yBAAyB,+BAA+B;AACjE,SAAS,gBAAgB;AACzB,SAAS,oBAAoB;AAC7B,SAAS,+BAA+B;AACxC,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,mCAAmC;AAC5C,SAAS,2BAA2B;AACpC,SAAS,aAAa,2BAA2B;AACjD,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,kBAAkB,kBAAkC;AAC7D,SAAS,kBAAkB,yBAAiD;AAC5E,SAAS,MAAM,aAAa,UAAU,mBAAmB;AACzD,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,eAAe,2BAA2B;AACnD,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;AACrC,SAAS,cAAc,mBAAmB;AAC1C,SAAS,iBAAiB;AAC1B,SAAS,qBAAqB;AAC9B,SAAS,gCAAgC;AAczC,MAAM,YAAY;AAClB,MAAM,OAAO;AAEb,MAAM,aAAoE;AAAA,EACxE,cAAc,MAAM;AAAA,EACpB,eAAe,CAAC,MAAM,0BAA0B,CAAC;AAAA,EACjD,cAAc,CAAC,MAAM,sBAAsB,CAAC;AAAA,EAC5C,WAAW,CAAC,MAAM,mBAAmB,CAAC;AACxC;AAGO,SAAS,+BAA+B,YAAoC;AACjF,SAAO,CAAC,CAAC,WAAW,gBAAgB,WAAW,aAAa,YAAY,WAAW,aAAa;AAClG;AAEA,SAAS,OAAO,OAA6B,QAAwD;AACnG,QAAM,WAAW,OAAO,OAAO,UAAU,YAAY;AACrD,QAAM,SAAS,OAAO,OAAO,YAAY,WAAW,MAAM,MAAM,SAAS,IAAI;AAC7E,QAAM,OAAO,WAAW,YAAY,QAAQ,QAAQ,IAAI;AACxD,SAAO,QAAQ,QAAQ,MAAM,MAAM,IAAI,OAAO,UAAU,SAAS,IAAI;AACvE;AAEA,SAAS,WAAW,EAAE,OAAO,MAAM,OAAO,GAA8E;AACtH,SACE,qBAAC,SAAI,WAAU,sDACb;AAAA,wBAAC,SAAM,WAAU,sCAAqC;AAAA,IACtD,oBAAC,OAAE,WAAU,6CAA6C,iBAAM;AAAA,IAChE,oBAAC,OAAE,WAAU,6CAA6C,gBAAK;AAAA,IAC9D,SACC,qBAAC,QAAK,MAAM,OAAO,MAAM,WAAU,6IACjC;AAAA,0BAAC,YAAS,WAAU,eAAc;AAAA,MACjC,OAAO;AAAA,OACV,IACE;AAAA,KACN;AAEJ;AAEA,SAAS,mBAAmB,UAAkB;AAC5C,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,CAAC;AAClC,QAAM,CAAC,MAAM,OAAO,IAAI,SAA+B,QAAQ;AAC/D,QAAM,CAAC,WAAW,YAAY,IAAI,SAAqB,CAAC,CAAC;AACzD,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,SAAmC,CAAC,CAAC;AACnF,QAAM,EAAE,QAAQ,MAAM,UAAU,IAAI,oBAAoB,UAAU,MAAM,WAAW,IAAI;AAEvF,QAAM,mBAAmB,CAAC,SAA+B;AACvD,YAAQ,IAAI;AACZ,YAAQ,CAAC;AACT,iBAAa,CAAC,CAAC;AAAA,EACjB;AAEA,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,EAAG;AACzB,iBAAa,CAAC,SAAS;AACrB,YAAM,MAAM,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM,GAAG,EAAE,eAAe,IAAI,EAAE,OAAO,EAAE,CAAC;AACxE,aAAO,SAAS,IAAI,SAAS,CAAC,GAAG,MAAM,GAAG,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,eAAe,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;AAAA,IAC/G,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,IAAI,CAAC;AAEjB,SAAO,EAAE,MAAM,WAAW,SAAS,MAAM,kBAAkB,WAAW,iBAAiB,mBAAmB;AAC5G;AAIA,SAAS,gBAAgB,EAAE,OAAO,gBAAgB,UAAU,UAAU,GAA6G;AACjL,QAAM,EAAE,MAAM,WAAW,SAAS,MAAM,kBAAkB,WAAW,iBAAiB,mBAAmB,IAAI;AAC7G,QAAM,YAAY,aAAa;AAE/B,QAAM,mBAAmB,QAAQ,MAAM,IAAI,IAAI,eAAe,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,YAAa,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC;AAE3I,QAAM,gBAAgB,QAAQ,MAAM;AAClC,UAAM,UAAU,OAAO,QAAQ,eAAe;AAC9C,WAAO,UAAU,OAAO,CAAC,UAAU;AACjC,UAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,YAAM,QAAQ,MAAM,QAAQ,MAAM,UAAU,UAAU,IAAK,MAAM,SAAS,aAA2D,CAAC;AACtI,aAAO,QAAQ,MAAM,CAAC,CAAC,WAAW,MAAM,MAAM,MAAM,KAAK,CAAC,MAAM,EAAE,eAAe,aAAa,OAAO,SAAS,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;AAAA,IACjI,CAAC;AAAA,EACH,GAAG,CAAC,WAAW,eAAe,CAAC;AAE/B,MAAI,aAAa,UAAU,WAAW,GAAG;AACvC,WAAO,oBAAC,SAAI,WAAW,MAAO,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,oBAAC,uBAAuB,CAAG,CAAE,GAAE;AAAA,EACvG;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,WACL,oBAAC,cAAW,OAAM,6BAA4B,MAAK,kDAAiD,QAAQ,EAAE,MAAM,UAAU,OAAO,uBAAuB,GAAG,IAE/J,oBAAC,cAAW,OAAM,gBAAe,MAAK,4DAA2D;AAAA,EAErG;AAEA,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,wBAAC,2BAAwB,QAAQ,WAAW,UAAU,iBAAiB,UAAU,oBAAoB,MAAY,cAAc,kBAAkB;AAAA,IAChJ,cAAc,WAAW,IACxB,oBAAC,cAAW,OAAM,gCAA+B,MAAK,kDAAiD,IAEvG,oBAAC,SAAI,WAAW,MACb,wBAAc,IAAI,CAAC,MAAM;AACxB,YAAM,UACJ,EAAE,cAAc,KAAK,CAAC,MAAM,EAAE,MAAM,aAAa,YAAY,EAAE,MAAM,aAAa,SAAS,KAAK,iBAAiB,IAAI,EAAE,OAAO;AAChI,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,MAAM,UAAU,EAAE,OAAgB,EAAE,iBAAiB,EAAE,OAAO;AAAA,UAC9D,MAAM,EAAE,UAAU,QAAQ,UAAU,EAAE,OAAO;AAAA,UAC7C,OAAO,EAAE,UAAU;AAAA,UACnB,cAAc,EAAE,UAAU;AAAA,UAC1B,MAAM,yBAAyB,EAAE,OAAgB,EAAE,eAAe;AAAA,UAClE,QAAQ,EAAE,UAAU;AAAA,UACpB,OAAO,UAAU,EAAE,GAAG,QAAQ,OAAO,UAAU,OAAO,SAAS,SAAS,EAAE,IAAI;AAAA,UAC9E,YAAY,EAAE;AAAA,UACd,UAAU,EAAE,mBAAmB,aAAa,EAAE,mBAAmB;AAAA,UACjE;AAAA;AAAA,QAVK,GAAG,EAAE,eAAe,IAAI,EAAE,OAAO;AAAA,MAWxC;AAAA,IAEJ,CAAC,GACH;AAAA,IAEF,oBAAC,oBAAiB,SAAS,OAAO,UAAU,UAAU,KAAK,SAAS,KAAK,OAAO,WAAsB,YAAY,MAAM,QAAQ,CAAC,MAAM,IAAI,CAAC,GAAG;AAAA,KACjJ;AAEJ;AAEA,SAAS,aAAa,EAAE,WAAW,GAAkC;AACnE,QAAM,UAAU,WAAW,WAAW,OAAO,GAAG;AAChD,QAAM,WAAW,WAAW;AAC5B,MAAI,YAAY,cAAc;AAC5B,WACE,qBAAC,QAAK,MAAM,sBAAsB,QAAQ,SAAS,WAAU,0JAC3D;AAAA,0BAAC,UAAO,WAAU,eAAc;AAAA,MAAE;AAAA,OAEpC;AAAA,EAEJ;AACA,MAAI,YAAY,UAAW,QAAO,oBAAC,oBAAiB,iBAAiB,UAAU,SAAO,MAAC;AACvF,SAAO;AACT;AAOO,SAAS,eAAe,EAAE,UAAU,MAAM,GAAwB;AACvE,QAAM,EAAE,cAAc,IAAI,gBAAgB;AAC1C,QAAM,EAAE,YAAY,WAAW,kBAAkB,IAAI,cAAc,QAAQ;AAC3E,QAAM,EAAE,QAAQ,IAAI,qBAAqB,QAAQ;AACjD,QAAM,aAAa,MAAM,gBAAgB,SAAS,kBAAkB,WAAW,MAAS;AACxF,QAAM,SAAS,MAAM,iBAAiB;AACtC,QAAM,EAAE,QAAQ,WAAW,cAAc,IAAI,UAAU,EAAE,YAAY,UAAU,QAAQ,UAAU,MAAM,UAAU,OAAO,IAAI,CAAC;AAE7H,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAClD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,QAAQ;AACnD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAgC,UAAU;AAC5E,QAAM,CAAC,cAAc,eAAe,IAAI,SAAoB,QAAQ;AACpE,QAAM,CAAC,YAAY,aAAa,IAAI,SAAoB,QAAQ;AAChE,QAAM,YAAY,aAAa;AAC/B,QAAM,QAAQ,mBAAmB,QAAQ;AAEzC,QAAM,iBAAiB,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,aAAa,EAAE,MAAM,aAAa,YAAY,EAAE,MAAM,aAAa,UAAU;AACtI,QAAM,aAAa,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,YAAY,EAAE,MAAM,aAAa,OAAO;AAC7F,QAAM,UAAU,CAAC,CAAC,YAAY,SAAS,CAAC,CAAC,iBAAiB,cAAc,WAAW,OAAO,aAAa;AACvG,QAAM,WAAW,WAAW,aAAa,WAAW,WAAW,WAAW,OAAO,GAAG,MAAM,EAAE,IAAI,QAAQ,KAAK,OAAO;AACpH,QAAM,EAAE,cAAc,IAAI;AAE1B,QAAM,cAAc,CAACA,QAAmB,MAAiB,YACvD,oBAAC,SAAI,WAAW,MACb,qBAAWA,QAAO,IAAI,EAAE,IAAI,CAAC,MAC5B;AAAA,IAAC;AAAA;AAAA,MAEC,OAAO;AAAA,MACP,OAAO,WAAW,CAAC,cAAc,EAAE,SAAS,aAAa,IAAI,OAAO,MAAM;AAAA,MAC1E,UAAU,OAAO,GAAG,SAAS;AAAA,MAC7B,cAAc,oBAAC,mBAAgB,OAAO,GAAG;AAAA;AAAA,IAJpC,EAAE;AAAA,EAKT,CACD,GACH;AAEF,QAAM,cAAc,oBAAC,SAAI,WAAW,MAAO,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,oBAAC,yBAAyB,CAAG,CAAE,GAAE;AAEpH,SACE,qBAAC,SAAI,WAAU,6BACX;AAAA,gBAA0D,WAAW,oBAAC,uBAAoB,IAAK;AAAA,IAEjG,qBAAC,SAAI,WAAU,qCACb;AAAA,2BAAC,oBAAiB,YAAwB,SAAS,mBAChD;AAAA,sBAAc,UAAU,oBAAC,gBAAa,YAAwB,IAAK;AAAA,QACnE,aAAa,oBAAC,iBAAc,SAAS,WAAW,SAAS,iBAAiB,WAAW,iBAAiB,IAAK;AAAA,SAC9G;AAAA,MACC,cAAc,UAAU,oBAAC,oBAAiB,SAAkB,OAAO,YAAY,iBAAiB,MAAM,aAAa,WAAW,GAAG,IAAK;AAAA,OACzI;AAAA,IAEA,oBAAC,SAAI,WAAU,sBACb,+BAAC,QAAK,OAAO,WAAW,eAAe,cACrC;AAAA,2BAAC,SAAI,WAAU,uDACb;AAAA,6BAAC,YAAS,WAAU,6DAClB;AAAA,+BAAC,eAAY,OAAM,UAAS,WAAU,uBAAsB;AAAA;AAAA,YACnD,YAAY,cAAc,KAAK,WAAW,YAAY,eAAe,CAAC,MAAM;AAAA,aACrF;AAAA,UACA,qBAAC,eAAY,OAAM,UAAS,WAAU,uBAAsB;AAAA;AAAA,YACnD,CAAC,iBAAiB,eAAe,SAAS,WAAW,SAAS,KAAK,KAAK,eAAe,SAAS,WAAW,MAAM;AAAA,aAC1H;AAAA,UACA,oBAAC,eAAY,OAAM,cAAa,WAAU,uBAAsB,wBAAU;AAAA,UACzE,SAAS,kBACR,qBAAC,eAAY,OAAM,aAAY,WAAU,+BACvC;AAAA,gCAAC,QAAK,WAAU,eAAc;AAAA,YAAE;AAAA,aAElC,IACE;AAAA,WACN;AAAA,QACA,qBAAC,SAAI,WAAU,4CACZ;AAAA,wBAAc,YAAY,MAAM,UAAU,SAAS,IAClD,oBAAC,2BAAwB,QAAQ,MAAM,WAAW,UAAU,MAAM,iBAAiB,UAAU,MAAM,oBAAoB,MAAM,MAAM,MAAM,cAAc,MAAM,kBAAkB,OAAO,OAAO,IAC3L;AAAA,UACH,aACC;AAAA,YAAC;AAAA;AAAA,cACC,cAAc,GAAG,YAAY,aAAa,WAAW,eAAe;AAAA,cACpE,YAAY,WAAW,QAAQ;AAAA,cAC/B,UAAU,MAAM,cAAc,IAAI;AAAA;AAAA,UACpC,IACE;AAAA,WACN;AAAA,SACF;AAAA,MAEA,oBAAC,eAAY,OAAM,UAAS,WAAU,QACnC,uBAAa,oBAAC,mBAAgB,OAAc,gBAAgC,UAAoB,WAAW,gBAAgB,WAAW,SAAS,WAAW,QAAQ,MAAM,OAAO,IAAK,MACvL;AAAA,MAEA,oBAAC,eAAY,OAAM,UAAS,WAAU,QACpC,+BAAC,QAAK,OAAO,WAAW,eAAe,CAAC,MAAM,aAAa,CAA0B,GACnF;AAAA,6BAAC,YAAS,WAAU,OAClB;AAAA,+BAAC,eAAY,OAAM,YAAW,WAAU,qBAAoB;AAAA;AAAA,YACjD,CAAC,iBAAiB,eAAe,SAAS,KAAK,KAAK,eAAe,MAAM;AAAA,aACpF;AAAA,UACA,qBAAC,eAAY,OAAM,UAAS,WAAU,qBAAoB;AAAA;AAAA,YACjD,CAAC,iBAAiB,WAAW,SAAS,KAAK,KAAK,WAAW,MAAM;AAAA,aAC1E;AAAA,WACF;AAAA,QAEA,oBAAC,eAAY,OAAM,YAAW,WAAU,QACrC,0BAAgB,cAAc,eAAe,WAAW,IACvD,oBAAC,cAAW,OAAM,sBAAqB,MAAK,2EAA0E,IAEtH,qBAAC,SAAI,WAAU,aACb;AAAA,8BAAC,SAAI,WAAU,oBACb,8BAAC,oBAAiB,OAAO,cAAc,UAAU,iBAAiB,GACpE;AAAA,UACC,YAAY,gBAAgB,cAAc,IAAI;AAAA,WACjD,GAEJ;AAAA,QAEA,qBAAC,eAAY,OAAM,UAAS,WAAU,QACpC;AAAA,+BAAC,SAAI,WAAU,4CACZ;AAAA,aAAC,iBAAiB,WAAW,SAAS,IAAI,oBAAC,oBAAiB,OAAO,YAAY,UAAU,eAAe,IAAK;AAAA,YAC9G,oBAAC,mBAAgB,UAAoB,QAAQ,OAAO,OAAO;AAAA,aAC7D;AAAA,UACC,gBAAgB,cAAc,WAAW,WAAW,IACnD,oBAAC,cAAW,OAAM,oBAAmB,MAAK,sEAAqE,IAE/G,YAAY,YAAY,YAAY,KAAK;AAAA,WAE7C;AAAA,SACF,GACF;AAAA,MAEA,oBAAC,eAAY,OAAM,cAAa,WAAU,QACxC,8BAAC,2BAAwB,UAAoB,GAC/C;AAAA,MAEC,SAAS,kBACR,oBAAC,eAAY,OAAM,aAAY,WAAU,QACvC,8BAAC,qBAAkB,OAAO,YAAY,kBAAkB,MAAM;AAAE,qBAAa,UAAU;AAAG,qBAAa,QAAQ;AAAA,MAAG,GAAG,GACvH,IACE;AAAA,OACN,GACF;AAAA,IAEC,cAAc,UACb,qBAAC,SAAI,WAAU,+BACb;AAAA,0BAAC,mBAAgB,UAAoB,SAAS,WAAW,MAAM;AAAA,MAC9D,+BAA+B,UAAU,IACxC,oBAAC,SAAI,WAAU,oBACb,8BAAC,+BAA4B,cAAc,WAAW,cAAe,cAAc,WAAW,OAAQ,gBAAgB,WAAW,MAAM,GACzI,IACE;AAAA,OACN,IACE;AAAA,IAEH,aACC,oBAAC,gBAAa,MAAM,YAAY,cAAc,eAAe,QAAQ,EAAE,MAAM,cAAc,UAAU,WAAW,iBAAiB,MAAM,WAAW,QAAQ,OAAU,GAAG,IACrK;AAAA,IACH,OAAO;AAAA,KACV;AAEJ;","names":["items"]}
|
|
@@ -95,6 +95,9 @@ const DEFAULTS = {
|
|
|
95
95
|
aiPolicy: "Allowed",
|
|
96
96
|
royalty: 0
|
|
97
97
|
};
|
|
98
|
+
function suggestedExternalUrl(collection) {
|
|
99
|
+
return collection?.contractAddress ? `https://medialane.io${(0, import_sdk.collectionHref)("STARKNET", collection.contractAddress)}` : "";
|
|
100
|
+
}
|
|
98
101
|
function SingleEditionMint({ aside }) {
|
|
99
102
|
const app = (0, import_medialane_app.useMedialaneApp)();
|
|
100
103
|
const walletAddress = app.walletAddress;
|
|
@@ -121,11 +124,16 @@ function SingleEditionMint({ aside }) {
|
|
|
121
124
|
(0, import_react.useEffect)(() => {
|
|
122
125
|
if (collections.length > 0 && !form.getValues("collectionId")) form.setValue("collectionId", collections[0].collectionId);
|
|
123
126
|
}, [collections, form]);
|
|
127
|
+
const suggestedUrl = suggestedExternalUrl(selectedCollection);
|
|
128
|
+
const autoUrlRef = (0, import_react.useRef)("");
|
|
124
129
|
(0, import_react.useEffect)(() => {
|
|
125
|
-
if (
|
|
126
|
-
|
|
130
|
+
if (!suggestedUrl) return;
|
|
131
|
+
const current = form.getValues("external_url");
|
|
132
|
+
if (!current || current === autoUrlRef.current) {
|
|
133
|
+
form.setValue("external_url", suggestedUrl);
|
|
134
|
+
autoUrlRef.current = suggestedUrl;
|
|
127
135
|
}
|
|
128
|
-
}, [
|
|
136
|
+
}, [suggestedUrl, form]);
|
|
129
137
|
const handleLicenseChange = (value) => {
|
|
130
138
|
form.setValue("licenseType", value);
|
|
131
139
|
const def = import_ip.LICENSE_TYPES.find((l) => l.value === value);
|
|
@@ -141,7 +149,9 @@ function SingleEditionMint({ aside }) {
|
|
|
141
149
|
};
|
|
142
150
|
const handleAgain = () => {
|
|
143
151
|
tx.reset();
|
|
144
|
-
|
|
152
|
+
const first = collections[0] ?? null;
|
|
153
|
+
autoUrlRef.current = suggestedExternalUrl(first);
|
|
154
|
+
form.reset({ ...DEFAULTS, collectionId: first?.collectionId ?? "", external_url: autoUrlRef.current });
|
|
145
155
|
metadataFieldsRef.current = [];
|
|
146
156
|
setMetadataResetKey((key) => key + 1);
|
|
147
157
|
setImageFile(null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/launchpad/single-edition-mint.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport * as z from \"zod\";\nimport { Boxes, ChevronDown, ImagePlus, Layers, ShieldCheck, Upload } from \"lucide-react\";\nimport { assetHref, collectionHref, getService, profileHref } from \"@medialane/sdk\";\nimport { acceptFor, uploadError } from \"../../utils/upload-limits.js\";\nimport { FIELD_LIMITS } from \"../../utils/field-limits.js\";\nimport { mintedTokenIdFromReceipt } from \"@medialane/sdk/starknet\";\nimport Image from \"../image.js\";\nimport { Input } from \"../input.js\";\nimport { Textarea } from \"../textarea.js\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"../select.js\";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"../collapsible.js\";\nimport { CollapsibleSection } from \"../collapsible-section.js\";\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"../form.js\";\nimport { ToggleGroup } from \"../create-form-primitives.js\";\nimport { IPTypeFields } from \"../ip-type-fields.js\";\nimport { ClaimRouteShell } from \"../claim-route-shell.js\";\nimport { TransactionSuccess } from \"../transaction-success.js\";\nimport { MedialaneCollectionCard } from \"../medialane-collection-card.js\";\nimport { TransactionDialog } from \"../transaction-dialog.js\";\nimport { WalletRequired } from \"../wallet-required.js\";\nimport { useMedialaneApp } from \"../medialane-app.js\";\nimport { RewardEarned } from \"../rewards/reward-earned.js\";\nimport { CollectionPicker } from \"./collection-picker.js\";\nimport { AI_POLICIES, DERIVATIVES_OPTIONS, IP_TYPES, LICENSE_TYPES, type IPType } from \"../../data/ip.js\";\nimport { cn } from \"../../utils/cn.js\";\nimport { runIntentCalls } from \"../../utils/run-intent-calls.js\";\nimport { pinAssetMetadata, uploadFileToIpfs } from \"../../utils/ipfs-upload.js\";\nimport { useCollectionsByOwner } from \"../../utils/use-collections.js\";\nimport { useTransaction } from \"../../utils/use-transaction.js\";\nimport { invalidatePortfolioCache } from \"../../utils/portfolio-cache.js\";\nimport type { MetadataField } from \"../ip-type-fields.js\";\n\nconst schema = z.object({\n collectionId: z.string().min(1, \"Select a collection\"),\n name: z.string().min(1, \"Name required\").max(FIELD_LIMITS.name),\n description: z.string().max(FIELD_LIMITS.description).optional(),\n external_url: z\n .string()\n .max(500)\n .refine((v) => !v || v.startsWith(\"http://\") || v.startsWith(\"https://\"), { message: \"Must start with http:// or https://\" })\n .optional(),\n ipType: z.enum(IP_TYPES),\n licenseType: z.string().min(1, \"License required\"),\n commercialUse: z.enum([\"Yes\", \"No\"]),\n derivatives: z.enum([\"Allowed\", \"Not Allowed\", \"Share-Alike\"]),\n attribution: z.enum([\"Required\", \"Not Required\"]),\n geographicScope: z.string(),\n aiPolicy: z.enum([\"Allowed\", \"Not Allowed\", \"Training Only\"]),\n royalty: z.coerce.number().min(0).max(50),\n image: z.instanceof(File).optional(),\n});\ntype FormValues = z.infer<typeof schema>;\n\nconst DEFAULTS: FormValues = {\n collectionId: \"\",\n name: \"\",\n description: \"\",\n external_url: \"\",\n ipType: \"NFT\",\n licenseType: \"CC BY-SA\",\n commercialUse: \"Yes\",\n derivatives: \"Share-Alike\",\n attribution: \"Required\",\n geographicScope: \"Worldwide\",\n aiPolicy: \"Allowed\",\n royalty: 0,\n};\n\nexport function SingleEditionMint({ aside }: { aside?: ReactNode }) {\n const app = useMedialaneApp();\n const walletAddress = app.walletAddress;\n const tx = useTransaction();\n const { collections: allCollections, isLoading: collectionsLoading } = useCollectionsByOwner(walletAddress ?? null);\n const collections = allCollections.filter((c) => getService(c.service)?.id === \"mip-erc721\" && c.collectionId != null);\n\n const [imageFile, setImageFile] = useState<File | null>(null);\n const [imagePreview, setImagePreview] = useState<string | null>(null);\n const [advancedOpen, setAdvancedOpen] = useState(false);\n const [licensingOpen, setLicensingOpen] = useState(false);\n const [ipTypeOpen, setIpTypeOpen] = useState(false);\n const [metadataResetKey, setMetadataResetKey] = useState(0);\n const metadataFieldsRef = useRef<MetadataField[]>([]);\n const previewUrlRef = useRef<string | null>(null);\n const imageInputRef = useRef<HTMLInputElement | null>(null);\n\n useEffect(() => {\n return () => {\n if (previewUrlRef.current) URL.revokeObjectURL(previewUrlRef.current);\n };\n }, []);\n\n const form = useForm<FormValues>({ resolver: zodResolver(schema), defaultValues: DEFAULTS });\n const selectedCollectionId = form.watch(\"collectionId\");\n const selectedCollection = collections.find((c) => c.collectionId === selectedCollectionId) ?? null;\n\n useEffect(() => {\n if (collections.length > 0 && !form.getValues(\"collectionId\")) form.setValue(\"collectionId\", collections[0]!.collectionId!);\n }, [collections, form]);\n\n useEffect(() => {\n if (selectedCollection?.contractAddress && !form.getValues(\"external_url\")) {\n form.setValue(\"external_url\", `https://medialane.io${collectionHref(\"STARKNET\", selectedCollection.contractAddress)}`);\n }\n }, [selectedCollection?.contractAddress, form]);\n\n const handleLicenseChange = (value: string) => {\n form.setValue(\"licenseType\", value);\n const def = LICENSE_TYPES.find((l) => l.value === value);\n if (def) {\n form.setValue(\"commercialUse\", def.commercialUse);\n form.setValue(\"derivatives\", def.derivatives);\n form.setValue(\"attribution\", def.attribution);\n }\n };\n\n const uploadDocument = async (file: File) => {\n await app.ensureSignedIn?.();\n return (await uploadFileToIpfs(app.getClient().api, file, \"document\")).uri;\n };\n\n const handleAgain = () => {\n tx.reset();\n form.reset({ ...DEFAULTS, collectionId: collections[0]?.collectionId ?? \"\" });\n metadataFieldsRef.current = [];\n setMetadataResetKey((key) => key + 1);\n setImageFile(null);\n setImagePreview(null);\n if (imageInputRef.current) imageInputRef.current.value = \"\";\n };\n\n const onSubmit = (values: FormValues) => {\n if (!walletAddress) return;\n void tx.run(async (signer) => {\n await app.ensureSignedIn?.();\n const api = app.getClient().api;\n const pinned = await pinAssetMetadata(api, {\n name: values.name,\n description: values.description ?? \"\",\n externalUrl: values.external_url,\n creator: walletAddress,\n ipType: values.ipType,\n licenseType: values.licenseType,\n commercialUse: values.commercialUse,\n derivatives: values.derivatives,\n attribution: values.attribution,\n geographicScope: values.geographicScope,\n aiPolicy: values.aiPolicy,\n royalty: String(values.royalty),\n imageFile,\n templateTraits: metadataFieldsRef.current.filter((f) => f.traitType.trim() && f.value.trim()).map((f) => ({ traitType: f.traitType.trim(), value: f.value.trim() })),\n });\n await runIntentCalls(signer, () =>\n api.intents.create(\"mint\", {\n owner: walletAddress,\n collectionId: values.collectionId,\n recipient: walletAddress,\n tokenUri: pinned.uri,\n royaltyBps: Math.round(values.royalty * 100),\n }),\n );\n invalidatePortfolioCache(walletAddress);\n });\n };\n\n const mintedTokenId = tx.receipt && selectedCollection ? mintedTokenIdFromReceipt(tx.receipt, selectedCollection.contractAddress) : null;\n const mintedHref = mintedTokenId && selectedCollection ? assetHref(\"STARKNET\", selectedCollection.contractAddress, mintedTokenId) : null;\n const busy = tx.phase !== \"idle\" || collectionsLoading || collections.length === 0;\n\n return (\n <WalletRequired\n icon={ImagePlus}\n iconClassName=\"text-brand-blue\"\n title=\"Secure your account to create\"\n description=\"Publish your creative work as a single-copy NFT in a collection you own.\"\n >\n <TransactionDialog tx={tx} title=\"Mint NFT\" workingLabel=\"Minting your work…\" firstStepLabel=\"Upload to IPFS\">\n <TransactionSuccess\n name={form.getValues(\"name\") || \"Your asset\"}\n image={imagePreview}\n title=\"Asset minted\"\n description=\"Your wallet is the owner. The license terms and royalty are recorded in its metadata.\"\n actions={[\n ...(mintedHref ? [{ href: mintedHref, label: \"View asset\" }] : []),\n { href: \"/portfolio/assets\", label: \"View portfolio\" },\n { label: \"Mint another\", onClick: handleAgain },\n ]}\n >\n <RewardEarned actionType=\"mint_asset\" />\n </TransactionSuccess>\n </TransactionDialog>\n\n <ClaimRouteShell\n icon={<ImagePlus className=\"h-4 w-4 text-white\" />}\n title=\"Mint NFT\"\n subtitle=\"Publish your creative work as a single-copy NFT in a collection you own — free to mint, and it's yours.\"\n aside={\n <>\n <MedialaneCollectionCard\n image={imagePreview}\n name={form.watch(\"name\")}\n collection={selectedCollection?.name || \"IP Asset\"}\n creator={walletAddress ? `${walletAddress.slice(0, 6)}…${walletAddress.slice(-4)}` : undefined}\n creatorHref={walletAddress ? profileHref({ address: walletAddress }) : undefined}\n />\n {aside}\n </>\n }\n >\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n <FormField control={form.control} name=\"collectionId\" render={({ field }) => (\n <FormItem>\n <FormLabel className=\"flex items-center gap-1.5\"><Boxes className=\"h-4 w-4\" />Collection *</FormLabel>\n <CollectionPicker\n collections={collections}\n loading={collectionsLoading}\n value={field.value}\n onChange={field.onChange}\n newCollectionHref=\"/launchpad/single-editions/collection\"\n />\n <FormMessage />\n </FormItem>\n )} />\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Cover image</label>\n <div\n className=\"border-2 border-dashed border-border rounded-xl p-8 text-center cursor-pointer hover:border-primary/50 transition-colors\"\n role=\"button\"\n tabIndex={0}\n aria-label=\"Upload image\"\n onClick={() => imageInputRef.current?.click()}\n onKeyDown={(e) => { if (e.key === \"Enter\" || e.key === \" \") { e.preventDefault(); imageInputRef.current?.click(); } }}\n >\n {imagePreview ? (\n <div className=\"relative mx-auto h-48 w-48 overflow-hidden rounded-lg\">\n <Image src={imagePreview} alt=\"Preview\" fill unoptimized className=\"object-cover\" />\n </div>\n ) : (\n <div className=\"flex flex-col items-center gap-2 text-muted-foreground\">\n <Upload className=\"h-8 w-8\" />\n <p className=\"text-sm\">Click to upload (JPG, PNG, GIF, SVG, WebP)</p>\n </div>\n )}\n <input\n ref={imageInputRef}\n type=\"file\"\n accept={acceptFor(\"image\")}\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const fileError = uploadError(file, \"image\");\n if (fileError) {\n form.setError(\"image\", { message: fileError });\n e.target.value = \"\";\n return;\n }\n form.clearErrors(\"image\");\n setImageFile(file);\n form.setValue(\"image\", file);\n if (previewUrlRef.current) URL.revokeObjectURL(previewUrlRef.current);\n const objectUrl = URL.createObjectURL(file);\n previewUrlRef.current = objectUrl;\n setImagePreview(objectUrl);\n }}\n />\n </div>\n {form.formState.errors.image && <p role=\"alert\" className=\"text-sm text-destructive\">{form.formState.errors.image.message}</p>}\n </div>\n\n <FormField control={form.control} name=\"name\" render={({ field }) => (\n <FormItem>\n <FormLabel>Name *</FormLabel>\n <FormControl><Input placeholder=\"My Creative Work\" {...field} /></FormControl>\n <FormMessage />\n </FormItem>\n )} />\n\n <FormField control={form.control} name=\"description\" render={({ field }) => (\n <FormItem>\n <FormLabel>Description</FormLabel>\n <FormControl><Textarea placeholder=\"Describe your work, its story, and any context for buyers…\" rows={4} {...field} /></FormControl>\n <FormMessage />\n </FormItem>\n )} />\n\n <FormField control={form.control} name=\"external_url\" render={({ field }) => (\n <FormItem>\n <FormLabel>External link <span className=\"text-muted-foreground font-normal\">(optional)</span></FormLabel>\n <FormControl><Input placeholder=\"https://yourwebsite.com\" {...field} /></FormControl>\n <FormMessage />\n </FormItem>\n )} />\n\n <CollapsibleSection\n open={licensingOpen}\n onOpenChange={setLicensingOpen}\n icon={<ShieldCheck className=\"h-4 w-4 text-primary\" />}\n label=\"Licensing Terms\"\n hint=\"Optional · Berne Convention\"\n >\n <p className=\"text-xs text-muted-foreground\">Set how others can use your work. These terms are saved permanently with it as proof of authorship.</p>\n <FormField control={form.control} name=\"licenseType\" render={({ field }) => (\n <FormItem>\n <FormLabel>License</FormLabel>\n <Select value={field.value} onValueChange={handleLicenseChange}>\n <FormControl><SelectTrigger><SelectValue /></SelectTrigger></FormControl>\n <SelectContent>{LICENSE_TYPES.map((l) => <SelectItem key={l.value} value={l.value}>{l.label}</SelectItem>)}</SelectContent>\n </Select>\n {(() => { const def = LICENSE_TYPES.find((l) => l.value === field.value); return def ? <p className=\"text-xs text-muted-foreground mt-1\">{def.description}</p> : null; })()}\n <FormMessage />\n </FormItem>\n )} />\n <FormField control={form.control} name=\"commercialUse\" render={({ field }) => (\n <FormItem><FormLabel>Commercial Use</FormLabel><ToggleGroup value={field.value} options={[\"Yes\", \"No\"]} onChange={field.onChange} /></FormItem>\n )} />\n <FormField control={form.control} name=\"derivatives\" render={({ field }) => (\n <FormItem><FormLabel>Derivatives</FormLabel><ToggleGroup value={field.value} options={DERIVATIVES_OPTIONS} onChange={field.onChange} /></FormItem>\n )} />\n <FormField control={form.control} name=\"attribution\" render={({ field }) => (\n <FormItem><FormLabel>Attribution</FormLabel><ToggleGroup value={field.value} options={[\"Required\", \"Not Required\"]} onChange={field.onChange} /></FormItem>\n )} />\n <Collapsible open={advancedOpen} onOpenChange={setAdvancedOpen}>\n <CollapsibleTrigger asChild>\n <button type=\"button\" className=\"flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors\">\n <ChevronDown className={cn(\"h-3.5 w-3.5 transition-transform\", advancedOpen && \"rotate-180\")} />\n Advanced options\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent className=\"space-y-4 pt-3\">\n <FormField control={form.control} name=\"geographicScope\" render={({ field }) => (\n <FormItem>\n <FormLabel>Territory</FormLabel>\n <FormControl><Input placeholder=\"Worldwide\" {...field} /></FormControl>\n </FormItem>\n )} />\n <FormField control={form.control} name=\"aiPolicy\" render={({ field }) => (\n <FormItem><FormLabel>AI & Data Mining</FormLabel><ToggleGroup value={field.value} options={AI_POLICIES} onChange={field.onChange} /></FormItem>\n )} />\n <FormField control={form.control} name=\"royalty\" render={({ field }) => (\n <FormItem>\n <FormLabel>Royalty % (0–50)</FormLabel>\n <FormControl>\n <Input type=\"number\" min={0} max={50} step={0.5} placeholder=\"0\" {...field} onChange={(e) => field.onChange(parseFloat(e.target.value) || 0)} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )} />\n </CollapsibleContent>\n </Collapsible>\n </CollapsibleSection>\n\n <CollapsibleSection\n open={ipTypeOpen}\n onOpenChange={setIpTypeOpen}\n icon={<Layers className=\"h-4 w-4 text-primary\" />}\n label=\"IP Type & Metadata\"\n hint=\"Optional\"\n >\n <p className=\"text-xs text-muted-foreground\">Choose a content type, fill suggested metadata, or add your own trait pairs.</p>\n <FormField control={form.control} name=\"ipType\" render={({ field }) => (\n <FormItem>\n <FormLabel>IP Type</FormLabel>\n <Select onValueChange={field.onChange} value={field.value}>\n <FormControl><SelectTrigger><SelectValue /></SelectTrigger></FormControl>\n <SelectContent>{IP_TYPES.map((t) => <SelectItem key={t} value={t}>{t}</SelectItem>)}</SelectContent>\n </Select>\n </FormItem>\n )} />\n <IPTypeFields\n key={metadataResetKey}\n ipType={form.watch(\"ipType\") as IPType}\n onChange={(fields) => { metadataFieldsRef.current = fields; }}\n uploadDocument={uploadDocument}\n />\n </CollapsibleSection>\n\n <button\n type=\"submit\"\n disabled={busy}\n className={`w-full h-12 text-base font-semibold text-white rounded-xl flex items-center justify-center gap-2 transition-all hover:brightness-110 active:scale-[0.98] bg-brand-blue ${busy ? \"opacity-40 pointer-events-none\" : \"\"}`}\n >\n Mint NFT\n </button>\n <p className=\"text-xs text-center text-muted-foreground\">Free to mint — protocol fee is zero.</p>\n </form>\n </Form>\n </ClaimRouteShell>\n </WalletRequired>\n );\n}\n"],"mappings":"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","names":["Image"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/launchpad/single-edition-mint.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport * as z from \"zod\";\nimport { Boxes, ChevronDown, ImagePlus, Layers, ShieldCheck, Upload } from \"lucide-react\";\nimport { assetHref, collectionHref, getService, profileHref } from \"@medialane/sdk\";\nimport { acceptFor, uploadError } from \"../../utils/upload-limits.js\";\nimport { FIELD_LIMITS } from \"../../utils/field-limits.js\";\nimport { mintedTokenIdFromReceipt } from \"@medialane/sdk/starknet\";\nimport Image from \"../image.js\";\nimport { Input } from \"../input.js\";\nimport { Textarea } from \"../textarea.js\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"../select.js\";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"../collapsible.js\";\nimport { CollapsibleSection } from \"../collapsible-section.js\";\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"../form.js\";\nimport { ToggleGroup } from \"../create-form-primitives.js\";\nimport { IPTypeFields } from \"../ip-type-fields.js\";\nimport { ClaimRouteShell } from \"../claim-route-shell.js\";\nimport { TransactionSuccess } from \"../transaction-success.js\";\nimport { MedialaneCollectionCard } from \"../medialane-collection-card.js\";\nimport { TransactionDialog } from \"../transaction-dialog.js\";\nimport { WalletRequired } from \"../wallet-required.js\";\nimport { useMedialaneApp } from \"../medialane-app.js\";\nimport { RewardEarned } from \"../rewards/reward-earned.js\";\nimport { CollectionPicker } from \"./collection-picker.js\";\nimport { AI_POLICIES, DERIVATIVES_OPTIONS, IP_TYPES, LICENSE_TYPES, type IPType } from \"../../data/ip.js\";\nimport { cn } from \"../../utils/cn.js\";\nimport { runIntentCalls } from \"../../utils/run-intent-calls.js\";\nimport { pinAssetMetadata, uploadFileToIpfs } from \"../../utils/ipfs-upload.js\";\nimport { useCollectionsByOwner } from \"../../utils/use-collections.js\";\nimport { useTransaction } from \"../../utils/use-transaction.js\";\nimport { invalidatePortfolioCache } from \"../../utils/portfolio-cache.js\";\nimport type { MetadataField } from \"../ip-type-fields.js\";\n\nconst schema = z.object({\n collectionId: z.string().min(1, \"Select a collection\"),\n name: z.string().min(1, \"Name required\").max(FIELD_LIMITS.name),\n description: z.string().max(FIELD_LIMITS.description).optional(),\n external_url: z\n .string()\n .max(500)\n .refine((v) => !v || v.startsWith(\"http://\") || v.startsWith(\"https://\"), { message: \"Must start with http:// or https://\" })\n .optional(),\n ipType: z.enum(IP_TYPES),\n licenseType: z.string().min(1, \"License required\"),\n commercialUse: z.enum([\"Yes\", \"No\"]),\n derivatives: z.enum([\"Allowed\", \"Not Allowed\", \"Share-Alike\"]),\n attribution: z.enum([\"Required\", \"Not Required\"]),\n geographicScope: z.string(),\n aiPolicy: z.enum([\"Allowed\", \"Not Allowed\", \"Training Only\"]),\n royalty: z.coerce.number().min(0).max(50),\n image: z.instanceof(File).optional(),\n});\ntype FormValues = z.infer<typeof schema>;\n\nconst DEFAULTS: FormValues = {\n collectionId: \"\",\n name: \"\",\n description: \"\",\n external_url: \"\",\n ipType: \"NFT\",\n licenseType: \"CC BY-SA\",\n commercialUse: \"Yes\",\n derivatives: \"Share-Alike\",\n attribution: \"Required\",\n geographicScope: \"Worldwide\",\n aiPolicy: \"Allowed\",\n royalty: 0,\n};\n\nfunction suggestedExternalUrl(collection: { contractAddress?: string | null } | null): string {\n return collection?.contractAddress ? `https://medialane.io${collectionHref(\"STARKNET\", collection.contractAddress)}` : \"\";\n}\n\nexport function SingleEditionMint({ aside }: { aside?: ReactNode }) {\n const app = useMedialaneApp();\n const walletAddress = app.walletAddress;\n const tx = useTransaction();\n const { collections: allCollections, isLoading: collectionsLoading } = useCollectionsByOwner(walletAddress ?? null);\n const collections = allCollections.filter((c) => getService(c.service)?.id === \"mip-erc721\" && c.collectionId != null);\n\n const [imageFile, setImageFile] = useState<File | null>(null);\n const [imagePreview, setImagePreview] = useState<string | null>(null);\n const [advancedOpen, setAdvancedOpen] = useState(false);\n const [licensingOpen, setLicensingOpen] = useState(false);\n const [ipTypeOpen, setIpTypeOpen] = useState(false);\n const [metadataResetKey, setMetadataResetKey] = useState(0);\n const metadataFieldsRef = useRef<MetadataField[]>([]);\n const previewUrlRef = useRef<string | null>(null);\n const imageInputRef = useRef<HTMLInputElement | null>(null);\n\n useEffect(() => {\n return () => {\n if (previewUrlRef.current) URL.revokeObjectURL(previewUrlRef.current);\n };\n }, []);\n\n const form = useForm<FormValues>({ resolver: zodResolver(schema), defaultValues: DEFAULTS });\n const selectedCollectionId = form.watch(\"collectionId\");\n const selectedCollection = collections.find((c) => c.collectionId === selectedCollectionId) ?? null;\n\n useEffect(() => {\n if (collections.length > 0 && !form.getValues(\"collectionId\")) form.setValue(\"collectionId\", collections[0]!.collectionId!);\n }, [collections, form]);\n\n const suggestedUrl = suggestedExternalUrl(selectedCollection);\n const autoUrlRef = useRef(\"\");\n\n useEffect(() => {\n if (!suggestedUrl) return;\n const current = form.getValues(\"external_url\");\n if (!current || current === autoUrlRef.current) {\n form.setValue(\"external_url\", suggestedUrl);\n autoUrlRef.current = suggestedUrl;\n }\n }, [suggestedUrl, form]);\n\n const handleLicenseChange = (value: string) => {\n form.setValue(\"licenseType\", value);\n const def = LICENSE_TYPES.find((l) => l.value === value);\n if (def) {\n form.setValue(\"commercialUse\", def.commercialUse);\n form.setValue(\"derivatives\", def.derivatives);\n form.setValue(\"attribution\", def.attribution);\n }\n };\n\n const uploadDocument = async (file: File) => {\n await app.ensureSignedIn?.();\n return (await uploadFileToIpfs(app.getClient().api, file, \"document\")).uri;\n };\n\n const handleAgain = () => {\n tx.reset();\n const first = collections[0] ?? null;\n autoUrlRef.current = suggestedExternalUrl(first);\n form.reset({ ...DEFAULTS, collectionId: first?.collectionId ?? \"\", external_url: autoUrlRef.current });\n metadataFieldsRef.current = [];\n setMetadataResetKey((key) => key + 1);\n setImageFile(null);\n setImagePreview(null);\n if (imageInputRef.current) imageInputRef.current.value = \"\";\n };\n\n const onSubmit = (values: FormValues) => {\n if (!walletAddress) return;\n void tx.run(async (signer) => {\n await app.ensureSignedIn?.();\n const api = app.getClient().api;\n const pinned = await pinAssetMetadata(api, {\n name: values.name,\n description: values.description ?? \"\",\n externalUrl: values.external_url,\n creator: walletAddress,\n ipType: values.ipType,\n licenseType: values.licenseType,\n commercialUse: values.commercialUse,\n derivatives: values.derivatives,\n attribution: values.attribution,\n geographicScope: values.geographicScope,\n aiPolicy: values.aiPolicy,\n royalty: String(values.royalty),\n imageFile,\n templateTraits: metadataFieldsRef.current.filter((f) => f.traitType.trim() && f.value.trim()).map((f) => ({ traitType: f.traitType.trim(), value: f.value.trim() })),\n });\n await runIntentCalls(signer, () =>\n api.intents.create(\"mint\", {\n owner: walletAddress,\n collectionId: values.collectionId,\n recipient: walletAddress,\n tokenUri: pinned.uri,\n royaltyBps: Math.round(values.royalty * 100),\n }),\n );\n invalidatePortfolioCache(walletAddress);\n });\n };\n\n const mintedTokenId = tx.receipt && selectedCollection ? mintedTokenIdFromReceipt(tx.receipt, selectedCollection.contractAddress) : null;\n const mintedHref = mintedTokenId && selectedCollection ? assetHref(\"STARKNET\", selectedCollection.contractAddress, mintedTokenId) : null;\n const busy = tx.phase !== \"idle\" || collectionsLoading || collections.length === 0;\n\n return (\n <WalletRequired\n icon={ImagePlus}\n iconClassName=\"text-brand-blue\"\n title=\"Secure your account to create\"\n description=\"Publish your creative work as a single-copy NFT in a collection you own.\"\n >\n <TransactionDialog tx={tx} title=\"Mint NFT\" workingLabel=\"Minting your work…\" firstStepLabel=\"Upload to IPFS\">\n <TransactionSuccess\n name={form.getValues(\"name\") || \"Your asset\"}\n image={imagePreview}\n title=\"Asset minted\"\n description=\"Your wallet is the owner. The license terms and royalty are recorded in its metadata.\"\n actions={[\n ...(mintedHref ? [{ href: mintedHref, label: \"View asset\" }] : []),\n { href: \"/portfolio/assets\", label: \"View portfolio\" },\n { label: \"Mint another\", onClick: handleAgain },\n ]}\n >\n <RewardEarned actionType=\"mint_asset\" />\n </TransactionSuccess>\n </TransactionDialog>\n\n <ClaimRouteShell\n icon={<ImagePlus className=\"h-4 w-4 text-white\" />}\n title=\"Mint NFT\"\n subtitle=\"Publish your creative work as a single-copy NFT in a collection you own — free to mint, and it's yours.\"\n aside={\n <>\n <MedialaneCollectionCard\n image={imagePreview}\n name={form.watch(\"name\")}\n collection={selectedCollection?.name || \"IP Asset\"}\n creator={walletAddress ? `${walletAddress.slice(0, 6)}…${walletAddress.slice(-4)}` : undefined}\n creatorHref={walletAddress ? profileHref({ address: walletAddress }) : undefined}\n />\n {aside}\n </>\n }\n >\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n <FormField control={form.control} name=\"collectionId\" render={({ field }) => (\n <FormItem>\n <FormLabel className=\"flex items-center gap-1.5\"><Boxes className=\"h-4 w-4\" />Collection *</FormLabel>\n <CollectionPicker\n collections={collections}\n loading={collectionsLoading}\n value={field.value}\n onChange={field.onChange}\n newCollectionHref=\"/launchpad/single-editions/collection\"\n />\n <FormMessage />\n </FormItem>\n )} />\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Cover image</label>\n <div\n className=\"border-2 border-dashed border-border rounded-xl p-8 text-center cursor-pointer hover:border-primary/50 transition-colors\"\n role=\"button\"\n tabIndex={0}\n aria-label=\"Upload image\"\n onClick={() => imageInputRef.current?.click()}\n onKeyDown={(e) => { if (e.key === \"Enter\" || e.key === \" \") { e.preventDefault(); imageInputRef.current?.click(); } }}\n >\n {imagePreview ? (\n <div className=\"relative mx-auto h-48 w-48 overflow-hidden rounded-lg\">\n <Image src={imagePreview} alt=\"Preview\" fill unoptimized className=\"object-cover\" />\n </div>\n ) : (\n <div className=\"flex flex-col items-center gap-2 text-muted-foreground\">\n <Upload className=\"h-8 w-8\" />\n <p className=\"text-sm\">Click to upload (JPG, PNG, GIF, SVG, WebP)</p>\n </div>\n )}\n <input\n ref={imageInputRef}\n type=\"file\"\n accept={acceptFor(\"image\")}\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const fileError = uploadError(file, \"image\");\n if (fileError) {\n form.setError(\"image\", { message: fileError });\n e.target.value = \"\";\n return;\n }\n form.clearErrors(\"image\");\n setImageFile(file);\n form.setValue(\"image\", file);\n if (previewUrlRef.current) URL.revokeObjectURL(previewUrlRef.current);\n const objectUrl = URL.createObjectURL(file);\n previewUrlRef.current = objectUrl;\n setImagePreview(objectUrl);\n }}\n />\n </div>\n {form.formState.errors.image && <p role=\"alert\" className=\"text-sm text-destructive\">{form.formState.errors.image.message}</p>}\n </div>\n\n <FormField control={form.control} name=\"name\" render={({ field }) => (\n <FormItem>\n <FormLabel>Name *</FormLabel>\n <FormControl><Input placeholder=\"My Creative Work\" {...field} /></FormControl>\n <FormMessage />\n </FormItem>\n )} />\n\n <FormField control={form.control} name=\"description\" render={({ field }) => (\n <FormItem>\n <FormLabel>Description</FormLabel>\n <FormControl><Textarea placeholder=\"Describe your work, its story, and any context for buyers…\" rows={4} {...field} /></FormControl>\n <FormMessage />\n </FormItem>\n )} />\n\n <FormField control={form.control} name=\"external_url\" render={({ field }) => (\n <FormItem>\n <FormLabel>External link <span className=\"text-muted-foreground font-normal\">(optional)</span></FormLabel>\n <FormControl><Input placeholder=\"https://yourwebsite.com\" {...field} /></FormControl>\n <FormMessage />\n </FormItem>\n )} />\n\n <CollapsibleSection\n open={licensingOpen}\n onOpenChange={setLicensingOpen}\n icon={<ShieldCheck className=\"h-4 w-4 text-primary\" />}\n label=\"Licensing Terms\"\n hint=\"Optional · Berne Convention\"\n >\n <p className=\"text-xs text-muted-foreground\">Set how others can use your work. These terms are saved permanently with it as proof of authorship.</p>\n <FormField control={form.control} name=\"licenseType\" render={({ field }) => (\n <FormItem>\n <FormLabel>License</FormLabel>\n <Select value={field.value} onValueChange={handleLicenseChange}>\n <FormControl><SelectTrigger><SelectValue /></SelectTrigger></FormControl>\n <SelectContent>{LICENSE_TYPES.map((l) => <SelectItem key={l.value} value={l.value}>{l.label}</SelectItem>)}</SelectContent>\n </Select>\n {(() => { const def = LICENSE_TYPES.find((l) => l.value === field.value); return def ? <p className=\"text-xs text-muted-foreground mt-1\">{def.description}</p> : null; })()}\n <FormMessage />\n </FormItem>\n )} />\n <FormField control={form.control} name=\"commercialUse\" render={({ field }) => (\n <FormItem><FormLabel>Commercial Use</FormLabel><ToggleGroup value={field.value} options={[\"Yes\", \"No\"]} onChange={field.onChange} /></FormItem>\n )} />\n <FormField control={form.control} name=\"derivatives\" render={({ field }) => (\n <FormItem><FormLabel>Derivatives</FormLabel><ToggleGroup value={field.value} options={DERIVATIVES_OPTIONS} onChange={field.onChange} /></FormItem>\n )} />\n <FormField control={form.control} name=\"attribution\" render={({ field }) => (\n <FormItem><FormLabel>Attribution</FormLabel><ToggleGroup value={field.value} options={[\"Required\", \"Not Required\"]} onChange={field.onChange} /></FormItem>\n )} />\n <Collapsible open={advancedOpen} onOpenChange={setAdvancedOpen}>\n <CollapsibleTrigger asChild>\n <button type=\"button\" className=\"flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors\">\n <ChevronDown className={cn(\"h-3.5 w-3.5 transition-transform\", advancedOpen && \"rotate-180\")} />\n Advanced options\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent className=\"space-y-4 pt-3\">\n <FormField control={form.control} name=\"geographicScope\" render={({ field }) => (\n <FormItem>\n <FormLabel>Territory</FormLabel>\n <FormControl><Input placeholder=\"Worldwide\" {...field} /></FormControl>\n </FormItem>\n )} />\n <FormField control={form.control} name=\"aiPolicy\" render={({ field }) => (\n <FormItem><FormLabel>AI & Data Mining</FormLabel><ToggleGroup value={field.value} options={AI_POLICIES} onChange={field.onChange} /></FormItem>\n )} />\n <FormField control={form.control} name=\"royalty\" render={({ field }) => (\n <FormItem>\n <FormLabel>Royalty % (0–50)</FormLabel>\n <FormControl>\n <Input type=\"number\" min={0} max={50} step={0.5} placeholder=\"0\" {...field} onChange={(e) => field.onChange(parseFloat(e.target.value) || 0)} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )} />\n </CollapsibleContent>\n </Collapsible>\n </CollapsibleSection>\n\n <CollapsibleSection\n open={ipTypeOpen}\n onOpenChange={setIpTypeOpen}\n icon={<Layers className=\"h-4 w-4 text-primary\" />}\n label=\"IP Type & Metadata\"\n hint=\"Optional\"\n >\n <p className=\"text-xs text-muted-foreground\">Choose a content type, fill suggested metadata, or add your own trait pairs.</p>\n <FormField control={form.control} name=\"ipType\" render={({ field }) => (\n <FormItem>\n <FormLabel>IP Type</FormLabel>\n <Select onValueChange={field.onChange} value={field.value}>\n <FormControl><SelectTrigger><SelectValue /></SelectTrigger></FormControl>\n <SelectContent>{IP_TYPES.map((t) => <SelectItem key={t} value={t}>{t}</SelectItem>)}</SelectContent>\n </Select>\n </FormItem>\n )} />\n <IPTypeFields\n key={metadataResetKey}\n ipType={form.watch(\"ipType\") as IPType}\n onChange={(fields) => { metadataFieldsRef.current = fields; }}\n uploadDocument={uploadDocument}\n />\n </CollapsibleSection>\n\n <button\n type=\"submit\"\n disabled={busy}\n className={`w-full h-12 text-base font-semibold text-white rounded-xl flex items-center justify-center gap-2 transition-all hover:brightness-110 active:scale-[0.98] bg-brand-blue ${busy ? \"opacity-40 pointer-events-none\" : \"\"}`}\n >\n Mint NFT\n </button>\n <p className=\"text-xs text-center text-muted-foreground\">Free to mint — protocol fee is zero.</p>\n </form>\n </Form>\n </ClaimRouteShell>\n </WalletRequired>\n );\n}\n"],"mappings":"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","names":["Image"]}
|
|
@@ -62,6 +62,9 @@ const DEFAULTS = {
|
|
|
62
62
|
aiPolicy: "Allowed",
|
|
63
63
|
royalty: 0
|
|
64
64
|
};
|
|
65
|
+
function suggestedExternalUrl(collection) {
|
|
66
|
+
return collection?.contractAddress ? `https://medialane.io${collectionHref("STARKNET", collection.contractAddress)}` : "";
|
|
67
|
+
}
|
|
65
68
|
function SingleEditionMint({ aside }) {
|
|
66
69
|
const app = useMedialaneApp();
|
|
67
70
|
const walletAddress = app.walletAddress;
|
|
@@ -88,11 +91,16 @@ function SingleEditionMint({ aside }) {
|
|
|
88
91
|
useEffect(() => {
|
|
89
92
|
if (collections.length > 0 && !form.getValues("collectionId")) form.setValue("collectionId", collections[0].collectionId);
|
|
90
93
|
}, [collections, form]);
|
|
94
|
+
const suggestedUrl = suggestedExternalUrl(selectedCollection);
|
|
95
|
+
const autoUrlRef = useRef("");
|
|
91
96
|
useEffect(() => {
|
|
92
|
-
if (
|
|
93
|
-
|
|
97
|
+
if (!suggestedUrl) return;
|
|
98
|
+
const current = form.getValues("external_url");
|
|
99
|
+
if (!current || current === autoUrlRef.current) {
|
|
100
|
+
form.setValue("external_url", suggestedUrl);
|
|
101
|
+
autoUrlRef.current = suggestedUrl;
|
|
94
102
|
}
|
|
95
|
-
}, [
|
|
103
|
+
}, [suggestedUrl, form]);
|
|
96
104
|
const handleLicenseChange = (value) => {
|
|
97
105
|
form.setValue("licenseType", value);
|
|
98
106
|
const def = LICENSE_TYPES.find((l) => l.value === value);
|
|
@@ -108,7 +116,9 @@ function SingleEditionMint({ aside }) {
|
|
|
108
116
|
};
|
|
109
117
|
const handleAgain = () => {
|
|
110
118
|
tx.reset();
|
|
111
|
-
|
|
119
|
+
const first = collections[0] ?? null;
|
|
120
|
+
autoUrlRef.current = suggestedExternalUrl(first);
|
|
121
|
+
form.reset({ ...DEFAULTS, collectionId: first?.collectionId ?? "", external_url: autoUrlRef.current });
|
|
112
122
|
metadataFieldsRef.current = [];
|
|
113
123
|
setMetadataResetKey((key) => key + 1);
|
|
114
124
|
setImageFile(null);
|