From 554733cf0d4be4b6526d0a2cfbc383ab3ce883af Mon Sep 17 00:00:00 2001 From: Simo Date: Fri, 27 Feb 2026 10:35:33 -0400 Subject: [PATCH 1/2] wip Signed-off-by: Simo --- .../waves/MarketplaceItemPreviewCard.test.tsx | 92 +++++++++++++------ ...MarketplaceManifoldListingPreview.test.tsx | 2 + .../MarketplaceOpenseaAssetPreview.test.tsx | 2 + .../waves/marketplace/common.test.ts | 4 + .../useMarketplacePreviewState.test.tsx | 6 ++ .../MarketplacePreviewWebSocketSync.test.tsx | 6 ++ .../waves/MarketplaceItemPreviewCard.tsx | 70 +++++++++++++- .../marketplace/MarketplaceCompactCta.tsx | 18 +++- .../MarketplaceFoundationMintPreview.tsx | 1 + .../marketplace/MarketplaceFullFooter.tsx | 16 +++- .../MarketplaceItemPreviewCard.types.ts | 1 + .../MarketplaceManifoldListingPreview.tsx | 1 + .../MarketplaceOpenseaAssetPreview.tsx | 1 + .../MarketplaceOpenseaItemPreview.tsx | 1 + .../MarketplaceSuperrareArtworkPreview.tsx | 1 + .../MarketplaceTransientMintPreview.tsx | 1 + .../MarketplaceTransientNftPreview.tsx | 1 + components/waves/marketplace/common.ts | 11 +++ .../marketplace/useMarketplacePreviewState.ts | 2 + helpers/Types.tsx | 1 + 20 files changed, 197 insertions(+), 41 deletions(-) diff --git a/__tests__/components/waves/MarketplaceItemPreviewCard.test.tsx b/__tests__/components/waves/MarketplaceItemPreviewCard.test.tsx index 2d4cc17e7e..60397ec422 100644 --- a/__tests__/components/waves/MarketplaceItemPreviewCard.test.tsx +++ b/__tests__/components/waves/MarketplaceItemPreviewCard.test.tsx @@ -46,7 +46,8 @@ describe("MarketplaceItemPreviewCard", () => { mediaUrl="https://arweave.net/test-image" mediaMimeType="image/*" title=" Wave Artifact " - price=" 1.25 ETH " + price=" 1.25 " + priceCurrency=" ETH " /> ); @@ -73,9 +74,10 @@ describe("MarketplaceItemPreviewCard", () => { expect(screen.getByTestId("marketplace-item-title")).toHaveTextContent( "Wave Artifact" ); - expect(screen.getByTestId("manifold-item-price")).toHaveTextContent( - "1.25 ETH" - ); + expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("1.25"); + expect( + screen.getByTestId("marketplace-item-price-currency") + ).toHaveTextContent("ETH"); expect( screen.getByTestId("marketplace-item-copy-button") ).toBeInTheDocument(); @@ -103,16 +105,18 @@ describe("MarketplaceItemPreviewCard", () => { href={href} mediaUrl="https://arweave.net/test-image" mediaMimeType="image/*" - price=" 0.77 ETH " + price=" 0.77 " + priceCurrency=" ETH " /> ); const foundationLogo = screen.getByAltText("Foundation logo"); - expect(foundationLogo).toHaveAttribute("src", "/foundation-icon.jpg"); - expect(screen.getByTestId("manifold-item-price")).toHaveTextContent( - "0.77 ETH" - ); + expect(foundationLogo).toHaveAttribute("src", "/foundation.png"); + expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("0.77"); + expect( + screen.getByTestId("marketplace-item-price-currency") + ).toHaveTextContent("ETH"); expect(screen.getByTestId("marketplace-item-cta-link")).toHaveAttribute( "aria-label", "Open on Foundation - 0.77 ETH" @@ -158,7 +162,8 @@ describe("MarketplaceItemPreviewCard", () => { href="https://example.com/item/3" mediaUrl="https://arweave.net/test-image" mediaMimeType="image/*" - price=" 0.42 ETH " + price=" 0.42 " + priceCurrency=" USDC " /> ); @@ -167,14 +172,36 @@ describe("MarketplaceItemPreviewCard", () => { expect(ctaLink.className).toContain("tw-bg-[#E5E5E5]"); expect(ctaLink.className).toContain("tw-text-[#0A0A0A]"); expect(ctaLink.className).toContain("tw-border-white"); - expect(ctaLink).toHaveAttribute("aria-label", "Open listing - 0.42 ETH"); + expect(ctaLink).toHaveAttribute("aria-label", "Open listing - 0.42 USDC"); expect(screen.queryByTestId("marketplace-item-cta-open-icon")).toBeNull(); - expect(screen.getByTestId("manifold-item-price")).toHaveTextContent( - "0.42 ETH" - ); + expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("0.42"); + expect( + screen.getByTestId("marketplace-item-price-currency") + ).toHaveTextContent("USDC"); expect(screen.queryByAltText(/logo$/i)).toBeNull(); }); + it("strips trailing currency token from price when price_currency matches", () => { + render( + + + + ); + + const ctaLink = screen.getByTestId("marketplace-item-cta-link"); + expect(ctaLink).toHaveAttribute("aria-label", "Open listing - 1.25 ETH"); + expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("1.25"); + expect( + screen.getByTestId("marketplace-item-price-currency") + ).toHaveTextContent("ETH"); + }); + it("renders full-mode light brand CTA when price is missing but marketplace is known", () => { render( @@ -186,7 +213,9 @@ describe("MarketplaceItemPreviewCard", () => { ); - const ctaLink = screen.getByTestId("marketplace-item-cta-link"); + const ctaLink = screen.getByRole("link", { + name: "Open on Manifold", + }); expect(ctaLink).toHaveAttribute("aria-label", "Open on Manifold"); expect(ctaLink.className).toContain("tw-bg-[#E5E5E5]"); expect(ctaLink.className).toContain("tw-text-[#0A0A0A]"); @@ -238,23 +267,27 @@ describe("MarketplaceItemPreviewCard", () => { mediaUrl="https://arweave.net/test-image" mediaMimeType="image/*" compact={true} - price=" 1.25 ETH " + price=" 1.25 " + priceCurrency=" ETH " /> ); expect(screen.queryByTestId("marketplace-item-footer")).toBeNull(); - const ctaLink = screen.getByTestId("marketplace-item-cta-link"); + const ctaLink = screen.getByRole("link", { + name: "Open on Manifold - 1.25 ETH", + }); expect(ctaLink).toHaveClass("tw-absolute", "tw-right-3", "tw-top-[5.5rem]"); expect(ctaLink).toHaveAttribute( "aria-label", "Open on Manifold - 1.25 ETH" ); expect(screen.getByAltText("Manifold logo")).toBeInTheDocument(); - expect(screen.getByTestId("manifold-item-price")).toHaveTextContent( - "1.25 ETH" - ); + expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("1.25"); + expect( + screen.getByTestId("marketplace-item-price-currency") + ).toHaveTextContent("ETH"); expect( screen.getByTestId("marketplace-item-overlay-copy-button") ).toBeInTheDocument(); @@ -282,7 +315,7 @@ describe("MarketplaceItemPreviewCard", () => { expect( screen.queryByTestId("marketplace-item-overlay-open-link") ).toBeNull(); - expect(screen.getByTestId("marketplace-item-cta-link")).toHaveClass( + expect(screen.getByRole("link", { name: "Open on Manifold" })).toHaveClass( "tw-top-3" ); }); @@ -295,7 +328,8 @@ describe("MarketplaceItemPreviewCard", () => { mediaUrl="https://arweave.net/test-image" mediaMimeType="image/*" compact={true} - price=" 0.42 ETH " + price=" 0.42 " + priceCurrency=" ETH " /> ); @@ -303,13 +337,13 @@ describe("MarketplaceItemPreviewCard", () => { expect( screen.getByTestId("marketplace-item-cta-fallback-icon") ).toBeInTheDocument(); - expect(screen.getByTestId("marketplace-item-cta-link")).toHaveAttribute( - "aria-label", - "Open listing - 0.42 ETH" - ); - expect(screen.getByTestId("manifold-item-price")).toHaveTextContent( - "0.42 ETH" - ); + expect( + screen.getByRole("link", { name: "Open listing - 0.42 ETH" }) + ).toBeInTheDocument(); + expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("0.42"); + expect( + screen.getByTestId("marketplace-item-price-currency") + ).toHaveTextContent("ETH"); expect(screen.queryByAltText(/logo$/i)).toBeNull(); }); }); diff --git a/__tests__/components/waves/marketplace/MarketplaceManifoldListingPreview.test.tsx b/__tests__/components/waves/marketplace/MarketplaceManifoldListingPreview.test.tsx index c074334edc..5d876c2c5a 100644 --- a/__tests__/components/waves/marketplace/MarketplaceManifoldListingPreview.test.tsx +++ b/__tests__/components/waves/marketplace/MarketplaceManifoldListingPreview.test.tsx @@ -70,6 +70,7 @@ describe("MarketplaceManifoldListingPreview", () => { media_uri: "https://cdn.example.com/nft-image.png", last_error_message: null, price: "1.25 ETH", + price_currency: "ETH", last_successfully_updated: 1735689600, failed_since: null, }, @@ -86,6 +87,7 @@ describe("MarketplaceManifoldListingPreview", () => { mediaUrl: "https://cdn.example.com/nft-image.png", mediaMimeType: "image/png", price: "1.25 ETH", + priceCurrency: "ETH", title: "Wave Artifact", compact: true, hideActions: true, diff --git a/__tests__/components/waves/marketplace/MarketplaceOpenseaAssetPreview.test.tsx b/__tests__/components/waves/marketplace/MarketplaceOpenseaAssetPreview.test.tsx index 37fbfec638..61b31c255e 100644 --- a/__tests__/components/waves/marketplace/MarketplaceOpenseaAssetPreview.test.tsx +++ b/__tests__/components/waves/marketplace/MarketplaceOpenseaAssetPreview.test.tsx @@ -106,6 +106,7 @@ describe("MarketplaceOpenseaAssetPreview", () => { media_uri: "https://cdn.example.com/nft-image.png", last_error_message: null, price: "0.5 ETH", + price_currency: "ETH", last_successfully_updated: 1735689600, failed_since: null, }, @@ -120,6 +121,7 @@ describe("MarketplaceOpenseaAssetPreview", () => { mediaUrl: "https://cdn.example.com/nft-image.png", mediaMimeType: "image/png", price: "0.5 ETH", + priceCurrency: "ETH", title: "OpenSea Asset #42", }) ) diff --git a/__tests__/components/waves/marketplace/common.test.ts b/__tests__/components/waves/marketplace/common.test.ts index 163f1381f2..913680928c 100644 --- a/__tests__/components/waves/marketplace/common.test.ts +++ b/__tests__/components/waves/marketplace/common.test.ts @@ -26,6 +26,7 @@ const DEFAULT_NFT_LINK_DATA: NonNullable = { media_uri: "https://cdn.example.com/nft.png", last_error_message: null, price: "0.5 ETH", + price_currency: "ETH", last_successfully_updated: 1735689600, failed_since: null, media_preview: null, @@ -104,6 +105,7 @@ describe("primeMarketplacePreviewCacheFromNftLinks", () => { platform: "opensea", title: "Seeded NFT", price: "0.5 ETH", + priceCurrency: "ETH", media: { url: "https://cdn.example.com/nft.png", mimeType: "image/png", @@ -290,6 +292,7 @@ describe("primeMarketplacePreviewCacheFromNftLinks", () => { description: null, media: null, price: null, + priceCurrency: null, } ); @@ -310,6 +313,7 @@ describe("primeMarketplacePreviewCacheFromNftLinks", () => { title: "Existing title", description: "Seeded from drop nft_links", price: "0.5 ETH", + priceCurrency: "ETH", media: { url: "https://cdn.example.com/nft.png", mimeType: "image/png", diff --git a/__tests__/components/waves/marketplace/useMarketplacePreviewState.test.tsx b/__tests__/components/waves/marketplace/useMarketplacePreviewState.test.tsx index f762160f7e..f71cc79333 100644 --- a/__tests__/components/waves/marketplace/useMarketplacePreviewState.test.tsx +++ b/__tests__/components/waves/marketplace/useMarketplacePreviewState.test.tsx @@ -55,6 +55,7 @@ describe("useMarketplacePreviewState", () => { media_uri: "https://cdn.example.com/nft-image.png", last_error_message: null, price: "1.25 ETH", + price_currency: "ETH", last_successfully_updated: 1735689600, failed_since: null, }, @@ -71,6 +72,7 @@ describe("useMarketplacePreviewState", () => { href, resolvedTitle: "Wave Artifact", resolvedPrice: "1.25 ETH", + resolvedPriceCurrency: "ETH", resolvedMedia: { url: "https://cdn.example.com/nft-image.png", mimeType: "image/png", @@ -97,6 +99,7 @@ describe("useMarketplacePreviewState", () => { media_uri: "https://cdn.example.com/nft-image.png", last_error_message: null, price: "0.42 ETH", + price_currency: "ETH", last_successfully_updated: 1735689600, failed_since: null, }, @@ -125,6 +128,7 @@ describe("useMarketplacePreviewState", () => { mimeType: "image/png", }, resolvedPrice: "0.42 ETH", + resolvedPriceCurrency: "ETH", }) ) ); @@ -147,6 +151,7 @@ describe("useMarketplacePreviewState", () => { media_uri: "https://cdn.example.com/nft-image.png", last_error_message: null, price: "0.42 ETH", + price_currency: "ETH", last_successfully_updated: 1735689600, failed_since: null, }, @@ -169,6 +174,7 @@ describe("useMarketplacePreviewState", () => { mimeType: "image/png", }, resolvedPrice: "0.42 ETH", + resolvedPriceCurrency: "ETH", }) ) ); diff --git a/__tests__/services/websocket/MarketplacePreviewWebSocketSync.test.tsx b/__tests__/services/websocket/MarketplacePreviewWebSocketSync.test.tsx index 6032d7e5aa..3d2cec6c3f 100644 --- a/__tests__/services/websocket/MarketplacePreviewWebSocketSync.test.tsx +++ b/__tests__/services/websocket/MarketplacePreviewWebSocketSync.test.tsx @@ -29,6 +29,7 @@ const createMediaLinkUpdatedEvent = ( media_uri: "https://cdn.example.com/updated-image.jpg", last_error_message: null, price: "1.5", + price_currency: "ETH", last_successfully_updated: "1771516351724", failed_since: null, ...overrides, @@ -75,6 +76,7 @@ describe("MarketplacePreviewWebSocketSync", () => { mimeType: "image/jpeg", }, price: "1.0", + priceCurrency: "ETH", }); queryClient.setQueryData(nonMatchingQueryKey, { href: "https://example.com/2", @@ -87,6 +89,7 @@ describe("MarketplacePreviewWebSocketSync", () => { mimeType: "image/jpeg", }, price: "3.0", + priceCurrency: "USDC", }); render( @@ -114,6 +117,7 @@ describe("MarketplacePreviewWebSocketSync", () => { mimeType: "image/jpeg", }, price: "1.5", + priceCurrency: "ETH", }); expect( @@ -129,6 +133,7 @@ describe("MarketplacePreviewWebSocketSync", () => { mimeType: "image/jpeg", }, price: "3.0", + priceCurrency: "USDC", }); }); @@ -150,6 +155,7 @@ describe("MarketplacePreviewWebSocketSync", () => { mimeType: "image/jpeg", }, price: "2.0", + priceCurrency: "ETH", }); render( diff --git a/components/waves/MarketplaceItemPreviewCard.tsx b/components/waves/MarketplaceItemPreviewCard.tsx index 61bc2831b3..2abe088916 100644 --- a/components/waves/MarketplaceItemPreviewCard.tsx +++ b/components/waves/MarketplaceItemPreviewCard.tsx @@ -15,25 +15,83 @@ import { import MarketplaceOverlayActionButtons from "./marketplace/MarketplaceOverlayActionButtons"; import { getMarketplaceContainerClass } from "./marketplace/previewLayout"; +const normalizeSpaceSeparatedText = (value: string): string => + value.trim().replace(/\s+/g, " "); + +const buildDisplayPriceParts = ({ + price, + priceCurrency, +}: { + readonly price: string; + readonly priceCurrency: string; +}) => { + if (price.length === 0) { + return { + priceValueText: "", + priceCurrencyText: "", + ariaPriceText: "", + }; + } + + let priceValueText = price; + if (priceCurrency.length > 0) { + const tokens = price.split(" "); + const lastToken = tokens[tokens.length - 1]; + + if ( + typeof lastToken === "string" && + tokens.length > 1 && + lastToken.toUpperCase() === priceCurrency.toUpperCase() + ) { + const strippedPrice = tokens.slice(0, -1).join(" ").trim(); + if (strippedPrice.length > 0) { + priceValueText = strippedPrice; + } + } + } + + const ariaPriceText = + priceCurrency.length > 0 + ? `${priceValueText} ${priceCurrency}` + : priceValueText; + + return { + priceValueText, + priceCurrencyText: priceCurrency, + ariaPriceText, + }; +}; + export default function MarketplaceItemPreviewCard({ href, mediaUrl, mediaMimeType, price, + priceCurrency, title, compact = false, hideActions = false, }: MarketplaceItemPreviewCardProps) { const variant = useLinkPreviewVariant(); const resolvedPreviewHref = resolvePreviewHref(href); - const normalizedPrice = typeof price === "string" ? price.trim() : ""; + const normalizedPrice = + typeof price === "string" ? normalizeSpaceSeparatedText(price) : ""; + const normalizedPriceCurrency = + typeof priceCurrency === "string" + ? normalizeSpaceSeparatedText(priceCurrency) + : ""; + const { priceValueText, priceCurrencyText, ariaPriceText } = + buildDisplayPriceParts({ + price: normalizedPrice, + priceCurrency: normalizedPriceCurrency, + }); const normalizedTitle = typeof title === "string" ? title.trim() : ""; - const hasPrice = normalizedPrice.length > 0; + const hasPrice = priceValueText.length > 0; const hasTitle = normalizedTitle.length > 0; const displayTitle = hasTitle ? normalizedTitle : DEFAULT_MARKETPLACE_TITLE; const marketplaceBrand = getMarketplaceBrand(href); const ctaAriaLabel = buildMarketplaceCtaLabel({ - normalizedPrice, + normalizedPrice: ariaPriceText, marketplaceBrand, }); @@ -54,7 +112,8 @@ export default function MarketplaceItemPreviewCard({ ctaAriaLabel={ctaAriaLabel} hideActions={hideActions} hasPrice={hasPrice} - normalizedPrice={normalizedPrice} + priceValueText={priceValueText} + priceCurrencyText={priceCurrencyText || undefined} marketplaceBrand={marketplaceBrand} /> {!hideActions && ( @@ -86,7 +145,8 @@ export default function MarketplaceItemPreviewCard({ ctaAriaLabel={ctaAriaLabel} hideActions={hideActions} hasPrice={hasPrice} - normalizedPrice={normalizedPrice} + priceValueText={priceValueText} + priceCurrencyText={priceCurrencyText || undefined} marketplaceBrand={marketplaceBrand} /> diff --git a/components/waves/marketplace/MarketplaceCompactCta.tsx b/components/waves/marketplace/MarketplaceCompactCta.tsx index 2ba624e8ab..a7e1f75c65 100644 --- a/components/waves/marketplace/MarketplaceCompactCta.tsx +++ b/components/waves/marketplace/MarketplaceCompactCta.tsx @@ -12,7 +12,8 @@ interface MarketplaceCompactCtaProps { readonly ctaAriaLabel: string; readonly hideActions: boolean; readonly hasPrice: boolean; - readonly normalizedPrice: string; + readonly priceValueText: string; + readonly priceCurrencyText?: string | undefined; readonly marketplaceBrand: MarketplaceBrand | null; } @@ -21,7 +22,8 @@ export default function MarketplaceCompactCta({ ctaAriaLabel, hideActions, hasPrice, - normalizedPrice, + priceValueText, + priceCurrencyText, marketplaceBrand, }: MarketplaceCompactCtaProps) { const { href, target, rel } = resolvedPreviewHref; @@ -61,9 +63,17 @@ export default function MarketplaceCompactCta({ {hasPrice && ( - {normalizedPrice} + {priceValueText} + + )} + {hasPrice && priceCurrencyText && ( + + {priceCurrencyText} )} diff --git a/components/waves/marketplace/MarketplaceFoundationMintPreview.tsx b/components/waves/marketplace/MarketplaceFoundationMintPreview.tsx index e44d337c41..2455079ef9 100644 --- a/components/waves/marketplace/MarketplaceFoundationMintPreview.tsx +++ b/components/waves/marketplace/MarketplaceFoundationMintPreview.tsx @@ -29,6 +29,7 @@ export default function MarketplaceFoundationMintPreview({ mediaUrl={media.url} mediaMimeType={media.mimeType} price={state.resolvedPrice} + priceCurrency={state.resolvedPriceCurrency} title={state.resolvedTitle} compact={compact} hideActions={compact} diff --git a/components/waves/marketplace/MarketplaceFullFooter.tsx b/components/waves/marketplace/MarketplaceFullFooter.tsx index 2034f227ba..03558a2a0d 100644 --- a/components/waves/marketplace/MarketplaceFullFooter.tsx +++ b/components/waves/marketplace/MarketplaceFullFooter.tsx @@ -15,7 +15,8 @@ interface MarketplaceFullFooterProps { readonly ctaAriaLabel: string; readonly hideActions: boolean; readonly hasPrice: boolean; - readonly normalizedPrice: string; + readonly priceValueText: string; + readonly priceCurrencyText?: string | undefined; readonly marketplaceBrand: MarketplaceBrand | null; } @@ -26,7 +27,8 @@ export default function MarketplaceFullFooter({ ctaAriaLabel, hideActions, hasPrice, - normalizedPrice, + priceValueText, + priceCurrencyText, marketplaceBrand, }: MarketplaceFullFooterProps) { const { href: resolvedHref, target, rel } = resolvedPreviewHref; @@ -71,7 +73,15 @@ export default function MarketplaceFullFooter({ className="tw-max-w-[8rem] tw-truncate" data-testid="manifold-item-price" > - {normalizedPrice} + {priceValueText} + + )} + {hasPrice && priceCurrencyText && ( + + {priceCurrencyText} )} diff --git a/components/waves/marketplace/MarketplaceItemPreviewCard.types.ts b/components/waves/marketplace/MarketplaceItemPreviewCard.types.ts index a1402c01b5..c10450db3f 100644 --- a/components/waves/marketplace/MarketplaceItemPreviewCard.types.ts +++ b/components/waves/marketplace/MarketplaceItemPreviewCard.types.ts @@ -3,6 +3,7 @@ export interface MarketplaceItemPreviewCardProps { readonly mediaUrl: string; readonly mediaMimeType: string; readonly price?: string | undefined; + readonly priceCurrency?: string | undefined; readonly title?: string | undefined; readonly compact?: boolean | undefined; readonly hideActions?: boolean | undefined; diff --git a/components/waves/marketplace/MarketplaceManifoldListingPreview.tsx b/components/waves/marketplace/MarketplaceManifoldListingPreview.tsx index d57215b94d..879bf7f105 100644 --- a/components/waves/marketplace/MarketplaceManifoldListingPreview.tsx +++ b/components/waves/marketplace/MarketplaceManifoldListingPreview.tsx @@ -29,6 +29,7 @@ export default function MarketplaceManifoldListingPreview({ mediaUrl={media.url} mediaMimeType={media.mimeType} price={state.resolvedPrice} + priceCurrency={state.resolvedPriceCurrency} title={state.resolvedTitle} compact={compact} hideActions={compact} diff --git a/components/waves/marketplace/MarketplaceOpenseaAssetPreview.tsx b/components/waves/marketplace/MarketplaceOpenseaAssetPreview.tsx index 4b881089e8..2e0393cbe0 100644 --- a/components/waves/marketplace/MarketplaceOpenseaAssetPreview.tsx +++ b/components/waves/marketplace/MarketplaceOpenseaAssetPreview.tsx @@ -32,6 +32,7 @@ export default function MarketplaceOpenseaAssetPreview({ mediaUrl={media.url} mediaMimeType={media.mimeType} price={state.resolvedPrice} + priceCurrency={state.resolvedPriceCurrency} title={state.resolvedTitle} compact={compact} hideActions={compact} diff --git a/components/waves/marketplace/MarketplaceOpenseaItemPreview.tsx b/components/waves/marketplace/MarketplaceOpenseaItemPreview.tsx index d229e9ab83..6dd4fa144f 100644 --- a/components/waves/marketplace/MarketplaceOpenseaItemPreview.tsx +++ b/components/waves/marketplace/MarketplaceOpenseaItemPreview.tsx @@ -32,6 +32,7 @@ export default function MarketplaceOpenseaItemPreview({ mediaUrl={media.url} mediaMimeType={media.mimeType} price={state.resolvedPrice} + priceCurrency={state.resolvedPriceCurrency} title={state.resolvedTitle} compact={compact} hideActions={compact} diff --git a/components/waves/marketplace/MarketplaceSuperrareArtworkPreview.tsx b/components/waves/marketplace/MarketplaceSuperrareArtworkPreview.tsx index 2780d62925..c576e419cc 100644 --- a/components/waves/marketplace/MarketplaceSuperrareArtworkPreview.tsx +++ b/components/waves/marketplace/MarketplaceSuperrareArtworkPreview.tsx @@ -29,6 +29,7 @@ export default function MarketplaceSuperrareArtworkPreview({ mediaUrl={media.url} mediaMimeType={media.mimeType} price={state.resolvedPrice} + priceCurrency={state.resolvedPriceCurrency} title={state.resolvedTitle} compact={compact} hideActions={compact} diff --git a/components/waves/marketplace/MarketplaceTransientMintPreview.tsx b/components/waves/marketplace/MarketplaceTransientMintPreview.tsx index e7b46b0491..7158d9adf5 100644 --- a/components/waves/marketplace/MarketplaceTransientMintPreview.tsx +++ b/components/waves/marketplace/MarketplaceTransientMintPreview.tsx @@ -29,6 +29,7 @@ export default function MarketplaceTransientMintPreview({ mediaUrl={media.url} mediaMimeType={media.mimeType} price={state.resolvedPrice} + priceCurrency={state.resolvedPriceCurrency} title={state.resolvedTitle} compact={compact} hideActions={compact} diff --git a/components/waves/marketplace/MarketplaceTransientNftPreview.tsx b/components/waves/marketplace/MarketplaceTransientNftPreview.tsx index 069b28ba0d..b4def8249c 100644 --- a/components/waves/marketplace/MarketplaceTransientNftPreview.tsx +++ b/components/waves/marketplace/MarketplaceTransientNftPreview.tsx @@ -29,6 +29,7 @@ export default function MarketplaceTransientNftPreview({ mediaUrl={media.url} mediaMimeType={media.mimeType} price={state.resolvedPrice} + priceCurrency={state.resolvedPriceCurrency} title={state.resolvedTitle} compact={compact} hideActions={compact} diff --git a/components/waves/marketplace/common.ts b/components/waves/marketplace/common.ts index ddacfb26fd..d16340abc4 100644 --- a/components/waves/marketplace/common.ts +++ b/components/waves/marketplace/common.ts @@ -30,6 +30,7 @@ export type MarketplacePreviewState = readonly href: string; readonly resolvedMedia?: PickedMedia | undefined; readonly resolvedPrice?: string | undefined; + readonly resolvedPriceCurrency?: string | undefined; readonly resolvedTitle?: string | undefined; } | { readonly type: "error"; readonly href: string; readonly error: Error }; @@ -47,6 +48,7 @@ export interface MarketplacePreviewData { readonly description: string | null; readonly media: PickedMedia | null; readonly price: string | null; + readonly priceCurrency: string | null; } const OPENSEA_HOST = "opensea.io"; @@ -225,6 +227,10 @@ const pickNftLinkPrice = ( response: ApiNftLinkResponse | undefined ): string | undefined => asNonEmptyString(response?.data?.price); +const pickNftLinkPriceCurrency = ( + response: ApiNftLinkResponse | undefined +): string | undefined => asNonEmptyString(response?.data?.price_currency); + const pickNftLinkTitle = ( response: ApiNftLinkResponse | undefined ): string | undefined => asNonEmptyString(response?.data?.name); @@ -247,6 +253,7 @@ export const fromNftLink = ({ description: pickNftLinkDescription(response) ?? null, media: pickNftLinkMedia(response) ?? null, price: pickNftLinkPrice(response) ?? null, + priceCurrency: pickNftLinkPriceCurrency(response) ?? null, }); const fromApiDropNftLink = ({ @@ -284,6 +291,7 @@ const mergeSeededMarketplacePreviewData = ({ description: current.description ?? seeded.description, media: current.media ?? seeded.media, price: current.price ?? seeded.price, + priceCurrency: current.priceCurrency ?? seeded.priceCurrency, }; }; @@ -388,6 +396,7 @@ export const patchFromMediaLinkUpdate = ({ const nextTitle = asNonEmptyString(update.name); const nextDescription = asNonEmptyString(update.description); const nextPrice = asNonEmptyString(update.price); + const nextPriceCurrency = asNonEmptyString(update.price_currency); const nextMedia = pickMediaFromUrl(update.media_uri) ?? current.media; const patched: MarketplacePreviewData = { @@ -398,6 +407,7 @@ export const patchFromMediaLinkUpdate = ({ description: nextDescription ?? current.description, media: nextMedia, price: nextPrice ?? current.price, + priceCurrency: nextPriceCurrency ?? current.priceCurrency, }; const didChange = @@ -406,6 +416,7 @@ export const patchFromMediaLinkUpdate = ({ patched.title !== current.title || patched.description !== current.description || patched.price !== current.price || + patched.priceCurrency !== current.priceCurrency || !isSameMedia(patched.media, current.media); return didChange ? patched : current; diff --git a/components/waves/marketplace/useMarketplacePreviewState.ts b/components/waves/marketplace/useMarketplacePreviewState.ts index fd64bc5406..1a3a322ff7 100644 --- a/components/waves/marketplace/useMarketplacePreviewState.ts +++ b/components/waves/marketplace/useMarketplacePreviewState.ts @@ -104,6 +104,8 @@ export const useMarketplacePreviewState = ({ href, resolvedMedia, resolvedPrice: marketplacePreviewQuery.data?.price ?? undefined, + resolvedPriceCurrency: + marketplacePreviewQuery.data?.priceCurrency ?? undefined, resolvedTitle: toNonEmptyString(marketplacePreviewQuery.data?.title), }; } diff --git a/helpers/Types.tsx b/helpers/Types.tsx index a37d6ac85e..0963f4e91a 100644 --- a/helpers/Types.tsx +++ b/helpers/Types.tsx @@ -370,6 +370,7 @@ export interface WsMediaLinkUpdatedData { readonly media_uri: string | null; readonly last_error_message: string | null; readonly price: string | null; + readonly price_currency: string | null; readonly last_successfully_updated: string | number | null; readonly failed_since: string | number | null; } From 68533e373d88a9e6f3f35f49f13613663f68442a Mon Sep 17 00:00:00 2001 From: Simo Date: Fri, 27 Feb 2026 11:04:58 -0400 Subject: [PATCH 2/2] wip Signed-off-by: Simo --- .../waves/MarketplaceItemPreviewCard.test.tsx | 31 +++++++++++++------ .../marketplace/MarketplaceCompactCta.tsx | 2 +- .../marketplace/MarketplaceFullFooter.tsx | 2 +- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/__tests__/components/waves/MarketplaceItemPreviewCard.test.tsx b/__tests__/components/waves/MarketplaceItemPreviewCard.test.tsx index 60397ec422..cb8bd01c12 100644 --- a/__tests__/components/waves/MarketplaceItemPreviewCard.test.tsx +++ b/__tests__/components/waves/MarketplaceItemPreviewCard.test.tsx @@ -1,8 +1,7 @@ import { act, fireEvent, render, screen } from "@testing-library/react"; -import React from "react"; -import MarketplaceItemPreviewCard from "@/components/waves/MarketplaceItemPreviewCard"; import { LinkPreviewProvider } from "@/components/waves/LinkPreviewContext"; +import MarketplaceItemPreviewCard from "@/components/waves/MarketplaceItemPreviewCard"; const mockClipboardWriteText = jest.fn, [string]>(); @@ -74,7 +73,9 @@ describe("MarketplaceItemPreviewCard", () => { expect(screen.getByTestId("marketplace-item-title")).toHaveTextContent( "Wave Artifact" ); - expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("1.25"); + expect(screen.getByTestId("marketplace-item-price")).toHaveTextContent( + "1.25" + ); expect( screen.getByTestId("marketplace-item-price-currency") ).toHaveTextContent("ETH"); @@ -113,7 +114,9 @@ describe("MarketplaceItemPreviewCard", () => { const foundationLogo = screen.getByAltText("Foundation logo"); expect(foundationLogo).toHaveAttribute("src", "/foundation.png"); - expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("0.77"); + expect(screen.getByTestId("marketplace-item-price")).toHaveTextContent( + "0.77" + ); expect( screen.getByTestId("marketplace-item-price-currency") ).toHaveTextContent("ETH"); @@ -174,7 +177,9 @@ describe("MarketplaceItemPreviewCard", () => { expect(ctaLink.className).toContain("tw-border-white"); expect(ctaLink).toHaveAttribute("aria-label", "Open listing - 0.42 USDC"); expect(screen.queryByTestId("marketplace-item-cta-open-icon")).toBeNull(); - expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("0.42"); + expect(screen.getByTestId("marketplace-item-price")).toHaveTextContent( + "0.42" + ); expect( screen.getByTestId("marketplace-item-price-currency") ).toHaveTextContent("USDC"); @@ -196,7 +201,9 @@ describe("MarketplaceItemPreviewCard", () => { const ctaLink = screen.getByTestId("marketplace-item-cta-link"); expect(ctaLink).toHaveAttribute("aria-label", "Open listing - 1.25 ETH"); - expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("1.25"); + expect(screen.getByTestId("marketplace-item-price")).toHaveTextContent( + "1.25" + ); expect( screen.getByTestId("marketplace-item-price-currency") ).toHaveTextContent("ETH"); @@ -222,7 +229,7 @@ describe("MarketplaceItemPreviewCard", () => { expect(ctaLink.className).toContain("tw-border-white"); expect(ctaLink).not.toHaveClass("tw-size-8"); expect(screen.getByAltText("Manifold logo")).toBeInTheDocument(); - expect(screen.queryByTestId("manifold-item-price")).toBeNull(); + expect(screen.queryByTestId("marketplace-item-price")).toBeNull(); }); it("hides copy action in full mode when hideActions is true", () => { @@ -256,7 +263,7 @@ describe("MarketplaceItemPreviewCard", () => { expect(ctaLink).toHaveAttribute("aria-label", "Open listing"); expect(ctaLink).toHaveClass("tw-size-8", "tw-bg-black/50", "tw-text-white"); expect(screen.queryByAltText(/logo$/i)).toBeNull(); - expect(screen.queryByTestId("manifold-item-price")).toBeNull(); + expect(screen.queryByTestId("marketplace-item-price")).toBeNull(); }); it("keeps compact mode CTA style with overlay actions when hideActions is false", () => { @@ -284,7 +291,9 @@ describe("MarketplaceItemPreviewCard", () => { "Open on Manifold - 1.25 ETH" ); expect(screen.getByAltText("Manifold logo")).toBeInTheDocument(); - expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("1.25"); + expect(screen.getByTestId("marketplace-item-price")).toHaveTextContent( + "1.25" + ); expect( screen.getByTestId("marketplace-item-price-currency") ).toHaveTextContent("ETH"); @@ -340,7 +349,9 @@ describe("MarketplaceItemPreviewCard", () => { expect( screen.getByRole("link", { name: "Open listing - 0.42 ETH" }) ).toBeInTheDocument(); - expect(screen.getByTestId("manifold-item-price")).toHaveTextContent("0.42"); + expect(screen.getByTestId("marketplace-item-price")).toHaveTextContent( + "0.42" + ); expect( screen.getByTestId("marketplace-item-price-currency") ).toHaveTextContent("ETH"); diff --git a/components/waves/marketplace/MarketplaceCompactCta.tsx b/components/waves/marketplace/MarketplaceCompactCta.tsx index a7e1f75c65..030ca54465 100644 --- a/components/waves/marketplace/MarketplaceCompactCta.tsx +++ b/components/waves/marketplace/MarketplaceCompactCta.tsx @@ -63,7 +63,7 @@ export default function MarketplaceCompactCta({ {hasPrice && ( {priceValueText} diff --git a/components/waves/marketplace/MarketplaceFullFooter.tsx b/components/waves/marketplace/MarketplaceFullFooter.tsx index 03558a2a0d..2a23730396 100644 --- a/components/waves/marketplace/MarketplaceFullFooter.tsx +++ b/components/waves/marketplace/MarketplaceFullFooter.tsx @@ -71,7 +71,7 @@ export default function MarketplaceFullFooter({ {hasPrice && ( {priceValueText}