@fluid-app/portal-sdk 0.1.382 → 0.1.384

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.
Files changed (60) hide show
  1. package/dist/{EmbedWidget-CgC5yVnq.cjs → EmbedWidget-CWStqe63.cjs} +3 -3
  2. package/dist/{EmbedWidget-CgC5yVnq.cjs.map → EmbedWidget-CWStqe63.cjs.map} +1 -1
  3. package/dist/{EmbedWidget-B6sco5Sh.mjs → EmbedWidget-D4HybHKj.mjs} +3 -3
  4. package/dist/{EmbedWidget-B6sco5Sh.mjs.map → EmbedWidget-D4HybHKj.mjs.map} +1 -1
  5. package/dist/{EmbedWidget-Dr6gaAZp.cjs → EmbedWidget-fJRuj5uw.cjs} +1 -1
  6. package/dist/{FluidProvider-CblbC7cR.cjs → FluidProvider-BRKrtfF7.cjs} +3 -3
  7. package/dist/{FluidProvider-CblbC7cR.cjs.map → FluidProvider-BRKrtfF7.cjs.map} +1 -1
  8. package/dist/{FluidProvider-BxRc9UtX.mjs → FluidProvider-sNDwysAs.mjs} +3 -3
  9. package/dist/{FluidProvider-BxRc9UtX.mjs.map → FluidProvider-sNDwysAs.mjs.map} +1 -1
  10. package/dist/{MessagingScreen-xsZB4aha.cjs → MessagingScreen-BFCqA6Ge.cjs} +3 -3
  11. package/dist/{MessagingScreen-OxLhD-jj.mjs → MessagingScreen-C53Z7xHW.mjs} +2 -2
  12. package/dist/{MessagingScreen-OxLhD-jj.mjs.map → MessagingScreen-C53Z7xHW.mjs.map} +1 -1
  13. package/dist/{MessagingScreen-DMDqLVqA.mjs → MessagingScreen-CfdnXLuG.mjs} +3 -3
  14. package/dist/{MessagingScreen-BlN1Aw1K.cjs → MessagingScreen-YeyZcW87.cjs} +2 -2
  15. package/dist/{MessagingScreen-BlN1Aw1K.cjs.map → MessagingScreen-YeyZcW87.cjs.map} +1 -1
  16. package/dist/{OrdersScreen-CBoMj1nE.cjs → OrdersScreen-BG6zoehy.cjs} +4 -4
  17. package/dist/{OrdersScreen-Ch8SM5_B.cjs → OrdersScreen-BMnnZh8v.cjs} +3 -3
  18. package/dist/{OrdersScreen-Ch8SM5_B.cjs.map → OrdersScreen-BMnnZh8v.cjs.map} +1 -1
  19. package/dist/{OrdersScreen-mjVvkEbJ.mjs → OrdersScreen-D30UcCb9.mjs} +4 -4
  20. package/dist/{OrdersScreen-C845bV9m.mjs → OrdersScreen-jCE23-nN.mjs} +3 -3
  21. package/dist/{OrdersScreen-C845bV9m.mjs.map → OrdersScreen-jCE23-nN.mjs.map} +1 -1
  22. package/dist/{ProfileScreen-DJrxz420.mjs → ProfileScreen-Bu55j8bD.mjs} +5 -5
  23. package/dist/{ProfileScreen-Bk8N2sP8.cjs → ProfileScreen-CAmRD0vt.cjs} +4 -4
  24. package/dist/{ProfileScreen-Bk8N2sP8.cjs.map → ProfileScreen-CAmRD0vt.cjs.map} +1 -1
  25. package/dist/{ProfileScreen-CMRiSGqm.mjs → ProfileScreen-D5-4xHyf.mjs} +4 -4
  26. package/dist/{ProfileScreen-CMRiSGqm.mjs.map → ProfileScreen-D5-4xHyf.mjs.map} +1 -1
  27. package/dist/{ProfileScreen-D-RJtx2L.cjs → ProfileScreen-Zl1bPxXG.cjs} +5 -5
  28. package/dist/{ShopScreen-Dp-9FXFz.cjs → ShopScreen-BGsmn1iD.cjs} +3 -3
  29. package/dist/{ShopScreen-Ku6qG3Il.cjs → ShopScreen-BcmLO7P5.cjs} +9 -4
  30. package/dist/{ShopScreen-Ku6qG3Il.cjs.map → ShopScreen-BcmLO7P5.cjs.map} +1 -1
  31. package/dist/{ShopScreen-D88P7zES.mjs → ShopScreen-ChngOndQ.mjs} +3 -3
  32. package/dist/{ShopScreen-rJIdTJng.mjs → ShopScreen-bF8kdNws.mjs} +9 -4
  33. package/dist/{ShopScreen-rJIdTJng.mjs.map → ShopScreen-bF8kdNws.mjs.map} +1 -1
  34. package/dist/{SubscriptionsScreen-DubPYOFS.cjs → SubscriptionsScreen-BZBppAEb.cjs} +5 -5
  35. package/dist/{SubscriptionsScreen-BKIgK5d4.cjs → SubscriptionsScreen-Chg41CCa.cjs} +4 -4
  36. package/dist/{SubscriptionsScreen-BKIgK5d4.cjs.map → SubscriptionsScreen-Chg41CCa.cjs.map} +1 -1
  37. package/dist/{SubscriptionsScreen-n2OC2f95.mjs → SubscriptionsScreen-RClWcQ88.mjs} +4 -4
  38. package/dist/{SubscriptionsScreen-n2OC2f95.mjs.map → SubscriptionsScreen-RClWcQ88.mjs.map} +1 -1
  39. package/dist/{SubscriptionsScreen-BA68a8Xr.mjs → SubscriptionsScreen-eF122WP7.mjs} +5 -5
  40. package/dist/{display-JuYIguJK.cjs → display-DKzN3DZd.cjs} +9 -3
  41. package/dist/display-DKzN3DZd.cjs.map +1 -0
  42. package/dist/{display-B3BfkaBm.mjs → display-vZrlWWCP.mjs} +9 -3
  43. package/dist/display-vZrlWWCP.mjs.map +1 -0
  44. package/dist/index.cjs +20 -20
  45. package/dist/index.d.cts.map +1 -1
  46. package/dist/index.d.mts.map +1 -1
  47. package/dist/index.mjs +20 -20
  48. package/dist/preview/preview-entry.cjs +3 -3
  49. package/dist/preview/preview-entry.mjs +3 -3
  50. package/dist/{use-portal-card-add-3ds-flow-CW-sJsDW.mjs → use-portal-card-add-3ds-flow-CHdZounD.mjs} +3 -3
  51. package/dist/{use-portal-card-add-3ds-flow-CW-sJsDW.mjs.map → use-portal-card-add-3ds-flow-CHdZounD.mjs.map} +1 -1
  52. package/dist/{use-portal-card-add-3ds-flow-DnZEut5p.cjs → use-portal-card-add-3ds-flow-u-PUJ_-8.cjs} +3 -3
  53. package/dist/{use-portal-card-add-3ds-flow-DnZEut5p.cjs.map → use-portal-card-add-3ds-flow-u-PUJ_-8.cjs.map} +1 -1
  54. package/dist/{widget-package-utils-B92IpLB6.cjs → widget-package-utils-BS3nP1P3.cjs} +2 -2
  55. package/dist/{widget-package-utils-B92IpLB6.cjs.map → widget-package-utils-BS3nP1P3.cjs.map} +1 -1
  56. package/dist/{widget-package-utils-Dz3l38G-.mjs → widget-package-utils-Cuc1XGS2.mjs} +2 -2
  57. package/dist/{widget-package-utils-Dz3l38G-.mjs.map → widget-package-utils-Cuc1XGS2.mjs.map} +1 -1
  58. package/package.json +22 -22
  59. package/dist/display-B3BfkaBm.mjs.map +0 -1
  60. package/dist/display-JuYIguJK.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ShopScreen-Ku6qG3Il.cjs","names":["defaultRenderImage","useShopTranslation","getProductImageUrl","isVideoUrl","formatPortalPrice","determineProductPrice","formatPortalPriceRange","getVideoThumbnailUrl","CirclePlay","Badge","Card","useShopTranslation","isVideoUrl","ChevronLeft","ChevronRight","Dialog","DialogContent","DialogTitle","DialogDescription","DialogClose","X","Button","useShopTranslation","formatSavings","RadioGroup","RadioGroupItem","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","isVariantSubscribable","Skeleton","useShopTranslation","usePortalProductCatalog","SearchSort","DropdownMenu","DropdownMenuTrigger","Button","ArrowUpDown","DropdownMenuContent","DropdownMenuLabel","DropdownMenuSeparator","DropdownMenuRadioGroup","DropdownMenuRadioItem","usePortalProductDetail","usePortalProducts","formatPrice","isStaticBundle","formatPriceRange","bundleSubscriptionPrice","Badge","ExternalLink","ShoppingCart","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","React","useShopTranslation","Button","ShoppingCart","useFluidContext","useShopTranslation","useStore","useAccount","useAppNavigation","ScreenHeaderBreadcrumbs","Breadcrumb","BreadcrumbList","BreadcrumbItem","BreadcrumbPage","ScreenHeaderActions","useNavigationParent","usePortalProductDetail","BreadcrumbLink","BreadcrumbSeparator"],"sources":["../../../shop/ui/src/components/product-card.tsx","../../../shop/ui/src/components/image-gallery.tsx","../../../shop/ui/src/components/quantity-selector.tsx","../../../shop/ui/src/components/purchase-options.tsx","../../../shop/ui/src/utils/is-variant-unavailable.ts","../../../shop/ui/src/components/shop-app.tsx","../../../cart/ui/src/components/cart-script.tsx","../../../cart/ui/src/components/cart-widget.tsx","../../../cart/ui/src/components/cart-button.tsx","../../../cart/ui/src/components/shop-container.tsx","../src/screens/ShopScreen.tsx"],"sourcesContent":["import type React from \"react\";\nimport { useState, type ReactNode } from \"react\";\nimport type { products, portalProducts } from \"@fluid-app/products-core\";\nimport {\n determineProductPrice,\n formatPortalPrice,\n formatPortalPriceRange,\n getProductImageUrl,\n} from \"@fluid-app/products-core\";\nimport { Badge, Card } from \"@fluid-app/ui-primitives\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\nimport { CirclePlay } from \"lucide-react\";\nimport { getVideoThumbnailUrl, isVideoUrl } from \"../utils/media-helpers\";\n\ntype LegacyProduct = (products.Product | products.ShopProduct) & {\n kind?: string;\n video_url?: string;\n};\n\nexport interface RenderImageProps {\n src: string;\n alt: string;\n fill?: boolean;\n className?: string;\n onError?: (e: React.SyntheticEvent<HTMLImageElement>) => void;\n unoptimized?: boolean;\n}\n\ntype TaggedPortalProduct = portalProducts.Product & {\n readonly __portalProduct: true;\n};\n\nexport type ProductCardProduct = LegacyProduct | TaggedPortalProduct;\n\ninterface ProductCardProps {\n product: ProductCardProduct;\n countryIso?: string;\n companyLogoUrl?: string | null;\n showShareModal?: boolean;\n setShareModalOpen?: (open: boolean) => void;\n setSelectedProduct?: (product: LegacyProduct) => void;\n renderLink?: (props: { href: string; children: ReactNode }) => ReactNode;\n renderImage?: (props: RenderImageProps) => ReactNode;\n onClick?: () => void;\n}\n\nexport function tagPortalProduct(\n product: portalProducts.Product,\n): TaggedPortalProduct {\n return { ...product, __portalProduct: true as const };\n}\n\nfunction isPortalProduct(\n product: ProductCardProduct,\n): product is TaggedPortalProduct {\n return \"__portalProduct\" in product && product.__portalProduct === true;\n}\n\nfunction getPortalProductCoverImage(\n product: portalProducts.Product,\n): string | null {\n if (product.images && product.images.length > 0) {\n return product.images[0]?.url ?? null;\n }\n return null;\n}\n\nfunction defaultRenderImage({\n src,\n alt,\n fill,\n className,\n onError,\n}: RenderImageProps): ReactNode {\n return (\n <img\n src={src}\n alt={alt}\n className={`${fill ? \"absolute inset-0 h-full w-full\" : \"\"} ${className ?? \"\"}`}\n onError={onError}\n />\n );\n}\n\nfunction ProductCardContent({\n product,\n countryIso,\n companyLogoUrl,\n renderImage = defaultRenderImage,\n}: {\n product: ProductCardProduct;\n countryIso?: string;\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n}) {\n const [isHovered, setIsHovered] = useState(false);\n const { t } = useShopTranslation();\n\n const isPortal = isPortalProduct(product);\n const coverImage = isPortal\n ? getPortalProductCoverImage(product)\n : getProductImageUrl(product as Parameters<typeof getProductImageUrl>[0]);\n const isVideo = isVideoUrl(coverImage);\n const productName = isPortal\n ? product.name || t(\"no_title\")\n : (product as LegacyProduct).title || t(\"no_title\");\n\n const isBundle = isPortal && product.is_bundle === true;\n\n let repPrice: string | null | undefined = null;\n let price: string | null | undefined = null;\n if (isPortal) {\n // wholesale_price is non-null for reps, null for customers\n if (product.wholesale_price) {\n repPrice = formatPortalPrice(product.wholesale_price, product.currency);\n // Show retail as strikethrough if different from wholesale\n const retailFormatted = formatPortalPrice(\n product.price,\n product.currency,\n );\n if (retailFormatted !== repPrice) {\n price = retailFormatted;\n }\n } else {\n repPrice = formatPortalPrice(product.price, product.currency);\n }\n } else if (countryIso) {\n const prices = determineProductPrice(product, countryIso);\n repPrice = prices.repPrice;\n price = prices.price;\n }\n\n // A bundle's master-variant price is often $0, so show the resolved range.\n // Fall back to the single (backend-guaranteed non-zero) retail price when no\n // range — matching the detail page's fallback so card and detail never diverge.\n const bundlePrice = isBundle\n ? (formatPortalPriceRange(product.price_range, product.currency) ??\n formatPortalPrice(product.price, product.currency))\n : null;\n\n const resolvedCoverImage =\n isVideo && coverImage\n ? getVideoThumbnailUrl(coverImage)\n : coverImage ||\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\";\n\n return (\n <>\n {/* Image/Video container */}\n <div\n className=\"bg-muted/40 relative aspect-square overflow-hidden rounded-lg\"\n onMouseEnter={() => isVideo && setIsHovered(true)}\n onMouseLeave={() => isVideo && setIsHovered(false)}\n >\n {isVideo && isHovered ? (\n <video\n src={coverImage || \"\"}\n className=\"absolute inset-0 h-full w-full object-cover\"\n autoPlay\n muted\n loop\n playsInline\n />\n ) : (\n renderImage({\n src: resolvedCoverImage,\n alt: productName,\n fill: true,\n className:\n \"object-cover transition-transform duration-300 hover:scale-[1.02]\",\n onError: (e) => {\n e.currentTarget.src =\n companyLogoUrl ||\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\";\n },\n unoptimized: true,\n })\n )}\n\n {/* Video play indicator */}\n {isVideo && !isHovered && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"flex size-16 items-center justify-center rounded-full bg-black/50 backdrop-blur-sm\">\n <CirclePlay className=\"size-12 text-white\" />\n </div>\n </div>\n )}\n\n {/* Bundle badge */}\n {isBundle && (\n <Badge variant=\"secondary\" className=\"absolute top-2 left-2\">\n {t(\"bundle_badge\")}\n </Badge>\n )}\n </div>\n\n {/* Product info */}\n <div className=\"px-0.5 pt-2 pb-1\">\n <h3 className=\"text-foreground line-clamp-1 text-sm leading-snug font-semibold\">\n {productName}\n </h3>\n\n <div className=\"flex items-center gap-2\">\n {isBundle ? (\n bundlePrice && (\n <span className=\"text-foreground text-sm leading-none font-semibold\">\n {bundlePrice}\n </span>\n )\n ) : (\n <>\n {repPrice && (\n <span className=\"text-foreground text-sm leading-none font-semibold\">\n {repPrice}\n </span>\n )}\n {price && (\n <span className=\"text-muted-foreground text-sm leading-none line-through\">\n {price}\n </span>\n )}\n </>\n )}\n </div>\n\n {!isPortal && countryIso && (\n <div className=\"text-muted-foreground mt-1 text-xs\">\n CV{\" \"}\n {getVariantCountryValue(\n getSelectedVariant(product as LegacyProduct),\n countryIso,\n \"cv\",\n ) || \"-\"}{\" \"}\n | QV{\" \"}\n {getVariantCountryValue(\n getSelectedVariant(product as LegacyProduct),\n countryIso,\n \"qv\",\n ) || \"-\"}\n </div>\n )}\n\n {isPortal && product.wholesale_price != null && (\n <div className=\"text-muted-foreground mt-1 text-xs\">\n CV {product.cv ?? \"-\"} | QV {product.qv ?? \"-\"}\n </div>\n )}\n </div>\n </>\n );\n}\n\nfunction getSelectedVariant(\n product: LegacyProduct,\n): products.Variant | products.ShopVariant | null {\n if (!product.variants || product.variants.length === 0) return null;\n\n const masterVariant = product.variants.find(\n (v: products.Variant | products.ShopVariant) => {\n return \"is_master\" in v && v.is_master;\n },\n );\n if (masterVariant) return masterVariant;\n\n return product.variants[0] || null;\n}\n\nfunction getVariantCountryValue(\n variant: products.Variant | products.ShopVariant | null,\n countryIso: string,\n field: \"cv\" | \"qv\",\n): number | null {\n if (!variant || !variant.variant_countries) return null;\n\n if (\n typeof variant.variant_countries === \"object\" &&\n !Array.isArray(variant.variant_countries)\n ) {\n const countryData = variant.variant_countries[countryIso] as\n | products.VariantCountry\n | undefined;\n return countryData?.[field] ?? null;\n }\n\n if (Array.isArray(variant.variant_countries)) {\n const countryData = variant.variant_countries.find(\n (vc: products.ShopVariantCountry) => vc.country_iso === countryIso,\n );\n return countryData?.[field] ?? null;\n }\n\n return null;\n}\n\nexport default function ProductCard({\n product,\n countryIso,\n companyLogoUrl,\n showShareModal = false,\n setShareModalOpen,\n setSelectedProduct,\n renderLink,\n renderImage,\n onClick,\n}: ProductCardProps): React.JSX.Element {\n const cardContent = (\n <ProductCardContent\n product={product}\n {...(countryIso !== undefined && { countryIso })}\n {...(companyLogoUrl !== undefined && { companyLogoUrl })}\n {...(renderImage !== undefined && { renderImage })}\n />\n );\n\n const cardClassName =\n \"bg-transparent overflow-hidden border-0 shadow-none pt-0 gap-0\";\n\n if (showShareModal && !isPortalProduct(product)) {\n const handleShareClick = () => {\n if (setSelectedProduct && setShareModalOpen) {\n setSelectedProduct(product);\n setShareModalOpen(true);\n }\n };\n return (\n <Card className={cardClassName}>\n <button\n onClick={handleShareClick}\n className=\"group block w-full cursor-pointer text-left\"\n >\n {cardContent}\n </button>\n </Card>\n );\n }\n\n if (onClick) {\n return (\n <Card className={cardClassName}>\n <button\n onClick={onClick}\n className=\"group block w-full cursor-pointer text-left\"\n >\n {cardContent}\n </button>\n </Card>\n );\n }\n\n const href = `/portal/shop/${product.id}`;\n\n if (renderLink) {\n return (\n <Card className={cardClassName}>\n {renderLink({ href, children: cardContent })}\n </Card>\n );\n }\n\n return (\n <Card className={cardClassName}>\n <a href={href} className=\"group block cursor-pointer\">\n {cardContent}\n </a>\n </Card>\n );\n}\n","import type React from \"react\";\nimport { type ReactNode, useEffect, useMemo, useState } from \"react\";\nimport { ChevronLeft, ChevronRight, X } from \"lucide-react\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogTitle,\n DialogClose,\n} from \"@fluid-app/ui-primitives\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\nimport { isVideoUrl } from \"../utils/media-helpers\";\nimport type { RenderImageProps } from \"./product-card\";\n\ninterface ImageGalleryProps {\n images: Array<{\n id: number;\n image_url: string;\n image_path: string | null;\n position: number;\n }>;\n fallbackImageUrl: string;\n productTitle: string;\n renderImage?: (props: RenderImageProps) => ReactNode;\n}\n\nfunction defaultRenderImage({\n src,\n alt,\n fill,\n className,\n onError,\n}: RenderImageProps): ReactNode {\n return (\n <img\n src={src}\n alt={alt}\n className={`${fill ? \"absolute inset-0 h-full w-full\" : \"\"} ${className ?? \"\"}`}\n onError={onError}\n />\n );\n}\n\nexport default function ImageGallery({\n images,\n fallbackImageUrl,\n productTitle,\n renderImage = defaultRenderImage,\n}: ImageGalleryProps): React.JSX.Element {\n const { t } = useShopTranslation();\n const [currentImageIndex, setCurrentImageIndex] = useState(0);\n const [viewerOpen, setViewerOpen] = useState(false);\n\n const hasMultipleImages = images && images.length > 0;\n const displayImages = useMemo(\n () =>\n hasMultipleImages\n ? images.toSorted((a, b) => a.position - b.position)\n : [{ id: 0, image_url: fallbackImageUrl, position: 0 }],\n [images, hasMultipleImages, fallbackImageUrl],\n );\n\n // Reset to first image when the images array changes (e.g. variant switch)\n useEffect(() => {\n setCurrentImageIndex(0);\n }, [displayImages]);\n\n const nextImage = () => {\n if (displayImages.length > 1) {\n setCurrentImageIndex((prev) => (prev + 1) % displayImages.length);\n }\n };\n\n const prevImage = () => {\n if (displayImages.length > 1) {\n setCurrentImageIndex(\n (prev) => (prev - 1 + displayImages.length) % displayImages.length,\n );\n }\n };\n\n return (\n <div className=\"flex flex-col gap-3 md:flex-row-reverse md:items-start\">\n <div className=\"min-w-0 flex-1\">\n {/* Main Image */}\n <div className=\"bg-muted/30 group relative aspect-[3/4] max-h-[760px] overflow-hidden rounded-xl shadow-sm\">\n {isVideoUrl(displayImages[currentImageIndex]?.image_url) ? (\n <video\n key={displayImages[currentImageIndex]?.id}\n src={displayImages[currentImageIndex]?.image_url}\n className=\"absolute inset-0 h-full w-full object-cover\"\n controls\n loop\n playsInline\n />\n ) : (\n <button\n type=\"button\"\n onClick={() => setViewerOpen(true)}\n className=\"group absolute inset-0 z-[1] cursor-pointer border-0 bg-transparent p-0\"\n aria-label={t(\"open_image_viewer\")}\n >\n {renderImage({\n src:\n displayImages[currentImageIndex]?.image_url ||\n fallbackImageUrl,\n alt: productTitle,\n fill: true,\n className: \"rounded-xl object-cover md:shadow-sm\",\n onError: (e) => {\n e.currentTarget.src =\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\";\n },\n unoptimized: true,\n })}\n <span className=\"group-focus-visible:ring-ring pointer-events-none absolute inset-0 rounded-xl group-focus-visible:ring-2 group-focus-visible:ring-inset\" />\n </button>\n )}\n\n {/* Navigation arrows */}\n {displayImages.length > 1 && (\n <>\n <button\n type=\"button\"\n aria-label={t(\"previous_image\")}\n className=\"bg-background/80 text-foreground hover:bg-background absolute top-1/2 left-3 z-10 flex size-10 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full shadow-md transition-opacity md:opacity-0 md:group-hover:opacity-100\"\n onClick={prevImage}\n >\n <ChevronLeft className=\"size-5\" />\n </button>\n <button\n type=\"button\"\n aria-label={t(\"next_image\")}\n className=\"bg-background/80 text-foreground hover:bg-background absolute top-1/2 right-3 z-10 flex size-10 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full shadow-md transition-opacity md:opacity-0 md:group-hover:opacity-100\"\n onClick={nextImage}\n >\n <ChevronRight className=\"size-5\" />\n </button>\n </>\n )}\n </div>\n </div>\n\n {displayImages.length > 1 && (\n <div className=\"grid grid-cols-5 gap-2 sm:grid-cols-6 md:w-14 md:grid-cols-1\">\n {displayImages.map((image, index) => {\n const imageUrl = image.image_url || fallbackImageUrl;\n const isSelected = index === currentImageIndex;\n return (\n <button\n type=\"button\"\n key={`${image.id}-${imageUrl}`}\n aria-label={t(\"go_to_image\", { index: String(index + 1) })}\n className={`bg-background relative aspect-square overflow-hidden rounded-lg border-2 transition ${\n isSelected\n ? \"border-foreground\"\n : \"hover:border-border border-transparent\"\n }`}\n onClick={() => setCurrentImageIndex(index)}\n >\n {renderImage({\n src: imageUrl,\n alt: productTitle,\n fill: true,\n className: \"object-cover\",\n onError: (e) => {\n e.currentTarget.src =\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\";\n },\n unoptimized: true,\n })}\n </button>\n );\n })}\n </div>\n )}\n\n {/* Image viewer dialog */}\n <Dialog open={viewerOpen} onOpenChange={setViewerOpen}>\n <DialogContent\n className=\"h-[95vh] w-[95vw] max-w-none border-0 bg-transparent p-0 shadow-none sm:max-w-none\"\n showCloseButton={false}\n overlayClassName=\"bg-foreground/90\"\n >\n <DialogTitle className=\"sr-only\">{productTitle}</DialogTitle>\n <DialogDescription className=\"sr-only\">\n {t(\"image_viewer_description\")}\n </DialogDescription>\n <DialogClose\n aria-label={t(\"close_image_viewer\")}\n className=\"bg-foreground/60 text-background hover:bg-foreground/80 focus-visible:ring-ring focus-visible:ring-offset-background absolute top-4 right-4 z-10 flex size-10 cursor-pointer items-center justify-center rounded-full transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none\"\n >\n <X className=\"size-5\" />\n <span className=\"sr-only\">{t(\"close_image_viewer\")}</span>\n </DialogClose>\n <div className=\"relative flex h-full w-full items-center justify-center\">\n {renderImage({\n src:\n displayImages[currentImageIndex]?.image_url || fallbackImageUrl,\n alt: productTitle,\n fill: true,\n className: \"object-contain\",\n onError: (e) => {\n e.currentTarget.src =\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\";\n },\n unoptimized: true,\n })}\n </div>\n </DialogContent>\n </Dialog>\n </div>\n );\n}\n","import type React from \"react\";\nimport { Button } from \"@fluid-app/ui-primitives\";\n\ninterface QuantitySelectorProps {\n quantity: number;\n setQuantity: (quantity: number) => void;\n disabled?: boolean;\n}\n\nexport default function QuantitySelector({\n quantity,\n setQuantity,\n disabled = false,\n}: QuantitySelectorProps): React.JSX.Element {\n return (\n <div className=\"inline-flex items-center\">\n <div className=\"border-border bg-background inline-flex items-center rounded-full border p-1\">\n <Button\n variant=\"ghost\"\n onClick={() => setQuantity(Math.max(1, quantity - 1))}\n className=\"text-foreground size-8 rounded-full border-0 p-0 shadow-none\"\n disabled={disabled}\n >\n −\n </Button>\n <span className=\"text-foreground min-w-9 px-2 text-center text-sm font-semibold\">\n {quantity}\n </span>\n <Button\n variant=\"ghost\"\n onClick={() => setQuantity(quantity + 1)}\n className=\"text-foreground size-8 rounded-full border-0 p-0 shadow-none\"\n disabled={disabled}\n >\n +\n </Button>\n </div>\n </div>\n );\n}\n","import type React from \"react\";\nimport { useMemo } from \"react\";\nimport { formatSavings, type products } from \"@fluid-app/products-core\";\nimport {\n RadioGroup,\n RadioGroupItem,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@fluid-app/ui-primitives\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\n\ninterface PurchaseOptionsProps {\n showBuyOnce: boolean;\n showSubscribe: boolean;\n isSubscribe: boolean;\n onSubscribeChange: (subscribe: boolean) => void;\n product_subscription_plans: products.ProductSubscriptionPlan[];\n selectedSubscriptionPlan?: products.ProductSubscriptionPlan;\n onSubscriptionPlanChange?: (plan: products.ProductSubscriptionPlan) => void;\n wholesalePrice?: number;\n wholesaleSubscriptionPrice?: number;\n currency?: string;\n}\n\nexport default function PurchaseOptions({\n showBuyOnce,\n showSubscribe,\n isSubscribe,\n onSubscribeChange,\n product_subscription_plans,\n selectedSubscriptionPlan,\n onSubscriptionPlanChange,\n wholesalePrice,\n wholesaleSubscriptionPrice,\n currency,\n}: PurchaseOptionsProps): React.JSX.Element | null {\n const { t, locale } = useShopTranslation();\n\n // Find default subscription plan or use first one\n const defaultSubscriptionPlan = useMemo(() => {\n if (!product_subscription_plans?.length) return null;\n return (\n product_subscription_plans.find((plan) => plan.default) ||\n product_subscription_plans[0]\n );\n }, [product_subscription_plans]);\n\n // Use selected plan or default to the default/first plan\n const currentSubscriptionPlan =\n selectedSubscriptionPlan || defaultSubscriptionPlan;\n\n const savingsMode =\n currentSubscriptionPlan?.subscription_plan.savings_display_mode ??\n \"percent\";\n\n const savingsText = useMemo(\n () =>\n formatSavings({\n wholesalePrice,\n wholesaleSubscriptionPrice,\n // When currency is unknown, skip amount formatting (which would\n // misrender as \"$X.XX\" on a non-USD store) and fall back to percent.\n mode: currency !== undefined ? savingsMode : \"percent\",\n currency: currency ?? \"USD\",\n locale,\n }),\n [wholesalePrice, wholesaleSubscriptionPrice, savingsMode, currency, locale],\n );\n\n // Format subscription plan display name\n const formatSubscriptionPlan = (plan: products.ProductSubscriptionPlan) => {\n const interval = plan.subscription_plan.billing_interval;\n const unit = plan.subscription_plan.billing_interval_unit;\n return `${interval} ${unit} (${plan.subscription_plan.name})`;\n };\n\n // Prepare subscription plan options for Select component\n const subscriptionPlanOptions = useMemo(() => {\n if (!product_subscription_plans?.length) return [];\n\n return product_subscription_plans.map((plan) => ({\n value: plan.subscription_plan.id.toString(),\n label: formatSubscriptionPlan(plan),\n }));\n }, [product_subscription_plans]);\n\n // Don't render if only buy once is shown and subscribe is false\n if (showBuyOnce && !showSubscribe) {\n return null;\n }\n const handleSubscriptionPlanChange = (planId: string) => {\n const selectedPlan = product_subscription_plans?.find(\n (plan) => plan.subscription_plan.id.toString() === planId,\n );\n if (selectedPlan && onSubscriptionPlanChange) {\n onSubscriptionPlanChange(selectedPlan);\n }\n };\n\n const purchaseType = isSubscribe ? \"subscribe\" : \"once\";\n\n return (\n <div className=\"mb-3 flex flex-col\">\n <RadioGroup\n value={purchaseType}\n onValueChange={(value) => onSubscribeChange(value === \"subscribe\")}\n className=\"gap-0 space-y-0\"\n >\n {showSubscribe && (\n <div\n onClick={() => onSubscribeChange(true)}\n className={`cursor-pointer rounded-t-lg p-4 text-left transition-all duration-200 ${showBuyOnce ? \"border border-b-0\" : \"rounded-b-lg\"} ${isSubscribe ? \"bg-muted\" : \"bg-background\"}`}\n >\n <div className=\"flex items-start gap-x-3\">\n <RadioGroupItem\n value=\"subscribe\"\n onClick={(e) => e.stopPropagation()}\n className={`flex items-center justify-center [&_svg]:h-1.5 [&_svg]:w-1.5 [&_svg]:fill-white ${\n isSubscribe\n ? \"border-contrast bg-contrast text-foreground\"\n : \"border-border bg-background text-muted-foreground\"\n }`}\n />\n <div className=\"flex-1\">\n <div className=\"text-foreground mb-1 text-sm leading-tight font-medium\">\n {savingsText\n ? t(\"subscribe_and_save\", { savings: savingsText })\n : t(\"subscribe\")}\n </div>\n\n {/* Subscription Plan Dropdown*/}\n {product_subscription_plans?.length > 0 && (\n <div\n className=\"bg-muted mt-3 rounded-lg p-2\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"text-foreground mb-1 text-xs font-medium\">\n {t(\"delivery_frequency\")}\n </div>\n <Select\n value={\n currentSubscriptionPlan?.subscription_plan.id.toString() ||\n \"\"\n }\n onValueChange={handleSubscriptionPlanChange}\n disabled={product_subscription_plans?.length === 1}\n >\n <SelectTrigger className=\"bg-background text-foreground! w-full text-xs\">\n <SelectValue\n placeholder={t(\"select_delivery_schedule\")}\n />\n </SelectTrigger>\n <SelectContent>\n {subscriptionPlanOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n {showBuyOnce && (\n <div\n onClick={() => onSubscribeChange(false)}\n className={`cursor-pointer rounded-b-lg border p-4 text-left transition-all duration-200 ${showSubscribe ? \"border-t-0\" : \"rounded-t-lg\"} ${!isSubscribe ? \"bg-muted\" : \"bg-background\"}`}\n >\n <div className=\"flex items-center gap-x-3\">\n <RadioGroupItem\n value=\"once\"\n onClick={(e) => e.stopPropagation()}\n className={`flex items-center justify-center [&_svg]:h-1.5 [&_svg]:w-1.5 [&_svg]:fill-white ${\n !isSubscribe\n ? \"border-contrast bg-contrast text-foreground\"\n : \"border-border bg-background text-muted-foreground\"\n }`}\n />\n <div className=\"text-foreground mb-1 text-sm leading-tight font-medium\">\n {t(\"one_time_purchase\")}\n </div>\n </div>\n </div>\n )}\n </RadioGroup>\n </div>\n );\n}\n","import {\n isVariantSubscribable,\n type portalProducts,\n} from \"@fluid-app/products-core\";\n\n/**\n * Decides whether a product variant should disable its purchase CTA on the\n * portal shop page.\n */\nexport function isVariantUnavailable(\n variant: portalProducts.Variant | undefined,\n product: portalProducts.Product | undefined,\n): boolean {\n if (!variant) return true;\n if (variant.available === false) return true;\n // Subscription-only variants price via `subscription_pricing`, so `price` is\n // often \"0\"/null. Purchasability is the shared `isVariantSubscribable` rule,\n // which tolerates whichever subscribability signal the API populates (the\n // portal-tenant BFF sends `subscription_pricing`, not `allow_subscription`).\n if (variant.subscription_only) {\n return !isVariantSubscribable(variant);\n }\n // Match the render path's fallback (variant.price ?? product.price) so a\n // variant inheriting price from the product isn't blocked.\n const rawPrice = variant.price ?? product?.price;\n if (rawPrice == null || rawPrice === \"\") return true;\n const numericPrice = Number(rawPrice);\n if (Number.isNaN(numericPrice)) return true;\n if (numericPrice <= 0) return true;\n return false;\n}\n","import type React from \"react\";\nimport {\n useState,\n useMemo,\n useEffect,\n useRef,\n useCallback,\n type ReactNode,\n} from \"react\";\nimport {\n bundleSubscriptionPrice,\n formatPortalPrice as formatPrice,\n formatPortalPriceRange as formatPriceRange,\n isStaticBundle,\n usePortalProductCatalog,\n usePortalProductDetail,\n usePortalProducts,\n type PortalProductPageParam,\n type portalProducts,\n type products,\n} from \"@fluid-app/products-core\";\nimport { useInfiniteQuery } from \"@tanstack/react-query\";\nimport {\n Badge,\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Skeleton,\n} from \"@fluid-app/ui-primitives\";\nimport { SearchSort } from \"@fluid-app/ui-components/components/SearchSort\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\nimport { ArrowUpDown, ExternalLink, ShoppingCart } from \"lucide-react\";\nimport ProductCard, {\n tagPortalProduct,\n type RenderImageProps,\n} from \"./product-card\";\nimport ImageGallery from \"./image-gallery\";\nimport QuantitySelector from \"./quantity-selector\";\nimport PurchaseOptions from \"./purchase-options\";\nimport { isVariantUnavailable } from \"../utils/is-variant-unavailable\";\n\ninterface ShopAppProps {\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n /** When provided, controls which product detail to show (URL-driven routing) */\n productId?: string | null;\n /** Called when a product is selected from the listing */\n onSelectProduct?: (productId: string) => void;\n /** Called when user navigates back from product detail */\n onBack?: () => void;\n /** Optional cart button to render in the header area */\n cartButton?: ReactNode;\n}\n\nconst PAGE_SIZE = 25;\nconst RELATED_PRODUCTS_LIMIT = 5;\nconst RELATED_PRODUCTS_GRID_CLASS =\n \"grid grid-cols-2 gap-x-4 gap-y-8 sm:grid-cols-3 lg:grid-cols-5\";\n\nfunction sanitizeHtml(html: string): string {\n const doc = new DOMParser().parseFromString(html, \"text/html\");\n for (const el of doc.querySelectorAll(\n \"script, iframe, object, embed, form, base, meta, link, style\",\n )) {\n el.remove();\n }\n for (const el of doc.querySelectorAll(\"*\")) {\n for (const attr of [...el.attributes]) {\n if (\n attr.name.toLowerCase().startsWith(\"on\") ||\n attr.value.toLowerCase().trim().startsWith(\"javascript:\")\n ) {\n el.removeAttribute(attr.name);\n }\n }\n }\n return doc.body.innerHTML;\n}\n\nconst GRID_CLASS =\n \"grid grid-cols-2 gap-x-3 gap-y-6 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5\";\n\nfunction SkeletonGrid({\n count = 8,\n className = GRID_CLASS,\n}: {\n count?: number;\n className?: string;\n}) {\n return (\n <div className={className}>\n {Array.from({ length: count }, (_, i) => (\n <div key={i} className=\"space-y-2\">\n <Skeleton className=\"aspect-square w-full rounded-lg\" />\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-4 w-1/2\" />\n <Skeleton className=\"h-3 w-1/3\" />\n </div>\n ))}\n </div>\n );\n}\n\nfunction ProductListing({\n companyLogoUrl,\n renderImage,\n onSelectProduct,\n cartButton,\n}: {\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n onSelectProduct: (productId: string) => void;\n cartButton?: ReactNode;\n}) {\n const observerTarget = useRef<HTMLDivElement>(null);\n const { t } = useShopTranslation();\n\n const catalog = usePortalProductCatalog({ perPage: PAGE_SIZE });\n\n const {\n data,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n fetchNextPage,\n error,\n isFetched,\n } = useInfiniteQuery({\n queryKey: catalog.queryKey,\n queryFn: ({ pageParam, signal }) =>\n catalog.fetchProducts(pageParam, signal),\n getNextPageParam: catalog.getNextPageParam,\n initialPageParam: undefined as PortalProductPageParam,\n });\n\n const handleIntersect = useCallback(\n (entries: IntersectionObserverEntry[]) => {\n if (entries[0]?.isIntersecting && hasNextPage && !isFetchingNextPage) {\n fetchNextPage();\n }\n },\n [hasNextPage, isFetchingNextPage, fetchNextPage],\n );\n\n useEffect(() => {\n const target = observerTarget.current;\n if (!target) return;\n\n const observer = new IntersectionObserver(handleIntersect, {\n threshold: 0.1,\n rootMargin: \"200px\",\n });\n observer.observe(target);\n return () => observer.disconnect();\n }, [handleIntersect]);\n\n const allProducts = data?.pages.flatMap((page) => page.products) ?? [];\n\n const sortOptions = useMemo(\n () => [\n { id: \"title_asc\", label: t(\"sort_title_asc\") },\n { id: \"title_desc\", label: t(\"sort_title_desc\") },\n { id: \"price_asc\", label: t(\"sort_price_asc\") },\n { id: \"price_desc\", label: t(\"sort_price_desc\") },\n { id: \"created_at_desc\", label: t(\"sort_recent\") },\n { id: \"created_at_asc\", label: t(\"sort_oldest\") },\n ],\n [t],\n );\n\n return (\n <div>\n <div className=\"mx-auto px-2 md:px-10\">\n {/* Search + Sort */}\n <div className=\"flex flex-col gap-3 py-4 sm:flex-row sm:items-center sm:justify-between\">\n <h1 className=\"text-foreground text-3xl leading-tight font-semibold tracking-tight\">\n {t(\"shop_all\")}\n </h1>\n <div className=\"flex items-center gap-2 sm:ml-auto\">\n <div className=\"w-full max-w-sm sm:w-80 md:w-96\">\n <SearchSort\n searchValue={catalog.searchTerm}\n onSearchChange={catalog.setSearchTerm}\n placeholder={t(\"search_placeholder\")}\n />\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"outline\"\n size=\"icon\"\n className=\"border-foreground/10 shadow-input size-9 shrink-0\"\n >\n <ArrowUpDown className=\"size-3\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-60\">\n <DropdownMenuLabel>{t(\"sort_by\")}</DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuRadioGroup\n value={catalog.currentSort}\n onValueChange={catalog.setCurrentSort}\n >\n {sortOptions.map((opt) => (\n <DropdownMenuRadioItem key={opt.id} value={opt.id}>\n {opt.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n {cartButton && (\n <div className=\"flex shrink-0 items-center gap-3\">\n {cartButton}\n </div>\n )}\n </div>\n </div>\n </div>\n\n {/* Product Grid */}\n <div className=\"mx-auto space-y-8 px-2 md:px-10 md:py-8\">\n {isLoading ? (\n <SkeletonGrid />\n ) : error ? (\n <p className=\"mx-auto my-6 rounded-lg bg-red-100 px-3 py-2 text-red-500\">\n {t(\"error_generic\")}\n </p>\n ) : isFetched && allProducts.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-8 text-center\">\n <p className=\"text-muted-foreground text-sm\">\n {catalog.searchTerm\n ? t(\"no_search_results\", { term: catalog.searchTerm })\n : t(\"no_products\")}\n </p>\n </div>\n ) : (\n <>\n <div className={GRID_CLASS}>\n {allProducts.map((product) => (\n <ProductCard\n key={product.id}\n product={tagPortalProduct(product)}\n {...(companyLogoUrl !== undefined && { companyLogoUrl })}\n {...(renderImage !== undefined && { renderImage })}\n onClick={() => onSelectProduct(String(product.id))}\n />\n ))}\n </div>\n <div ref={observerTarget} />\n {isFetchingNextPage && <SkeletonGrid count={4} />}\n </>\n )}\n </div>\n </div>\n );\n}\n\ninterface OptionGroup {\n optionId: number;\n name: string;\n values: { id: number; name: string }[];\n}\n\n/**\n * Build the variant options map by grouping option_values across all variants.\n * Master variants can represent real selectable options in portal product\n * responses, so include them when they carry option_values.\n * Groups by option_id, collecting unique value entries.\n */\nfunction buildOptionGroups(variants: portalProducts.Variant[]): OptionGroup[] {\n const groupMap = new Map<\n number,\n { name: string; values: Map<number, string> }\n >();\n\n for (const variant of variants) {\n for (const ov of variant.option_values ?? []) {\n if (ov.option_id == null || ov.id == null) continue;\n if (!groupMap.has(ov.option_id)) {\n groupMap.set(ov.option_id, {\n name: ov.option_name ?? `Option ${ov.option_id}`,\n values: new Map(),\n });\n }\n groupMap.get(ov.option_id)!.values.set(ov.id, ov.name ?? String(ov.id));\n }\n }\n\n return [...groupMap.entries()].map(([optionId, group]) => ({\n optionId,\n name: group.name,\n values: [...group.values.entries()].map(([id, name]) => ({ id, name })),\n }));\n}\n\n/**\n * Find the variant matching a set of selected option value IDs.\n * selections is a map of optionId → selected value id.\n */\nfunction findVariantBySelections(\n variants: portalProducts.Variant[],\n selections: Record<number, number>,\n): portalProducts.Variant | undefined {\n const entries = Object.entries(selections).map(\n ([k, v]) => [Number(k), v] as const,\n );\n if (entries.length === 0) return undefined;\n const matchingVariants = variants.filter((v) =>\n entries.every(([optionId, valueId]) =>\n v.option_values?.some(\n (ov) => ov.option_id === optionId && ov.id === valueId,\n ),\n ),\n );\n // When duplicate option values exist, prefer the concrete non-master\n // variant. A master variant is still returned when it is the only match.\n return (\n matchingVariants.find((v) => v.is_master !== true) ?? matchingVariants[0]\n );\n}\n\n/**\n * Map BFF flat subscription plans to the legacy ProductSubscriptionPlan shape\n * expected by the PurchaseOptions component.\n */\nfunction mapToLegacySubscriptionPlans(\n plans: portalProducts.SubscriptionPlan[],\n): products.ProductSubscriptionPlan[] {\n return plans.map((plan, idx) => ({\n ...(plan.id !== undefined && { id: plan.id }),\n default: idx === 0,\n products_count: null,\n subscribers_count: null,\n active: true,\n subscription_plan: {\n id: plan.id ?? 0,\n name: plan.name ?? \"\",\n billing_interval: plan.billing_interval ?? 1,\n billing_interval_unit: plan.billing_interval_unit ?? \"month\",\n billing_frequency_in_words:\n plan.billing_frequency ??\n `${plan.billing_interval} ${plan.billing_interval_unit}`,\n active: true,\n // Intentionally null on the legacy shape: bundle subscription pricing\n // reads price_adjustment_type/amount from the raw BFF plan\n // (selectedBundlePlan), not this mapped legacy plan.\n price_adjustment_amount: null,\n price_adjustment_type: null,\n ...(plan.savings_display_mode !== undefined && {\n savings_display_mode: plan.savings_display_mode,\n }),\n },\n }));\n}\n\nfunction ProductDetail({\n companyLogoUrl,\n productId,\n renderImage,\n onSelectProduct,\n}: {\n companyLogoUrl?: string | null;\n productId: string;\n renderImage?: (props: RenderImageProps) => ReactNode;\n onSelectProduct: (productId: string) => void;\n}) {\n const [quantity, setQuantity] = useState(1);\n // selections: optionId → selected value id\n const [selections, setSelections] = useState<Record<number, number>>({});\n const [userSelectedSubscribe, setUserSelectedSubscribe] = useState<\n boolean | null\n >(null);\n const [selectedSubscriptionPlan, setSelectedSubscriptionPlan] = useState<\n products.ProductSubscriptionPlan | undefined\n >(undefined);\n\n const { t } = useShopTranslation();\n\n const { product, isLoading, error, images } = usePortalProductDetail({\n productId,\n });\n const relatedProductsParams = useMemo(\n () => ({ limit: RELATED_PRODUCTS_LIMIT + 1, sort: \"created_at_desc\" }),\n [],\n );\n const { data: relatedProductsData, isLoading: isRelatedProductsLoading } =\n usePortalProducts(relatedProductsParams);\n\n const variants = useMemo(() => product?.variants ?? [], [product?.variants]);\n const subscriptionPlans = useMemo(\n () => product?.subscription_plans ?? [],\n [product?.subscription_plans],\n );\n\n // Default to the master variant, or the first available variant\n const masterVariant = useMemo(\n () => variants.find((v) => v.is_master) ?? variants[0],\n [variants],\n );\n\n // Build option groups from all variants with option_values\n const optionGroups = useMemo(() => buildOptionGroups(variants), [variants]);\n\n // Title-based fallback: products that distinguish variants by `title` only\n // (no Options/OptionValues set up) — list every variant by title.\n const showVariantChoices = optionGroups.length === 0 && variants.length > 1;\n const [selectedVariantId, setSelectedVariantId] = useState<number | null>(\n null,\n );\n\n // Initialise selections from the master variant when it carries option values,\n // otherwise fall back to the first variant with option values.\n useEffect(() => {\n if (optionGroups.length === 0) return;\n const source = masterVariant?.option_values?.length\n ? masterVariant\n : variants.find((v) => v.option_values?.length);\n if (!source?.option_values?.length) return;\n const defaults: Record<number, number> = {};\n for (const ov of source.option_values) {\n if (ov.option_id != null && ov.id != null) {\n defaults[ov.option_id] = ov.id;\n }\n }\n setSelections(defaults);\n }, [optionGroups, variants, masterVariant]);\n\n // Default the title-based picker to the master variant\n useEffect(() => {\n if (!showVariantChoices) return;\n if (selectedVariantId != null) return;\n if (masterVariant?.id == null) return;\n setSelectedVariantId(masterVariant.id);\n }, [showVariantChoices, selectedVariantId, masterVariant?.id]);\n\n // Resolve the currently selected variant\n const selectedVariant = useMemo(() => {\n if (showVariantChoices) {\n return variants.find((v) => v.id === selectedVariantId) ?? masterVariant;\n }\n if (optionGroups.length === 0) return masterVariant;\n return findVariantBySelections(variants, selections) ?? masterVariant;\n }, [\n variants,\n optionGroups,\n selections,\n masterVariant,\n showVariantChoices,\n selectedVariantId,\n ]);\n\n // Map BFF subscription plans → legacy ProductSubscriptionPlan shape for PurchaseOptions\n const legacySubscriptionPlans = useMemo(\n () => mapToLegacySubscriptionPlans(subscriptionPlans),\n [subscriptionPlans],\n );\n\n // Derive subscription state from variant, falling back to subscribe-by-default\n // when the product offers subscription plans — matches the front-facing storefront.\n const showSubscribe = legacySubscriptionPlans.length > 0;\n const showBuyOnce = selectedVariant?.subscription_only !== true;\n const isSubscribe =\n selectedVariant?.subscription_only === true ||\n (userSelectedSubscribe ?? showSubscribe);\n\n // Prefer variant-specific images when available, fall back to product-level images\n const galleryImages = useMemo(() => {\n const variantImages = selectedVariant?.images;\n if (variantImages && variantImages.length > 0) {\n return variantImages.map((img, idx) => ({\n id: idx,\n image_url: img.url ?? \"\",\n image_path: null as string | null,\n position: idx,\n }));\n }\n return images.map((img, idx) => ({\n id: img.id ?? idx,\n image_url: img.url,\n image_path: null as string | null,\n position: idx,\n }));\n }, [selectedVariant?.images, images]);\n\n const coverImage = galleryImages[0]?.image_url ?? null;\n const relatedProducts = useMemo(\n () =>\n (relatedProductsData?.products ?? [])\n .filter((relatedProduct) => String(relatedProduct.id) !== productId)\n .slice(0, RELATED_PRODUCTS_LIMIT),\n [productId, relatedProductsData?.products],\n );\n\n // Pricing: use selected variant's subscription_pricing for wholesale comparison\n const selectedPricing = selectedVariant?.subscription_pricing?.find(\n (sp) =>\n sp.plan_id ===\n (selectedSubscriptionPlan?.subscription_plan.id ??\n legacySubscriptionPlans[0]?.subscription_plan.id),\n );\n const wholesalePrice = selectedVariant?.wholesale_price\n ? Number(selectedVariant.wholesale_price)\n : undefined;\n const wholesaleSubscriptionPrice = selectedPricing?.wholesale_price\n ? Number(selectedPricing.wholesale_price)\n : undefined;\n\n // Display prices\n // price = retail price, wholesale_price = rep/logged-in price\n // subscription_pricing.wholesale_price = subscription wholesale price\n const currency = selectedVariant?.currency ?? product?.currency;\n const displayPrice = formatPrice(\n selectedVariant?.price ?? product?.price,\n currency,\n );\n const displayWholesalePrice = formatPrice(\n selectedVariant?.wholesale_price ??\n selectedVariant?.price ??\n product?.price,\n currency,\n );\n const displayWholesaleSubscriptionPrice = formatPrice(\n selectedPricing?.wholesale_price ??\n selectedPricing?.price ??\n selectedVariant?.wholesale_price ??\n undefined,\n currency,\n );\n\n // Resolve subscription plan ID for the cart SDK\n const resolvedPlanId =\n selectedSubscriptionPlan?.subscription_plan.id ??\n legacySubscriptionPlans.find((p) => p.default)?.subscription_plan.id ??\n legacySubscriptionPlans[0]?.subscription_plan.id;\n\n // Cart data attributes — SDK expects variant ID, not product ID\n const cartVariantId = String(selectedVariant?.id ?? product?.id ?? \"\");\n\n if (isLoading) {\n return (\n <div className=\"mx-auto max-w-7xl py-8 pr-4 pl-0 md:pr-6 lg:pr-8 lg:pl-0\">\n <div className=\"grid grid-cols-1 gap-5 lg:grid-cols-2\">\n <Skeleton className=\"aspect-square w-full rounded-lg\" />\n <div className=\"space-y-4 pl-2 lg:pl-20\">\n <Skeleton className=\"h-8 w-3/4\" />\n <Skeleton className=\"h-5 w-1/4\" />\n <Skeleton className=\"h-20 w-full\" />\n <Skeleton className=\"h-10 w-1/2\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"text-center\">\n <h3 className=\"text-foreground mb-2 text-lg font-medium\">\n {t(\"error_loading\")}\n </h3>\n <p className=\"text-muted-foreground\">{t(\"error_generic\")}</p>\n </div>\n </div>\n );\n }\n\n if (!product) {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"text-center\">\n <h3 className=\"text-foreground mb-2 text-lg font-medium\">\n {t(\"product_not_found\")}\n </h3>\n <p className=\"text-muted-foreground\">\n {t(\"product_not_found_description\")}\n </p>\n </div>\n </div>\n );\n }\n\n const title = product.name || t(\"product_fallback_name\");\n const isBundle = product.is_bundle === true;\n const bundleUrl = isBundle && product.shop_link ? product.shop_link : null;\n // A static bundle (no customizable groups) is functionally just a product, so\n // keep logged-in shoppers in-app with wholesale pricing by adding it straight\n // to the cart instead of bouncing to the storefront. Gate on a real variant\n // ID (the cart SDK expects a variant, not a product ID — `cartVariantId`\n // falls back to `product.id`): without a master variant we can't add it\n // reliably, so fall back to the storefront link below.\n const staticBundle =\n isBundle && isStaticBundle(product) && selectedVariant?.id != null;\n const displayCv = isBundle ? product.cv : selectedVariant?.cv;\n const displayQv = isBundle ? product.qv : selectedVariant?.qv;\n // `price_range` is tier-aware (the backend resolves wholesale for reps,\n // retail for customers), so display it directly — no client-side\n // wholesale/retail strikethrough. A static bundle has min === max, which\n // formatPriceRange collapses to a single price.\n const bundlePriceDisplay = isBundle\n ? (formatPriceRange(product.price_range, currency) ??\n formatPrice(product.price, currency))\n : null;\n // Static-bundle subscription price: the tier base is price_range.min (== max\n // for a static bundle); the per-plan subscription price is derived from the\n // selected plan's adjustment (percentage off the base, or the tier-aware\n // subscription_price_range). The plan's $0 master variant carries no usable\n // subscription price, so we compute it from the bundle payload instead.\n const bundleBasePrice =\n product.price_range?.min != null\n ? Number(product.price_range.min)\n : undefined;\n const selectedBundlePlan =\n subscriptionPlans.find((p) => p.id === resolvedPlanId) ??\n subscriptionPlans[0];\n const bundleSubPrice = staticBundle\n ? bundleSubscriptionPrice(\n bundleBasePrice,\n product.subscription_price_range,\n selectedBundlePlan,\n )\n : undefined;\n const staticBundleSubDisplay =\n bundleSubPrice !== undefined\n ? formatPrice(bundleSubPrice.toFixed(2), currency)\n : null;\n const isUnavailable =\n !isBundle && isVariantUnavailable(selectedVariant, product);\n return (\n <div className=\"pb-8 md:pl-8\">\n <div className=\"mx-auto max-w-7xl px-4 py-8 md:pr-6 md:pl-0 lg:pr-8 lg:pl-0\">\n <div className=\"grid grid-cols-1 gap-8 lg:grid-cols-[minmax(0,1.12fr)_minmax(320px,0.88fr)] xl:gap-12\">\n {/* Image Gallery */}\n <div className=\"lg:sticky lg:top-8 lg:self-start\">\n <ImageGallery\n images={galleryImages}\n fallbackImageUrl={\n coverImage ??\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\"\n }\n productTitle={title}\n {...(renderImage !== undefined && { renderImage })}\n />\n </div>\n\n {/* Product Info */}\n <div className=\"self-start lg:pt-4\">\n <div className=\"flex flex-wrap items-start gap-2\">\n <h1 className=\"text-foreground flex-1 text-4xl leading-tight font-bold tracking-normal\">\n {title}\n </h1>\n {isBundle && (\n <Badge variant=\"secondary\">{t(\"bundle_badge\")}</Badge>\n )}\n </div>\n\n {/* Customizable bundle: show the retail price range */}\n {isBundle && !staticBundle && bundlePriceDisplay && (\n <div className=\"mt-5 mb-2 flex items-center gap-2\">\n <span className=\"text-foreground text-xl font-semibold\">\n {bundlePriceDisplay}\n </span>\n </div>\n )}\n\n {/* Static bundle: show the tier-resolved price_range directly. The\n backend already resolved the tier (wholesale for reps, retail\n for customers), so — unlike a normal product — there is no\n separate retail value to strike through in buy-once mode\n (bundle price/wholesale_price are the $0 master-variant\n placeholder). When subscribed, show the discounted subscription\n price with the base price struck through (the subscribe\n savings). */}\n {staticBundle && bundlePriceDisplay && (\n <div className=\"mt-5 mb-2 flex items-center gap-2\">\n <span className=\"text-foreground text-xl font-semibold\">\n {isSubscribe && staticBundleSubDisplay\n ? staticBundleSubDisplay\n : bundlePriceDisplay}\n </span>\n {isSubscribe &&\n staticBundleSubDisplay &&\n staticBundleSubDisplay !== bundlePriceDisplay && (\n <span className=\"text-muted-foreground text-sm line-through\">\n {bundlePriceDisplay}\n </span>\n )}\n </div>\n )}\n\n {/* Price — matches admin exactly */}\n {!isBundle && !isUnavailable && (\n <div className=\"mt-5 mb-2 flex items-center gap-2\">\n <span className=\"text-foreground text-xl font-semibold\">\n {isSubscribe\n ? displayWholesaleSubscriptionPrice\n : displayWholesalePrice}\n </span>\n {((isSubscribe &&\n displayWholesaleSubscriptionPrice !==\n displayWholesalePrice) ||\n (!isSubscribe && displayWholesalePrice !== displayPrice)) && (\n <span className=\"text-muted-foreground text-sm line-through\">\n {isSubscribe ? displayWholesalePrice : displayPrice}\n </span>\n )}\n </div>\n )}\n\n {product.wholesale_price != null && (\n <div className=\"text-muted-foreground bg-muted/50 mt-3 mb-5 inline-flex rounded-full px-3 py-1 text-xs font-medium\">\n CV {displayCv ?? \"-\"} | QV {displayQv ?? \"-\"}\n </div>\n )}\n\n {isBundle && !staticBundle ? (\n <div className=\"pt-4\">\n <Button\n variant=\"default\"\n className=\"h-12 w-full rounded-full text-base font-semibold\"\n disabled={!bundleUrl}\n onClick={() => {\n if (bundleUrl)\n window.open(bundleUrl, \"_blank\", \"noopener,noreferrer\");\n }}\n >\n {t(\"purchase_bundle\")}\n <ExternalLink className=\"size-4\" />\n </Button>\n {!bundleUrl && (\n <p className=\"text-muted-foreground mt-2 text-center text-xs\">\n {t(\"bundle_unavailable\")}\n </p>\n )}\n </div>\n ) : staticBundle ? (\n <div className=\"pt-4\">\n {/* Static bundle: buy in-app like a product, including\n subscription when the bundle offers plans. Pricing is the\n tier-aware bundle total: base = price_range, subscription =\n bundleSubPrice (computed from the plan adjustment), so\n PurchaseOptions shows the real \"save X%\". */}\n <PurchaseOptions\n showBuyOnce={showBuyOnce}\n showSubscribe={showSubscribe}\n isSubscribe={isSubscribe}\n onSubscribeChange={setUserSelectedSubscribe}\n {...(bundleBasePrice !== undefined && {\n wholesalePrice: bundleBasePrice,\n })}\n {...(bundleSubPrice !== undefined && {\n wholesaleSubscriptionPrice: bundleSubPrice,\n })}\n {...(currency !== undefined && { currency })}\n product_subscription_plans={legacySubscriptionPlans}\n {...(selectedSubscriptionPlan !== undefined && {\n selectedSubscriptionPlan,\n })}\n onSubscriptionPlanChange={setSelectedSubscriptionPlan}\n />\n <div className=\"mt-5 space-y-4\">\n <div>\n <h3 className=\"text-foreground mb-2 text-sm font-semibold\">\n {t(\"quantity\")}\n </h3>\n <QuantitySelector\n quantity={quantity}\n setQuantity={setQuantity}\n disabled={isUnavailable}\n />\n </div>\n <Button\n variant=\"default\"\n className=\"h-12 w-full rounded-full text-base font-semibold\"\n disabled={isUnavailable}\n {...(!isUnavailable && {\n \"data-fluid-add-to-cart\": cartVariantId,\n \"data-fluid-quantity\": quantity,\n \"data-fluid-subscribe\": isSubscribe,\n \"data-fluid-subscription-plan-id\": isSubscribe\n ? String(resolvedPlanId ?? \"\")\n : \"\",\n \"data-fluid-open-cart-after-add\": \"true\",\n })}\n >\n <ShoppingCart className=\"size-4\" />\n {isSubscribe ? t(\"subscribe\") : t(\"add_to_cart\")}\n </Button>\n </div>\n </div>\n ) : (\n <>\n {/* Purchase Options — matches admin PurchaseOptions component */}\n <PurchaseOptions\n showBuyOnce={showBuyOnce}\n showSubscribe={showSubscribe}\n isSubscribe={isSubscribe}\n onSubscribeChange={setUserSelectedSubscribe}\n {...(wholesalePrice !== undefined && { wholesalePrice })}\n {...(wholesaleSubscriptionPrice !== undefined && {\n wholesaleSubscriptionPrice,\n })}\n {...(currency !== undefined && { currency })}\n product_subscription_plans={legacySubscriptionPlans}\n {...(selectedSubscriptionPlan !== undefined && {\n selectedSubscriptionPlan,\n })}\n onSubscriptionPlanChange={setSelectedSubscriptionPlan}\n />\n\n {/* Variant Options — matches admin layout */}\n {optionGroups.length > 0 && (\n <div className=\"mb-4 pt-4\">\n {optionGroups.map((group) => (\n <div\n key={group.optionId}\n className=\"mb-3 flex items-center\"\n >\n <h3 className=\"text-md text-foreground w-24 font-bold\">\n {group.name.charAt(0).toUpperCase() +\n group.name.slice(1)}\n </h3>\n <Select\n value={String(selections[group.optionId] ?? \"\")}\n onValueChange={(value) =>\n setSelections((prev) => ({\n ...prev,\n [group.optionId]: Number(value),\n }))\n }\n >\n <SelectTrigger className=\"w-48 max-w-full\">\n <SelectValue\n placeholder={t(\"select_option\", {\n name: group.name,\n })}\n />\n </SelectTrigger>\n <SelectContent position=\"popper\" className=\"max-h-60\">\n {group.values.map((v) => (\n <SelectItem key={v.id} value={String(v.id)}>\n {v.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ))}\n </div>\n )}\n\n {/* Title-based variant picker — for products without Options */}\n {showVariantChoices && (\n <div className=\"mb-4 pt-4\">\n <div className=\"mb-3 flex items-center\">\n <h3 className=\"text-md text-foreground w-24 font-bold\">\n {t(\"variant_label\")}\n </h3>\n <Select\n value={\n selectedVariantId != null\n ? String(selectedVariantId)\n : \"\"\n }\n onValueChange={(value) =>\n setSelectedVariantId(Number(value))\n }\n >\n <SelectTrigger className=\"w-48 max-w-full\">\n <SelectValue placeholder={t(\"select_variant\")} />\n </SelectTrigger>\n <SelectContent position=\"popper\" className=\"max-h-60\">\n {variants.map((v, idx) =>\n v.id == null ? null : (\n <SelectItem key={v.id} value={String(v.id)}>\n {v.title ||\n t(\"variant_fallback_name\", {\n index: String(idx + 1),\n })}\n </SelectItem>\n ),\n )}\n </SelectContent>\n </Select>\n </div>\n </div>\n )}\n\n {/* Unavailable product message */}\n {isUnavailable && (\n <div className=\"text-muted-foreground text-sm\">\n {t(\"product_unavailable\")}\n </div>\n )}\n\n {/* Quantity and Add to Cart — matches admin. data-fluid-* attrs are stripped when unavailable so the cart SDK can't bind to a disabled button. */}\n <div className=\"mt-5 space-y-4\">\n <div>\n <h3 className=\"text-foreground mb-2 text-sm font-semibold\">\n {t(\"quantity\")}\n </h3>\n <QuantitySelector\n quantity={quantity}\n setQuantity={setQuantity}\n disabled={isUnavailable}\n />\n </div>\n\n <Button\n variant=\"default\"\n className=\"h-12 w-full rounded-full text-base font-semibold\"\n disabled={isUnavailable}\n {...(!isUnavailable && {\n \"data-fluid-add-to-cart\": cartVariantId,\n \"data-fluid-quantity\": quantity,\n \"data-fluid-subscribe\": isSubscribe,\n \"data-fluid-subscription-plan-id\": isSubscribe\n ? String(resolvedPlanId ?? \"\")\n : \"\",\n \"data-fluid-open-cart-after-add\": \"true\",\n })}\n >\n <ShoppingCart className=\"size-4\" />\n {isSubscribe ? t(\"subscribe\") : t(\"add_to_cart\")}\n </Button>\n </div>\n </>\n )}\n\n {/* Product Description */}\n <div className=\"border-border/70 mt-8 border-t pt-6\">\n <h3 className=\"text-foreground mb-2 text-lg font-bold\">\n {t(\"product_description\")}\n </h3>\n <div\n className=\"text-muted-foreground [&_a]:text-foreground space-y-3 text-sm leading-6 [&_a]:underline [&_li]:ml-4 [&_li]:list-disc\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtml(product.description ?? \"\"),\n }}\n />\n </div>\n </div>\n </div>\n\n {(isRelatedProductsLoading || relatedProducts.length > 0) && (\n <section className=\"border-border/70 mt-12 border-t pt-8\">\n <h2 className=\"text-foreground mb-5 text-2xl font-bold\">\n {t(\"more_to_shop\")}\n </h2>\n {isRelatedProductsLoading ? (\n <SkeletonGrid\n count={RELATED_PRODUCTS_LIMIT}\n className={RELATED_PRODUCTS_GRID_CLASS}\n />\n ) : (\n <div className={RELATED_PRODUCTS_GRID_CLASS}>\n {relatedProducts.map((relatedProduct) => (\n <ProductCard\n key={relatedProduct.id}\n product={tagPortalProduct(relatedProduct)}\n {...(companyLogoUrl !== undefined && { companyLogoUrl })}\n {...(renderImage !== undefined && { renderImage })}\n onClick={() => onSelectProduct(String(relatedProduct.id))}\n />\n ))}\n </div>\n )}\n </section>\n )}\n </div>\n </div>\n );\n}\n\nexport default function ShopApp({\n companyLogoUrl,\n renderImage,\n productId: controlledProductId,\n onSelectProduct: onSelectProductProp,\n onBack: _onBack,\n cartButton,\n}: ShopAppProps): React.JSX.Element {\n // Internal state used only when navigation is not controlled externally\n const [internalProductId, setInternalProductId] = useState<string | null>(\n null,\n );\n\n const isControlled = controlledProductId !== undefined;\n const activeProductId = isControlled\n ? controlledProductId\n : internalProductId;\n\n const handleSelectProduct = onSelectProductProp ?? setInternalProductId;\n\n if (activeProductId) {\n return (\n <ProductDetail\n key={activeProductId}\n {...(companyLogoUrl !== undefined && { companyLogoUrl })}\n productId={activeProductId}\n {...(renderImage !== undefined && { renderImage })}\n onSelectProduct={handleSelectProduct}\n />\n );\n }\n\n return (\n <ProductListing\n {...(companyLogoUrl !== undefined && { companyLogoUrl })}\n {...(renderImage !== undefined && { renderImage })}\n onSelectProduct={handleSelectProduct}\n cartButton={cartButton}\n />\n );\n}\n","import { useEffect, useRef } from \"react\";\n\ninterface CartScriptProps {\n subdomain: string;\n authJwt?: string;\n /** Enable BFF mode — uses portal session cookies instead of JWT for cart auth. */\n bffMode?: boolean;\n /** Override the SDK script URL (e.g. \"http://localhost:4444/index.js\" for local dev). */\n scriptSrc?: string;\n /** Override the API base URL the SDK uses (e.g. \"http://localhost:3000\" for local dev). */\n apiBaseUrl?: string;\n /** Enable SDK debug logging. */\n debug?: boolean;\n /**\n * Initial ISO 3166-1 alpha-2 country code to seed the FairShare SDK with\n * before any cart operation. Renders as `data-fluid-country` on the SDK\n * script tag; the SDK reads it at init time and uses it for cart creation\n * paths so they don't fall back to locale-derived country. Requires\n * fluid-fairshare PR #443 (web-widgets bundle with data-fluid-country\n * parsing) on the CDN.\n */\n country?: string;\n}\n\nconst SCRIPT_ID = \"fluid-cdn-script\";\nconst LEAD_CAPTURE_ID = \"fluid-lead-capture-suppress\";\nconst DEFAULT_SCRIPT_SRC =\n \"https://assets.fluid.app/scripts/fluid-sdk/latest/web-widgets/index.js\";\n\nexport default function CartScript({\n subdomain,\n authJwt,\n bffMode,\n scriptSrc,\n apiBaseUrl,\n debug,\n country,\n}: CartScriptProps): React.ReactNode {\n // Use a ref so the script is injected once with the initial values.\n // ES modules are cached by URL — re-inserting the same script won't\n // re-execute it, so changing props after the first load has no effect.\n const authJwtRef = useRef(authJwt);\n authJwtRef.current = authJwt;\n const countryRef = useRef(country);\n countryRef.current = country;\n\n useEffect(() => {\n if (!subdomain) return;\n\n // Don't add a duplicate script\n if (document.getElementById(SCRIPT_ID)) return;\n\n const script = document.createElement(\"script\");\n script.id = SCRIPT_ID;\n script.src = scriptSrc ?? DEFAULT_SCRIPT_SRC;\n script.type = \"module\";\n script.crossOrigin = \"anonymous\";\n script.dataset.fluidShop = subdomain;\n if (bffMode) {\n script.dataset.bffMode = \"true\";\n } else if (authJwtRef.current) {\n script.dataset.authJwt = authJwtRef.current;\n }\n if (apiBaseUrl) {\n script.dataset.fluidApiBaseUrl = apiBaseUrl;\n }\n if (debug) {\n script.dataset.debug = \"true\";\n }\n if (countryRef.current) {\n script.dataset.fluidCountry = countryRef.current;\n }\n document.head.appendChild(script);\n\n // Suppress the SDK's auto-injected lead capture widget.\n // The SDK skips injection when it finds an existing element with hide-widget.\n const leadCapture = document.createElement(\"fluid-lead-capture-widget\");\n leadCapture.id = LEAD_CAPTURE_ID;\n leadCapture.setAttribute(\"hide-widget\", \"true\");\n document.body.appendChild(leadCapture);\n\n return () => {\n const existing = document.getElementById(SCRIPT_ID);\n if (existing) existing.remove();\n const existingLeadCapture = document.getElementById(LEAD_CAPTURE_ID);\n if (existingLeadCapture) existingLeadCapture.remove();\n };\n // `authJwt` and `country` are intentionally omitted from deps: the SDK\n // reads data attributes only once when this module script first executes.\n // Re-inserting the same module URL after those props change does not\n // re-run FairShare initialization, so treat them as inject-time values.\n }, [subdomain, bffMode, scriptSrc, apiBaseUrl, debug]);\n\n return null;\n}\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface CartWidgetProps {\n theme?: Record<string, string>;\n}\n\nexport default function CartWidget({\n theme,\n}: CartWidgetProps): React.ReactNode {\n const [mounted, setMounted] = useState(false);\n const widgetRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (!mounted) return;\n const el = widgetRef.current;\n if (!el) return;\n if (theme) {\n el.setAttribute(\"theme\", JSON.stringify(theme));\n } else {\n el.removeAttribute(\"theme\");\n }\n }, [theme, mounted]);\n\n const widget = React.createElement(\"fluid-cart-widget\", {\n ref: (el: HTMLElement | null) => {\n widgetRef.current = el;\n },\n \"data-fluid-widget\": \"true\",\n \"hide-widget\": \"true\",\n \"is-primary\": \"true\",\n });\n\n // Portal to document.body so the cart drawer escapes any\n // overflow-hidden / isolation stacking contexts in the layout.\n if (mounted) {\n return createPortal(widget, document.body);\n }\n\n return null;\n}\n","\"use client\";\n\nimport { Button } from \"@fluid-app/ui-primitives\";\nimport { ShoppingCart } from \"lucide-react\";\nimport React, { useEffect, useCallback, useState } from \"react\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\n\ndeclare global {\n interface Window {\n FluidCommerceSDK?: {\n getCheckoutUrl: () => string;\n setOnCheckout: (callback: () => void) => void;\n };\n FairShareSDK?: {\n getCartItemCount: () => number;\n isBffMode: () => boolean;\n updateLocaleSettings: (options: {\n language?: string;\n country?: string;\n }) => Promise<void>;\n };\n fluidCart?: {\n open: () => void;\n };\n }\n}\n\ninterface CartButtonProps {\n onCheckout?: (checkoutUrl: string) => void;\n}\n\nconst MAX_SDK_POLL_ATTEMPTS = 50; // 5 seconds at 100ms intervals\n\nexport function CartButton({ onCheckout }: CartButtonProps): React.ReactNode {\n const { t } = useShopTranslation();\n const [initialCount, setInitialCount] = useState(0);\n\n const navigateToCheckout = useCallback(() => {\n if (!window.FluidCommerceSDK) {\n console.error(\"FluidCommerceSDK not available\");\n return;\n }\n\n try {\n const checkoutUrl = window.FluidCommerceSDK.getCheckoutUrl();\n if (!checkoutUrl) {\n console.error(\"No checkout URL available\");\n return;\n }\n onCheckout?.(checkoutUrl);\n } catch (error) {\n console.error(\"Error getting checkout URL:\", error);\n }\n }, [onCheckout]);\n\n useEffect(() => {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let attempts = 0;\n let cancelled = false;\n\n const setupSDK = () => {\n if (cancelled) return;\n if (window.FluidCommerceSDK) {\n if (onCheckout) {\n window.FluidCommerceSDK.setOnCheckout(navigateToCheckout);\n }\n const count = window.FairShareSDK?.getCartItemCount?.();\n if (count != null) {\n setInitialCount(count);\n }\n } else if (attempts < MAX_SDK_POLL_ATTEMPTS) {\n attempts++;\n timeoutId = setTimeout(setupSDK, 100);\n }\n };\n\n setupSDK();\n return () => {\n cancelled = true;\n if (timeoutId) clearTimeout(timeoutId);\n };\n }, [navigateToCheckout, onCheckout]);\n\n return (\n <Button\n className=\"bg-primary text-primary-foreground hover:bg-primary/70 relative flex h-8 items-center gap-2 rounded-sm px-3 py-1 text-xs\"\n onClick={() => {\n window.fluidCart?.open();\n }}\n >\n <div className=\"relative\">\n <ShoppingCart className=\"size-4\" />\n <span\n id=\"fluid-cart-count\"\n className=\"bg-primary-foreground text-primary absolute -top-1 -right-2 flex size-3.5 items-center justify-center rounded-full text-[8px] font-bold\"\n >\n {initialCount}\n </span>\n </div>\n <span>{t(\"cart\")}</span>\n </Button>\n );\n}\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface ShopContainerProps {\n children: React.ReactNode;\n className?: string;\n cartScript?: React.ReactNode;\n cartWidget?: React.ReactNode;\n}\n\nexport default function ShopContainer({\n children,\n className = \"\",\n cartScript,\n cartWidget,\n}: ShopContainerProps): React.ReactNode {\n const containerRef = useRef<HTMLDivElement>(null);\n const [portalContainer, setPortalContainer] = useState<HTMLDivElement | null>(\n null,\n );\n\n useEffect(() => {\n const currentContainer = containerRef.current;\n if (!currentContainer) return;\n\n const reactContentWrapper = document.createElement(\"div\");\n reactContentWrapper.id = \"react-content-wrapper\";\n reactContentWrapper.style.cssText = `\n position: relative;\n `;\n reactContentWrapper.className = \"min-h-full\";\n\n currentContainer.appendChild(reactContentWrapper);\n\n setPortalContainer(reactContentWrapper);\n\n return () => {\n if (currentContainer && reactContentWrapper) {\n try {\n currentContainer.removeChild(reactContentWrapper);\n } catch (e) {\n console.warn(\"Failed to cleanup isolated container:\", e);\n }\n }\n setPortalContainer(null);\n };\n }, []);\n\n return (\n <>\n <div\n ref={containerRef}\n className={`isolated-shop-wrapper ${className} h-full`}\n >\n {portalContainer &&\n createPortal(\n <>\n {cartScript}\n {cartWidget}\n {children}\n </>,\n portalContainer,\n )}\n </div>\n </>\n );\n}\n","import { type ComponentProps } from \"react\";\nimport ShopApp from \"@fluid-app/shop-ui/components/shop-app\";\nimport {\n CartButton,\n CartScript,\n CartWidget,\n ShopContainer,\n} from \"@fluid-app/cart-ui\";\nimport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@fluid-app/ui-primitives\";\nimport {\n ScreenHeaderBreadcrumbs,\n ScreenHeaderActions,\n} from \"@fluid-app/portal-react/shell/ScreenHeaderContext\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { useFluidContext } from \"../providers/FluidProvider\";\nimport { useAppNavigation } from \"../shell/AppNavigationContext\";\nimport { useNavigationParent } from \"../shell/use-navigation-parent\";\nimport { useStore } from \"../hooks/use-store\";\nimport { useAccount } from \"../hooks/use-account\";\nimport { usePortalProductDetail } from \"@fluid-app/products-core\";\n\ntype ShopScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\nexport function ShopScreen(props: ShopScreenProps): React.JSX.Element {\n return <ShopScreenContent {...props} />;\n}\n\nfunction ShopScreenContent({\n /* eslint-disable @typescript-eslint/no-unused-vars -- destructured to exclude from divProps spread */\n background,\n textColor,\n accentColor,\n padding,\n borderRadius,\n /* eslint-enable @typescript-eslint/no-unused-vars */\n ...divProps\n}: ShopScreenProps): React.JSX.Element {\n const { config } = useFluidContext();\n const { t } = useShopTranslation();\n const { data: store } = useStore();\n const { isPending: accountPending } = useAccount();\n const { currentSlug, navigate } = useAppNavigation();\n const countryCode = config.countryIso ?? \"US\";\n const subdomain = store?.subdomain;\n\n // Parse product ID from slug: \"shop/{productId}\"\n const parts = currentSlug.split(\"/\");\n const productId = parts[1] ?? null;\n\n // TODO(portal-theme): Cart widget theming requires AppShell to expose\n // resolvedTheme via context. Currently it's local state in AppShell.\n\n return (\n <>\n {!productId && (\n <ScreenHeaderBreadcrumbs>\n <Breadcrumb>\n <BreadcrumbList className=\"text-lg\">\n <BreadcrumbItem>\n <BreadcrumbPage className=\"font-semibold\">\n {t(\"breadcrumb\")}\n </BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n </ScreenHeaderBreadcrumbs>\n )}\n <ScreenHeaderActions>\n <div className=\"flex items-center gap-4\">\n <CartButton />\n </div>\n </ScreenHeaderActions>\n <div {...divProps} className={divProps.className ?? \"\"}>\n <ShopContainer\n cartScript={\n // Mount CartScript ONLY when both:\n // (a) subdomain is known (otherwise data-fluid-shop is empty), and\n // (b) the customer's account has resolved (so FluidConfigHydrator\n // has already merged account.default_country_iso into\n // config.countryIso, and countryCode is the real country\n // rather than the \"US\" fallback).\n // ES modules are cached by URL, so the SDK script only executes\n // once per page. Mounting before account resolves would seed\n // fs_country with \"US\" and a later re-render with the real\n // country would NOT re-execute the module — fluid-fairshare#443's\n // data-fluid-country seeding only works at first script init.\n subdomain && !accountPending ? (\n <CartScript\n subdomain={subdomain}\n bffMode\n scriptSrc={\n import.meta.env.DEV\n ? String(\n import.meta.env.VITE_FAIRSHARE_SDK_URL ||\n \"http://localhost:4444/index.js\",\n )\n : undefined\n }\n apiBaseUrl={\n import.meta.env.DEV\n ? String(\n import.meta.env.VITE_FAIRSHARE_API_BASE_URL ||\n \"http://api.fluid.localhost:3000\",\n )\n : undefined\n }\n debug={import.meta.env.DEV}\n country={countryCode}\n />\n ) : null\n }\n cartWidget={<CartWidget />}\n >\n {productId && <ProductBreadcrumb productId={productId} />}\n <ShopApp\n companyLogoUrl={store?.logo_url ?? undefined}\n productId={productId}\n onSelectProduct={(id) => navigate(`shop/${id}`)}\n onBack={() => navigate(\"shop\")}\n />\n </ShopContainer>\n </div>\n </>\n );\n}\n\nexport const shopScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"ShopScreen\",\n displayName: \"Shop Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n\n/**\n * Renders inside PortalProductsCoreProvider to set breadcrumbs with the\n * product name: \"Shop > {product name}\". Overrides the parent's \"Shop\"\n * breadcrumb once product data loads.\n */\nfunction ProductBreadcrumb({ productId }: { productId: string }) {\n const { navigate } = useAppNavigation();\n const parentBreadcrumb = useNavigationParent();\n const { t } = useShopTranslation();\n const { product } = usePortalProductDetail({ productId });\n const productName = product?.name ?? t(\"product_fallback_name\");\n\n const parentLabel = parentBreadcrumb?.label ?? t(\"breadcrumb\");\n const onParentClick = parentBreadcrumb?.onClick ?? (() => navigate(\"shop\"));\n\n return (\n <ScreenHeaderBreadcrumbs>\n <Breadcrumb>\n <BreadcrumbList className=\"text-lg\">\n <BreadcrumbItem>\n <BreadcrumbLink\n onClick={onParentClick}\n className=\"cursor-pointer font-semibold\"\n >\n {parentLabel}\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage className=\"font-semibold\">\n {productName}\n </BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n </ScreenHeaderBreadcrumbs>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ShopScreen-BcmLO7P5.cjs","names":["defaultRenderImage","useShopTranslation","getProductImageUrl","isVideoUrl","formatPortalPrice","determineProductPrice","formatPortalPriceRange","getVideoThumbnailUrl","CirclePlay","Badge","Card","useShopTranslation","isVideoUrl","ChevronLeft","ChevronRight","Dialog","DialogContent","DialogTitle","DialogDescription","DialogClose","X","Button","useShopTranslation","formatSavings","RadioGroup","RadioGroupItem","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","isVariantSubscribable","Skeleton","useShopTranslation","usePortalProductCatalog","SearchSort","DropdownMenu","DropdownMenuTrigger","Button","ArrowUpDown","DropdownMenuContent","DropdownMenuLabel","DropdownMenuSeparator","DropdownMenuRadioGroup","DropdownMenuRadioItem","usePortalProductDetail","usePortalProducts","formatPrice","isStaticBundle","formatPriceRange","bundleSubscriptionPrice","Badge","ExternalLink","ShoppingCart","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","React","useShopTranslation","Button","ShoppingCart","useFluidContext","useShopTranslation","useStore","useAccount","useAppNavigation","ScreenHeaderBreadcrumbs","Breadcrumb","BreadcrumbList","BreadcrumbItem","BreadcrumbPage","ScreenHeaderActions","useNavigationParent","usePortalProductDetail","BreadcrumbLink","BreadcrumbSeparator"],"sources":["../../../shop/ui/src/components/product-card.tsx","../../../shop/ui/src/components/image-gallery.tsx","../../../shop/ui/src/components/quantity-selector.tsx","../../../shop/ui/src/components/purchase-options.tsx","../../../shop/ui/src/utils/is-variant-unavailable.ts","../../../shop/ui/src/components/shop-app.tsx","../../../cart/ui/src/components/cart-script.tsx","../../../cart/ui/src/components/cart-widget.tsx","../../../cart/ui/src/components/cart-button.tsx","../../../cart/ui/src/components/shop-container.tsx","../src/screens/ShopScreen.tsx"],"sourcesContent":["import type React from \"react\";\nimport { useState, type ReactNode } from \"react\";\nimport type { products, portalProducts } from \"@fluid-app/products-core\";\nimport {\n determineProductPrice,\n formatPortalPrice,\n formatPortalPriceRange,\n getProductImageUrl,\n} from \"@fluid-app/products-core\";\nimport { Badge, Card } from \"@fluid-app/ui-primitives\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\nimport { CirclePlay } from \"lucide-react\";\nimport { getVideoThumbnailUrl, isVideoUrl } from \"../utils/media-helpers\";\n\ntype LegacyProduct = (products.Product | products.ShopProduct) & {\n kind?: string;\n video_url?: string;\n};\n\nexport interface RenderImageProps {\n src: string;\n alt: string;\n fill?: boolean;\n className?: string;\n onError?: (e: React.SyntheticEvent<HTMLImageElement>) => void;\n unoptimized?: boolean;\n}\n\ntype TaggedPortalProduct = portalProducts.Product & {\n readonly __portalProduct: true;\n};\n\nexport type ProductCardProduct = LegacyProduct | TaggedPortalProduct;\n\ninterface ProductCardProps {\n product: ProductCardProduct;\n countryIso?: string;\n companyLogoUrl?: string | null;\n showShareModal?: boolean;\n setShareModalOpen?: (open: boolean) => void;\n setSelectedProduct?: (product: LegacyProduct) => void;\n renderLink?: (props: { href: string; children: ReactNode }) => ReactNode;\n renderImage?: (props: RenderImageProps) => ReactNode;\n onClick?: () => void;\n}\n\nexport function tagPortalProduct(\n product: portalProducts.Product,\n): TaggedPortalProduct {\n return { ...product, __portalProduct: true as const };\n}\n\nfunction isPortalProduct(\n product: ProductCardProduct,\n): product is TaggedPortalProduct {\n return \"__portalProduct\" in product && product.__portalProduct === true;\n}\n\nfunction getPortalProductCoverImage(\n product: portalProducts.Product,\n): string | null {\n if (product.images && product.images.length > 0) {\n return product.images[0]?.url ?? null;\n }\n return null;\n}\n\nfunction defaultRenderImage({\n src,\n alt,\n fill,\n className,\n onError,\n}: RenderImageProps): ReactNode {\n return (\n <img\n src={src}\n alt={alt}\n className={`${fill ? \"absolute inset-0 h-full w-full\" : \"\"} ${className ?? \"\"}`}\n onError={onError}\n />\n );\n}\n\nfunction ProductCardContent({\n product,\n countryIso,\n companyLogoUrl,\n renderImage = defaultRenderImage,\n}: {\n product: ProductCardProduct;\n countryIso?: string;\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n}) {\n const [isHovered, setIsHovered] = useState(false);\n const { t } = useShopTranslation();\n\n const isPortal = isPortalProduct(product);\n const coverImage = isPortal\n ? getPortalProductCoverImage(product)\n : getProductImageUrl(product as Parameters<typeof getProductImageUrl>[0]);\n const isVideo = isVideoUrl(coverImage);\n const productName = isPortal\n ? product.name || t(\"no_title\")\n : (product as LegacyProduct).title || t(\"no_title\");\n\n const isBundle = isPortal && product.is_bundle === true;\n\n let repPrice: string | null | undefined = null;\n let price: string | null | undefined = null;\n if (isPortal) {\n // wholesale_price is non-null for reps, null for customers\n if (product.wholesale_price) {\n repPrice = formatPortalPrice(product.wholesale_price, product.currency);\n // Show retail as strikethrough if different from wholesale\n const retailFormatted = formatPortalPrice(\n product.price,\n product.currency,\n );\n if (retailFormatted !== repPrice) {\n price = retailFormatted;\n }\n } else {\n repPrice = formatPortalPrice(product.price, product.currency);\n }\n } else if (countryIso) {\n const prices = determineProductPrice(product, countryIso);\n repPrice = prices.repPrice;\n price = prices.price;\n }\n\n // A bundle's master-variant price is often $0, so show the resolved range.\n // Fall back to the single (backend-guaranteed non-zero) retail price when no\n // range — matching the detail page's fallback so card and detail never diverge.\n const bundlePrice = isBundle\n ? (formatPortalPriceRange(product.price_range, product.currency) ??\n formatPortalPrice(product.price, product.currency))\n : null;\n\n const resolvedCoverImage =\n isVideo && coverImage\n ? getVideoThumbnailUrl(coverImage)\n : coverImage ||\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\";\n\n return (\n <>\n {/* Image/Video container */}\n <div\n className=\"bg-muted/40 relative aspect-square overflow-hidden rounded-lg\"\n onMouseEnter={() => isVideo && setIsHovered(true)}\n onMouseLeave={() => isVideo && setIsHovered(false)}\n >\n {isVideo && isHovered ? (\n <video\n src={coverImage || \"\"}\n className=\"absolute inset-0 h-full w-full object-cover\"\n autoPlay\n muted\n loop\n playsInline\n />\n ) : (\n renderImage({\n src: resolvedCoverImage,\n alt: productName,\n fill: true,\n className:\n \"object-cover transition-transform duration-300 hover:scale-[1.02]\",\n onError: (e) => {\n e.currentTarget.src =\n companyLogoUrl ||\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\";\n },\n unoptimized: true,\n })\n )}\n\n {/* Video play indicator */}\n {isVideo && !isHovered && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"flex size-16 items-center justify-center rounded-full bg-black/50 backdrop-blur-sm\">\n <CirclePlay className=\"size-12 text-white\" />\n </div>\n </div>\n )}\n\n {/* Bundle badge */}\n {isBundle && (\n <Badge variant=\"secondary\" className=\"absolute top-2 left-2\">\n {t(\"bundle_badge\")}\n </Badge>\n )}\n </div>\n\n {/* Product info */}\n <div className=\"px-0.5 pt-2 pb-1\">\n <h3 className=\"text-foreground line-clamp-1 text-sm leading-snug font-semibold\">\n {productName}\n </h3>\n\n <div className=\"flex items-center gap-2\">\n {isBundle ? (\n bundlePrice && (\n <span className=\"text-foreground text-sm leading-none font-semibold\">\n {bundlePrice}\n </span>\n )\n ) : (\n <>\n {repPrice && (\n <span className=\"text-foreground text-sm leading-none font-semibold\">\n {repPrice}\n </span>\n )}\n {price && (\n <span className=\"text-muted-foreground text-sm leading-none line-through\">\n {price}\n </span>\n )}\n </>\n )}\n </div>\n\n {!isPortal && countryIso && (\n <div className=\"text-muted-foreground mt-1 text-xs\">\n CV{\" \"}\n {getVariantCountryValue(\n getSelectedVariant(product as LegacyProduct),\n countryIso,\n \"cv\",\n ) || \"-\"}{\" \"}\n | QV{\" \"}\n {getVariantCountryValue(\n getSelectedVariant(product as LegacyProduct),\n countryIso,\n \"qv\",\n ) || \"-\"}\n </div>\n )}\n\n {isPortal && product.wholesale_price != null && (\n <div className=\"text-muted-foreground mt-1 text-xs\">\n CV {product.cv ?? \"-\"} | QV {product.qv ?? \"-\"}\n </div>\n )}\n </div>\n </>\n );\n}\n\nfunction getSelectedVariant(\n product: LegacyProduct,\n): products.Variant | products.ShopVariant | null {\n if (!product.variants || product.variants.length === 0) return null;\n\n const masterVariant = product.variants.find(\n (v: products.Variant | products.ShopVariant) => {\n return \"is_master\" in v && v.is_master;\n },\n );\n if (masterVariant) return masterVariant;\n\n return product.variants[0] || null;\n}\n\nfunction getVariantCountryValue(\n variant: products.Variant | products.ShopVariant | null,\n countryIso: string,\n field: \"cv\" | \"qv\",\n): number | null {\n if (!variant || !variant.variant_countries) return null;\n\n if (\n typeof variant.variant_countries === \"object\" &&\n !Array.isArray(variant.variant_countries)\n ) {\n const countryData = variant.variant_countries[countryIso] as\n | products.VariantCountry\n | undefined;\n return countryData?.[field] ?? null;\n }\n\n if (Array.isArray(variant.variant_countries)) {\n const countryData = variant.variant_countries.find(\n (vc: products.ShopVariantCountry) => vc.country_iso === countryIso,\n );\n return countryData?.[field] ?? null;\n }\n\n return null;\n}\n\nexport default function ProductCard({\n product,\n countryIso,\n companyLogoUrl,\n showShareModal = false,\n setShareModalOpen,\n setSelectedProduct,\n renderLink,\n renderImage,\n onClick,\n}: ProductCardProps): React.JSX.Element {\n const cardContent = (\n <ProductCardContent\n product={product}\n {...(countryIso !== undefined && { countryIso })}\n {...(companyLogoUrl !== undefined && { companyLogoUrl })}\n {...(renderImage !== undefined && { renderImage })}\n />\n );\n\n const cardClassName =\n \"bg-transparent overflow-hidden border-0 shadow-none pt-0 gap-0\";\n\n if (showShareModal && !isPortalProduct(product)) {\n const handleShareClick = () => {\n if (setSelectedProduct && setShareModalOpen) {\n setSelectedProduct(product);\n setShareModalOpen(true);\n }\n };\n return (\n <Card className={cardClassName}>\n <button\n onClick={handleShareClick}\n className=\"group block w-full cursor-pointer text-left\"\n >\n {cardContent}\n </button>\n </Card>\n );\n }\n\n if (onClick) {\n return (\n <Card className={cardClassName}>\n <button\n onClick={onClick}\n className=\"group block w-full cursor-pointer text-left\"\n >\n {cardContent}\n </button>\n </Card>\n );\n }\n\n const href = `/portal/shop/${product.id}`;\n\n if (renderLink) {\n return (\n <Card className={cardClassName}>\n {renderLink({ href, children: cardContent })}\n </Card>\n );\n }\n\n return (\n <Card className={cardClassName}>\n <a href={href} className=\"group block cursor-pointer\">\n {cardContent}\n </a>\n </Card>\n );\n}\n","import type React from \"react\";\nimport { type ReactNode, useEffect, useMemo, useState } from \"react\";\nimport { ChevronLeft, ChevronRight, X } from \"lucide-react\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogTitle,\n DialogClose,\n} from \"@fluid-app/ui-primitives\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\nimport { isVideoUrl } from \"../utils/media-helpers\";\nimport type { RenderImageProps } from \"./product-card\";\n\ninterface ImageGalleryProps {\n images: Array<{\n id: number;\n image_url: string;\n image_path: string | null;\n position: number;\n }>;\n fallbackImageUrl: string;\n productTitle: string;\n renderImage?: (props: RenderImageProps) => ReactNode;\n}\n\nfunction defaultRenderImage({\n src,\n alt,\n fill,\n className,\n onError,\n}: RenderImageProps): ReactNode {\n return (\n <img\n src={src}\n alt={alt}\n className={`${fill ? \"absolute inset-0 h-full w-full\" : \"\"} ${className ?? \"\"}`}\n onError={onError}\n />\n );\n}\n\nexport default function ImageGallery({\n images,\n fallbackImageUrl,\n productTitle,\n renderImage = defaultRenderImage,\n}: ImageGalleryProps): React.JSX.Element {\n const { t } = useShopTranslation();\n const [currentImageIndex, setCurrentImageIndex] = useState(0);\n const [viewerOpen, setViewerOpen] = useState(false);\n\n const hasMultipleImages = images && images.length > 0;\n const displayImages = useMemo(\n () =>\n hasMultipleImages\n ? images.toSorted((a, b) => a.position - b.position)\n : [{ id: 0, image_url: fallbackImageUrl, position: 0 }],\n [images, hasMultipleImages, fallbackImageUrl],\n );\n\n // Reset to first image when the images array changes (e.g. variant switch)\n useEffect(() => {\n setCurrentImageIndex(0);\n }, [displayImages]);\n\n const nextImage = () => {\n if (displayImages.length > 1) {\n setCurrentImageIndex((prev) => (prev + 1) % displayImages.length);\n }\n };\n\n const prevImage = () => {\n if (displayImages.length > 1) {\n setCurrentImageIndex(\n (prev) => (prev - 1 + displayImages.length) % displayImages.length,\n );\n }\n };\n\n return (\n <div className=\"flex flex-col gap-3 md:flex-row-reverse md:items-start\">\n <div className=\"min-w-0 flex-1\">\n {/* Main Image */}\n <div className=\"bg-muted/30 group relative aspect-[3/4] max-h-[760px] overflow-hidden rounded-xl shadow-sm\">\n {isVideoUrl(displayImages[currentImageIndex]?.image_url) ? (\n <video\n key={displayImages[currentImageIndex]?.id}\n src={displayImages[currentImageIndex]?.image_url}\n className=\"absolute inset-0 h-full w-full object-cover\"\n controls\n loop\n playsInline\n />\n ) : (\n <button\n type=\"button\"\n onClick={() => setViewerOpen(true)}\n className=\"group absolute inset-0 z-[1] cursor-pointer border-0 bg-transparent p-0\"\n aria-label={t(\"open_image_viewer\")}\n >\n {renderImage({\n src:\n displayImages[currentImageIndex]?.image_url ||\n fallbackImageUrl,\n alt: productTitle,\n fill: true,\n className: \"rounded-xl object-cover md:shadow-sm\",\n onError: (e) => {\n e.currentTarget.src =\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\";\n },\n unoptimized: true,\n })}\n <span className=\"group-focus-visible:ring-ring pointer-events-none absolute inset-0 rounded-xl group-focus-visible:ring-2 group-focus-visible:ring-inset\" />\n </button>\n )}\n\n {/* Navigation arrows */}\n {displayImages.length > 1 && (\n <>\n <button\n type=\"button\"\n aria-label={t(\"previous_image\")}\n className=\"bg-background/80 text-foreground hover:bg-background absolute top-1/2 left-3 z-10 flex size-10 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full shadow-md transition-opacity md:opacity-0 md:group-hover:opacity-100\"\n onClick={prevImage}\n >\n <ChevronLeft className=\"size-5\" />\n </button>\n <button\n type=\"button\"\n aria-label={t(\"next_image\")}\n className=\"bg-background/80 text-foreground hover:bg-background absolute top-1/2 right-3 z-10 flex size-10 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full shadow-md transition-opacity md:opacity-0 md:group-hover:opacity-100\"\n onClick={nextImage}\n >\n <ChevronRight className=\"size-5\" />\n </button>\n </>\n )}\n </div>\n </div>\n\n {displayImages.length > 1 && (\n <div className=\"grid grid-cols-5 gap-2 sm:grid-cols-6 md:w-14 md:grid-cols-1\">\n {displayImages.map((image, index) => {\n const imageUrl = image.image_url || fallbackImageUrl;\n const isSelected = index === currentImageIndex;\n return (\n <button\n type=\"button\"\n key={`${image.id}-${imageUrl}`}\n aria-label={t(\"go_to_image\", { index: String(index + 1) })}\n className={`bg-background relative aspect-square overflow-hidden rounded-lg border-2 transition ${\n isSelected\n ? \"border-foreground\"\n : \"hover:border-border border-transparent\"\n }`}\n onClick={() => setCurrentImageIndex(index)}\n >\n {renderImage({\n src: imageUrl,\n alt: productTitle,\n fill: true,\n className: \"object-cover\",\n onError: (e) => {\n e.currentTarget.src =\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\";\n },\n unoptimized: true,\n })}\n </button>\n );\n })}\n </div>\n )}\n\n {/* Image viewer dialog */}\n <Dialog open={viewerOpen} onOpenChange={setViewerOpen}>\n <DialogContent\n className=\"h-[95vh] w-[95vw] max-w-none border-0 bg-transparent p-0 shadow-none sm:max-w-none\"\n showCloseButton={false}\n overlayClassName=\"bg-foreground/90\"\n >\n <DialogTitle className=\"sr-only\">{productTitle}</DialogTitle>\n <DialogDescription className=\"sr-only\">\n {t(\"image_viewer_description\")}\n </DialogDescription>\n <DialogClose\n aria-label={t(\"close_image_viewer\")}\n className=\"bg-foreground/60 text-background hover:bg-foreground/80 focus-visible:ring-ring focus-visible:ring-offset-background absolute top-4 right-4 z-10 flex size-10 cursor-pointer items-center justify-center rounded-full transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none\"\n >\n <X className=\"size-5\" />\n <span className=\"sr-only\">{t(\"close_image_viewer\")}</span>\n </DialogClose>\n <div className=\"relative flex h-full w-full items-center justify-center\">\n {renderImage({\n src:\n displayImages[currentImageIndex]?.image_url || fallbackImageUrl,\n alt: productTitle,\n fill: true,\n className: \"object-contain\",\n onError: (e) => {\n e.currentTarget.src =\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\";\n },\n unoptimized: true,\n })}\n </div>\n </DialogContent>\n </Dialog>\n </div>\n );\n}\n","import type React from \"react\";\nimport { Button } from \"@fluid-app/ui-primitives\";\n\ninterface QuantitySelectorProps {\n quantity: number;\n setQuantity: (quantity: number) => void;\n disabled?: boolean;\n}\n\nexport default function QuantitySelector({\n quantity,\n setQuantity,\n disabled = false,\n}: QuantitySelectorProps): React.JSX.Element {\n return (\n <div className=\"inline-flex items-center\">\n <div className=\"border-border bg-background inline-flex items-center rounded-full border p-1\">\n <Button\n variant=\"ghost\"\n onClick={() => setQuantity(Math.max(1, quantity - 1))}\n className=\"text-foreground size-8 rounded-full border-0 p-0 shadow-none\"\n disabled={disabled}\n >\n −\n </Button>\n <span className=\"text-foreground min-w-9 px-2 text-center text-sm font-semibold\">\n {quantity}\n </span>\n <Button\n variant=\"ghost\"\n onClick={() => setQuantity(quantity + 1)}\n className=\"text-foreground size-8 rounded-full border-0 p-0 shadow-none\"\n disabled={disabled}\n >\n +\n </Button>\n </div>\n </div>\n );\n}\n","import type React from \"react\";\nimport { useMemo } from \"react\";\nimport { formatSavings, type products } from \"@fluid-app/products-core\";\nimport {\n RadioGroup,\n RadioGroupItem,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@fluid-app/ui-primitives\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\n\ninterface PurchaseOptionsProps {\n showBuyOnce: boolean;\n showSubscribe: boolean;\n isSubscribe: boolean;\n onSubscribeChange: (subscribe: boolean) => void;\n product_subscription_plans: products.ProductSubscriptionPlan[];\n selectedSubscriptionPlan?: products.ProductSubscriptionPlan;\n onSubscriptionPlanChange?: (plan: products.ProductSubscriptionPlan) => void;\n wholesalePrice?: number;\n wholesaleSubscriptionPrice?: number;\n currency?: string;\n}\n\nexport default function PurchaseOptions({\n showBuyOnce,\n showSubscribe,\n isSubscribe,\n onSubscribeChange,\n product_subscription_plans,\n selectedSubscriptionPlan,\n onSubscriptionPlanChange,\n wholesalePrice,\n wholesaleSubscriptionPrice,\n currency,\n}: PurchaseOptionsProps): React.JSX.Element | null {\n const { t, locale } = useShopTranslation();\n\n // Find default subscription plan or use first one\n const defaultSubscriptionPlan = useMemo(() => {\n if (!product_subscription_plans?.length) return null;\n return (\n product_subscription_plans.find((plan) => plan.default) ||\n product_subscription_plans[0]\n );\n }, [product_subscription_plans]);\n\n // Use selected plan or default to the default/first plan\n const currentSubscriptionPlan =\n selectedSubscriptionPlan || defaultSubscriptionPlan;\n\n const savingsMode =\n currentSubscriptionPlan?.subscription_plan.savings_display_mode ??\n \"percent\";\n\n const savingsText = useMemo(\n () =>\n formatSavings({\n wholesalePrice,\n wholesaleSubscriptionPrice,\n // When currency is unknown, skip amount formatting (which would\n // misrender as \"$X.XX\" on a non-USD store) and fall back to percent.\n mode: currency !== undefined ? savingsMode : \"percent\",\n currency: currency ?? \"USD\",\n locale,\n }),\n [wholesalePrice, wholesaleSubscriptionPrice, savingsMode, currency, locale],\n );\n\n // Format subscription plan display name\n const formatSubscriptionPlan = (plan: products.ProductSubscriptionPlan) => {\n const interval = plan.subscription_plan.billing_interval;\n const unit = plan.subscription_plan.billing_interval_unit;\n return `${interval} ${unit} (${plan.subscription_plan.name})`;\n };\n\n // Prepare subscription plan options for Select component\n const subscriptionPlanOptions = useMemo(() => {\n if (!product_subscription_plans?.length) return [];\n\n return product_subscription_plans.map((plan) => ({\n value: plan.subscription_plan.id.toString(),\n label: formatSubscriptionPlan(plan),\n }));\n }, [product_subscription_plans]);\n\n // Don't render if only buy once is shown and subscribe is false\n if (showBuyOnce && !showSubscribe) {\n return null;\n }\n const handleSubscriptionPlanChange = (planId: string) => {\n const selectedPlan = product_subscription_plans?.find(\n (plan) => plan.subscription_plan.id.toString() === planId,\n );\n if (selectedPlan && onSubscriptionPlanChange) {\n onSubscriptionPlanChange(selectedPlan);\n }\n };\n\n const purchaseType = isSubscribe ? \"subscribe\" : \"once\";\n\n return (\n <div className=\"mb-3 flex flex-col\">\n <RadioGroup\n value={purchaseType}\n onValueChange={(value) => onSubscribeChange(value === \"subscribe\")}\n className=\"gap-0 space-y-0\"\n >\n {showSubscribe && (\n <div\n onClick={() => onSubscribeChange(true)}\n className={`cursor-pointer rounded-t-lg p-4 text-left transition-all duration-200 ${showBuyOnce ? \"border border-b-0\" : \"rounded-b-lg\"} ${isSubscribe ? \"bg-muted\" : \"bg-background\"}`}\n >\n <div className=\"flex items-start gap-x-3\">\n <RadioGroupItem\n value=\"subscribe\"\n onClick={(e) => e.stopPropagation()}\n className={`flex items-center justify-center [&_svg]:h-1.5 [&_svg]:w-1.5 [&_svg]:fill-white ${\n isSubscribe\n ? \"border-contrast bg-contrast text-foreground\"\n : \"border-border bg-background text-muted-foreground\"\n }`}\n />\n <div className=\"flex-1\">\n <div className=\"text-foreground mb-1 text-sm leading-tight font-medium\">\n {savingsText\n ? t(\"subscribe_and_save\", { savings: savingsText })\n : t(\"subscribe\")}\n </div>\n\n {/* Subscription Plan Dropdown*/}\n {product_subscription_plans?.length > 0 && (\n <div\n className=\"bg-muted mt-3 rounded-lg p-2\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"text-foreground mb-1 text-xs font-medium\">\n {t(\"delivery_frequency\")}\n </div>\n <Select\n value={\n currentSubscriptionPlan?.subscription_plan.id.toString() ||\n \"\"\n }\n onValueChange={handleSubscriptionPlanChange}\n disabled={product_subscription_plans?.length === 1}\n >\n <SelectTrigger className=\"bg-background text-foreground! w-full text-xs\">\n <SelectValue\n placeholder={t(\"select_delivery_schedule\")}\n />\n </SelectTrigger>\n <SelectContent>\n {subscriptionPlanOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n {showBuyOnce && (\n <div\n onClick={() => onSubscribeChange(false)}\n className={`cursor-pointer rounded-b-lg border p-4 text-left transition-all duration-200 ${showSubscribe ? \"border-t-0\" : \"rounded-t-lg\"} ${!isSubscribe ? \"bg-muted\" : \"bg-background\"}`}\n >\n <div className=\"flex items-center gap-x-3\">\n <RadioGroupItem\n value=\"once\"\n onClick={(e) => e.stopPropagation()}\n className={`flex items-center justify-center [&_svg]:h-1.5 [&_svg]:w-1.5 [&_svg]:fill-white ${\n !isSubscribe\n ? \"border-contrast bg-contrast text-foreground\"\n : \"border-border bg-background text-muted-foreground\"\n }`}\n />\n <div className=\"text-foreground mb-1 text-sm leading-tight font-medium\">\n {t(\"one_time_purchase\")}\n </div>\n </div>\n </div>\n )}\n </RadioGroup>\n </div>\n );\n}\n","import {\n isVariantSubscribable,\n type portalProducts,\n} from \"@fluid-app/products-core\";\n\n/**\n * Decides whether a product variant should disable its purchase CTA on the\n * portal shop page.\n */\nexport function isVariantUnavailable(\n variant: portalProducts.Variant | undefined,\n product: portalProducts.Product | undefined,\n): boolean {\n if (!variant) return true;\n if (variant.available === false) return true;\n // Subscription-only variants price via `subscription_pricing`, so `price` is\n // often \"0\"/null. Purchasability is the shared `isVariantSubscribable` rule,\n // which tolerates whichever subscribability signal the API populates (the\n // portal-tenant BFF sends `subscription_pricing`, not `allow_subscription`).\n if (variant.subscription_only) {\n return !isVariantSubscribable(variant);\n }\n // Match the render path's fallback (variant.price ?? product.price) so a\n // variant inheriting price from the product isn't blocked.\n const rawPrice = variant.price ?? product?.price;\n if (rawPrice == null || rawPrice === \"\") return true;\n const numericPrice = Number(rawPrice);\n if (Number.isNaN(numericPrice)) return true;\n if (numericPrice <= 0) return true;\n return false;\n}\n","import type React from \"react\";\nimport {\n useState,\n useMemo,\n useEffect,\n useRef,\n useCallback,\n type ReactNode,\n} from \"react\";\nimport {\n bundleSubscriptionPrice,\n formatPortalPrice as formatPrice,\n formatPortalPriceRange as formatPriceRange,\n isStaticBundle,\n usePortalProductCatalog,\n usePortalProductDetail,\n usePortalProducts,\n type PortalProductPageParam,\n type portalProducts,\n type products,\n} from \"@fluid-app/products-core\";\nimport { useInfiniteQuery } from \"@tanstack/react-query\";\nimport {\n Badge,\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Skeleton,\n} from \"@fluid-app/ui-primitives\";\nimport { SearchSort } from \"@fluid-app/ui-components/components/SearchSort\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\nimport { ArrowUpDown, ExternalLink, ShoppingCart } from \"lucide-react\";\nimport ProductCard, {\n tagPortalProduct,\n type RenderImageProps,\n} from \"./product-card\";\nimport ImageGallery from \"./image-gallery\";\nimport QuantitySelector from \"./quantity-selector\";\nimport PurchaseOptions from \"./purchase-options\";\nimport { isVariantUnavailable } from \"../utils/is-variant-unavailable\";\n\ninterface ShopAppProps {\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n /** When provided, controls which product detail to show (URL-driven routing) */\n productId?: string | null;\n /** Called when a product is selected from the listing */\n onSelectProduct?: (productId: string) => void;\n /** Called when user navigates back from product detail */\n onBack?: () => void;\n /** Optional cart button to render in the header area */\n cartButton?: ReactNode;\n}\n\nconst PAGE_SIZE = 25;\nconst RELATED_PRODUCTS_LIMIT = 5;\nconst RELATED_PRODUCTS_GRID_CLASS =\n \"grid grid-cols-2 gap-x-4 gap-y-8 sm:grid-cols-3 lg:grid-cols-5\";\n\nfunction sanitizeHtml(html: string): string {\n const doc = new DOMParser().parseFromString(html, \"text/html\");\n for (const el of doc.querySelectorAll(\n \"script, iframe, object, embed, form, base, meta, link, style\",\n )) {\n el.remove();\n }\n for (const el of doc.querySelectorAll(\"*\")) {\n for (const attr of [...el.attributes]) {\n if (\n attr.name.toLowerCase().startsWith(\"on\") ||\n attr.value.toLowerCase().trim().startsWith(\"javascript:\")\n ) {\n el.removeAttribute(attr.name);\n }\n }\n }\n return doc.body.innerHTML;\n}\n\nconst GRID_CLASS =\n \"grid grid-cols-2 gap-x-3 gap-y-6 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5\";\n\nfunction SkeletonGrid({\n count = 8,\n className = GRID_CLASS,\n}: {\n count?: number;\n className?: string;\n}) {\n return (\n <div className={className}>\n {Array.from({ length: count }, (_, i) => (\n <div key={i} className=\"space-y-2\">\n <Skeleton className=\"aspect-square w-full rounded-lg\" />\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-4 w-1/2\" />\n <Skeleton className=\"h-3 w-1/3\" />\n </div>\n ))}\n </div>\n );\n}\n\nfunction ProductListing({\n companyLogoUrl,\n renderImage,\n onSelectProduct,\n cartButton,\n}: {\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n onSelectProduct: (productId: string) => void;\n cartButton?: ReactNode;\n}) {\n const observerTarget = useRef<HTMLDivElement>(null);\n const { t } = useShopTranslation();\n\n const catalog = usePortalProductCatalog({ perPage: PAGE_SIZE });\n\n const {\n data,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n fetchNextPage,\n error,\n isFetched,\n } = useInfiniteQuery({\n queryKey: catalog.queryKey,\n queryFn: ({ pageParam, signal }) =>\n catalog.fetchProducts(pageParam, signal),\n getNextPageParam: catalog.getNextPageParam,\n initialPageParam: undefined as PortalProductPageParam,\n });\n\n const handleIntersect = useCallback(\n (entries: IntersectionObserverEntry[]) => {\n if (entries[0]?.isIntersecting && hasNextPage && !isFetchingNextPage) {\n fetchNextPage();\n }\n },\n [hasNextPage, isFetchingNextPage, fetchNextPage],\n );\n\n useEffect(() => {\n const target = observerTarget.current;\n if (!target) return;\n\n const observer = new IntersectionObserver(handleIntersect, {\n threshold: 0.1,\n rootMargin: \"200px\",\n });\n observer.observe(target);\n return () => observer.disconnect();\n }, [handleIntersect]);\n\n const allProducts = data?.pages.flatMap((page) => page.products) ?? [];\n\n const sortOptions = useMemo(\n () => [\n { id: \"title_asc\", label: t(\"sort_title_asc\") },\n { id: \"title_desc\", label: t(\"sort_title_desc\") },\n { id: \"price_asc\", label: t(\"sort_price_asc\") },\n { id: \"price_desc\", label: t(\"sort_price_desc\") },\n { id: \"created_at_desc\", label: t(\"sort_recent\") },\n { id: \"created_at_asc\", label: t(\"sort_oldest\") },\n ],\n [t],\n );\n\n return (\n <div>\n <div className=\"mx-auto px-2 md:px-10\">\n {/* Search + Sort */}\n <div className=\"flex flex-col gap-3 py-4 sm:flex-row sm:items-center sm:justify-between\">\n <h1 className=\"text-foreground text-3xl leading-tight font-semibold tracking-tight\">\n {t(\"shop_all\")}\n </h1>\n <div className=\"flex items-center gap-2 sm:ml-auto\">\n <div className=\"w-full max-w-sm sm:w-80 md:w-96\">\n <SearchSort\n searchValue={catalog.searchTerm}\n onSearchChange={catalog.setSearchTerm}\n placeholder={t(\"search_placeholder\")}\n />\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"outline\"\n size=\"icon\"\n className=\"border-foreground/10 shadow-input size-9 shrink-0\"\n >\n <ArrowUpDown className=\"size-3\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-60\">\n <DropdownMenuLabel>{t(\"sort_by\")}</DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuRadioGroup\n value={catalog.currentSort}\n onValueChange={catalog.setCurrentSort}\n >\n {sortOptions.map((opt) => (\n <DropdownMenuRadioItem key={opt.id} value={opt.id}>\n {opt.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n {cartButton && (\n <div className=\"flex shrink-0 items-center gap-3\">\n {cartButton}\n </div>\n )}\n </div>\n </div>\n </div>\n\n {/* Product Grid */}\n <div className=\"mx-auto space-y-8 px-2 md:px-10 md:py-8\">\n {isLoading ? (\n <SkeletonGrid />\n ) : error ? (\n <p className=\"mx-auto my-6 rounded-lg bg-red-100 px-3 py-2 text-red-500\">\n {t(\"error_generic\")}\n </p>\n ) : isFetched && allProducts.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-8 text-center\">\n <p className=\"text-muted-foreground text-sm\">\n {catalog.searchTerm\n ? t(\"no_search_results\", { term: catalog.searchTerm })\n : t(\"no_products\")}\n </p>\n </div>\n ) : (\n <>\n <div className={GRID_CLASS}>\n {allProducts.map((product) => (\n <ProductCard\n key={product.id}\n product={tagPortalProduct(product)}\n {...(companyLogoUrl !== undefined && { companyLogoUrl })}\n {...(renderImage !== undefined && { renderImage })}\n onClick={() => onSelectProduct(String(product.id))}\n />\n ))}\n </div>\n <div ref={observerTarget} />\n {isFetchingNextPage && <SkeletonGrid count={4} />}\n </>\n )}\n </div>\n </div>\n );\n}\n\ninterface OptionGroup {\n optionId: number;\n name: string;\n values: { id: number; name: string }[];\n}\n\n/**\n * Build the variant options map by grouping option_values across all variants.\n * Master variants can represent real selectable options in portal product\n * responses, so include them when they carry option_values.\n * Groups by option_id, collecting unique value entries.\n */\nfunction buildOptionGroups(variants: portalProducts.Variant[]): OptionGroup[] {\n const groupMap = new Map<\n number,\n { name: string; values: Map<number, string> }\n >();\n\n for (const variant of variants) {\n for (const ov of variant.option_values ?? []) {\n if (ov.option_id == null || ov.id == null) continue;\n if (!groupMap.has(ov.option_id)) {\n groupMap.set(ov.option_id, {\n name: ov.option_name ?? `Option ${ov.option_id}`,\n values: new Map(),\n });\n }\n groupMap.get(ov.option_id)!.values.set(ov.id, ov.name ?? String(ov.id));\n }\n }\n\n return [...groupMap.entries()].map(([optionId, group]) => ({\n optionId,\n name: group.name,\n values: [...group.values.entries()].map(([id, name]) => ({ id, name })),\n }));\n}\n\n/**\n * Find the variant matching a set of selected option value IDs.\n * selections is a map of optionId → selected value id.\n */\nfunction findVariantBySelections(\n variants: portalProducts.Variant[],\n selections: Record<number, number>,\n): portalProducts.Variant | undefined {\n const entries = Object.entries(selections).map(\n ([k, v]) => [Number(k), v] as const,\n );\n if (entries.length === 0) return undefined;\n const matchingVariants = variants.filter((v) =>\n entries.every(([optionId, valueId]) =>\n v.option_values?.some(\n (ov) => ov.option_id === optionId && ov.id === valueId,\n ),\n ),\n );\n // When duplicate option values exist, prefer the concrete non-master\n // variant. A master variant is still returned when it is the only match.\n return (\n matchingVariants.find((v) => v.is_master !== true) ?? matchingVariants[0]\n );\n}\n\n/**\n * Map BFF flat subscription plans to the legacy ProductSubscriptionPlan shape\n * expected by the PurchaseOptions component.\n */\nfunction mapToLegacySubscriptionPlans(\n plans: portalProducts.SubscriptionPlan[],\n): products.ProductSubscriptionPlan[] {\n return plans.map((plan, idx) => ({\n ...(plan.id !== undefined && { id: plan.id }),\n default: idx === 0,\n products_count: null,\n subscribers_count: null,\n active: true,\n subscription_plan: {\n id: plan.id ?? 0,\n name: plan.name ?? \"\",\n billing_interval: plan.billing_interval ?? 1,\n billing_interval_unit: plan.billing_interval_unit ?? \"month\",\n billing_frequency_in_words:\n plan.billing_frequency ??\n `${plan.billing_interval} ${plan.billing_interval_unit}`,\n active: true,\n // Intentionally null on the legacy shape: bundle subscription pricing\n // reads price_adjustment_type/amount from the raw BFF plan\n // (selectedBundlePlan), not this mapped legacy plan.\n price_adjustment_amount: null,\n price_adjustment_type: null,\n ...(plan.savings_display_mode !== undefined && {\n savings_display_mode: plan.savings_display_mode,\n }),\n },\n }));\n}\n\nfunction ProductDetail({\n companyLogoUrl,\n productId,\n renderImage,\n onSelectProduct,\n}: {\n companyLogoUrl?: string | null;\n productId: string;\n renderImage?: (props: RenderImageProps) => ReactNode;\n onSelectProduct: (productId: string) => void;\n}) {\n const [quantity, setQuantity] = useState(1);\n // selections: optionId → selected value id\n const [selections, setSelections] = useState<Record<number, number>>({});\n const [userSelectedSubscribe, setUserSelectedSubscribe] = useState<\n boolean | null\n >(null);\n const [selectedSubscriptionPlan, setSelectedSubscriptionPlan] = useState<\n products.ProductSubscriptionPlan | undefined\n >(undefined);\n\n const { t } = useShopTranslation();\n\n const { product, isLoading, error, images } = usePortalProductDetail({\n productId,\n });\n const relatedProductsParams = useMemo(\n () => ({ limit: RELATED_PRODUCTS_LIMIT + 1, sort: \"created_at_desc\" }),\n [],\n );\n const { data: relatedProductsData, isLoading: isRelatedProductsLoading } =\n usePortalProducts(relatedProductsParams);\n\n const variants = useMemo(() => product?.variants ?? [], [product?.variants]);\n const subscriptionPlans = useMemo(\n () => product?.subscription_plans ?? [],\n [product?.subscription_plans],\n );\n\n // Default to the master variant, or the first available variant\n const masterVariant = useMemo(\n () => variants.find((v) => v.is_master) ?? variants[0],\n [variants],\n );\n\n // Build option groups from all variants with option_values\n const optionGroups = useMemo(() => buildOptionGroups(variants), [variants]);\n\n // Title-based fallback: products that distinguish variants by `title` only\n // (no Options/OptionValues set up) — list every variant by title.\n const showVariantChoices = optionGroups.length === 0 && variants.length > 1;\n const [selectedVariantId, setSelectedVariantId] = useState<number | null>(\n null,\n );\n\n // Initialise selections from the master variant when it carries option values,\n // otherwise fall back to the first variant with option values.\n useEffect(() => {\n if (optionGroups.length === 0) return;\n const source = masterVariant?.option_values?.length\n ? masterVariant\n : variants.find((v) => v.option_values?.length);\n if (!source?.option_values?.length) return;\n const defaults: Record<number, number> = {};\n for (const ov of source.option_values) {\n if (ov.option_id != null && ov.id != null) {\n defaults[ov.option_id] = ov.id;\n }\n }\n setSelections(defaults);\n }, [optionGroups, variants, masterVariant]);\n\n // Default the title-based picker to the master variant\n useEffect(() => {\n if (!showVariantChoices) return;\n if (selectedVariantId != null) return;\n if (masterVariant?.id == null) return;\n setSelectedVariantId(masterVariant.id);\n }, [showVariantChoices, selectedVariantId, masterVariant?.id]);\n\n // Resolve the currently selected variant\n const selectedVariant = useMemo(() => {\n if (showVariantChoices) {\n return variants.find((v) => v.id === selectedVariantId) ?? masterVariant;\n }\n if (optionGroups.length === 0) return masterVariant;\n return findVariantBySelections(variants, selections) ?? masterVariant;\n }, [\n variants,\n optionGroups,\n selections,\n masterVariant,\n showVariantChoices,\n selectedVariantId,\n ]);\n\n // Map BFF subscription plans → legacy ProductSubscriptionPlan shape for PurchaseOptions\n const legacySubscriptionPlans = useMemo(\n () => mapToLegacySubscriptionPlans(subscriptionPlans),\n [subscriptionPlans],\n );\n\n // Derive subscription state from variant, falling back to subscribe-by-default\n // when the product offers subscription plans — matches the front-facing storefront.\n const showSubscribe = legacySubscriptionPlans.length > 0;\n const showBuyOnce = selectedVariant?.subscription_only !== true;\n const isSubscribe =\n selectedVariant?.subscription_only === true ||\n (userSelectedSubscribe ?? showSubscribe);\n\n // Prefer variant-specific images when available, fall back to product-level images\n const galleryImages = useMemo(() => {\n const variantImages = selectedVariant?.images;\n if (variantImages && variantImages.length > 0) {\n return variantImages.map((img, idx) => ({\n id: idx,\n image_url: img.url ?? \"\",\n image_path: null as string | null,\n position: idx,\n }));\n }\n return images.map((img, idx) => ({\n id: img.id ?? idx,\n image_url: img.url,\n image_path: null as string | null,\n position: idx,\n }));\n }, [selectedVariant?.images, images]);\n\n const coverImage = galleryImages[0]?.image_url ?? null;\n const relatedProducts = useMemo(\n () =>\n (relatedProductsData?.products ?? [])\n .filter((relatedProduct) => String(relatedProduct.id) !== productId)\n .slice(0, RELATED_PRODUCTS_LIMIT),\n [productId, relatedProductsData?.products],\n );\n\n // Pricing: use selected variant's subscription_pricing for wholesale comparison\n const selectedPricing = selectedVariant?.subscription_pricing?.find(\n (sp) =>\n sp.plan_id ===\n (selectedSubscriptionPlan?.subscription_plan.id ??\n legacySubscriptionPlans[0]?.subscription_plan.id),\n );\n const wholesalePrice = selectedVariant?.wholesale_price\n ? Number(selectedVariant.wholesale_price)\n : undefined;\n const wholesaleSubscriptionPrice = selectedPricing?.wholesale_price\n ? Number(selectedPricing.wholesale_price)\n : undefined;\n\n // Display prices\n // price = retail price, wholesale_price = rep/logged-in price\n // subscription_pricing.wholesale_price = subscription wholesale price\n const currency = selectedVariant?.currency ?? product?.currency;\n const displayPrice = formatPrice(\n selectedVariant?.price ?? product?.price,\n currency,\n );\n const displayWholesalePrice = formatPrice(\n selectedVariant?.wholesale_price ??\n selectedVariant?.price ??\n product?.price,\n currency,\n );\n const displayWholesaleSubscriptionPrice = formatPrice(\n selectedPricing?.wholesale_price ??\n selectedPricing?.price ??\n selectedVariant?.wholesale_price ??\n undefined,\n currency,\n );\n\n // Resolve subscription plan ID for the cart SDK\n const resolvedPlanId =\n selectedSubscriptionPlan?.subscription_plan.id ??\n legacySubscriptionPlans.find((p) => p.default)?.subscription_plan.id ??\n legacySubscriptionPlans[0]?.subscription_plan.id;\n\n // Cart data attributes — SDK expects variant ID, not product ID\n const cartVariantId = String(selectedVariant?.id ?? product?.id ?? \"\");\n\n if (isLoading) {\n return (\n <div className=\"mx-auto max-w-7xl py-8 pr-4 pl-0 md:pr-6 lg:pr-8 lg:pl-0\">\n <div className=\"grid grid-cols-1 gap-5 lg:grid-cols-2\">\n <Skeleton className=\"aspect-square w-full rounded-lg\" />\n <div className=\"space-y-4 pl-2 lg:pl-20\">\n <Skeleton className=\"h-8 w-3/4\" />\n <Skeleton className=\"h-5 w-1/4\" />\n <Skeleton className=\"h-20 w-full\" />\n <Skeleton className=\"h-10 w-1/2\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"text-center\">\n <h3 className=\"text-foreground mb-2 text-lg font-medium\">\n {t(\"error_loading\")}\n </h3>\n <p className=\"text-muted-foreground\">{t(\"error_generic\")}</p>\n </div>\n </div>\n );\n }\n\n if (!product) {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"text-center\">\n <h3 className=\"text-foreground mb-2 text-lg font-medium\">\n {t(\"product_not_found\")}\n </h3>\n <p className=\"text-muted-foreground\">\n {t(\"product_not_found_description\")}\n </p>\n </div>\n </div>\n );\n }\n\n const title = product.name || t(\"product_fallback_name\");\n const isBundle = product.is_bundle === true;\n const bundleUrl = isBundle && product.shop_link ? product.shop_link : null;\n // A static bundle (no customizable groups) is functionally just a product, so\n // keep logged-in shoppers in-app with wholesale pricing by adding it straight\n // to the cart instead of bouncing to the storefront. Gate on a real variant\n // ID (the cart SDK expects a variant, not a product ID — `cartVariantId`\n // falls back to `product.id`): without a master variant we can't add it\n // reliably, so fall back to the storefront link below.\n const staticBundle =\n isBundle && isStaticBundle(product) && selectedVariant?.id != null;\n const displayCv = isBundle ? product.cv : selectedVariant?.cv;\n const displayQv = isBundle ? product.qv : selectedVariant?.qv;\n // `price_range` is tier-aware (the backend resolves wholesale for reps,\n // retail for customers), so display it directly — no client-side\n // wholesale/retail strikethrough. A static bundle has min === max, which\n // formatPriceRange collapses to a single price.\n const bundlePriceDisplay = isBundle\n ? (formatPriceRange(product.price_range, currency) ??\n formatPrice(product.price, currency))\n : null;\n // Static-bundle subscription price: the tier base is price_range.min (== max\n // for a static bundle); the per-plan subscription price is derived from the\n // selected plan's adjustment (percentage off the base, or the tier-aware\n // subscription_price_range). The plan's $0 master variant carries no usable\n // subscription price, so we compute it from the bundle payload instead.\n const bundleBasePrice =\n product.price_range?.min != null\n ? Number(product.price_range.min)\n : undefined;\n const selectedBundlePlan =\n subscriptionPlans.find((p) => p.id === resolvedPlanId) ??\n subscriptionPlans[0];\n const bundleSubPrice = staticBundle\n ? bundleSubscriptionPrice(\n bundleBasePrice,\n product.subscription_price_range,\n selectedBundlePlan,\n )\n : undefined;\n const staticBundleSubDisplay =\n bundleSubPrice !== undefined\n ? formatPrice(bundleSubPrice.toFixed(2), currency)\n : null;\n const isUnavailable =\n !isBundle && isVariantUnavailable(selectedVariant, product);\n return (\n <div className=\"pb-8 md:pl-8\">\n <div className=\"mx-auto max-w-7xl px-4 py-8 md:pr-6 md:pl-0 lg:pr-8 lg:pl-0\">\n <div className=\"grid grid-cols-1 gap-8 lg:grid-cols-[minmax(0,1.12fr)_minmax(320px,0.88fr)] xl:gap-12\">\n {/* Image Gallery */}\n <div className=\"lg:sticky lg:top-8 lg:self-start\">\n <ImageGallery\n images={galleryImages}\n fallbackImageUrl={\n coverImage ??\n \"https://ik.imagekit.io/fluid/tr:w-1500,h-1500,cm-pad_resize,bg-FFFFFF/980191006/images/WJHL8V/WeCommerce_Logotype-Black_NcO-MzatB.png\"\n }\n productTitle={title}\n {...(renderImage !== undefined && { renderImage })}\n />\n </div>\n\n {/* Product Info */}\n <div className=\"self-start lg:pt-4\">\n <div className=\"flex flex-wrap items-start gap-2\">\n <h1 className=\"text-foreground flex-1 text-4xl leading-tight font-bold tracking-normal\">\n {title}\n </h1>\n {isBundle && (\n <Badge variant=\"secondary\">{t(\"bundle_badge\")}</Badge>\n )}\n </div>\n\n {/* Customizable bundle: show the retail price range */}\n {isBundle && !staticBundle && bundlePriceDisplay && (\n <div className=\"mt-5 mb-2 flex items-center gap-2\">\n <span className=\"text-foreground text-xl font-semibold\">\n {bundlePriceDisplay}\n </span>\n </div>\n )}\n\n {/* Static bundle: show the tier-resolved price_range directly. The\n backend already resolved the tier (wholesale for reps, retail\n for customers), so — unlike a normal product — there is no\n separate retail value to strike through in buy-once mode\n (bundle price/wholesale_price are the $0 master-variant\n placeholder). When subscribed, show the discounted subscription\n price with the base price struck through (the subscribe\n savings). */}\n {staticBundle && bundlePriceDisplay && (\n <div className=\"mt-5 mb-2 flex items-center gap-2\">\n <span className=\"text-foreground text-xl font-semibold\">\n {isSubscribe && staticBundleSubDisplay\n ? staticBundleSubDisplay\n : bundlePriceDisplay}\n </span>\n {isSubscribe &&\n staticBundleSubDisplay &&\n staticBundleSubDisplay !== bundlePriceDisplay && (\n <span className=\"text-muted-foreground text-sm line-through\">\n {bundlePriceDisplay}\n </span>\n )}\n </div>\n )}\n\n {/* Price — matches admin exactly */}\n {!isBundle && !isUnavailable && (\n <div className=\"mt-5 mb-2 flex items-center gap-2\">\n <span className=\"text-foreground text-xl font-semibold\">\n {isSubscribe\n ? displayWholesaleSubscriptionPrice\n : displayWholesalePrice}\n </span>\n {((isSubscribe &&\n displayWholesaleSubscriptionPrice !==\n displayWholesalePrice) ||\n (!isSubscribe && displayWholesalePrice !== displayPrice)) && (\n <span className=\"text-muted-foreground text-sm line-through\">\n {isSubscribe ? displayWholesalePrice : displayPrice}\n </span>\n )}\n </div>\n )}\n\n {product.wholesale_price != null && (\n <div className=\"text-muted-foreground bg-muted/50 mt-3 mb-5 inline-flex rounded-full px-3 py-1 text-xs font-medium\">\n CV {displayCv ?? \"-\"} | QV {displayQv ?? \"-\"}\n </div>\n )}\n\n {isBundle && !staticBundle ? (\n <div className=\"pt-4\">\n <Button\n variant=\"default\"\n className=\"h-12 w-full rounded-full text-base font-semibold\"\n disabled={!bundleUrl}\n onClick={() => {\n if (bundleUrl)\n window.open(bundleUrl, \"_blank\", \"noopener,noreferrer\");\n }}\n >\n {t(\"purchase_bundle\")}\n <ExternalLink className=\"size-4\" />\n </Button>\n {!bundleUrl && (\n <p className=\"text-muted-foreground mt-2 text-center text-xs\">\n {t(\"bundle_unavailable\")}\n </p>\n )}\n </div>\n ) : staticBundle ? (\n <div className=\"pt-4\">\n {/* Static bundle: buy in-app like a product, including\n subscription when the bundle offers plans. Pricing is the\n tier-aware bundle total: base = price_range, subscription =\n bundleSubPrice (computed from the plan adjustment), so\n PurchaseOptions shows the real \"save X%\". */}\n <PurchaseOptions\n showBuyOnce={showBuyOnce}\n showSubscribe={showSubscribe}\n isSubscribe={isSubscribe}\n onSubscribeChange={setUserSelectedSubscribe}\n {...(bundleBasePrice !== undefined && {\n wholesalePrice: bundleBasePrice,\n })}\n {...(bundleSubPrice !== undefined && {\n wholesaleSubscriptionPrice: bundleSubPrice,\n })}\n {...(currency !== undefined && { currency })}\n product_subscription_plans={legacySubscriptionPlans}\n {...(selectedSubscriptionPlan !== undefined && {\n selectedSubscriptionPlan,\n })}\n onSubscriptionPlanChange={setSelectedSubscriptionPlan}\n />\n <div className=\"mt-5 space-y-4\">\n <div>\n <h3 className=\"text-foreground mb-2 text-sm font-semibold\">\n {t(\"quantity\")}\n </h3>\n <QuantitySelector\n quantity={quantity}\n setQuantity={setQuantity}\n disabled={isUnavailable}\n />\n </div>\n <Button\n variant=\"default\"\n className=\"h-12 w-full rounded-full text-base font-semibold\"\n disabled={isUnavailable}\n {...(!isUnavailable && {\n \"data-fluid-add-to-cart\": cartVariantId,\n \"data-fluid-quantity\": quantity,\n \"data-fluid-subscribe\": isSubscribe,\n \"data-fluid-subscription-plan-id\": isSubscribe\n ? String(resolvedPlanId ?? \"\")\n : \"\",\n \"data-fluid-open-cart-after-add\": \"true\",\n })}\n >\n <ShoppingCart className=\"size-4\" />\n {isSubscribe ? t(\"subscribe\") : t(\"add_to_cart\")}\n </Button>\n </div>\n </div>\n ) : (\n <>\n {/* Purchase Options — matches admin PurchaseOptions component */}\n <PurchaseOptions\n showBuyOnce={showBuyOnce}\n showSubscribe={showSubscribe}\n isSubscribe={isSubscribe}\n onSubscribeChange={setUserSelectedSubscribe}\n {...(wholesalePrice !== undefined && { wholesalePrice })}\n {...(wholesaleSubscriptionPrice !== undefined && {\n wholesaleSubscriptionPrice,\n })}\n {...(currency !== undefined && { currency })}\n product_subscription_plans={legacySubscriptionPlans}\n {...(selectedSubscriptionPlan !== undefined && {\n selectedSubscriptionPlan,\n })}\n onSubscriptionPlanChange={setSelectedSubscriptionPlan}\n />\n\n {/* Variant Options — matches admin layout */}\n {optionGroups.length > 0 && (\n <div className=\"mb-4 pt-4\">\n {optionGroups.map((group) => (\n <div\n key={group.optionId}\n className=\"mb-3 flex items-center\"\n >\n <h3 className=\"text-md text-foreground w-24 font-bold\">\n {group.name.charAt(0).toUpperCase() +\n group.name.slice(1)}\n </h3>\n <Select\n value={String(selections[group.optionId] ?? \"\")}\n onValueChange={(value) =>\n setSelections((prev) => ({\n ...prev,\n [group.optionId]: Number(value),\n }))\n }\n >\n <SelectTrigger className=\"w-48 max-w-full\">\n <SelectValue\n placeholder={t(\"select_option\", {\n name: group.name,\n })}\n />\n </SelectTrigger>\n <SelectContent position=\"popper\" className=\"max-h-60\">\n {group.values.map((v) => (\n <SelectItem key={v.id} value={String(v.id)}>\n {v.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ))}\n </div>\n )}\n\n {/* Title-based variant picker — for products without Options */}\n {showVariantChoices && (\n <div className=\"mb-4 pt-4\">\n <div className=\"mb-3 flex items-center\">\n <h3 className=\"text-md text-foreground w-24 font-bold\">\n {t(\"variant_label\")}\n </h3>\n <Select\n value={\n selectedVariantId != null\n ? String(selectedVariantId)\n : \"\"\n }\n onValueChange={(value) =>\n setSelectedVariantId(Number(value))\n }\n >\n <SelectTrigger className=\"w-48 max-w-full\">\n <SelectValue placeholder={t(\"select_variant\")} />\n </SelectTrigger>\n <SelectContent position=\"popper\" className=\"max-h-60\">\n {variants.map((v, idx) =>\n v.id == null ? null : (\n <SelectItem key={v.id} value={String(v.id)}>\n {v.title ||\n t(\"variant_fallback_name\", {\n index: String(idx + 1),\n })}\n </SelectItem>\n ),\n )}\n </SelectContent>\n </Select>\n </div>\n </div>\n )}\n\n {/* Unavailable product message */}\n {isUnavailable && (\n <div className=\"text-muted-foreground text-sm\">\n {t(\"product_unavailable\")}\n </div>\n )}\n\n {/* Quantity and Add to Cart — matches admin. data-fluid-* attrs are stripped when unavailable so the cart SDK can't bind to a disabled button. */}\n <div className=\"mt-5 space-y-4\">\n <div>\n <h3 className=\"text-foreground mb-2 text-sm font-semibold\">\n {t(\"quantity\")}\n </h3>\n <QuantitySelector\n quantity={quantity}\n setQuantity={setQuantity}\n disabled={isUnavailable}\n />\n </div>\n\n <Button\n variant=\"default\"\n className=\"h-12 w-full rounded-full text-base font-semibold\"\n disabled={isUnavailable}\n {...(!isUnavailable && {\n \"data-fluid-add-to-cart\": cartVariantId,\n \"data-fluid-quantity\": quantity,\n \"data-fluid-subscribe\": isSubscribe,\n \"data-fluid-subscription-plan-id\": isSubscribe\n ? String(resolvedPlanId ?? \"\")\n : \"\",\n \"data-fluid-open-cart-after-add\": \"true\",\n })}\n >\n <ShoppingCart className=\"size-4\" />\n {isSubscribe ? t(\"subscribe\") : t(\"add_to_cart\")}\n </Button>\n </div>\n </>\n )}\n\n {/* Product Description */}\n <div className=\"border-border/70 mt-8 border-t pt-6\">\n <h3 className=\"text-foreground mb-2 text-lg font-bold\">\n {t(\"product_description\")}\n </h3>\n <div\n className=\"text-muted-foreground [&_a]:text-foreground space-y-3 text-sm leading-6 [&_a]:underline [&_li]:ml-4 [&_li]:list-disc\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtml(product.description ?? \"\"),\n }}\n />\n </div>\n </div>\n </div>\n\n {(isRelatedProductsLoading || relatedProducts.length > 0) && (\n <section className=\"border-border/70 mt-12 border-t pt-8\">\n <h2 className=\"text-foreground mb-5 text-2xl font-bold\">\n {t(\"more_to_shop\")}\n </h2>\n {isRelatedProductsLoading ? (\n <SkeletonGrid\n count={RELATED_PRODUCTS_LIMIT}\n className={RELATED_PRODUCTS_GRID_CLASS}\n />\n ) : (\n <div className={RELATED_PRODUCTS_GRID_CLASS}>\n {relatedProducts.map((relatedProduct) => (\n <ProductCard\n key={relatedProduct.id}\n product={tagPortalProduct(relatedProduct)}\n {...(companyLogoUrl !== undefined && { companyLogoUrl })}\n {...(renderImage !== undefined && { renderImage })}\n onClick={() => onSelectProduct(String(relatedProduct.id))}\n />\n ))}\n </div>\n )}\n </section>\n )}\n </div>\n </div>\n );\n}\n\nexport default function ShopApp({\n companyLogoUrl,\n renderImage,\n productId: controlledProductId,\n onSelectProduct: onSelectProductProp,\n onBack: _onBack,\n cartButton,\n}: ShopAppProps): React.JSX.Element {\n // Internal state used only when navigation is not controlled externally\n const [internalProductId, setInternalProductId] = useState<string | null>(\n null,\n );\n\n const isControlled = controlledProductId !== undefined;\n const activeProductId = isControlled\n ? controlledProductId\n : internalProductId;\n\n const handleSelectProduct = onSelectProductProp ?? setInternalProductId;\n\n if (activeProductId) {\n return (\n <ProductDetail\n key={activeProductId}\n {...(companyLogoUrl !== undefined && { companyLogoUrl })}\n productId={activeProductId}\n {...(renderImage !== undefined && { renderImage })}\n onSelectProduct={handleSelectProduct}\n />\n );\n }\n\n return (\n <ProductListing\n {...(companyLogoUrl !== undefined && { companyLogoUrl })}\n {...(renderImage !== undefined && { renderImage })}\n onSelectProduct={handleSelectProduct}\n cartButton={cartButton}\n />\n );\n}\n","import { useEffect, useRef } from \"react\";\n\ninterface CartScriptProps {\n subdomain: string;\n authJwt?: string;\n /** Enable BFF mode — uses portal session cookies instead of JWT for cart auth. */\n bffMode?: boolean;\n /** Override the SDK script URL (e.g. \"http://localhost:4444/index.js\" for local dev). */\n scriptSrc?: string;\n /** Override the API base URL the SDK uses (e.g. \"http://localhost:3000\" for local dev). */\n apiBaseUrl?: string;\n /** Enable SDK debug logging. */\n debug?: boolean;\n /**\n * Initial ISO 3166-1 alpha-2 country code to seed the FairShare SDK with\n * before any cart operation. Renders as `data-fluid-country` on the SDK\n * script tag; the SDK reads it at init time and uses it for cart creation\n * paths so they don't fall back to locale-derived country. Requires\n * fluid-fairshare PR #443 (web-widgets bundle with data-fluid-country\n * parsing) on the CDN.\n */\n country?: string;\n /**\n * Explicit cookie domain for the FairShare SDK, rendered as\n * `data-fluid-cookie-domain` on the SDK script tag. When set, the SDK scopes\n * its cookies (session, affiliate/attribution, locale, etc.) to exactly this domain\n * instead of inferring an apex/brand domain from the hostname.\n *\n * This is required in the portal's hub/tenant model: the SDK's hostname\n * heuristic resolves a tenant host like `tacobell.portal.fluid.app` to the\n * shared `.portal.fluid.app` level, which leaks attribution across tenants.\n * Pass the current tenant host so cookies stay isolated per company.\n * Storefronts load the SDK directly (not via this component) and keep the\n * default brand-wide behavior. Requires a web-widgets bundle that parses\n * `data-fluid-cookie-domain`.\n */\n cookieDomain?: string;\n}\n\nconst SCRIPT_ID = \"fluid-cdn-script\";\nconst LEAD_CAPTURE_ID = \"fluid-lead-capture-suppress\";\nconst DEFAULT_SCRIPT_SRC =\n \"https://assets.fluid.app/scripts/fluid-sdk/latest/web-widgets/index.js\";\n\nexport default function CartScript({\n subdomain,\n authJwt,\n bffMode,\n scriptSrc,\n apiBaseUrl,\n debug,\n country,\n cookieDomain,\n}: CartScriptProps): React.ReactNode {\n // Use a ref so the script is injected once with the initial values.\n // ES modules are cached by URL — re-inserting the same script won't\n // re-execute it, so changing props after the first load has no effect.\n const authJwtRef = useRef(authJwt);\n authJwtRef.current = authJwt;\n const countryRef = useRef(country);\n countryRef.current = country;\n const cookieDomainRef = useRef(cookieDomain);\n cookieDomainRef.current = cookieDomain;\n\n useEffect(() => {\n if (!subdomain) return;\n\n // Don't add a duplicate script\n if (document.getElementById(SCRIPT_ID)) return;\n\n const script = document.createElement(\"script\");\n script.id = SCRIPT_ID;\n script.src = scriptSrc ?? DEFAULT_SCRIPT_SRC;\n script.type = \"module\";\n script.crossOrigin = \"anonymous\";\n script.dataset.fluidShop = subdomain;\n if (bffMode) {\n script.dataset.bffMode = \"true\";\n } else if (authJwtRef.current) {\n script.dataset.authJwt = authJwtRef.current;\n }\n if (apiBaseUrl) {\n script.dataset.fluidApiBaseUrl = apiBaseUrl;\n }\n if (debug) {\n script.dataset.debug = \"true\";\n }\n if (countryRef.current) {\n script.dataset.fluidCountry = countryRef.current;\n }\n if (cookieDomainRef.current) {\n script.dataset.fluidCookieDomain = cookieDomainRef.current;\n }\n document.head.appendChild(script);\n\n // Suppress the SDK's auto-injected lead capture widget.\n // The SDK skips injection when it finds an existing element with hide-widget.\n const leadCapture = document.createElement(\"fluid-lead-capture-widget\");\n leadCapture.id = LEAD_CAPTURE_ID;\n leadCapture.setAttribute(\"hide-widget\", \"true\");\n document.body.appendChild(leadCapture);\n\n return () => {\n const existing = document.getElementById(SCRIPT_ID);\n if (existing) existing.remove();\n const existingLeadCapture = document.getElementById(LEAD_CAPTURE_ID);\n if (existingLeadCapture) existingLeadCapture.remove();\n };\n // `authJwt`, `country`, and `cookieDomain` are intentionally omitted from\n // deps: the SDK reads data attributes only once when this module script\n // first executes.\n // Re-inserting the same module URL after those props change does not\n // re-run FairShare initialization, so treat them as inject-time values.\n }, [subdomain, bffMode, scriptSrc, apiBaseUrl, debug]);\n\n return null;\n}\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface CartWidgetProps {\n theme?: Record<string, string>;\n}\n\nexport default function CartWidget({\n theme,\n}: CartWidgetProps): React.ReactNode {\n const [mounted, setMounted] = useState(false);\n const widgetRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (!mounted) return;\n const el = widgetRef.current;\n if (!el) return;\n if (theme) {\n el.setAttribute(\"theme\", JSON.stringify(theme));\n } else {\n el.removeAttribute(\"theme\");\n }\n }, [theme, mounted]);\n\n const widget = React.createElement(\"fluid-cart-widget\", {\n ref: (el: HTMLElement | null) => {\n widgetRef.current = el;\n },\n \"data-fluid-widget\": \"true\",\n \"hide-widget\": \"true\",\n \"is-primary\": \"true\",\n });\n\n // Portal to document.body so the cart drawer escapes any\n // overflow-hidden / isolation stacking contexts in the layout.\n if (mounted) {\n return createPortal(widget, document.body);\n }\n\n return null;\n}\n","\"use client\";\n\nimport { Button } from \"@fluid-app/ui-primitives\";\nimport { ShoppingCart } from \"lucide-react\";\nimport React, { useEffect, useCallback, useState } from \"react\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\n\ndeclare global {\n interface Window {\n FluidCommerceSDK?: {\n getCheckoutUrl: () => string;\n setOnCheckout: (callback: () => void) => void;\n };\n FairShareSDK?: {\n getCartItemCount: () => number;\n isBffMode: () => boolean;\n updateLocaleSettings: (options: {\n language?: string;\n country?: string;\n }) => Promise<void>;\n };\n fluidCart?: {\n open: () => void;\n };\n }\n}\n\ninterface CartButtonProps {\n onCheckout?: (checkoutUrl: string) => void;\n}\n\nconst MAX_SDK_POLL_ATTEMPTS = 50; // 5 seconds at 100ms intervals\n\nexport function CartButton({ onCheckout }: CartButtonProps): React.ReactNode {\n const { t } = useShopTranslation();\n const [initialCount, setInitialCount] = useState(0);\n\n const navigateToCheckout = useCallback(() => {\n if (!window.FluidCommerceSDK) {\n console.error(\"FluidCommerceSDK not available\");\n return;\n }\n\n try {\n const checkoutUrl = window.FluidCommerceSDK.getCheckoutUrl();\n if (!checkoutUrl) {\n console.error(\"No checkout URL available\");\n return;\n }\n onCheckout?.(checkoutUrl);\n } catch (error) {\n console.error(\"Error getting checkout URL:\", error);\n }\n }, [onCheckout]);\n\n useEffect(() => {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let attempts = 0;\n let cancelled = false;\n\n const setupSDK = () => {\n if (cancelled) return;\n if (window.FluidCommerceSDK) {\n if (onCheckout) {\n window.FluidCommerceSDK.setOnCheckout(navigateToCheckout);\n }\n const count = window.FairShareSDK?.getCartItemCount?.();\n if (count != null) {\n setInitialCount(count);\n }\n } else if (attempts < MAX_SDK_POLL_ATTEMPTS) {\n attempts++;\n timeoutId = setTimeout(setupSDK, 100);\n }\n };\n\n setupSDK();\n return () => {\n cancelled = true;\n if (timeoutId) clearTimeout(timeoutId);\n };\n }, [navigateToCheckout, onCheckout]);\n\n return (\n <Button\n className=\"bg-primary text-primary-foreground hover:bg-primary/70 relative flex h-8 items-center gap-2 rounded-sm px-3 py-1 text-xs\"\n onClick={() => {\n window.fluidCart?.open();\n }}\n >\n <div className=\"relative\">\n <ShoppingCart className=\"size-4\" />\n <span\n id=\"fluid-cart-count\"\n className=\"bg-primary-foreground text-primary absolute -top-1 -right-2 flex size-3.5 items-center justify-center rounded-full text-[8px] font-bold\"\n >\n {initialCount}\n </span>\n </div>\n <span>{t(\"cart\")}</span>\n </Button>\n );\n}\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface ShopContainerProps {\n children: React.ReactNode;\n className?: string;\n cartScript?: React.ReactNode;\n cartWidget?: React.ReactNode;\n}\n\nexport default function ShopContainer({\n children,\n className = \"\",\n cartScript,\n cartWidget,\n}: ShopContainerProps): React.ReactNode {\n const containerRef = useRef<HTMLDivElement>(null);\n const [portalContainer, setPortalContainer] = useState<HTMLDivElement | null>(\n null,\n );\n\n useEffect(() => {\n const currentContainer = containerRef.current;\n if (!currentContainer) return;\n\n const reactContentWrapper = document.createElement(\"div\");\n reactContentWrapper.id = \"react-content-wrapper\";\n reactContentWrapper.style.cssText = `\n position: relative;\n `;\n reactContentWrapper.className = \"min-h-full\";\n\n currentContainer.appendChild(reactContentWrapper);\n\n setPortalContainer(reactContentWrapper);\n\n return () => {\n if (currentContainer && reactContentWrapper) {\n try {\n currentContainer.removeChild(reactContentWrapper);\n } catch (e) {\n console.warn(\"Failed to cleanup isolated container:\", e);\n }\n }\n setPortalContainer(null);\n };\n }, []);\n\n return (\n <>\n <div\n ref={containerRef}\n className={`isolated-shop-wrapper ${className} h-full`}\n >\n {portalContainer &&\n createPortal(\n <>\n {cartScript}\n {cartWidget}\n {children}\n </>,\n portalContainer,\n )}\n </div>\n </>\n );\n}\n","import { type ComponentProps } from \"react\";\nimport ShopApp from \"@fluid-app/shop-ui/components/shop-app\";\nimport {\n CartButton,\n CartScript,\n CartWidget,\n ShopContainer,\n} from \"@fluid-app/cart-ui\";\nimport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@fluid-app/ui-primitives\";\nimport {\n ScreenHeaderBreadcrumbs,\n ScreenHeaderActions,\n} from \"@fluid-app/portal-react/shell/ScreenHeaderContext\";\nimport { useShopTranslation } from \"@fluid-app/shop-core/translation-api-context\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { useFluidContext } from \"../providers/FluidProvider\";\nimport { useAppNavigation } from \"../shell/AppNavigationContext\";\nimport { useNavigationParent } from \"../shell/use-navigation-parent\";\nimport { useStore } from \"../hooks/use-store\";\nimport { useAccount } from \"../hooks/use-account\";\nimport { usePortalProductDetail } from \"@fluid-app/products-core\";\n\ntype ShopScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\nexport function ShopScreen(props: ShopScreenProps): React.JSX.Element {\n return <ShopScreenContent {...props} />;\n}\n\nfunction ShopScreenContent({\n /* eslint-disable @typescript-eslint/no-unused-vars -- destructured to exclude from divProps spread */\n background,\n textColor,\n accentColor,\n padding,\n borderRadius,\n /* eslint-enable @typescript-eslint/no-unused-vars */\n ...divProps\n}: ShopScreenProps): React.JSX.Element {\n const { config } = useFluidContext();\n const { t } = useShopTranslation();\n const { data: store } = useStore();\n const { isPending: accountPending } = useAccount();\n const { currentSlug, navigate } = useAppNavigation();\n const countryCode = config.countryIso ?? \"US\";\n const subdomain = store?.subdomain;\n\n // Parse product ID from slug: \"shop/{productId}\"\n const parts = currentSlug.split(\"/\");\n const productId = parts[1] ?? null;\n\n // Tenant host (e.g. tacobell.portal.fluid.app), SSR-safe. Used to scope\n // FairShare cookies to this tenant so attribution stays isolated per company.\n const tenantHost =\n typeof window !== \"undefined\" ? window.location.hostname : undefined;\n\n // TODO(portal-theme): Cart widget theming requires AppShell to expose\n // resolvedTheme via context. Currently it's local state in AppShell.\n\n return (\n <>\n {!productId && (\n <ScreenHeaderBreadcrumbs>\n <Breadcrumb>\n <BreadcrumbList className=\"text-lg\">\n <BreadcrumbItem>\n <BreadcrumbPage className=\"font-semibold\">\n {t(\"breadcrumb\")}\n </BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n </ScreenHeaderBreadcrumbs>\n )}\n <ScreenHeaderActions>\n <div className=\"flex items-center gap-4\">\n <CartButton />\n </div>\n </ScreenHeaderActions>\n <div {...divProps} className={divProps.className ?? \"\"}>\n <ShopContainer\n cartScript={\n // Mount CartScript ONLY when both:\n // (a) subdomain is known (otherwise data-fluid-shop is empty), and\n // (b) the customer's account has resolved (so FluidConfigHydrator\n // has already merged account.default_country_iso into\n // config.countryIso, and countryCode is the real country\n // rather than the \"US\" fallback).\n // ES modules are cached by URL, so the SDK script only executes\n // once per page. Mounting before account resolves would seed\n // fs_country with \"US\" and a later re-render with the real\n // country would NOT re-execute the module — fluid-fairshare#443's\n // data-fluid-country seeding only works at first script init.\n subdomain && !accountPending ? (\n <CartScript\n subdomain={subdomain}\n bffMode\n scriptSrc={\n import.meta.env.DEV\n ? String(\n import.meta.env.VITE_FAIRSHARE_SDK_URL ||\n \"http://localhost:4444/index.js\",\n )\n : undefined\n }\n apiBaseUrl={\n import.meta.env.DEV\n ? String(\n import.meta.env.VITE_FAIRSHARE_API_BASE_URL ||\n \"http://api.fluid.localhost:3000\",\n )\n : undefined\n }\n debug={import.meta.env.DEV}\n country={countryCode}\n // Scope FairShare cookies to this tenant host (e.g.\n // tacobell.portal.fluid.app). Without this the SDK infers the\n // shared `.portal.fluid.app` domain and attribution leaks\n // across companies in the hub/tenant model.\n cookieDomain={tenantHost}\n />\n ) : null\n }\n cartWidget={<CartWidget />}\n >\n {productId && <ProductBreadcrumb productId={productId} />}\n <ShopApp\n companyLogoUrl={store?.logo_url ?? undefined}\n productId={productId}\n onSelectProduct={(id) => navigate(`shop/${id}`)}\n onBack={() => navigate(\"shop\")}\n />\n </ShopContainer>\n </div>\n </>\n );\n}\n\nexport const shopScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"ShopScreen\",\n displayName: \"Shop Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n\n/**\n * Renders inside PortalProductsCoreProvider to set breadcrumbs with the\n * product name: \"Shop > {product name}\". Overrides the parent's \"Shop\"\n * breadcrumb once product data loads.\n */\nfunction ProductBreadcrumb({ productId }: { productId: string }) {\n const { navigate } = useAppNavigation();\n const parentBreadcrumb = useNavigationParent();\n const { t } = useShopTranslation();\n const { product } = usePortalProductDetail({ productId });\n const productName = product?.name ?? t(\"product_fallback_name\");\n\n const parentLabel = parentBreadcrumb?.label ?? t(\"breadcrumb\");\n const onParentClick = parentBreadcrumb?.onClick ?? (() => navigate(\"shop\"));\n\n return (\n <ScreenHeaderBreadcrumbs>\n <Breadcrumb>\n <BreadcrumbList className=\"text-lg\">\n <BreadcrumbItem>\n <BreadcrumbLink\n onClick={onParentClick}\n className=\"cursor-pointer font-semibold\"\n >\n {parentLabel}\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage className=\"font-semibold\">\n {productName}\n </BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n </ScreenHeaderBreadcrumbs>\n );\n}\n"],"mappings":"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"}