storefront-layouts 1.0.10 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/use-pdp-variation.d.ts +1 -1
- package/dist/hooks/use-pdp-variation.d.ts.map +1 -1
- package/dist/hooks/use-pdp-variation.js +3 -17
- package/dist/layouts/booking/pages/ProductDetailPage.js +1 -1
- package/dist/layouts/booking-agenda/pages/ProductDetailPage.js +1 -1
- package/dist/layouts/clothing/pages/ProductDetailPage.js +1 -1
- package/dist/layouts/clothing-minimal/pages/ProductDetailPage.js +1 -1
- package/dist/layouts/electronics/pages/ProductDetailPage.js +1 -1
- package/dist/layouts/electronics-grid/pages/ProductDetailPage.js +1 -1
- package/dist/layouts/food/pages/ProductDetailPage.js +1 -1
- package/dist/layouts/food-modern/pages/ProductDetailPage.js +1 -1
- package/dist/lib/product-variation-utils.d.ts +1 -10
- package/dist/lib/product-variation-utils.d.ts.map +1 -1
- package/dist/lib/product-variation-utils.js +2 -68
- package/dist/lib/store-context.d.ts.map +1 -1
- package/dist/lib/store-context.js +2 -5
- package/package.json +8 -2
|
@@ -23,9 +23,9 @@ export declare function usePdpVariation(product?: StoreProduct): {
|
|
|
23
23
|
displaySKU: string;
|
|
24
24
|
stockView: {
|
|
25
25
|
name: string;
|
|
26
|
-
inStock: boolean;
|
|
27
26
|
trackInventory?: boolean;
|
|
28
27
|
availableStock?: number;
|
|
28
|
+
inStock: boolean;
|
|
29
29
|
lowStockThreshold?: number;
|
|
30
30
|
} | {
|
|
31
31
|
inStock: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-pdp-variation.d.ts","sourceRoot":"","sources":["../../src/hooks/use-pdp-variation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"use-pdp-variation.d.ts","sourceRoot":"","sources":["../../src/hooks/use-pdp-variation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AActD,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,YAAY;;;wBAW5C,MAAM,SAAS,MAAM;6BAerB,MAAM,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;iBAwBL,OAAO;;;;;8BAKc,MAAM;6BACP,MAAM;;;;;;;;;;;;;;;;;mCA0CjB,MAAM,SAAS,MAAM;;EAIvD"}
|
|
@@ -1,27 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { findMatchingVariation, formatVariationLabel, getVariationOptionGroups, getVariationOptionImage, isVariationOptionAvailable, reconcileSelectedAttributes, resolveProductGalleryImageUrls, resolveVariantPrice, resolveVariantSKU, resolveVariantStockProduct, } from '../lib/product-variation-utils.js';
|
|
4
4
|
export function usePdpVariation(product) {
|
|
5
5
|
const variants = product?.variants;
|
|
6
|
-
const optionGroups = useMemo(() =>
|
|
7
|
-
const groups = getVariationOptionGroups(variants);
|
|
8
|
-
return withBaseProductOption(groups, product);
|
|
9
|
-
}, [variants, product]);
|
|
6
|
+
const optionGroups = useMemo(() => getVariationOptionGroups(variants), [variants]);
|
|
10
7
|
const [selectedAttributes, setSelectedAttributes] = useState({});
|
|
11
8
|
useEffect(() => {
|
|
12
|
-
// Default to the original product so it appears selected with its main image.
|
|
13
|
-
const groups = withBaseProductOption(getVariationOptionGroups(variants), product);
|
|
14
|
-
const keys = getSortedVariationOptionKeys(groups);
|
|
15
|
-
if (keys.includes('color') && groups.color?.includes(BASE_PRODUCT_OPTION_VALUE)) {
|
|
16
|
-
setSelectedAttributes({ color: BASE_PRODUCT_OPTION_VALUE });
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
if (keys[0] && groups[keys[0]]?.includes(BASE_PRODUCT_OPTION_VALUE)) {
|
|
20
|
-
setSelectedAttributes({ [keys[0]]: BASE_PRODUCT_OPTION_VALUE });
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
9
|
setSelectedAttributes({});
|
|
24
|
-
}, [product?.id
|
|
10
|
+
}, [product?.id]);
|
|
25
11
|
const setAttribute = useCallback((key, value) => {
|
|
26
12
|
setSelectedAttributes((previous) => {
|
|
27
13
|
if (value &&
|
|
@@ -400,7 +400,7 @@ export function ProductDetailPage({ storeConfig: initialConfig, productSlug }) {
|
|
|
400
400
|
};
|
|
401
401
|
return (_jsxs("div", { className: "min-h-screen bg-white", children: [_jsxs("div", { "data-content-ready": true, className: "container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-7xl", children: [_jsx("div", { className: "mb-6", children: _jsx(Breadcrumbs, { items: breadcrumbItems }) }), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-16 mb-20", children: [_jsxs("div", { className: "relative lg:sticky lg:top-24 self-start z-0", children: [_jsxs("div", { className: "relative aspect-square bg-gray-50 rounded-xl overflow-hidden mb-4 border border-gray-100 shadow-sm group", children: [_jsx(ImageWithFallback, { "data-product-image": true, src: displayImages[selectedImage] || displayImages[0] || productImages[0], alt: product.name, className: cn("w-full h-full object-cover transition-transform duration-300 group-hover:scale-105", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }), isOutOfStock && (_jsx(OutOfStockOverlay, { badgePosition: "center" }))] }), displayImages.length > 0 && (_jsxs("div", { className: "grid grid-cols-5 gap-2", children: [displayImages.map((image, index) => (_jsx("button", { onClick: () => setSelectedImage(Math.min(index, displayImages.length - 1)), className: `aspect-square rounded-lg overflow-hidden border-2 transition-all ${selectedImage === index
|
|
402
402
|
? 'border-gray-900 ring-2 ring-gray-900 ring-offset-2'
|
|
403
|
-
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: directCategory?.name || storeConfig.name }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children:
|
|
403
|
+
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: directCategory?.name || storeConfig.name }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children: !isOutOfStock ? (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800", children: [_jsx(CheckCircle, { className: "w-3 h-3 mr-1" }), "In Stock"] })) : (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800", children: [_jsx(Info, { className: "w-3 h-3 mr-1" }), "Out of Stock"] })) }), _jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-baseline gap-4", children: [_jsx("span", { "data-product-price": true, className: "text-4xl lg:text-5xl font-bold text-gray-900", children: formatCurrency(displayPrice, product.currency || 'USD') }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsx("span", { className: "text-2xl text-gray-500 line-through", children: formatCurrency(displayCompareAt, product.currency || 'USD') }))] }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsxs("span", { className: "inline-block mt-2 bg-red-100 text-red-700 text-xs font-bold px-2 py-1 rounded", children: ["SAVE ", Math.round(((displayCompareAt - displayPrice) / displayCompareAt) * 100), "%"] }))] }), _jsx(PdpVariationSelectors, { optionGroups: optionGroups, selectedAttributes: selectedAttributes, setAttribute: setAttribute, isOptionAvailable: isOptionAvailable, getOptionImage: getOptionImage, storeSlug: storeConfig.slug, showSizeGuide: productDetailConfig?.showSizeGuide !== false, onAfterClearAttribute: () => setQuantity(1) }), _jsxs("div", { className: "flex flex-col gap-4 mb-8", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Quantity" }), _jsxs("div", { className: "flex items-center border border-gray-300 rounded-lg", children: [_jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-l-lg disabled:opacity-50", onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1, children: _jsx(Minus, { className: "h-4 w-4" }) }), _jsx("span", { className: "w-12 text-center font-semibold text-gray-900", children: quantity }), _jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-r-lg", onClick: () => setQuantity(quantity + 1), children: _jsx(Plus, { className: "h-4 w-4" }) })] })] }), _jsxs("div", { className: "flex flex-row items-stretch gap-2 sm:gap-3 mt-2 w-full", children: [_jsx(Button, { "data-add-to-cart": true, variant: "outline", size: "lg", onClick: handleAddToCart, disabled: isCartLoading || isOutOfStock, className: "flex-1 min-w-0 bg-white border-2 border-gray-900 text-gray-900 hover:bg-gray-50 rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold [&_svg]:text-gray-900 shadow-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : (_jsxs(_Fragment, { children: [_jsx(ShoppingCart, { className: "h-4 w-4 sm:h-5 sm:w-5 mr-1.5 sm:mr-2 shrink-0 text-gray-900" }), "Add to Cart"] })) }), _jsx(Button, { size: "lg", onClick: handleBuyNow, disabled: isOutOfStock || isBuyNowLoading || isCartLoading, className: "flex-1 min-w-0 bg-gray-900 hover:bg-gray-800 text-white rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold shadow-lg hover:shadow-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isBuyNowLoading || isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : ('Buy Now') }), storeConfig.features.wishlist && (_jsx(Button, { variant: "outline", size: "lg", onClick: handleWishlistClick, disabled: isWishlistLoading || !product, className: cn("h-12 w-12 sm:h-14 sm:w-14 shrink-0 rounded-full border-2 transition-all disabled:opacity-50 disabled:cursor-not-allowed", product && isInWishlist(product.id)
|
|
404
404
|
? "border-red-500 bg-red-50 text-red-500 hover:bg-red-100"
|
|
405
405
|
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50"), children: isWishlistLoading ? (_jsx(ButtonLoader, { className: "h-5 w-5" })) : (_jsx(Heart, { className: cn("h-5 w-5", product && isInWishlist(product.id) && "fill-current") })) }))] })] }), _jsx(ProductDeliveryInfoSection, { storeConfig: storeConfig, currency: storeConfig.settings?.currency || 'USD', productCurrency: product.currency, productPrice: displayPrice, quantity: quantity, shippingAddress: shippingAddress, updateShippingAddress: (patch) => setShippingAddress((prev) => ({ ...prev, ...patch })), shippingMethods: shippingMethods, isCalculatingShipping: isCalculatingShipping, shippingError: shippingError, freeShippingEligible: freeShippingEligible, freeShippingThreshold: freeShippingThreshold, onToast: addToast }), product.description && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-3", children: "Description" }), _jsxs("div", { className: "prose prose-sm max-w-none text-gray-600 leading-relaxed", children: [_jsx(SafeRichHtml, { value: product.description, fallbackPlain: "", as: "div" }), _jsxs("ul", { className: "list-disc pl-5 space-y-1 mt-2", children: [_jsx("li", { children: "Premium quality material" }), _jsx("li", { children: "Comfortable fit for all-day wear" }), _jsx("li", { children: "Durable stitching and finish" })] })] })] })), product.specifications && Object.keys(product.specifications).length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Specifications" }), _jsx("dl", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-4", children: Object.entries(product.specifications).map(([key, value]) => (_jsxs("div", { className: "flex flex-col p-3 bg-gray-50 rounded-lg", children: [_jsx("dt", { className: "text-xs text-gray-500 font-medium uppercase tracking-wider mb-1", children: key }), _jsx("dd", { className: "text-sm font-bold text-gray-900", children: value })] }, key))) })] }))] })] }), _jsx("div", { className: "mt-20 pt-16 border-t border-gray-200", children: _jsxs("div", { className: "max-w-4xl", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 mb-10", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-2xl lg:text-3xl font-bold text-gray-900 mb-4", children: "Customer Reviews" }), reviewCount > 0 && averageRating > 0 && (_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StarRating, { rating: averageRating, size: "lg" }), _jsx("span", { className: "text-2xl font-bold text-gray-900", children: averageRating.toFixed(1) }), _jsx("span", { className: "text-lg text-gray-500", children: "out of 5" })] }), _jsx("span", { className: "text-gray-300", children: "|" }), _jsxs("span", { className: "text-lg text-gray-600", children: [reviewCount, " ", reviewCount === 1 ? 'review' : 'reviews'] })] }))] }), reviewCount > 0 && (_jsx(Button, { onClick: () => {
|
|
406
406
|
if (!isAuthenticated) {
|
|
@@ -400,7 +400,7 @@ export function ProductDetailPage({ storeConfig: initialConfig, productSlug }) {
|
|
|
400
400
|
};
|
|
401
401
|
return (_jsxs("div", { className: "min-h-screen bg-white", children: [_jsxs("div", { "data-content-ready": true, className: "container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-7xl", children: [_jsx("div", { className: "mb-6", children: _jsx(Breadcrumbs, { items: breadcrumbItems }) }), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-16 mb-20", children: [_jsxs("div", { className: "relative lg:sticky lg:top-24 self-start z-0", children: [_jsxs("div", { className: "relative aspect-square bg-gray-50 rounded-xl overflow-hidden mb-4 border border-gray-100 shadow-sm group", children: [_jsx(ImageWithFallback, { "data-product-image": true, src: displayImages[selectedImage] || displayImages[0] || productImages[0], alt: product.name, className: cn("w-full h-full object-cover transition-transform duration-300 group-hover:scale-105", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }), isOutOfStock && (_jsx(OutOfStockOverlay, { badgePosition: "center" }))] }), displayImages.length > 0 && (_jsxs("div", { className: "grid grid-cols-5 gap-2", children: [displayImages.map((image, index) => (_jsx("button", { onClick: () => setSelectedImage(Math.min(index, displayImages.length - 1)), className: `aspect-square rounded-lg overflow-hidden border-2 transition-all ${selectedImage === index
|
|
402
402
|
? 'border-gray-900 ring-2 ring-gray-900 ring-offset-2'
|
|
403
|
-
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: directCategory?.name || storeConfig.name }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children:
|
|
403
|
+
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: directCategory?.name || storeConfig.name }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children: !isOutOfStock ? (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800", children: [_jsx(CheckCircle, { className: "w-3 h-3 mr-1" }), "In Stock"] })) : (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800", children: [_jsx(Info, { className: "w-3 h-3 mr-1" }), "Out of Stock"] })) }), _jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-baseline gap-4", children: [_jsx("span", { "data-product-price": true, className: "text-4xl lg:text-5xl font-bold text-gray-900", children: formatCurrency(displayPrice, product.currency || 'USD') }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsx("span", { className: "text-2xl text-gray-500 line-through", children: formatCurrency(displayCompareAt, product.currency || 'USD') }))] }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsxs("span", { className: "inline-block mt-2 bg-red-100 text-red-700 text-xs font-bold px-2 py-1 rounded", children: ["SAVE ", Math.round(((displayCompareAt - displayPrice) / displayCompareAt) * 100), "%"] }))] }), _jsx(PdpVariationSelectors, { optionGroups: optionGroups, selectedAttributes: selectedAttributes, setAttribute: setAttribute, isOptionAvailable: isOptionAvailable, getOptionImage: getOptionImage, storeSlug: storeConfig.slug, showSizeGuide: productDetailConfig?.showSizeGuide !== false, onAfterClearAttribute: () => setQuantity(1) }), _jsxs("div", { className: "flex flex-col gap-4 mb-8", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Quantity" }), _jsxs("div", { className: "flex items-center border border-gray-300 rounded-lg", children: [_jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-l-lg disabled:opacity-50", onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1, children: _jsx(Minus, { className: "h-4 w-4" }) }), _jsx("span", { className: "w-12 text-center font-semibold text-gray-900", children: quantity }), _jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-r-lg", onClick: () => setQuantity(quantity + 1), children: _jsx(Plus, { className: "h-4 w-4" }) })] })] }), _jsxs("div", { className: "flex flex-row items-stretch gap-2 sm:gap-3 mt-2 w-full", children: [_jsx(Button, { "data-add-to-cart": true, variant: "outline", size: "lg", onClick: handleAddToCart, disabled: isCartLoading || isOutOfStock, className: "flex-1 min-w-0 bg-white border-2 border-gray-900 text-gray-900 hover:bg-gray-50 rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold [&_svg]:text-gray-900 shadow-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : (_jsxs(_Fragment, { children: [_jsx(ShoppingCart, { className: "h-4 w-4 sm:h-5 sm:w-5 mr-1.5 sm:mr-2 shrink-0 text-gray-900" }), "Add to Cart"] })) }), _jsx(Button, { size: "lg", onClick: handleBuyNow, disabled: isOutOfStock || isBuyNowLoading || isCartLoading, className: "flex-1 min-w-0 bg-gray-900 hover:bg-gray-800 text-white rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold shadow-lg hover:shadow-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isBuyNowLoading || isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : ('Buy Now') }), storeConfig.features.wishlist && (_jsx(Button, { variant: "outline", size: "lg", onClick: handleWishlistClick, disabled: isWishlistLoading || !product, className: cn("h-12 w-12 sm:h-14 sm:w-14 shrink-0 rounded-full border-2 transition-all disabled:opacity-50 disabled:cursor-not-allowed", product && isInWishlist(product.id)
|
|
404
404
|
? "border-red-500 bg-red-50 text-red-500 hover:bg-red-100"
|
|
405
405
|
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50"), children: isWishlistLoading ? (_jsx(ButtonLoader, { className: "h-5 w-5" })) : (_jsx(Heart, { className: cn("h-5 w-5", product && isInWishlist(product.id) && "fill-current") })) }))] })] }), _jsx(ProductDeliveryInfoSection, { storeConfig: storeConfig, currency: storeConfig.settings?.currency || 'USD', productCurrency: product.currency, productPrice: displayPrice, quantity: quantity, shippingAddress: shippingAddress, updateShippingAddress: (patch) => setShippingAddress((prev) => ({ ...prev, ...patch })), shippingMethods: shippingMethods, isCalculatingShipping: isCalculatingShipping, shippingError: shippingError, freeShippingEligible: freeShippingEligible, freeShippingThreshold: freeShippingThreshold, onToast: addToast }), product.description && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-3", children: "Description" }), _jsxs("div", { className: "prose prose-sm max-w-none text-gray-600 leading-relaxed", children: [_jsx(SafeRichHtml, { value: product.description, fallbackPlain: "", as: "div" }), _jsxs("ul", { className: "list-disc pl-5 space-y-1 mt-2", children: [_jsx("li", { children: "Premium quality material" }), _jsx("li", { children: "Comfortable fit for all-day wear" }), _jsx("li", { children: "Durable stitching and finish" })] })] })] })), product.specifications && Object.keys(product.specifications).length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Specifications" }), _jsx("dl", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-4", children: Object.entries(product.specifications).map(([key, value]) => (_jsxs("div", { className: "flex flex-col p-3 bg-gray-50 rounded-lg", children: [_jsx("dt", { className: "text-xs text-gray-500 font-medium uppercase tracking-wider mb-1", children: key }), _jsx("dd", { className: "text-sm font-bold text-gray-900", children: value })] }, key))) })] }))] })] }), _jsx("div", { className: "mt-20 pt-16 border-t border-gray-200", children: _jsxs("div", { className: "max-w-4xl", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 mb-10", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-2xl lg:text-3xl font-bold text-gray-900 mb-4", children: "Customer Reviews" }), reviewCount > 0 && averageRating > 0 && (_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StarRating, { rating: averageRating, size: "lg" }), _jsx("span", { className: "text-2xl font-bold text-gray-900", children: averageRating.toFixed(1) }), _jsx("span", { className: "text-lg text-gray-500", children: "out of 5" })] }), _jsx("span", { className: "text-gray-300", children: "|" }), _jsxs("span", { className: "text-lg text-gray-600", children: [reviewCount, " ", reviewCount === 1 ? 'review' : 'reviews'] })] }))] }), reviewCount > 0 && (_jsx(Button, { onClick: () => {
|
|
406
406
|
if (!isAuthenticated) {
|
|
@@ -406,7 +406,7 @@ export function ProductDetailPage({ storeConfig: initialConfig, productSlug }) {
|
|
|
406
406
|
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: (() => {
|
|
407
407
|
const brandMatch = product.name.match(/\b(Nike|Adidas|Puma|Reebok|New Balance|Vans|Converse|Zara|H&M|Gucci|Prada|Levi's|Calvin Klein)\b/i);
|
|
408
408
|
return brandMatch ? brandMatch[1] : storeConfig.name;
|
|
409
|
-
})() }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children:
|
|
409
|
+
})() }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children: !isOutOfStock ? (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800", children: [_jsx(CheckCircle, { className: "w-3 h-3 mr-1" }), "In Stock"] })) : (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800", children: [_jsx(Info, { className: "w-3 h-3 mr-1" }), "Out of Stock"] })) }), _jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-baseline gap-4", children: [_jsx("span", { "data-product-price": true, className: "text-4xl lg:text-5xl font-bold text-gray-900", children: formatCurrency(displayPrice, product.currency || 'USD') }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsx("span", { className: "text-2xl text-gray-500 line-through", children: formatCurrency(displayCompareAt, product.currency || 'USD') }))] }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsxs("span", { className: "inline-block mt-2 bg-red-100 text-red-700 text-xs font-bold px-2 py-1 rounded", children: ["SAVE ", Math.round(((displayCompareAt - displayPrice) / displayCompareAt) * 100), "%"] }))] }), _jsx(PdpVariationSelectors, { optionGroups: optionGroups, selectedAttributes: selectedAttributes, setAttribute: setAttribute, isOptionAvailable: isOptionAvailable, getOptionImage: getOptionImage, storeSlug: storeConfig.slug, showSizeGuide: productDetailConfig?.showSizeGuide !== false, onAfterClearAttribute: () => setQuantity(1) }), _jsxs("div", { className: "flex flex-col gap-4 mb-8", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Quantity" }), _jsxs("div", { className: "flex items-center border border-gray-300 rounded-lg", children: [_jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-l-lg disabled:opacity-50", onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1, children: _jsx(Minus, { className: "h-4 w-4" }) }), _jsx("span", { className: "w-12 text-center font-semibold text-gray-900", children: quantity }), _jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-r-lg", onClick: () => setQuantity(quantity + 1), children: _jsx(Plus, { className: "h-4 w-4" }) })] })] }), _jsxs("div", { className: "flex flex-row items-stretch gap-2 sm:gap-3 mt-2 w-full", children: [productDetailConfig?.showAddToCart !== false && (_jsx(Button, { "data-add-to-cart": true, variant: "outline", size: "lg", onClick: handleAddToCart, disabled: isCartLoading || isOutOfStock, className: "flex-1 min-w-0 bg-white border-2 border-gray-900 text-gray-900 hover:bg-gray-50 rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold shadow-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed [&_svg]:text-gray-900", children: isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : (_jsxs(_Fragment, { children: [_jsx(ShoppingCart, { className: "h-4 w-4 sm:h-5 sm:w-5 mr-1.5 sm:mr-2 shrink-0 text-gray-900" }), "Add to Cart"] })) })), productDetailConfig?.showAddToCart !== false && (_jsx(Button, { size: "lg", onClick: handleBuyNow, disabled: isOutOfStock || isBuyNowLoading || isCartLoading, className: "flex-1 min-w-0 bg-gray-900 hover:bg-gray-800 text-white rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold shadow-lg hover:shadow-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isBuyNowLoading || isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : ('Buy Now') })), storeConfig.features.wishlist && productDetailConfig?.showWishlist !== false && (_jsx(Button, { variant: "outline", size: "lg", onClick: handleWishlistClick, disabled: isWishlistLoading || !product, className: cn("h-12 w-12 sm:h-14 sm:w-14 shrink-0 rounded-full border-2 transition-all disabled:opacity-50 disabled:cursor-not-allowed", product && isInWishlist(product.id)
|
|
410
410
|
? "border-red-500 bg-red-50 text-red-500 hover:bg-red-100"
|
|
411
411
|
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50"), children: isWishlistLoading ? (_jsx(ButtonLoader, { className: "h-5 w-5" })) : (_jsx(Heart, { className: cn("h-5 w-5", product && isInWishlist(product.id) && "fill-current") })) }))] })] }), _jsx(ProductDeliveryInfoSection, { storeConfig: storeConfig, currency: storeConfig.settings?.currency || 'USD', productCurrency: product.currency, productPrice: displayPrice, quantity: quantity, shippingAddress: shippingAddress, updateShippingAddress: (patch) => setShippingAddress((prev) => ({ ...prev, ...patch })), shippingMethods: shippingMethods, isCalculatingShipping: isCalculatingShipping, shippingError: shippingError, freeShippingEligible: freeShippingEligible, freeShippingThreshold: freeShippingThreshold, onToast: addToast }), product.description && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-3", children: "Description" }), _jsxs("div", { className: "prose prose-sm max-w-none text-gray-600 leading-relaxed", children: [_jsx(SafeRichHtml, { value: product.description, fallbackPlain: "", as: "div" }), _jsxs("ul", { className: "list-disc pl-5 space-y-1 mt-2", children: [_jsx("li", { children: "Premium quality material" }), _jsx("li", { children: "Comfortable fit for all-day wear" }), _jsx("li", { children: "Durable stitching and finish" })] })] })] })), product.specifications && Object.keys(product.specifications).length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Specifications" }), _jsx("dl", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-4", children: Object.entries(product.specifications).map(([key, value]) => (_jsxs("div", { className: "flex flex-col p-3 bg-gray-50 rounded-lg", children: [_jsx("dt", { className: "text-xs text-gray-500 font-medium uppercase tracking-wider mb-1", children: key }), _jsx("dd", { className: "text-sm font-bold text-gray-900", children: value })] }, key))) })] }))] })] }), productDetailConfig?.showReviews !== false && (_jsx("div", { className: "mt-20 pt-16 border-t border-gray-200", children: _jsxs("div", { className: "max-w-4xl", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 mb-10", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-2xl lg:text-3xl font-bold text-gray-900 mb-4", children: "Customer Reviews" }), reviewCount > 0 && averageRating > 0 && (_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StarRating, { rating: averageRating, size: "lg" }), _jsx("span", { className: "text-2xl font-bold text-gray-900", children: averageRating.toFixed(1) }), _jsx("span", { className: "text-lg text-gray-500", children: "out of 5" })] }), _jsx("span", { className: "text-gray-300", children: "|" }), _jsxs("span", { className: "text-lg text-gray-600", children: [reviewCount, " ", reviewCount === 1 ? 'review' : 'reviews'] })] }))] }), reviewCount > 0 && (_jsx(Button, { onClick: () => {
|
|
412
412
|
if (!isAuthenticated) {
|
|
@@ -404,7 +404,7 @@ export function ProductDetailPage({ storeConfig: initialConfig, productSlug }) {
|
|
|
404
404
|
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: (() => {
|
|
405
405
|
const brandMatch = product.name.match(/\b(Reebok|Nike|Adidas|Puma|New Balance|Vans|Converse)\b/i);
|
|
406
406
|
return brandMatch ? brandMatch[1] : storeConfig.name;
|
|
407
|
-
})() }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children:
|
|
407
|
+
})() }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children: !isOutOfStock ? (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800", children: [_jsx(CheckCircle, { className: "w-3 h-3 mr-1" }), "In Stock"] })) : (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800", children: [_jsx(Info, { className: "w-3 h-3 mr-1" }), "Out of Stock"] })) }), _jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-baseline gap-4", children: [_jsx("span", { "data-product-price": true, className: "text-4xl lg:text-5xl font-bold text-gray-900", children: formatCurrency(displayPrice, product.currency || 'USD') }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsx("span", { className: "text-2xl text-gray-500 line-through", children: formatCurrency(displayCompareAt, product.currency || 'USD') }))] }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsxs("span", { className: "inline-block mt-2 bg-red-100 text-red-700 text-xs font-bold px-2 py-1 rounded", children: ["SAVE ", Math.round(((displayCompareAt - displayPrice) / displayCompareAt) * 100), "%"] }))] }), _jsx(PdpVariationSelectors, { optionGroups: optionGroups, selectedAttributes: selectedAttributes, setAttribute: setAttribute, isOptionAvailable: isOptionAvailable, getOptionImage: getOptionImage, storeSlug: storeConfig.slug, showSizeGuide: productDetailConfig?.showSizeGuide !== false, onAfterClearAttribute: () => setQuantity(1) }), _jsxs("div", { className: "flex flex-col gap-4 mb-8", children: [_jsxs("div", { className: "flex items-center gap-2.5", children: [_jsx("span", { className: "text-sm font-normal leading-5 text-[#191C1F]", children: "Quantity" }), _jsxs("div", { className: "inline-flex h-8 w-fit items-center rounded-[2px] border border-[#E4E7E9] bg-white", children: [_jsx("button", { type: "button", className: "flex h-8 w-7 items-center justify-center text-[#475156] hover:bg-gray-50 disabled:opacity-40", onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1, "aria-label": "Decrease quantity", children: _jsx(Minus, { className: "h-3.5 w-3.5" }) }), _jsx("span", { className: "w-6 text-center text-sm font-medium tabular-nums text-[#191C1F]", children: quantity }), _jsx("button", { type: "button", className: "flex h-8 w-7 items-center justify-center text-[#475156] hover:bg-gray-50", onClick: () => setQuantity(quantity + 1), "aria-label": "Increase quantity", children: _jsx(Plus, { className: "h-3.5 w-3.5" }) })] })] }), _jsxs("div", { className: "flex flex-row items-stretch gap-2 sm:gap-3 mt-2 w-full", children: [productDetailConfig?.showAddToCart !== false && (_jsx(Button, { "data-add-to-cart": true, variant: "outline", size: "lg", onClick: handleAddToCart, disabled: isCartLoading || isOutOfStock, className: "flex-1 min-w-0 bg-white border-2 border-gray-900 text-gray-900 hover:bg-gray-50 rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold [&_svg]:text-gray-900 shadow-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : (_jsxs(_Fragment, { children: [_jsx(ShoppingCart, { className: "h-4 w-4 sm:h-5 sm:w-5 mr-1.5 sm:mr-2 shrink-0 text-gray-900" }), "Add to Cart"] })) })), productDetailConfig?.showAddToCart !== false && (_jsx(Button, { size: "lg", onClick: handleBuyNow, disabled: isOutOfStock || isBuyNowLoading || isCartLoading, className: "flex-1 min-w-0 bg-gray-900 hover:bg-gray-800 text-white rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold shadow-lg hover:shadow-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isBuyNowLoading || isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : ('Buy Now') })), storeConfig.features.wishlist && productDetailConfig?.showWishlist !== false && (_jsx(Button, { variant: "outline", size: "lg", onClick: handleWishlistClick, disabled: isWishlistLoading || !product, className: cn("h-12 w-12 sm:h-14 sm:w-14 shrink-0 rounded-full border-2 transition-all disabled:opacity-50 disabled:cursor-not-allowed", product && isInWishlist(product.id)
|
|
408
408
|
? "border-red-500 bg-red-50 text-red-500 hover:bg-red-100"
|
|
409
409
|
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50"), children: isWishlistLoading ? (_jsx(ButtonLoader, { className: "h-5 w-5" })) : (_jsx(Heart, { className: cn("h-5 w-5", product && isInWishlist(product.id) && "fill-current") })) }))] })] }), _jsx(ProductDeliveryInfoSection, { storeConfig: storeConfig, currency: storeConfig.settings?.currency || 'USD', productCurrency: product.currency, productPrice: displayPrice, quantity: quantity, shippingAddress: shippingAddress, updateShippingAddress: (patch) => setShippingAddress((prev) => ({ ...prev, ...patch })), shippingMethods: shippingMethods, isCalculatingShipping: isCalculatingShipping, shippingError: shippingError, freeShippingEligible: freeShippingEligible, freeShippingThreshold: freeShippingThreshold, onToast: addToast }), product.description && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-3", children: "Description" }), _jsxs("div", { className: "prose prose-sm max-w-none text-gray-600 leading-relaxed", children: [_jsx(SafeRichHtml, { value: product.description, fallbackPlain: "", as: "div" }), _jsxs("ul", { className: "list-disc pl-5 space-y-1 mt-2", children: [_jsx("li", { children: "Premium quality material" }), _jsx("li", { children: "Comfortable fit for all-day wear" }), _jsx("li", { children: "Durable stitching and finish" })] })] })] })), product.specifications && Object.keys(product.specifications).length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Specifications" }), _jsx("dl", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-4", children: Object.entries(product.specifications).map(([key, value]) => (_jsxs("div", { className: "flex flex-col p-3 bg-gray-50 rounded-lg", children: [_jsx("dt", { className: "text-xs text-gray-500 font-medium uppercase tracking-wider mb-1", children: key }), _jsx("dd", { className: "text-sm font-bold text-gray-900", children: value })] }, key))) })] }))] })] }), productDetailConfig?.showReviews !== false && (_jsx("div", { className: "mt-20 pt-16 border-t border-gray-200", children: _jsxs("div", { className: "max-w-4xl", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 mb-10", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-2xl lg:text-3xl font-bold text-gray-900 mb-4", children: "Customer Reviews" }), reviewCount > 0 && averageRating > 0 && (_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StarRating, { rating: averageRating, size: "lg" }), _jsx("span", { className: "text-2xl font-bold text-gray-900", children: averageRating.toFixed(1) }), _jsx("span", { className: "text-lg text-gray-500", children: "out of 5" })] }), _jsx("span", { className: "text-gray-300", children: "|" }), _jsxs("span", { className: "text-lg text-gray-600", children: [reviewCount, " ", reviewCount === 1 ? 'review' : 'reviews'] })] }))] }), reviewCount > 0 && (_jsx(Button, { onClick: () => {
|
|
410
410
|
if (!isAuthenticated) {
|
|
@@ -403,7 +403,7 @@ export function ProductDetailPage({ storeConfig: initialConfig, productSlug }) {
|
|
|
403
403
|
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: (() => {
|
|
404
404
|
const brandMatch = product.name.match(/\b(Sony|Samsung|Apple|LG|Dell|HP|Microsoft|Logitech|Razer|Corsair|Asus|Acer|Lenovo)\b/i);
|
|
405
405
|
return brandMatch ? brandMatch[1] : storeConfig.name;
|
|
406
|
-
})() }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children:
|
|
406
|
+
})() }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children: !isOutOfStock ? (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800", children: [_jsx(CheckCircle, { className: "w-3 h-3 mr-1" }), "In Stock"] })) : (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800", children: [_jsx(Info, { className: "w-3 h-3 mr-1" }), "Out of Stock"] })) }), _jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-baseline gap-4", children: [_jsx("span", { "data-product-price": true, className: "text-4xl lg:text-5xl font-bold text-gray-900", children: formatCurrency(displayPrice, product.currency || 'USD') }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsx("span", { className: "text-2xl text-gray-500 line-through", children: formatCurrency(displayCompareAt, product.currency || 'USD') }))] }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsxs("span", { className: "inline-block mt-2 bg-red-100 text-red-700 text-xs font-bold px-2 py-1 rounded", children: ["SAVE ", Math.round(((displayCompareAt - displayPrice) / displayCompareAt) * 100), "%"] }))] }), _jsx(PdpVariationSelectors, { optionGroups: optionGroups, selectedAttributes: selectedAttributes, setAttribute: setAttribute, isOptionAvailable: isOptionAvailable, getOptionImage: getOptionImage, storeSlug: storeConfig.slug, showSizeGuide: productDetailConfig?.showSizeGuide !== false, onAfterClearAttribute: () => setQuantity(1) }), _jsxs("div", { className: "flex flex-col gap-4 mb-8", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Quantity" }), _jsxs("div", { className: "flex items-center border border-gray-300 rounded-lg", children: [_jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-l-lg disabled:opacity-50", onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1, children: _jsx(Minus, { className: "h-4 w-4" }) }), _jsx("span", { className: "w-12 text-center font-semibold text-gray-900", children: quantity }), _jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-r-lg", onClick: () => setQuantity(quantity + 1), children: _jsx(Plus, { className: "h-4 w-4" }) })] })] }), _jsxs("div", { className: "flex flex-row items-stretch gap-2 sm:gap-3 mt-2 w-full", children: [_jsx(Button, { "data-add-to-cart": true, variant: "outline", size: "lg", onClick: handleAddToCart, disabled: isCartLoading || isOutOfStock, className: "flex-1 min-w-0 bg-white border-2 border-gray-900 text-gray-900 hover:bg-gray-50 rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold [&_svg]:text-gray-900 shadow-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : (_jsxs(_Fragment, { children: [_jsx(ShoppingCart, { className: "h-4 w-4 sm:h-5 sm:w-5 mr-1.5 sm:mr-2 shrink-0 text-gray-900" }), "Add to Cart"] })) }), _jsx(Button, { size: "lg", onClick: handleBuyNow, disabled: isOutOfStock || isBuyNowLoading || isCartLoading, className: "flex-1 min-w-0 bg-gray-900 hover:bg-gray-800 text-white rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold shadow-lg hover:shadow-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isBuyNowLoading || isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : ('Buy Now') }), storeConfig.features.wishlist && (_jsx(Button, { variant: "outline", size: "lg", onClick: handleWishlistClick, disabled: isWishlistLoading || !product, className: cn("h-12 w-12 sm:h-14 sm:w-14 shrink-0 rounded-full border-2 transition-all disabled:opacity-50 disabled:cursor-not-allowed", product && isInWishlist(product.id)
|
|
407
407
|
? "border-red-500 bg-red-50 text-red-500 hover:bg-red-100"
|
|
408
408
|
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50"), children: isWishlistLoading ? (_jsx(ButtonLoader, { className: "h-5 w-5" })) : (_jsx(Heart, { className: cn("h-5 w-5", product && isInWishlist(product.id) && "fill-current") })) }))] })] }), _jsx(ProductDeliveryInfoSection, { storeConfig: storeConfig, currency: storeConfig.settings?.currency || 'USD', productCurrency: product.currency, productPrice: displayPrice, quantity: quantity, shippingAddress: shippingAddress, updateShippingAddress: (patch) => setShippingAddress((prev) => ({ ...prev, ...patch })), shippingMethods: shippingMethods, isCalculatingShipping: isCalculatingShipping, shippingError: shippingError, freeShippingEligible: freeShippingEligible, freeShippingThreshold: freeShippingThreshold, onToast: addToast }), product.description && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-3", children: "Description" }), _jsxs("div", { className: "prose prose-sm max-w-none text-gray-600 leading-relaxed", children: [_jsx(SafeRichHtml, { value: product.description, fallbackPlain: "", as: "div" }), _jsxs("ul", { className: "list-disc pl-5 space-y-1 mt-2", children: [_jsx("li", { children: "Premium quality material" }), _jsx("li", { children: "Comfortable fit for all-day wear" }), _jsx("li", { children: "Durable stitching and finish" })] })] })] })), product.specifications && Object.keys(product.specifications).length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Specifications" }), _jsx("dl", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-4", children: Object.entries(product.specifications).map(([key, value]) => (_jsxs("div", { className: "flex flex-col p-3 bg-gray-50 rounded-lg", children: [_jsx("dt", { className: "text-xs text-gray-500 font-medium uppercase tracking-wider mb-1", children: key }), _jsx("dd", { className: "text-sm font-bold text-gray-900", children: value })] }, key))) })] }))] })] }), _jsx("div", { className: "mt-20 pt-16 border-t border-gray-200", children: _jsxs("div", { className: "max-w-4xl", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 mb-10", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-2xl lg:text-3xl font-bold text-gray-900 mb-4", children: "Customer Reviews" }), reviewCount > 0 && averageRating > 0 && (_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StarRating, { rating: averageRating, size: "lg" }), _jsx("span", { className: "text-2xl font-bold text-gray-900", children: averageRating.toFixed(1) }), _jsx("span", { className: "text-lg text-gray-500", children: "out of 5" })] }), _jsx("span", { className: "text-gray-300", children: "|" }), _jsxs("span", { className: "text-lg text-gray-600", children: [reviewCount, " ", reviewCount === 1 ? 'review' : 'reviews'] })] }))] }), reviewCount > 0 && (_jsx(Button, { onClick: () => {
|
|
409
409
|
if (!isAuthenticated) {
|
|
@@ -403,7 +403,7 @@ export function ProductDetailPage({ storeConfig: initialConfig, productSlug }) {
|
|
|
403
403
|
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: (() => {
|
|
404
404
|
const brandMatch = product.name.match(/\b(Sony|Samsung|Apple|LG|Dell|HP|Microsoft|Logitech|Razer|Corsair|Asus|Acer|Lenovo)\b/i);
|
|
405
405
|
return brandMatch ? brandMatch[1] : storeConfig.name;
|
|
406
|
-
})() }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children:
|
|
406
|
+
})() }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children: !isOutOfStock ? (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800", children: [_jsx(CheckCircle, { className: "w-3 h-3 mr-1" }), "In Stock"] })) : (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800", children: [_jsx(Info, { className: "w-3 h-3 mr-1" }), "Out of Stock"] })) }), _jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-baseline gap-4", children: [_jsx("span", { "data-product-price": true, className: "text-4xl lg:text-5xl font-bold text-gray-900", children: formatCurrency(displayPrice, product.currency || 'USD') }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsx("span", { className: "text-2xl text-gray-500 line-through", children: formatCurrency(displayCompareAt, product.currency || 'USD') }))] }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsxs("span", { className: "inline-block mt-2 bg-red-100 text-red-700 text-xs font-bold px-2 py-1 rounded", children: ["SAVE ", Math.round(((displayCompareAt - displayPrice) / displayCompareAt) * 100), "%"] }))] }), _jsx(PdpVariationSelectors, { optionGroups: optionGroups, selectedAttributes: selectedAttributes, setAttribute: setAttribute, isOptionAvailable: isOptionAvailable, getOptionImage: getOptionImage, storeSlug: storeConfig.slug, showSizeGuide: productDetailConfig?.showSizeGuide !== false, onAfterClearAttribute: () => setQuantity(1) }), _jsxs("div", { className: "flex flex-col gap-4 mb-8", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Quantity" }), _jsxs("div", { className: "flex items-center border border-gray-300 rounded-lg", children: [_jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-l-lg disabled:opacity-50", onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1, children: _jsx(Minus, { className: "h-4 w-4" }) }), _jsx("span", { className: "w-12 text-center font-semibold text-gray-900", children: quantity }), _jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-r-lg", onClick: () => setQuantity(quantity + 1), children: _jsx(Plus, { className: "h-4 w-4" }) })] })] }), _jsxs("div", { className: "flex flex-row items-stretch gap-2 sm:gap-3 mt-2 w-full", children: [_jsx(Button, { "data-add-to-cart": true, variant: "outline", size: "lg", onClick: handleAddToCart, disabled: isCartLoading || isOutOfStock, className: "flex-1 min-w-0 bg-white border-2 border-gray-900 text-gray-900 hover:bg-gray-50 rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold [&_svg]:text-gray-900 shadow-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : (_jsxs(_Fragment, { children: [_jsx(ShoppingCart, { className: "h-4 w-4 sm:h-5 sm:w-5 mr-1.5 sm:mr-2 shrink-0 text-gray-900" }), "Add to Cart"] })) }), _jsx(Button, { size: "lg", onClick: handleBuyNow, disabled: isOutOfStock || isBuyNowLoading || isCartLoading, className: "flex-1 min-w-0 bg-gray-900 hover:bg-gray-800 text-white rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold shadow-lg hover:shadow-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isBuyNowLoading || isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : ('Buy Now') }), storeConfig.features.wishlist && (_jsx(Button, { variant: "outline", size: "lg", onClick: handleWishlistClick, disabled: isWishlistLoading || !product, className: cn("h-12 w-12 sm:h-14 sm:w-14 shrink-0 rounded-full border-2 transition-all disabled:opacity-50 disabled:cursor-not-allowed", product && isInWishlist(product.id)
|
|
407
407
|
? "border-red-500 bg-red-50 text-red-500 hover:bg-red-100"
|
|
408
408
|
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50"), children: isWishlistLoading ? (_jsx(ButtonLoader, { className: "h-5 w-5" })) : (_jsx(Heart, { className: cn("h-5 w-5", product && isInWishlist(product.id) && "fill-current") })) }))] })] }), _jsx(ProductDeliveryInfoSection, { storeConfig: storeConfig, currency: storeConfig.settings?.currency || 'USD', productCurrency: product.currency, productPrice: displayPrice, quantity: quantity, shippingAddress: shippingAddress, updateShippingAddress: (patch) => setShippingAddress((prev) => ({ ...prev, ...patch })), shippingMethods: shippingMethods, isCalculatingShipping: isCalculatingShipping, shippingError: shippingError, freeShippingEligible: freeShippingEligible, freeShippingThreshold: freeShippingThreshold, onToast: addToast }), product.description && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-3", children: "Description" }), _jsxs("div", { className: "prose prose-sm max-w-none text-gray-600 leading-relaxed", children: [_jsx(SafeRichHtml, { value: product.description, fallbackPlain: "", as: "div" }), _jsxs("ul", { className: "list-disc pl-5 space-y-1 mt-2", children: [_jsx("li", { children: "Premium quality material" }), _jsx("li", { children: "Comfortable fit for all-day wear" }), _jsx("li", { children: "Durable stitching and finish" })] })] })] })), product.specifications && Object.keys(product.specifications).length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Specifications" }), _jsx("dl", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-4", children: Object.entries(product.specifications).map(([key, value]) => (_jsxs("div", { className: "flex flex-col p-3 bg-gray-50 rounded-lg", children: [_jsx("dt", { className: "text-xs text-gray-500 font-medium uppercase tracking-wider mb-1", children: key }), _jsx("dd", { className: "text-sm font-bold text-gray-900", children: value })] }, key))) })] }))] })] }), _jsx("div", { className: "mt-20 pt-16 border-t border-gray-200", children: _jsxs("div", { className: "max-w-4xl", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 mb-10", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-2xl lg:text-3xl font-bold text-gray-900 mb-4", children: "Customer Reviews" }), reviewCount > 0 && averageRating > 0 && (_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StarRating, { rating: averageRating, size: "lg" }), _jsx("span", { className: "text-2xl font-bold text-gray-900", children: averageRating.toFixed(1) }), _jsx("span", { className: "text-lg text-gray-500", children: "out of 5" })] }), _jsx("span", { className: "text-gray-300", children: "|" }), _jsxs("span", { className: "text-lg text-gray-600", children: [reviewCount, " ", reviewCount === 1 ? 'review' : 'reviews'] })] }))] }), reviewCount > 0 && (_jsx(Button, { onClick: () => {
|
|
409
409
|
if (!isAuthenticated) {
|
|
@@ -425,7 +425,7 @@ export function ProductDetailPage({ storeConfig: initialConfig, productSlug }) {
|
|
|
425
425
|
}, [product?.id, storeConfig?.id, displayPrice, trackEvent]);
|
|
426
426
|
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "min-h-screen bg-white", children: _jsxs("div", { "data-content-ready": true, className: "container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-7xl", children: [_jsx("div", { className: "mb-6", children: _jsx(Breadcrumbs, { items: breadcrumbItems }) }), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-16 mb-20", children: [_jsxs("div", { className: "relative lg:sticky lg:top-24 self-start z-0", children: [_jsxs("div", { className: "relative aspect-square bg-gray-50 rounded-xl overflow-hidden mb-4 border border-gray-100 shadow-sm group", children: [_jsx(ImageWithFallback, { "data-product-image": true, src: displayImages[selectedImage] || displayImages[0] || productImages[0], alt: product.name, className: cn("w-full h-full object-cover transition-transform duration-300 group-hover:scale-105", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }), isOutOfStock && (_jsx(OutOfStockOverlay, { badgePosition: "center" }))] }), displayImages.length > 0 && (_jsxs("div", { className: "grid grid-cols-5 gap-2", children: [displayImages.map((image, index) => (_jsx("button", { onClick: () => setSelectedImage(Math.min(index, displayImages.length - 1)), className: `aspect-square rounded-lg overflow-hidden border-2 transition-all ${selectedImage === index
|
|
427
427
|
? 'border-gray-900 ring-2 ring-gray-900 ring-offset-2'
|
|
428
|
-
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: directCategory?.name || storeConfig.name }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children:
|
|
428
|
+
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: directCategory?.name || storeConfig.name }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children: !isOutOfStock ? (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800", children: [_jsx(CheckCircle, { className: "w-3 h-3 mr-1" }), "In Stock"] })) : (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800", children: [_jsx(Info, { className: "w-3 h-3 mr-1" }), "Out of Stock"] })) }), _jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-baseline gap-4", children: [_jsx("span", { "data-product-price": true, className: "text-4xl lg:text-5xl font-bold text-gray-900", children: formatCurrency(displayPrice, product.currency || 'USD') }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsx("span", { className: "text-2xl text-gray-500 line-through", children: formatCurrency(displayCompareAt, product.currency || 'USD') }))] }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsxs("span", { className: "inline-block mt-2 bg-red-100 text-red-700 text-xs font-bold px-2 py-1 rounded", children: ["SAVE ", Math.round(((displayCompareAt - displayPrice) / displayCompareAt) * 100), "%"] }))] }), _jsx(PdpVariationSelectors, { optionGroups: optionGroups, selectedAttributes: selectedAttributes, setAttribute: setAttribute, isOptionAvailable: isOptionAvailable, getOptionImage: getOptionImage, storeSlug: storeConfig.slug, showSizeGuide: productDetailConfig?.showSizeGuide !== false, onAfterClearAttribute: () => setQuantity(1) }), _jsxs("div", { className: "flex flex-col gap-4 mb-8", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Quantity" }), _jsxs("div", { className: "flex items-center border border-gray-300 rounded-lg", children: [_jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-l-lg disabled:opacity-50", onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1, children: _jsx(Minus, { className: "h-4 w-4" }) }), _jsx("span", { className: "w-12 text-center font-semibold text-gray-900", children: quantity }), _jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-r-lg", onClick: () => setQuantity(quantity + 1), children: _jsx(Plus, { className: "h-4 w-4" }) })] })] }), _jsxs("div", { className: "flex flex-row items-stretch gap-2 sm:gap-3 mt-2 w-full", children: [_jsx(Button, { "data-add-to-cart": true, variant: "outline", size: "lg", onClick: handleAddToCart, disabled: isCartLoading || isOutOfStock, className: "flex-1 min-w-0 bg-white border-2 border-gray-900 text-gray-900 hover:bg-gray-50 rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold [&_svg]:text-gray-900 shadow-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : (_jsxs(_Fragment, { children: [_jsx(ShoppingCart, { className: "h-4 w-4 sm:h-5 sm:w-5 mr-1.5 sm:mr-2 shrink-0 text-gray-900" }), "Add to Cart"] })) }), _jsx(Button, { size: "lg", onClick: handleBuyNow, disabled: isOutOfStock || isBuyNowLoading || isCartLoading, className: "flex-1 min-w-0 bg-gray-900 hover:bg-gray-800 text-white rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold shadow-lg hover:shadow-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isBuyNowLoading || isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : ('Buy Now') }), storeConfig.features.wishlist && (_jsx(Button, { variant: "outline", size: "lg", onClick: handleWishlistClick, disabled: isWishlistLoading || !product, className: cn("h-12 w-12 sm:h-14 sm:w-14 shrink-0 rounded-full border-2 transition-all disabled:opacity-50 disabled:cursor-not-allowed", product && isInWishlist(product.id)
|
|
429
429
|
? "border-red-500 bg-red-50 text-red-500 hover:bg-red-100"
|
|
430
430
|
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50"), children: isWishlistLoading ? (_jsx(ButtonLoader, { className: "h-5 w-5" })) : (_jsx(Heart, { className: cn("h-5 w-5", product && isInWishlist(product.id) && "fill-current") })) }))] })] }), _jsx(ProductDeliveryInfoSection, { storeConfig: storeConfig, currency: storeConfig.settings?.currency || 'USD', productCurrency: product.currency, productPrice: displayPrice, quantity: quantity, shippingAddress: shippingAddress, updateShippingAddress: (patch) => setShippingAddress((prev) => ({ ...prev, ...patch })), shippingMethods: shippingMethods, isCalculatingShipping: isCalculatingShipping, shippingError: shippingError, freeShippingEligible: freeShippingEligible, freeShippingThreshold: freeShippingThreshold, onToast: addToast }), product.description && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-3", children: "Description" }), _jsxs("div", { className: "prose prose-sm max-w-none text-gray-600 leading-relaxed", children: [_jsx(SafeRichHtml, { value: product.description, fallbackPlain: "", as: "div" }), _jsxs("ul", { className: "list-disc pl-5 space-y-1 mt-2", children: [_jsx("li", { children: "Premium quality material" }), _jsx("li", { children: "Comfortable fit for all-day wear" }), _jsx("li", { children: "Durable stitching and finish" })] })] })] })), product.specifications && Object.keys(product.specifications).length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Specifications" }), _jsx("dl", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-4", children: Object.entries(product.specifications).map(([key, value]) => (_jsxs("div", { className: "flex flex-col p-3 bg-gray-50 rounded-lg", children: [_jsx("dt", { className: "text-xs text-gray-500 font-medium uppercase tracking-wider mb-1", children: key }), _jsx("dd", { className: "text-sm font-bold text-gray-900", children: value })] }, key))) })] }))] })] }), _jsx("div", { className: "mt-20 pt-16 border-t border-gray-200", children: _jsxs("div", { className: "max-w-4xl", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 mb-10", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-2xl lg:text-3xl font-bold text-gray-900 mb-4", children: "Customer Reviews" }), reviewCount > 0 && averageRating > 0 && (_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StarRating, { rating: averageRating, size: "lg" }), _jsx("span", { className: "text-2xl font-bold text-gray-900", children: averageRating.toFixed(1) }), _jsx("span", { className: "text-lg text-gray-500", children: "out of 5" })] }), _jsx("span", { className: "text-gray-300", children: "|" }), _jsxs("span", { className: "text-lg text-gray-600", children: [reviewCount, " ", reviewCount === 1 ? 'review' : 'reviews'] })] }))] }), reviewCount > 0 && (_jsx(Button, { onClick: () => {
|
|
431
431
|
if (!isAuthenticated) {
|
|
@@ -400,7 +400,7 @@ export function ProductDetailPage({ storeConfig: initialConfig, productSlug }) {
|
|
|
400
400
|
};
|
|
401
401
|
return (_jsxs("div", { className: "min-h-screen bg-white", children: [_jsxs("div", { "data-content-ready": true, className: "container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-7xl", children: [_jsx("div", { className: "mb-6", children: _jsx(Breadcrumbs, { items: breadcrumbItems }) }), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-16 mb-20", children: [_jsxs("div", { className: "relative lg:sticky lg:top-24 self-start z-0", children: [_jsxs("div", { className: "relative aspect-square bg-gray-50 rounded-xl overflow-hidden mb-4 border border-gray-100 shadow-sm group", children: [_jsx(ImageWithFallback, { "data-product-image": true, src: displayImages[selectedImage] || displayImages[0] || productImages[0], alt: product.name, className: cn("w-full h-full object-cover transition-transform duration-300 group-hover:scale-105", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }), isOutOfStock && (_jsx(OutOfStockOverlay, { badgePosition: "center" }))] }), displayImages.length > 0 && (_jsxs("div", { className: "grid grid-cols-5 gap-2", children: [displayImages.map((image, index) => (_jsx("button", { onClick: () => setSelectedImage(Math.min(index, displayImages.length - 1)), className: `aspect-square rounded-lg overflow-hidden border-2 transition-all ${selectedImage === index
|
|
402
402
|
? 'border-gray-900 ring-2 ring-gray-900 ring-offset-2'
|
|
403
|
-
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: directCategory?.name || storeConfig.name }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children:
|
|
403
|
+
: 'border-gray-200 hover:border-gray-300'}`, children: _jsx(ImageWithFallback, { src: image, alt: `${product.name} view ${index + 1}`, className: cn("w-full h-full object-cover", isOutOfStock && "grayscale"), skeletonAspectRatio: "square" }) }, index))), hasMoreImages && (_jsxs("div", { className: "aspect-square rounded-lg border-2 border-gray-200 bg-gray-50 flex items-center justify-center text-xs text-gray-500 font-medium", children: ["+", productImages.length - 5, " more"] }))] }))] }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700 uppercase tracking-wide", children: directCategory?.name || storeConfig.name }), _jsx("button", { onClick: handleShare, className: "text-gray-400 hover:text-gray-900 transition-colors p-2 rounded-full hover:bg-gray-100", title: "Share this product", children: _jsx(Share2, { className: "h-5 w-5" }) })] }), _jsx("h1", { "data-product-name": true, className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3 leading-tight tracking-tight", children: product.name }), _jsxs("p", { className: "text-sm text-gray-500 mb-6 font-mono", children: ["SKU: ", displaySKU] }), _jsx("div", { className: "mb-4 flex items-center gap-2", children: !isOutOfStock ? (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800", children: [_jsx(CheckCircle, { className: "w-3 h-3 mr-1" }), "In Stock"] })) : (_jsxs("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800", children: [_jsx(Info, { className: "w-3 h-3 mr-1" }), "Out of Stock"] })) }), _jsxs("div", { className: "mb-8", children: [_jsxs("div", { className: "flex items-baseline gap-4", children: [_jsx("span", { "data-product-price": true, className: "text-4xl lg:text-5xl font-bold text-gray-900", children: formatCurrency(displayPrice, product.currency || 'USD') }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsx("span", { className: "text-2xl text-gray-500 line-through", children: formatCurrency(displayCompareAt, product.currency || 'USD') }))] }), displayCompareAt != null && displayCompareAt > displayPrice && (_jsxs("span", { className: "inline-block mt-2 bg-red-100 text-red-700 text-xs font-bold px-2 py-1 rounded", children: ["SAVE ", Math.round(((displayCompareAt - displayPrice) / displayCompareAt) * 100), "%"] }))] }), _jsx(PdpVariationSelectors, { optionGroups: optionGroups, selectedAttributes: selectedAttributes, setAttribute: setAttribute, isOptionAvailable: isOptionAvailable, getOptionImage: getOptionImage, storeSlug: storeConfig.slug, showSizeGuide: productDetailConfig?.showSizeGuide !== false, onAfterClearAttribute: () => setQuantity(1) }), _jsxs("div", { className: "flex flex-col gap-4 mb-8", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: "Quantity" }), _jsxs("div", { className: "flex items-center border border-gray-300 rounded-lg", children: [_jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-l-lg disabled:opacity-50", onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1, children: _jsx(Minus, { className: "h-4 w-4" }) }), _jsx("span", { className: "w-12 text-center font-semibold text-gray-900", children: quantity }), _jsx("button", { className: "p-3 text-gray-600 hover:bg-gray-100 rounded-r-lg", onClick: () => setQuantity(quantity + 1), children: _jsx(Plus, { className: "h-4 w-4" }) })] })] }), _jsxs("div", { className: "flex flex-row items-stretch gap-2 sm:gap-3 mt-2 w-full", children: [_jsx(Button, { "data-add-to-cart": true, variant: "outline", size: "lg", onClick: handleAddToCart, disabled: isCartLoading || isOutOfStock, className: "flex-1 min-w-0 bg-white border-2 border-gray-900 text-gray-900 hover:bg-gray-50 rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold [&_svg]:text-gray-900 shadow-sm transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : (_jsxs(_Fragment, { children: [_jsx(ShoppingCart, { className: "h-4 w-4 sm:h-5 sm:w-5 mr-1.5 sm:mr-2 shrink-0 text-gray-900" }), "Add to Cart"] })) }), _jsx(Button, { size: "lg", onClick: handleBuyNow, disabled: isOutOfStock || isBuyNowLoading || isCartLoading, className: "flex-1 min-w-0 bg-gray-900 hover:bg-gray-800 text-white rounded-full h-12 sm:h-14 px-3 sm:px-6 text-sm sm:text-base font-bold shadow-lg hover:shadow-xl transition-all disabled:opacity-50 disabled:cursor-not-allowed", children: isBuyNowLoading || isCartLoading ? (_jsxs(_Fragment, { children: [_jsx(ButtonLoader, { className: "mr-1.5 sm:mr-2" }), "Adding..."] })) : ('Buy Now') }), storeConfig.features.wishlist && (_jsx(Button, { variant: "outline", size: "lg", onClick: handleWishlistClick, disabled: isWishlistLoading || !product, className: cn("h-12 w-12 sm:h-14 sm:w-14 shrink-0 rounded-full border-2 transition-all disabled:opacity-50 disabled:cursor-not-allowed", product && isInWishlist(product.id)
|
|
404
404
|
? "border-red-500 bg-red-50 text-red-500 hover:bg-red-100"
|
|
405
405
|
: "border-gray-200 hover:border-gray-300 hover:bg-gray-50"), children: isWishlistLoading ? (_jsx(ButtonLoader, { className: "h-5 w-5" })) : (_jsx(Heart, { className: cn("h-5 w-5", product && isInWishlist(product.id) && "fill-current") })) }))] })] }), _jsx(ProductDeliveryInfoSection, { storeConfig: storeConfig, currency: storeConfig.settings?.currency || 'USD', productCurrency: product.currency, productPrice: displayPrice, quantity: quantity, shippingAddress: shippingAddress, updateShippingAddress: (patch) => setShippingAddress((prev) => ({ ...prev, ...patch })), shippingMethods: shippingMethods, isCalculatingShipping: isCalculatingShipping, shippingError: shippingError, freeShippingEligible: freeShippingEligible, freeShippingThreshold: freeShippingThreshold, onToast: addToast }), product.description && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-3", children: "Description" }), _jsxs("div", { className: "prose prose-sm max-w-none text-gray-600 leading-relaxed", children: [_jsx(SafeRichHtml, { value: product.description, fallbackPlain: "", as: "div" }), _jsxs("ul", { className: "list-disc pl-5 space-y-1 mt-2", children: [_jsx("li", { children: "Premium quality material" }), _jsx("li", { children: "Comfortable fit for all-day wear" }), _jsx("li", { children: "Durable stitching and finish" })] })] })] })), product.specifications && Object.keys(product.specifications).length > 0 && (_jsxs("div", { className: "mb-8", children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Specifications" }), _jsx("dl", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-4", children: Object.entries(product.specifications).map(([key, value]) => (_jsxs("div", { className: "flex flex-col p-3 bg-gray-50 rounded-lg", children: [_jsx("dt", { className: "text-xs text-gray-500 font-medium uppercase tracking-wider mb-1", children: key }), _jsx("dd", { className: "text-sm font-bold text-gray-900", children: value })] }, key))) })] }))] })] }), _jsx("div", { className: "mt-20 pt-16 border-t border-gray-200", children: _jsxs("div", { className: "max-w-4xl", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 mb-10", children: [_jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-2xl lg:text-3xl font-bold text-gray-900 mb-4", children: "Customer Reviews" }), reviewCount > 0 && averageRating > 0 && (_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StarRating, { rating: averageRating, size: "lg" }), _jsx("span", { className: "text-2xl font-bold text-gray-900", children: averageRating.toFixed(1) }), _jsx("span", { className: "text-lg text-gray-500", children: "out of 5" })] }), _jsx("span", { className: "text-gray-300", children: "|" }), _jsxs("span", { className: "text-lg text-gray-600", children: [reviewCount, " ", reviewCount === 1 ? 'review' : 'reviews'] })] }))] }), reviewCount > 0 && (_jsx(Button, { onClick: () => {
|
|
406
406
|
if (!isAuthenticated) {
|
|
@@ -6,15 +6,6 @@ export declare function canonicalVariationOptionGroupKey(rawKey: string): string
|
|
|
6
6
|
export declare const VARIATION_ATTRIBUTE_LABELS: Record<string, string>;
|
|
7
7
|
export declare function getVariationAttributeLabel(attributeKey: string): string;
|
|
8
8
|
export declare function getSortedVariationOptionKeys(optionGroups: Record<string, string[]>): string[];
|
|
9
|
-
/** Label for the base / original product option in variation pickers. */
|
|
10
|
-
export declare const BASE_PRODUCT_OPTION_VALUE = "Original";
|
|
11
|
-
export declare function isBaseProductOptionValue(value: string | undefined | null): boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Prepend the base product as the first option in the primary attribute group
|
|
14
|
-
* (prefer Name/Color) so shoppers can pick the original listing alongside variants.
|
|
15
|
-
* Skips when a variation already uses the product’s primary image.
|
|
16
|
-
*/
|
|
17
|
-
export declare function withBaseProductOption(optionGroups: Record<string, string[]>, product?: Pick<StoreProduct, 'images' | 'variants'> | null): Record<string, string[]>;
|
|
18
9
|
export declare function getVariationOptionGroups(variants: StoreProductVariant[] | undefined): Record<string, string[]>;
|
|
19
10
|
export declare function getDefaultSelectedAttributes(optionGroups: Record<string, string[]>): Record<string, string>;
|
|
20
11
|
export declare function findMatchingVariation(variants: StoreProductVariant[] | undefined, selectedAttributes: Record<string, string>): StoreProductVariant | undefined;
|
|
@@ -32,7 +23,7 @@ export declare function resolveVariantSKU(product: Pick<StoreProduct, 'sku' | 's
|
|
|
32
23
|
export declare function resolveProductGalleryImageUrls(product: Pick<StoreProduct, 'images'>, variant?: StoreProductVariant | null): string[];
|
|
33
24
|
export declare function formatVariationLabel(variant?: StoreProductVariant | null): string | undefined;
|
|
34
25
|
export declare function getVariationOptionImage(variants: StoreProductVariant[] | undefined, attributeKey: string, value: string, product?: Pick<StoreProduct, 'images'> | null): string | undefined;
|
|
35
|
-
export declare function assertVariationSelected(product: StoreProduct, variant?: StoreProductVariant | null,
|
|
26
|
+
export declare function assertVariationSelected(product: StoreProduct, variant?: StoreProductVariant | null, _selectedAttributes?: Record<string, string>): void;
|
|
36
27
|
export declare function resolveVariantImageUrls(variant?: StoreProductVariant | null): string[];
|
|
37
28
|
export declare function buildCartLineProduct(product: StoreProduct, variant?: StoreProductVariant | null): StoreProduct;
|
|
38
29
|
export declare function getCartLineImage(item: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-variation-utils.d.ts","sourceRoot":"","sources":["../../src/lib/product-variation-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,MAAM,MAAM,mBAAmB,GAAG,WAAW,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAIhF,4FAA4F;AAC5F,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED,4GAA4G;AAC5G,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAM7D,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GACrC,MAAM,EAAE,CAWV;AAED,
|
|
1
|
+
{"version":3,"file":"product-variation-utils.d.ts","sourceRoot":"","sources":["../../src/lib/product-variation-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,MAAM,MAAM,mBAAmB,GAAG,WAAW,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAIhF,4FAA4F;AAC5F,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED,4GAA4G;AAC5G,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAM7D,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GACrC,MAAM,EAAE,CAWV;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,mBAAmB,EAAE,GAAG,SAAS,GAC1C,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CA4C1B;AAED,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GACrC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAaxB;AA8DD,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,mBAAmB,EAAE,GAAG,SAAS,EAC3C,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,mBAAmB,GAAG,SAAS,CAiBjC;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,mBAAmB,EAAE,GAAG,SAAS,EAC3C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA0CxB;AAED,6FAA6F;AAC7F,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,mBAAmB,EAAE,GAAG,SAAS,EAC3C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,OAAO,CAiBT;AAED,KAAK,kBAAkB,GAAG,IAAI,CAC5B,YAAY,EACZ,gBAAgB,GAAG,gBAAgB,GAAG,SAAS,GAAG,mBAAmB,GAAG,MAAM,CAC/E,CAAC;AAEF,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,kBAAkB,CAapB;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,EACpC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAER;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,KAAK,GAAG,MAAM,CAAC,EAC3C,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAOR;AAED,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,EACrC,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,GACnC,MAAM,EAAE,CAWV;AAED,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAS7F;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,mBAAmB,EAAE,GAAG,SAAS,EAC3C,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,GAAG,IAAI,GAC5C,MAAM,GAAG,SAAS,CAcpB;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,YAAY,EACrB,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,EACpC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3C,IAAI,CAMN;AAED,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,GAAG,MAAM,EAAE,CAyBtF;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,YAAY,EACrB,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,GACnC,YAAY,CAkBd;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,GAAG,SAAS,CAerB;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAYzD,CAAC"}
|
|
@@ -36,40 +36,6 @@ export function getSortedVariationOptionKeys(optionGroups) {
|
|
|
36
36
|
return indexA - indexB;
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
|
-
/** Label for the base / original product option in variation pickers. */
|
|
40
|
-
export const BASE_PRODUCT_OPTION_VALUE = 'Original';
|
|
41
|
-
export function isBaseProductOptionValue(value) {
|
|
42
|
-
return typeof value === 'string' && value.trim() === BASE_PRODUCT_OPTION_VALUE;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Prepend the base product as the first option in the primary attribute group
|
|
46
|
-
* (prefer Name/Color) so shoppers can pick the original listing alongside variants.
|
|
47
|
-
* Skips when a variation already uses the product’s primary image.
|
|
48
|
-
*/
|
|
49
|
-
export function withBaseProductOption(optionGroups, product) {
|
|
50
|
-
const variants = product?.variants;
|
|
51
|
-
if (!variants?.length)
|
|
52
|
-
return optionGroups;
|
|
53
|
-
const keys = getSortedVariationOptionKeys(optionGroups);
|
|
54
|
-
if (keys.length === 0)
|
|
55
|
-
return optionGroups;
|
|
56
|
-
const targetKey = keys.includes('color') ? 'color' : keys[0];
|
|
57
|
-
const values = optionGroups[targetKey] ?? [];
|
|
58
|
-
if (values.includes(BASE_PRODUCT_OPTION_VALUE)) {
|
|
59
|
-
return optionGroups;
|
|
60
|
-
}
|
|
61
|
-
const productImage = extractImageUrls(product?.images).find((url) => url.trim().length > 0);
|
|
62
|
-
if (productImage) {
|
|
63
|
-
const variantUsesProductImage = variants.some((variant) => resolveVariantImageUrls(variant).includes(productImage));
|
|
64
|
-
if (variantUsesProductImage) {
|
|
65
|
-
return optionGroups;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return {
|
|
69
|
-
...optionGroups,
|
|
70
|
-
[targetKey]: [BASE_PRODUCT_OPTION_VALUE, ...values],
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
39
|
export function getVariationOptionGroups(variants) {
|
|
74
40
|
if (!variants?.length)
|
|
75
41
|
return {};
|
|
@@ -181,10 +147,6 @@ export function findMatchingVariation(variants, selectedAttributes) {
|
|
|
181
147
|
if (selectedEntries.length === 0) {
|
|
182
148
|
return undefined;
|
|
183
149
|
}
|
|
184
|
-
// "Original" is the base product, not a merchant variation row.
|
|
185
|
-
if (selectedEntries.some(([, value]) => isBaseProductOptionValue(value))) {
|
|
186
|
-
return undefined;
|
|
187
|
-
}
|
|
188
150
|
return activeVariants.find((variant) => variantMatchesSelected(variant, selectedEntries));
|
|
189
151
|
}
|
|
190
152
|
/**
|
|
@@ -196,20 +158,7 @@ export function reconcileSelectedAttributes(variants, current, key, value) {
|
|
|
196
158
|
if (!value) {
|
|
197
159
|
return {};
|
|
198
160
|
}
|
|
199
|
-
// Selecting the original listing clears other attributes and keeps base product.
|
|
200
|
-
if (isBaseProductOptionValue(value)) {
|
|
201
|
-
return { [canonicalKey]: BASE_PRODUCT_OPTION_VALUE };
|
|
202
|
-
}
|
|
203
161
|
const next = { ...current, [canonicalKey]: value };
|
|
204
|
-
// Drop base marker when picking a real variation option
|
|
205
|
-
if (isBaseProductOptionValue(next[canonicalKey])) {
|
|
206
|
-
next[canonicalKey] = value;
|
|
207
|
-
}
|
|
208
|
-
for (const [selectedKey, selectedValue] of Object.entries(next)) {
|
|
209
|
-
if (isBaseProductOptionValue(selectedValue) && selectedKey !== canonicalKey) {
|
|
210
|
-
delete next[selectedKey];
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
162
|
const exact = findMatchingVariation(variants, next);
|
|
214
163
|
if (exact) {
|
|
215
164
|
return attributesFromVariant(exact);
|
|
@@ -226,8 +175,6 @@ export function reconcileSelectedAttributes(variants, current, key, value) {
|
|
|
226
175
|
for (const [selectedKey, selectedValue] of Object.entries(current)) {
|
|
227
176
|
if (selectedKey === canonicalKey)
|
|
228
177
|
continue;
|
|
229
|
-
if (isBaseProductOptionValue(selectedValue))
|
|
230
|
-
continue;
|
|
231
178
|
if (getVariantAttributeValue(candidate, selectedKey) === selectedValue) {
|
|
232
179
|
score += 1;
|
|
233
180
|
}
|
|
@@ -245,8 +192,6 @@ export function isVariationOptionAvailable(variants, selected, key, value) {
|
|
|
245
192
|
return true;
|
|
246
193
|
if (!value)
|
|
247
194
|
return true;
|
|
248
|
-
if (isBaseProductOptionValue(value))
|
|
249
|
-
return true;
|
|
250
195
|
const canonicalKey = canonicalVariationOptionGroupKey(key);
|
|
251
196
|
const activeVariants = variants.filter((variant) => variant.isActive !== false);
|
|
252
197
|
return activeVariants.some((variant) => {
|
|
@@ -255,8 +200,6 @@ export function isVariationOptionAvailable(variants, selected, key, value) {
|
|
|
255
200
|
return Object.entries(selected).every(([selectedKey, selectedValue]) => {
|
|
256
201
|
if (!selectedValue)
|
|
257
202
|
return true;
|
|
258
|
-
if (isBaseProductOptionValue(selectedValue))
|
|
259
|
-
return true;
|
|
260
203
|
if (canonicalVariationOptionGroupKey(selectedKey) === canonicalKey) {
|
|
261
204
|
return true;
|
|
262
205
|
}
|
|
@@ -316,9 +259,6 @@ export function getVariationOptionImage(variants, attributeKey, value, product)
|
|
|
316
259
|
const productImage = product
|
|
317
260
|
? extractImageUrls(product.images).find((url) => url.trim().length > 0)
|
|
318
261
|
: undefined;
|
|
319
|
-
if (isBaseProductOptionValue(value)) {
|
|
320
|
-
return productImage;
|
|
321
|
-
}
|
|
322
262
|
if (!variants?.length)
|
|
323
263
|
return productImage;
|
|
324
264
|
const match = variants.find((variant) => {
|
|
@@ -332,20 +272,14 @@ export function getVariationOptionImage(variants, attributeKey, value, product)
|
|
|
332
272
|
});
|
|
333
273
|
return resolveVariantImageUrls(match)[0] || productImage;
|
|
334
274
|
}
|
|
335
|
-
export function assertVariationSelected(product, variant,
|
|
275
|
+
export function assertVariationSelected(product, variant, _selectedAttributes) {
|
|
336
276
|
const groups = getVariationOptionGroups(product.variants);
|
|
337
277
|
const hasOptions = Object.values(groups).some((values) => values.length > 0);
|
|
338
278
|
if (!hasOptions)
|
|
339
279
|
return;
|
|
340
280
|
if (variant?.id)
|
|
341
281
|
return;
|
|
342
|
-
|
|
343
|
-
// Original / empty selection = base product is a valid purchase.
|
|
344
|
-
if (entries.length === 0 ||
|
|
345
|
-
entries.every(([, value]) => isBaseProductOptionValue(value))) {
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
throw new Error('Please select all product options before continuing');
|
|
282
|
+
throw new Error('Please select a variation');
|
|
349
283
|
}
|
|
350
284
|
export function resolveVariantImageUrls(variant) {
|
|
351
285
|
if (!variant?.images)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-context.d.ts","sourceRoot":"","sources":["../../src/lib/store-context.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAmB/D,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,gBAAgB;IACxB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAGrB,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,SAAS,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3F,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,wBAAwB,CAAC,EAAE,CAAC,UAAU,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxH,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,aAAa,EAAE,OAAO,CAAC;IAGvB,UAAU,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/C,eAAe,EAAE,MAAM,IAAI,CAAC;IAG5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,eAAO,MAAM,YAAY,2CAsBvB,CAAC;AAEH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,SAAS,EACT,aAAa,EACd,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CACpC,+
|
|
1
|
+
{"version":3,"file":"store-context.d.ts","sourceRoot":"","sources":["../../src/lib/store-context.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAmB/D,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,gBAAgB;IACxB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAGrB,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,SAAS,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3F,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,wBAAwB,CAAC,EAAE,CAAC,UAAU,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxH,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,aAAa,EAAE,OAAO,CAAC;IAGvB,UAAU,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/C,eAAe,EAAE,MAAM,IAAI,CAAC;IAG5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,eAAO,MAAM,YAAY,2CAsBvB,CAAC;AAEH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,SAAS,EACT,aAAa,EACd,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CACpC,+BAgdA;AAED,eAAO,MAAM,QAAQ,wBAAiC,CAAC"}
|
|
@@ -297,13 +297,10 @@ export function StoreProvider({ children, storeSlug, initialConfig }) {
|
|
|
297
297
|
const variant = variantId
|
|
298
298
|
? product.variants?.find((entry) => entry.id === variantId)
|
|
299
299
|
: undefined;
|
|
300
|
-
// Allow base product (no variantId) even when the listing has variations.
|
|
301
300
|
if (variantId && !variant) {
|
|
302
|
-
throw new Error('Please select
|
|
303
|
-
}
|
|
304
|
-
if (variantId) {
|
|
305
|
-
assertVariationSelected(product, variant);
|
|
301
|
+
throw new Error('Please select a variation');
|
|
306
302
|
}
|
|
303
|
+
assertVariationSelected(product, variant);
|
|
307
304
|
const lineProduct = buildCartLineProduct(product, variant);
|
|
308
305
|
if (!lineProduct.inStock) {
|
|
309
306
|
console.warn('[StoreContext] Attempted to add out-of-stock product to cart:', product.id);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "storefront-layouts",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"lts": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Shared layout components for Storefront applications",
|
|
@@ -85,7 +85,13 @@
|
|
|
85
85
|
"prepublishOnly": "npm run build",
|
|
86
86
|
"prepack": "npm run build",
|
|
87
87
|
"clean": "rm -rf dist",
|
|
88
|
-
"test": "echo \"No tests specified\" && exit 0"
|
|
88
|
+
"test": "echo \"No tests specified\" && exit 0",
|
|
89
|
+
"prepare": "git config core.hooksPath .githooks 2>/dev/null || true",
|
|
90
|
+
"version:staging": "npm version prerelease --preid=staging",
|
|
91
|
+
"release:staging": "node scripts/release-guard.mjs staging",
|
|
92
|
+
"publish:staging": "npm run release:staging && npm run build && npm publish --tag latest --access public --ignore-scripts",
|
|
93
|
+
"release:prod": "node scripts/release-guard.mjs prod",
|
|
94
|
+
"publish:prod": "npm run release:prod && npm run build && npm publish --tag latest --ignore-scripts"
|
|
89
95
|
},
|
|
90
96
|
"peerDependencies": {
|
|
91
97
|
"@rjsf/core": "^6.1.2",
|