pb-sxp-ui 1.20.26 → 1.20.27
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/index.cjs +292 -395
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +355 -291
- package/dist/index.js +292 -395
- package/dist/index.js.map +1 -1
- package/dist/index.min.cjs +6 -6
- package/dist/index.min.cjs.map +1 -1
- package/dist/index.min.js +6 -6
- package/dist/index.min.js.map +1 -1
- package/dist/pb-ui.js +292 -395
- package/dist/pb-ui.js.map +1 -1
- package/dist/pb-ui.min.js +6 -6
- package/dist/pb-ui.min.js.map +1 -1
- package/es/core/components/StructurePage/index.d.ts +4 -0
- package/es/core/components/StructurePage/index.js +8 -1
- package/es/core/components/SxpPageRender/Modal/index.d.ts +1 -0
- package/es/core/components/SxpPageRender/Modal/index.js +3 -3
- package/es/core/components/SxpPageRender/index.d.ts +1 -0
- package/es/core/components/SxpPageRender/typing.d.ts +1 -0
- package/es/materials/sxp/popup/AddToCart/index.d.ts +1 -27
- package/es/materials/sxp/popup/AddToCart/index.js +117 -173
- package/es/materials/sxp/popup/AddToCart/index.new.d.ts +8 -0
- package/es/materials/sxp/popup/AddToCart/index.new.js +174 -0
- package/es/materials/sxp/popup/AddToCart/index.old.d.ts +33 -0
- package/es/materials/sxp/popup/AddToCart/index.old.js +299 -0
- package/es/materials/sxp/popup/AddToCart/material.js +1 -54
- package/es/materials/sxp/popup/CommodityDetailDiroNew/index.js +48 -53
- package/lib/core/components/StructurePage/index.d.ts +4 -0
- package/lib/core/components/StructurePage/index.js +8 -1
- package/lib/core/components/SxpPageRender/Modal/index.d.ts +1 -0
- package/lib/core/components/SxpPageRender/Modal/index.js +3 -3
- package/lib/core/components/SxpPageRender/index.d.ts +1 -0
- package/lib/core/components/SxpPageRender/typing.d.ts +1 -0
- package/lib/materials/sxp/popup/AddToCart/index.d.ts +1 -27
- package/lib/materials/sxp/popup/AddToCart/index.js +115 -171
- package/lib/materials/sxp/popup/AddToCart/index.new.d.ts +8 -0
- package/lib/materials/sxp/popup/AddToCart/index.new.js +176 -0
- package/lib/materials/sxp/popup/AddToCart/index.old.d.ts +33 -0
- package/lib/materials/sxp/popup/AddToCart/index.old.js +301 -0
- package/lib/materials/sxp/popup/AddToCart/material.js +1 -54
- package/lib/materials/sxp/popup/CommodityDetailDiroNew/index.js +48 -53
- package/package.json +1 -1
package/dist/pb-ui.js
CHANGED
|
@@ -10538,7 +10538,7 @@
|
|
|
10538
10538
|
*
|
|
10539
10539
|
*/
|
|
10540
10540
|
const closeIcon$1 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAjhJREFUWEfFlztOw0AQhmeWiJ4CCmpQ5DiRQsIJyAWg5A0lR0AIChDiCJS8ER0cADgBeRSxt4CCDgkaKiq8i+zYeWx2413HEWmiJJv9v535Z2aN8M8vFPT9z3zETD0aAUChUJjwvPFHAJhBhB3Hqd6OAsK2yyucwykAvP38eJX398Z3AJDLlVYR8ToU9Rhj25TWr9KEsKy5dULIGQCMtfZly45TvwsAstm56UwG6wA4FUFwzrdctxZBDcWSy5XWEPG8I84/GcMipdWPtgcsaz5PCHtKG0IuTiqUvjT9U/WYMG2IOPE+AP+LtCB0xKUAAyA2Xbd2o2OG0NQXvTnvhL17D7EPtH9TRCIWwkRcGYGIQgYBABuqPuHXOQBc6pw80lBGwBQiiXhsBHQhkoprA6iM6acjhDQKu5YJZW6XeOI3XJdpvfsdTu52VfXEekD8owQiXGIubpSCbhDbLu8DwKEAd+A41SOdPpE4BS0viFOtvV2iKWqUgn5x/tmS70xR01GuDSCKc86/OCcLgTyyZ0ScDGNhFAktAJV4NFJ9YyaFiAWIE+9uVkkgBgLoig8DMWAa9ro9ynkUdlW5maZDCmB6clmz0k1HH4Cs1Ezbq2p2yEpUuBOKTSZZex00RUWIrltxuuK6EOGDSbGIOPZicpMx6fny650377qNRgBgWeVFQuA+6UjVgREhGIMlSqsPUQqIbZdOOIdZQmCv2axRnU1N1+TzJYsxOEaEV8ep7frPZ7Gd0FTEdP0ft0/kMNdg0eoAAAAASUVORK5CYII=';
|
|
10541
|
-
const Modal = ({ visible, onClose, children, modalStyle, padding, popup, schema, fullHeight, isFullScreen = false, openState }) => {
|
|
10541
|
+
const Modal = ({ visible, onClose, children, modalStyle, padding, popup, schema, fullHeight, isFullScreen = false, openState, showCloseButton = true }) => {
|
|
10542
10542
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
|
|
10543
10543
|
const { visibleHeight, bottomHeight } = useVisibleHeight();
|
|
10544
10544
|
const touchRef = React.useRef(null);
|
|
@@ -10718,8 +10718,8 @@
|
|
|
10718
10718
|
setScrollTop(15 - ((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.scrollTop));
|
|
10719
10719
|
}
|
|
10720
10720
|
})), child()),
|
|
10721
|
-
React.createElement("button", { className: 'modal-icon-wrapper', role: 'button', "aria-label": 'close button', onClick: onClose, style: { top: scrollTop } },
|
|
10722
|
-
React.createElement("img", { src: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.popupCloseIcon) || closeIcon$1, alt: 'close button', className: 'modal-icon' }))))))), modalEleRef.current);
|
|
10721
|
+
showCloseButton && (React.createElement("button", { className: 'modal-icon-wrapper', role: 'button', "aria-label": 'close button', onClick: onClose, style: { top: scrollTop } },
|
|
10722
|
+
React.createElement("img", { src: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.popupCloseIcon) || closeIcon$1, alt: 'close button', className: 'modal-icon' })))))))), modalEleRef.current);
|
|
10723
10723
|
};
|
|
10724
10724
|
var Modal$1 = React.memo(Modal);
|
|
10725
10725
|
|
|
@@ -11907,18 +11907,248 @@
|
|
|
11907
11907
|
}
|
|
11908
11908
|
];
|
|
11909
11909
|
|
|
11910
|
+
const AddToCartPopup$1 = ({ isActive = true }) => {
|
|
11911
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
11912
|
+
const { popupDetailData, globalConfig } = useSxpDataSource();
|
|
11913
|
+
const [productData, setProductData] = React.useState(null);
|
|
11914
|
+
const [selectedOptions, setSelectedOptions] = React.useState({});
|
|
11915
|
+
const [selectedVariant, setSelectedVariant] = React.useState(null);
|
|
11916
|
+
const [quantity, setQuantity] = React.useState(1);
|
|
11917
|
+
const [loading, setLoading] = React.useState(true);
|
|
11918
|
+
const [error, setError] = React.useState(null);
|
|
11919
|
+
const [showImagePreview, setShowImagePreview] = React.useState(false);
|
|
11920
|
+
const [previewImageUrl, setPreviewImageUrl] = React.useState('');
|
|
11921
|
+
// 获取商品数据
|
|
11922
|
+
const data = popupDetailData;
|
|
11923
|
+
const product = (_e = (_b = (_a = data === null || data === void 0 ? void 0 : data.video) === null || _a === void 0 ? void 0 : _a.bindProduct) !== null && _b !== void 0 ? _b : (_d = (_c = data === null || data === void 0 ? void 0 : data.video) === null || _c === void 0 ? void 0 : _c.bindProducts) === null || _d === void 0 ? void 0 : _d[0]) !== null && _e !== void 0 ? _e : data === null || data === void 0 ? void 0 : data.product;
|
|
11924
|
+
// Shopify 配置
|
|
11925
|
+
const shopifyConfig = window.__SHOPIFY_CONFIG__;
|
|
11926
|
+
const shopifyDomain = ((_f = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.shopify) === null || _f === void 0 ? void 0 : _f.domain) || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.shopifyDomain) || (shopifyConfig === null || shopifyConfig === void 0 ? void 0 : shopifyConfig.domain) || 'dev-store-749237498237498636.myshopify.com';
|
|
11927
|
+
const storefrontToken = ((_g = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.shopify) === null || _g === void 0 ? void 0 : _g.storefrontAccessToken) || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.storefrontAccessToken) || (shopifyConfig === null || shopifyConfig === void 0 ? void 0 : shopifyConfig.storefrontAccessToken) || '77d894c490f79430ce7bd0a7efdff6b7';
|
|
11928
|
+
const productId = (product === null || product === void 0 ? void 0 : product.shopifyId) || (product === null || product === void 0 ? void 0 : product.itemId) || '';
|
|
11929
|
+
// 查询 Shopify 商品数据
|
|
11930
|
+
const fetchProductData = React.useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
11931
|
+
var _k;
|
|
11932
|
+
if (!productId || !shopifyDomain || !storefrontToken) {
|
|
11933
|
+
setLoading(false);
|
|
11934
|
+
return;
|
|
11935
|
+
}
|
|
11936
|
+
setLoading(true);
|
|
11937
|
+
setError(null);
|
|
11938
|
+
try {
|
|
11939
|
+
const query = `
|
|
11940
|
+
query getProduct($id: ID!) {
|
|
11941
|
+
product(id: $id) {
|
|
11942
|
+
id
|
|
11943
|
+
title
|
|
11944
|
+
images(first: 10) {
|
|
11945
|
+
edges {
|
|
11946
|
+
node {
|
|
11947
|
+
url
|
|
11948
|
+
}
|
|
11949
|
+
}
|
|
11950
|
+
}
|
|
11951
|
+
options {
|
|
11952
|
+
name
|
|
11953
|
+
values
|
|
11954
|
+
}
|
|
11955
|
+
variants(first: 100) {
|
|
11956
|
+
edges {
|
|
11957
|
+
node {
|
|
11958
|
+
id
|
|
11959
|
+
title
|
|
11960
|
+
availableForSale
|
|
11961
|
+
quantityAvailable
|
|
11962
|
+
price {
|
|
11963
|
+
amount
|
|
11964
|
+
currencyCode
|
|
11965
|
+
}
|
|
11966
|
+
image {
|
|
11967
|
+
url
|
|
11968
|
+
}
|
|
11969
|
+
selectedOptions {
|
|
11970
|
+
name
|
|
11971
|
+
value
|
|
11972
|
+
}
|
|
11973
|
+
}
|
|
11974
|
+
}
|
|
11975
|
+
}
|
|
11976
|
+
}
|
|
11977
|
+
}
|
|
11978
|
+
`;
|
|
11979
|
+
const fullProductId = productId.startsWith('gid://') ? productId : `gid://shopify/Product/${productId}`;
|
|
11980
|
+
const response = yield fetch(`https://${shopifyDomain}/api/2024-01/graphql.json`, {
|
|
11981
|
+
method: 'POST',
|
|
11982
|
+
headers: {
|
|
11983
|
+
'Content-Type': 'application/json',
|
|
11984
|
+
'X-Shopify-Storefront-Access-Token': storefrontToken
|
|
11985
|
+
},
|
|
11986
|
+
body: JSON.stringify({
|
|
11987
|
+
query,
|
|
11988
|
+
variables: { id: fullProductId }
|
|
11989
|
+
})
|
|
11990
|
+
});
|
|
11991
|
+
const result = yield response.json();
|
|
11992
|
+
if (result.errors) {
|
|
11993
|
+
throw new Error(result.errors[0].message);
|
|
11994
|
+
}
|
|
11995
|
+
console.log('[AddToCart] Shopify Product Data:', result.data.product);
|
|
11996
|
+
console.log('[AddToCart] Options:', (_k = result.data.product) === null || _k === void 0 ? void 0 : _k.options);
|
|
11997
|
+
setProductData(result.data.product);
|
|
11998
|
+
}
|
|
11999
|
+
catch (err) {
|
|
12000
|
+
setError(err instanceof Error ? err.message : 'Failed to load product');
|
|
12001
|
+
console.error('[AddToCartPopup] 加载失败:', err);
|
|
12002
|
+
}
|
|
12003
|
+
finally {
|
|
12004
|
+
setLoading(false);
|
|
12005
|
+
}
|
|
12006
|
+
}), [productId, shopifyDomain, storefrontToken]);
|
|
12007
|
+
React.useEffect(() => {
|
|
12008
|
+
if (isActive) {
|
|
12009
|
+
fetchProductData();
|
|
12010
|
+
}
|
|
12011
|
+
}, [isActive, fetchProductData]);
|
|
12012
|
+
// 根据选中的规格匹配 variant
|
|
12013
|
+
React.useEffect(() => {
|
|
12014
|
+
if (!productData)
|
|
12015
|
+
return;
|
|
12016
|
+
const variants = productData.variants.edges.map(edge => edge.node);
|
|
12017
|
+
const optionsCount = productData.options.length;
|
|
12018
|
+
const selectedCount = Object.keys(selectedOptions).length;
|
|
12019
|
+
if (selectedCount === 0 || selectedCount < optionsCount) {
|
|
12020
|
+
setSelectedVariant(null);
|
|
12021
|
+
return;
|
|
12022
|
+
}
|
|
12023
|
+
const matchedVariant = variants.find(variant => {
|
|
12024
|
+
return variant.selectedOptions.every(option => {
|
|
12025
|
+
return selectedOptions[option.name] === option.value;
|
|
12026
|
+
});
|
|
12027
|
+
});
|
|
12028
|
+
setSelectedVariant(matchedVariant || null);
|
|
12029
|
+
// 当 variant 改变时,如果有库存数量限制,确保数量不超过库存
|
|
12030
|
+
if ((matchedVariant === null || matchedVariant === void 0 ? void 0 : matchedVariant.quantityAvailable) !== undefined && matchedVariant.quantityAvailable > 0) {
|
|
12031
|
+
setQuantity(prev => Math.min(prev, matchedVariant.quantityAvailable));
|
|
12032
|
+
}
|
|
12033
|
+
}, [selectedOptions, productData]);
|
|
12034
|
+
// 处理规格选择
|
|
12035
|
+
const handleOptionSelect = (optionName, value) => {
|
|
12036
|
+
setSelectedOptions(prev => (Object.assign(Object.assign({}, prev), { [optionName]: value })));
|
|
12037
|
+
};
|
|
12038
|
+
// 处理加购
|
|
12039
|
+
const handleAddToCart = () => {
|
|
12040
|
+
if (!selectedVariant) {
|
|
12041
|
+
alert('Please select all options');
|
|
12042
|
+
return;
|
|
12043
|
+
}
|
|
12044
|
+
// 提取 variant ID(去掉 gid://shopify/ProductVariant/ 前缀)
|
|
12045
|
+
const variantId = selectedVariant.id.replace('gid://shopify/ProductVariant/', '');
|
|
12046
|
+
console.log('[AddToCart] 添加到购物车:', {
|
|
12047
|
+
variantId,
|
|
12048
|
+
quantity,
|
|
12049
|
+
shopifyDomain,
|
|
12050
|
+
selectedVariant
|
|
12051
|
+
});
|
|
12052
|
+
// 使用 Shopify 的 /cart/add 接口,通过查询参数添加商品
|
|
12053
|
+
// 这种方式会跳转到购物车页面而不是结算页面
|
|
12054
|
+
const params = new URLSearchParams({
|
|
12055
|
+
id: variantId,
|
|
12056
|
+
quantity: quantity.toString()
|
|
12057
|
+
});
|
|
12058
|
+
const cartUrl = `https://${shopifyDomain}/cart/add?${params.toString()}`;
|
|
12059
|
+
console.log('[AddToCart] 跳转到购物车 URL:', cartUrl);
|
|
12060
|
+
window.location.href = cartUrl;
|
|
12061
|
+
};
|
|
12062
|
+
// 计算总价
|
|
12063
|
+
const totalPrice = selectedVariant
|
|
12064
|
+
? (parseFloat(selectedVariant.price.amount) * quantity).toFixed(2)
|
|
12065
|
+
: '0.00';
|
|
12066
|
+
if (loading) {
|
|
12067
|
+
return (React.createElement("div", { className: 'add-to-cart-popup' },
|
|
12068
|
+
React.createElement("div", { className: 'loading' }, "Loading...")));
|
|
12069
|
+
}
|
|
12070
|
+
if (error) {
|
|
12071
|
+
return (React.createElement("div", { className: 'add-to-cart-popup' },
|
|
12072
|
+
React.createElement("div", { className: 'error' }, error)));
|
|
12073
|
+
}
|
|
12074
|
+
if (!productData) {
|
|
12075
|
+
return null;
|
|
12076
|
+
}
|
|
12077
|
+
const mainImage = ((_h = productData.images.edges[0]) === null || _h === void 0 ? void 0 : _h.node.url) || '';
|
|
12078
|
+
const variantImage = ((_j = selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.image) === null || _j === void 0 ? void 0 : _j.url) || mainImage;
|
|
12079
|
+
const maxQuantity = (selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.quantityAvailable) || 999; // 如果没有库存数据,默认允许最多 999
|
|
12080
|
+
return (React.createElement("div", { className: 'add-to-cart-popup' },
|
|
12081
|
+
React.createElement("div", { className: 'popup-content' },
|
|
12082
|
+
React.createElement("div", { className: 'product-header' },
|
|
12083
|
+
React.createElement("div", { className: 'product-title' }, productData.title)),
|
|
12084
|
+
React.createElement("div", { className: 'variant-detail' },
|
|
12085
|
+
React.createElement("div", { className: 'variant-image-container', onClick: () => {
|
|
12086
|
+
if (variantImage) {
|
|
12087
|
+
setPreviewImageUrl(variantImage);
|
|
12088
|
+
setShowImagePreview(true);
|
|
12089
|
+
}
|
|
12090
|
+
}, style: { cursor: 'pointer' } },
|
|
12091
|
+
React.createElement("img", { src: variantImage, alt: 'Selected variant', className: 'variant-image' })),
|
|
12092
|
+
React.createElement("div", { className: 'variant-info' },
|
|
12093
|
+
React.createElement("div", { className: 'variant-specs-row' },
|
|
12094
|
+
React.createElement("div", { className: 'variant-specs' }, Object.keys(selectedOptions).length > 0 ? (Object.entries(selectedOptions).map(([key, value]) => (React.createElement("span", { key: key, className: 'spec-item' }, value)))) : (React.createElement("span", { className: 'spec-placeholder' }, "Please select options"))),
|
|
12095
|
+
selectedVariant && selectedVariant.quantityAvailable !== undefined && (React.createElement("div", { className: 'stock-info' },
|
|
12096
|
+
"Available: ",
|
|
12097
|
+
selectedVariant.quantityAvailable))),
|
|
12098
|
+
React.createElement("div", { className: 'variant-price-row' },
|
|
12099
|
+
React.createElement("div", { className: 'price' },
|
|
12100
|
+
"$",
|
|
12101
|
+
totalPrice),
|
|
12102
|
+
React.createElement("div", { className: 'quantity-selector' },
|
|
12103
|
+
React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1 }, "\u2212"),
|
|
12104
|
+
React.createElement("span", { className: 'qty-value' }, quantity),
|
|
12105
|
+
React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(quantity + 1), disabled: !selectedVariant || quantity >= maxQuantity }, "+"))))),
|
|
12106
|
+
React.createElement("div", { className: 'variant-options' }, productData.options.map(option => (React.createElement("div", { key: option.name, className: 'option-group' },
|
|
12107
|
+
React.createElement("div", { className: 'option-label' }, option.name),
|
|
12108
|
+
React.createElement("div", { className: 'option-values' }, option.values.map(value => {
|
|
12109
|
+
// 检查这个选项是否可选(availableForSale = true,如果有 quantityAvailable 则还需 > 0)
|
|
12110
|
+
const isAvailable = productData.variants.edges.some(({ node: variant }) => {
|
|
12111
|
+
const hasThisOption = variant.selectedOptions.some(opt => opt.name === option.name && opt.value === value);
|
|
12112
|
+
if (!hasThisOption || !variant.availableForSale)
|
|
12113
|
+
return false;
|
|
12114
|
+
// 如果有 quantityAvailable 字段,则需要检查库存
|
|
12115
|
+
if (variant.quantityAvailable !== undefined) {
|
|
12116
|
+
return variant.quantityAvailable > 0;
|
|
12117
|
+
}
|
|
12118
|
+
// 没有 quantityAvailable 字段时,只要 availableForSale 为 true 就可选
|
|
12119
|
+
return true;
|
|
12120
|
+
});
|
|
12121
|
+
const isSelected = selectedOptions[option.name] === value;
|
|
12122
|
+
return (React.createElement("button", { key: value, className: `option-btn ${isSelected ? 'selected' : ''} ${!isAvailable ? 'disabled' : ''}`, onClick: () => isAvailable && handleOptionSelect(option.name, value), disabled: !isAvailable }, value));
|
|
12123
|
+
}))))))),
|
|
12124
|
+
React.createElement("div", { className: 'popup-footer' },
|
|
12125
|
+
React.createElement("button", { className: 'add-to-cart-btn', onClick: handleAddToCart, disabled: !selectedVariant }, "Add To Cart")),
|
|
12126
|
+
showImagePreview && previewImageUrl && (React.createElement(Modal$1, { visible: showImagePreview, padding: 0, isFullScreen: true, onClose: () => setShowImagePreview(false) },
|
|
12127
|
+
React.createElement("div", { style: {
|
|
12128
|
+
width: '100%',
|
|
12129
|
+
height: '100%',
|
|
12130
|
+
display: 'flex',
|
|
12131
|
+
alignItems: 'center',
|
|
12132
|
+
justifyContent: 'center',
|
|
12133
|
+
backgroundColor: 'rgba(0, 0, 0, 0.9)'
|
|
12134
|
+
}, onClick: () => setShowImagePreview(false) },
|
|
12135
|
+
React.createElement("img", { src: previewImageUrl, alt: 'Preview', style: {
|
|
12136
|
+
maxWidth: '100%',
|
|
12137
|
+
maxHeight: '100%',
|
|
12138
|
+
objectFit: 'contain'
|
|
12139
|
+
} }))))));
|
|
12140
|
+
};
|
|
12141
|
+
|
|
11910
12142
|
const CommodityDetailDiroNew$1 = (_a) => {
|
|
11911
|
-
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4;
|
|
11912
|
-
var { style,
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
const {
|
|
11916
|
-
React.useState(false);
|
|
11917
|
-
React.useState(false);
|
|
11918
|
-
React.useState(true);
|
|
12143
|
+
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5;
|
|
12144
|
+
var { style, rec, viewTime, isPost, bottom_image, tipText, swiper, commodityStyles, buttonStyle, index, commodityGroup, popupBg, iframeIcon, commodityImgRatio, iframeBgColor, isActive = true } = _a, props = __rest(_a, ["style", "rec", "viewTime", "isPost", "bottom_image", "tipText", "swiper", "commodityStyles", "buttonStyle", "index", "commodityGroup", "popupBg", "iframeIcon", "commodityImgRatio", "iframeBgColor", "isActive"]);
|
|
12145
|
+
const { sxpParameter, popupCurTimeRef, popupDetailData, setPopupDetailData, isPreview, bffFbReport, checkCommodityIndexRef, globalConfig, ctaEvent } = useSxpDataSource();
|
|
12146
|
+
useEditor();
|
|
12147
|
+
const { productView } = useEventReport();
|
|
11919
12148
|
const [showModal, setShowModal] = React.useState(false);
|
|
11920
12149
|
const curTimeRef = React.useRef(null);
|
|
11921
12150
|
const [show3DModal, setShow3DModal] = React.useState(false);
|
|
12151
|
+
const [showAddToCart, setShowAddToCart] = React.useState(false);
|
|
11922
12152
|
const [checkCommodityIndex, setCheckCommodityIndex] = React.useState((_b = popupDetailData === null || popupDetailData === void 0 ? void 0 : popupDetailData.multiCheckIndex) !== null && _b !== void 0 ? _b : 0);
|
|
11923
12153
|
const swiperRef = React.useRef();
|
|
11924
12154
|
const [swiperActiveIndex, setSwiperActiveIndex] = React.useState(0);
|
|
@@ -11935,30 +12165,30 @@
|
|
|
11935
12165
|
cta = p === null || p === void 0 ? void 0 : p.bindCta;
|
|
11936
12166
|
}
|
|
11937
12167
|
const handleLink = (e) => {
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
|
|
11950
|
-
|
|
11951
|
-
|
|
11952
|
-
|
|
11953
|
-
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
|
|
11957
|
-
target_url: product.link
|
|
11958
|
-
});
|
|
11959
|
-
}
|
|
11960
|
-
window.location.href = window.getJointUtmLink(product.link);
|
|
12168
|
+
e.preventDefault();
|
|
12169
|
+
// 上报点击事件
|
|
12170
|
+
ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
|
|
12171
|
+
eventSubject: 'clickCta',
|
|
12172
|
+
eventDescription: 'User clicked the CTA'
|
|
12173
|
+
}, data, product, position);
|
|
12174
|
+
bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
|
|
12175
|
+
eventName: 'ClickCTA',
|
|
12176
|
+
product: product ? [product] : undefined,
|
|
12177
|
+
contentType: 'product',
|
|
12178
|
+
data,
|
|
12179
|
+
position,
|
|
12180
|
+
cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
|
|
12181
|
+
cta_action_type: 'open_internal_popup',
|
|
12182
|
+
target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
|
|
12183
|
+
target_url: product === null || product === void 0 ? void 0 : product.link
|
|
12184
|
+
});
|
|
12185
|
+
if (!isPost) {
|
|
12186
|
+
productView(data, product, cta, viewTime || curTimeRef.current, position);
|
|
11961
12187
|
}
|
|
12188
|
+
// 更新 popupDetailData,确保 AddToCart 组件能获取到商品数据
|
|
12189
|
+
setPopupDetailData === null || setPopupDetailData === void 0 ? void 0 : setPopupDetailData(Object.assign(Object.assign({}, data), { video: Object.assign(Object.assign({}, data === null || data === void 0 ? void 0 : data.video), { bindProduct: product }), index: position }));
|
|
12190
|
+
// 打开 AddToCart 弹窗
|
|
12191
|
+
setShowAddToCart(true);
|
|
11962
12192
|
};
|
|
11963
12193
|
React.useEffect(() => {
|
|
11964
12194
|
var _a, _b;
|
|
@@ -11979,7 +12209,7 @@
|
|
|
11979
12209
|
rec: recData,
|
|
11980
12210
|
position
|
|
11981
12211
|
});
|
|
11982
|
-
}, [isActive, bffFbReport, isPost]);
|
|
12212
|
+
}, [isActive, bffFbReport, isPost, data, product, position]);
|
|
11983
12213
|
React.useEffect(() => {
|
|
11984
12214
|
if (!isActive || isPost)
|
|
11985
12215
|
return;
|
|
@@ -12107,13 +12337,13 @@ Made in Italy` })));
|
|
|
12107
12337
|
swiperRef.current.swiper.slideTo(0);
|
|
12108
12338
|
swiperRef.current.swiper.autoplay.start();
|
|
12109
12339
|
}
|
|
12110
|
-
}, []);
|
|
12340
|
+
}, [popupCurTimeRef, checkCommodityIndexRef]);
|
|
12111
12341
|
const renderCommodityGroup = React.useCallback(() => {
|
|
12112
12342
|
var _a, _b, _c;
|
|
12113
12343
|
if (isPost)
|
|
12114
12344
|
return;
|
|
12115
12345
|
return (React.createElement(CommodityGroup$1, { products: (_a = data === null || data === void 0 ? void 0 : data.video) === null || _a === void 0 ? void 0 : _a.bindProducts, data: commodityGroup, defImg: (_c = (_b = sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.bottom_image) !== null && _b !== void 0 ? _b : bottom_image) !== null && _c !== void 0 ? _c : '', style: { padding: '0 19px' }, onCLick: handleClick, popupDetailData: popupDetailData, check: checkCommodityIndex }));
|
|
12116
|
-
}, [checkCommodityIndex]);
|
|
12346
|
+
}, [checkCommodityIndex, isPost, (_w = data === null || data === void 0 ? void 0 : data.video) === null || _w === void 0 ? void 0 : _w.bindProducts, commodityGroup, sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.bottom_image, bottom_image, handleClick, popupDetailData]);
|
|
12117
12347
|
const getDotsAlign = React.useMemo(() => {
|
|
12118
12348
|
const dotsAlignClass = {
|
|
12119
12349
|
left: 'commondityDetail-swiper-clickable-left',
|
|
@@ -12123,24 +12353,24 @@ Made in Italy` })));
|
|
|
12123
12353
|
return dotsAlignClass === null || dotsAlignClass === void 0 ? void 0 : dotsAlignClass[swiper === null || swiper === void 0 ? void 0 : swiper.dotsAlign];
|
|
12124
12354
|
}, [swiper === null || swiper === void 0 ? void 0 : swiper.dotsAlign]);
|
|
12125
12355
|
const iframeUrl = product === null || product === void 0 ? void 0 : product.remark;
|
|
12356
|
+
const isAlly = React.useMemo(() => getScreenReader(), []);
|
|
12126
12357
|
const handleMouseEnter = React.useCallback(() => {
|
|
12127
12358
|
if (swiperRef.current && swiperRef.current.swiper && isAlly) {
|
|
12128
12359
|
swiperRef.current.swiper.autoplay.stop();
|
|
12129
12360
|
}
|
|
12130
|
-
}, []);
|
|
12361
|
+
}, [isAlly]);
|
|
12131
12362
|
const handleMouseLeave = React.useCallback(() => {
|
|
12132
12363
|
if (swiperRef.current && swiperRef.current.swiper && isAlly) {
|
|
12133
12364
|
swiperRef.current.swiper.autoplay.start();
|
|
12134
12365
|
}
|
|
12135
|
-
}, []);
|
|
12366
|
+
}, [isAlly]);
|
|
12136
12367
|
const handleSlideChange = React.useCallback((swiper) => {
|
|
12137
12368
|
setSwiperActiveIndex(swiper.activeIndex);
|
|
12138
12369
|
}, []);
|
|
12139
|
-
const isAlly = React.useMemo(() => getScreenReader(), []);
|
|
12140
12370
|
return (React.createElement("div", { className: 'pb-commondityDiroNew' },
|
|
12141
12371
|
React.createElement("div", Object.assign({ className: css.css(Object.assign(Object.assign({}, style), { transform: 'translate3d(0px, 0px, 0px)' })) }, props),
|
|
12142
12372
|
React.createElement("div", { style: { position: 'relative' }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave },
|
|
12143
|
-
product && ((
|
|
12373
|
+
product && ((_x = product === null || product === void 0 ? void 0 : product.homePage) === null || _x === void 0 ? void 0 : _x.length) > 0 && (React.createElement(Swiper, Object.assign({ height: height, modules: [Pagination, Autoplay, ...(isAlly ? [Navigation, A11y, Mousewheel, Keyboard] : [])], pagination: {
|
|
12144
12374
|
clickable: true,
|
|
12145
12375
|
bulletActiveClass: 'swipe-item-active-bullet',
|
|
12146
12376
|
clickableClass: getDotsAlign,
|
|
@@ -12157,7 +12387,7 @@ Made in Italy` })));
|
|
|
12157
12387
|
: {}), { loop: true, ref: swiperRef, onSlideChange: handleSlideChange, autoplay: {
|
|
12158
12388
|
delay: (swiper === null || swiper === void 0 ? void 0 : swiper.delay) * 1000
|
|
12159
12389
|
}, className: css.css(Object.assign(Object.assign({ '.swiper-pagination': {
|
|
12160
|
-
bottom: (
|
|
12390
|
+
bottom: (_y = swiper === null || swiper === void 0 ? void 0 : swiper.dotsMarginBottom) !== null && _y !== void 0 ? _y : 0,
|
|
12161
12391
|
fontSize: '14px'
|
|
12162
12392
|
} }, ((swiper === null || swiper === void 0 ? void 0 : swiper.dotsBgColor) && {
|
|
12163
12393
|
'.swiper-pagination-bullet': {
|
|
@@ -12169,7 +12399,7 @@ Made in Italy` })));
|
|
|
12169
12399
|
backgroundColor: `${swiper === null || swiper === void 0 ? void 0 : swiper.dotsActiveColor}!important`,
|
|
12170
12400
|
opacity: 1
|
|
12171
12401
|
}
|
|
12172
|
-
}))) }), (
|
|
12402
|
+
}))) }), (_z = product === null || product === void 0 ? void 0 : product.homePage) === null || _z === void 0 ? void 0 : _z.map((src, srcKey) => {
|
|
12173
12403
|
var _a;
|
|
12174
12404
|
return (React.createElement(SwiperSlide, { key: srcKey, "aria-hidden": srcKey !== swiperActiveIndex },
|
|
12175
12405
|
React.createElement("div", { style: {
|
|
@@ -12185,7 +12415,7 @@ Made in Italy` })));
|
|
|
12185
12415
|
objectPosition: `50% ${(swiper === null || swiper === void 0 ? void 0 : swiper.translateY) ? (swiper === null || swiper === void 0 ? void 0 : swiper.translateY) + 50 : 50}%`
|
|
12186
12416
|
}, src: (_a = src !== null && src !== void 0 ? src : sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.bottom_image) !== null && _a !== void 0 ? _a : bottom_image }))));
|
|
12187
12417
|
}))),
|
|
12188
|
-
!((
|
|
12418
|
+
!((_0 = product === null || product === void 0 ? void 0 : product.homePage) === null || _0 === void 0 ? void 0 : _0.length) && (React.createElement("div", { className: css.css({
|
|
12189
12419
|
height,
|
|
12190
12420
|
width
|
|
12191
12421
|
}) },
|
|
@@ -12193,7 +12423,7 @@ Made in Italy` })));
|
|
|
12193
12423
|
objectFit: 'cover',
|
|
12194
12424
|
width: '100%',
|
|
12195
12425
|
height: '100%'
|
|
12196
|
-
}), src: (
|
|
12426
|
+
}), src: (_1 = sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.bottom_image) !== null && _1 !== void 0 ? _1 : bottom_image, alt: 'pdp image' }))),
|
|
12197
12427
|
(iframeUrl || !product) && iframeIcon && (React.createElement("div", { style: {
|
|
12198
12428
|
display: 'flex',
|
|
12199
12429
|
alignItems: 'center',
|
|
@@ -12210,7 +12440,7 @@ Made in Italy` })));
|
|
|
12210
12440
|
React.createElement("div", { className: 'pb-commondityDiroNew-content-top' },
|
|
12211
12441
|
React.createElement("div", { className: 'pb-commondityDiroNew-content-top-left' },
|
|
12212
12442
|
React.createElement("div", { className: 'pb-commondityDiroNew-content-top-left-title', style: getStyle(commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.title), dangerouslySetInnerHTML: {
|
|
12213
|
-
__html: setFontForText((
|
|
12443
|
+
__html: setFontForText((_2 = product === null || product === void 0 ? void 0 : product.title) !== null && _2 !== void 0 ? _2 : 'Large Dior Toujours BagLarge', commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.title)
|
|
12214
12444
|
} }),
|
|
12215
12445
|
React.createElement("div", { className: 'pb-commondityDiroNew-content-collection', hidden: !!product && (!(product === null || product === void 0 ? void 0 : product.collection) || (product === null || product === void 0 ? void 0 : product.collection) === ''), style: getStyle(commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.collection), dangerouslySetInnerHTML: {
|
|
12216
12446
|
__html: setFontForText((product === null || product === void 0 ? void 0 : product.collection) || 'Black Macrocannage CalfskinLarge', commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.collection)
|
|
@@ -12220,11 +12450,11 @@ Made in Italy` })));
|
|
|
12220
12450
|
__html: priceText !== null && priceText !== void 0 ? priceText : ''
|
|
12221
12451
|
} }),
|
|
12222
12452
|
React.createElement("div", { className: 'pb-commondityDiroNew-content-top-right-price', hidden: !!product && !(product === null || product === void 0 ? void 0 : product.taxInfo), style: getStyle(commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.taxInfo), dangerouslySetInnerHTML: {
|
|
12223
|
-
__html: setFontForText((
|
|
12453
|
+
__html: setFontForText((_3 = product === null || product === void 0 ? void 0 : product.taxInfo) !== null && _3 !== void 0 ? _3 : '税费', commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.taxInfo)
|
|
12224
12454
|
} }))),
|
|
12225
|
-
React.createElement("a", { "aria-label": (
|
|
12455
|
+
React.createElement("a", { "aria-label": (_4 = cta === null || cta === void 0 ? void 0 : cta.enTitle) !== null && _4 !== void 0 ? _4 : 'Shop now', role: 'button', tabIndex: 0, onClick: handleLink, className: 'pb-commondityDiroNew-btn', style: buttonStyle },
|
|
12226
12456
|
React.createElement("span", { dangerouslySetInnerHTML: {
|
|
12227
|
-
__html: setFontForText((
|
|
12457
|
+
__html: setFontForText((_5 = cta === null || cta === void 0 ? void 0 : cta.enTitle) !== null && _5 !== void 0 ? _5 : 'Shop now', buttonStyle)
|
|
12228
12458
|
} })),
|
|
12229
12459
|
productInfoText({ isPost }))),
|
|
12230
12460
|
React.createElement(Modal$1, { visible: showModal, onClose: () => setShowModal(false) },
|
|
@@ -12236,7 +12466,9 @@ Made in Italy` })));
|
|
|
12236
12466
|
height: 'calc(100% - 50px)',
|
|
12237
12467
|
marginTop: '50px',
|
|
12238
12468
|
border: 'none'
|
|
12239
|
-
} })))
|
|
12469
|
+
} }))),
|
|
12470
|
+
showAddToCart && (React.createElement(Modal$1, { visible: showAddToCart, padding: 0, isFullScreen: false, onClose: () => setShowAddToCart(false) },
|
|
12471
|
+
React.createElement(AddToCartPopup$1, { isActive: true })))));
|
|
12240
12472
|
};
|
|
12241
12473
|
var CommodityDetailDiroNewComponent = React.memo(CommodityDetailDiroNew$1);
|
|
12242
12474
|
|
|
@@ -13238,296 +13470,6 @@ Made in Italy` })));
|
|
|
13238
13470
|
React.createElement("li", null, "\u65E0\u5E93\u5B58\u6216\u4E0D\u53EF\u552E\u5356\u7684\u89C4\u683C\u81EA\u52A8\u7F6E\u7070\u4E0D\u53EF\u9009"))));
|
|
13239
13471
|
};
|
|
13240
13472
|
|
|
13241
|
-
const AddToCartPopup$1 = (_a) => {
|
|
13242
|
-
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
13243
|
-
var { style, isActive = true, index, shopifyDomain = '', storefrontAccessToken = '', variantStyles = {}, buttonStyle = {}, quantityStyle = {}, texts = {}, popupBg = {} } = _a, props = __rest(_a, ["style", "isActive", "index", "shopifyDomain", "storefrontAccessToken", "variantStyles", "buttonStyle", "quantityStyle", "texts", "popupBg"]);
|
|
13244
|
-
const { sxpParameter, popupDetailData, isPreview, bffFbReport, globalConfig } = useSxpDataSource();
|
|
13245
|
-
useEventReport();
|
|
13246
|
-
const curTimeRef = React.useRef(null);
|
|
13247
|
-
const [productData, setProductData] = React.useState(null);
|
|
13248
|
-
const [selectedOptions, setSelectedOptions] = React.useState({});
|
|
13249
|
-
const [selectedVariant, setSelectedVariant] = React.useState(null);
|
|
13250
|
-
const [quantity, setQuantity] = React.useState(1);
|
|
13251
|
-
const [loading, setLoading] = React.useState(true);
|
|
13252
|
-
const [error, setError] = React.useState(null);
|
|
13253
|
-
// 获取当前弹窗商品数据(自动从 popupDetailData 获取)
|
|
13254
|
-
const data = popupDetailData;
|
|
13255
|
-
const product = (_c = (_b = data === null || data === void 0 ? void 0 : data.video) === null || _b === void 0 ? void 0 : _b.bindProduct) !== null && _c !== void 0 ? _c : (_e = (_d = data === null || data === void 0 ? void 0 : data.video) === null || _d === void 0 ? void 0 : _d.bindProducts) === null || _e === void 0 ? void 0 : _e[0];
|
|
13256
|
-
product === null || product === void 0 ? void 0 : product.bindCta;
|
|
13257
|
-
const position = (_g = (_f = popupDetailData === null || popupDetailData === void 0 ? void 0 : popupDetailData.index) !== null && _f !== void 0 ? _f : index) !== null && _g !== void 0 ? _g : 0;
|
|
13258
|
-
// Shopify配置 - 优先级:props > globalConfig > 默认值
|
|
13259
|
-
const finalShopifyDomain = shopifyDomain || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.shopifyDomain) || 'dev-store-749237498237498636.myshopify.com';
|
|
13260
|
-
const finalStorefrontToken = storefrontAccessToken || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.storefrontAccessToken) || '77d894c490f79430ce7bd0a7efdff6b7';
|
|
13261
|
-
// 自动从商品数据获取 Shopify Product ID
|
|
13262
|
-
const productId = (product === null || product === void 0 ? void 0 : product.itemId) || '';
|
|
13263
|
-
// 文案
|
|
13264
|
-
const finalTexts = {
|
|
13265
|
-
addToCart: texts.addToCart || 'Add to Cart',
|
|
13266
|
-
selectOptions: texts.selectOptions || 'Please select options',
|
|
13267
|
-
loading: texts.loading || 'Loading...',
|
|
13268
|
-
error: texts.error || 'Failed to load product',
|
|
13269
|
-
color: texts.color || 'Color',
|
|
13270
|
-
size: texts.size || 'Size',
|
|
13271
|
-
material: texts.material || 'Material',
|
|
13272
|
-
style: texts.style || 'Style'
|
|
13273
|
-
};
|
|
13274
|
-
// 查询Shopify商品数据
|
|
13275
|
-
const fetchProductData = React.useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
13276
|
-
var _m;
|
|
13277
|
-
if (!productId || !finalShopifyDomain || !finalStorefrontToken) {
|
|
13278
|
-
console.log('[AddToCartPopup] 缺少必要配置:', {
|
|
13279
|
-
productId,
|
|
13280
|
-
shopifyDomain: finalShopifyDomain,
|
|
13281
|
-
hasToken: !!finalStorefrontToken
|
|
13282
|
-
});
|
|
13283
|
-
setLoading(false);
|
|
13284
|
-
return;
|
|
13285
|
-
}
|
|
13286
|
-
console.log('[AddToCartPopup] 开始加载商品数据:', {
|
|
13287
|
-
productId,
|
|
13288
|
-
shopifyDomain: finalShopifyDomain
|
|
13289
|
-
});
|
|
13290
|
-
setLoading(true);
|
|
13291
|
-
setError(null);
|
|
13292
|
-
try {
|
|
13293
|
-
const query = `
|
|
13294
|
-
query getProduct($id: ID!) {
|
|
13295
|
-
product(id: $id) {
|
|
13296
|
-
id
|
|
13297
|
-
title
|
|
13298
|
-
images(first: 10) {
|
|
13299
|
-
edges {
|
|
13300
|
-
node {
|
|
13301
|
-
url
|
|
13302
|
-
}
|
|
13303
|
-
}
|
|
13304
|
-
}
|
|
13305
|
-
options {
|
|
13306
|
-
name
|
|
13307
|
-
values
|
|
13308
|
-
}
|
|
13309
|
-
variants(first: 100) {
|
|
13310
|
-
edges {
|
|
13311
|
-
node {
|
|
13312
|
-
id
|
|
13313
|
-
title
|
|
13314
|
-
availableForSale
|
|
13315
|
-
quantityAvailable
|
|
13316
|
-
price {
|
|
13317
|
-
amount
|
|
13318
|
-
currencyCode
|
|
13319
|
-
}
|
|
13320
|
-
image {
|
|
13321
|
-
url
|
|
13322
|
-
}
|
|
13323
|
-
selectedOptions {
|
|
13324
|
-
name
|
|
13325
|
-
value
|
|
13326
|
-
}
|
|
13327
|
-
}
|
|
13328
|
-
}
|
|
13329
|
-
}
|
|
13330
|
-
}
|
|
13331
|
-
}
|
|
13332
|
-
`;
|
|
13333
|
-
// 确保 Product ID 格式正确
|
|
13334
|
-
const formattedProductId = productId.startsWith('gid://')
|
|
13335
|
-
? productId
|
|
13336
|
-
: `gid://shopify/Product/${productId}`;
|
|
13337
|
-
console.log('[AddToCartPopup] 使用的 Product ID:', formattedProductId);
|
|
13338
|
-
const response = yield fetch(`https://${finalShopifyDomain}/api/2024-01/graphql.json`, {
|
|
13339
|
-
method: 'POST',
|
|
13340
|
-
headers: {
|
|
13341
|
-
'Content-Type': 'application/json',
|
|
13342
|
-
'X-Shopify-Storefront-Access-Token': finalStorefrontToken
|
|
13343
|
-
},
|
|
13344
|
-
body: JSON.stringify({
|
|
13345
|
-
query,
|
|
13346
|
-
variables: { id: formattedProductId }
|
|
13347
|
-
})
|
|
13348
|
-
});
|
|
13349
|
-
if (!response.ok) {
|
|
13350
|
-
throw new Error(`HTTP ${response.status}`);
|
|
13351
|
-
}
|
|
13352
|
-
const result = yield response.json();
|
|
13353
|
-
if (result.errors) {
|
|
13354
|
-
console.error('[AddToCartPopup] GraphQL 错误:', result.errors);
|
|
13355
|
-
throw new Error(result.errors[0].message);
|
|
13356
|
-
}
|
|
13357
|
-
if (!((_m = result.data) === null || _m === void 0 ? void 0 : _m.product)) {
|
|
13358
|
-
console.error('[AddToCartPopup] 未找到商品');
|
|
13359
|
-
throw new Error('Product not found');
|
|
13360
|
-
}
|
|
13361
|
-
console.log('[AddToCartPopup] 商品数据加载成功:', result.data.product.title);
|
|
13362
|
-
setProductData(result.data.product);
|
|
13363
|
-
}
|
|
13364
|
-
catch (err) {
|
|
13365
|
-
const errorMessage = err instanceof Error ? err.message : finalTexts.error;
|
|
13366
|
-
setError(errorMessage);
|
|
13367
|
-
console.error('[AddToCartPopup] 加载失败:', err);
|
|
13368
|
-
}
|
|
13369
|
-
finally {
|
|
13370
|
-
setLoading(false);
|
|
13371
|
-
}
|
|
13372
|
-
}), [productId, finalShopifyDomain, finalStorefrontToken, finalTexts.error]);
|
|
13373
|
-
React.useEffect(() => {
|
|
13374
|
-
if (isActive) {
|
|
13375
|
-
fetchProductData();
|
|
13376
|
-
}
|
|
13377
|
-
}, [isActive, fetchProductData]);
|
|
13378
|
-
// 根据选中的规格匹配variant
|
|
13379
|
-
React.useEffect(() => {
|
|
13380
|
-
if (!productData)
|
|
13381
|
-
return;
|
|
13382
|
-
const variants = productData.variants.edges.map(edge => edge.node);
|
|
13383
|
-
const optionsCount = productData.options.length;
|
|
13384
|
-
const selectedCount = Object.keys(selectedOptions).length;
|
|
13385
|
-
if (selectedCount === 0 || selectedCount < optionsCount) {
|
|
13386
|
-
setSelectedVariant(null);
|
|
13387
|
-
return;
|
|
13388
|
-
}
|
|
13389
|
-
const matchedVariant = variants.find(variant => {
|
|
13390
|
-
return variant.selectedOptions.every(option => selectedOptions[option.name] === option.value);
|
|
13391
|
-
});
|
|
13392
|
-
setSelectedVariant(matchedVariant || null);
|
|
13393
|
-
setQuantity(1);
|
|
13394
|
-
}, [selectedOptions, productData]);
|
|
13395
|
-
// 处理规格选择
|
|
13396
|
-
const handleOptionSelect = React.useCallback((optionName, value) => {
|
|
13397
|
-
setSelectedOptions(prev => {
|
|
13398
|
-
const newOptions = Object.assign({}, prev);
|
|
13399
|
-
if (newOptions[optionName] === value) {
|
|
13400
|
-
delete newOptions[optionName];
|
|
13401
|
-
}
|
|
13402
|
-
else {
|
|
13403
|
-
newOptions[optionName] = value;
|
|
13404
|
-
}
|
|
13405
|
-
return newOptions;
|
|
13406
|
-
});
|
|
13407
|
-
}, []);
|
|
13408
|
-
// 处理数量变化
|
|
13409
|
-
const handleQuantityChange = React.useCallback((delta) => {
|
|
13410
|
-
setQuantity(prev => {
|
|
13411
|
-
var _a;
|
|
13412
|
-
const newQuantity = prev + delta;
|
|
13413
|
-
const maxQuantity = (_a = selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.quantityAvailable) !== null && _a !== void 0 ? _a : 999;
|
|
13414
|
-
return Math.max(1, Math.min(newQuantity, maxQuantity));
|
|
13415
|
-
});
|
|
13416
|
-
}, [selectedVariant]);
|
|
13417
|
-
// 检查某个规格值是否可用
|
|
13418
|
-
const isOptionValueAvailable = React.useCallback((optionName, value) => {
|
|
13419
|
-
if (!productData)
|
|
13420
|
-
return false;
|
|
13421
|
-
const variants = productData.variants.edges.map(edge => edge.node);
|
|
13422
|
-
const tempOptions = Object.assign(Object.assign({}, selectedOptions), { [optionName]: value });
|
|
13423
|
-
return variants.some(variant => {
|
|
13424
|
-
const matches = variant.selectedOptions.every(option => !tempOptions[option.name] || tempOptions[option.name] === option.value);
|
|
13425
|
-
const hasStock = variant.quantityAvailable === null || variant.quantityAvailable > 0;
|
|
13426
|
-
return matches && variant.availableForSale && hasStock;
|
|
13427
|
-
});
|
|
13428
|
-
}, [productData, selectedOptions]);
|
|
13429
|
-
// 处理加购
|
|
13430
|
-
const handleAddToCart = React.useCallback(() => {
|
|
13431
|
-
var _a;
|
|
13432
|
-
if (!selectedVariant || quantity === 0)
|
|
13433
|
-
return;
|
|
13434
|
-
const variantId = selectedVariant.id.split('/').pop();
|
|
13435
|
-
const cartUrl = `https://${finalShopifyDomain}/cart/add?id=${variantId}&quantity=${quantity}`;
|
|
13436
|
-
console.log('[AddToCartPopup] 加购:', {
|
|
13437
|
-
variantId,
|
|
13438
|
-
quantity,
|
|
13439
|
-
cartUrl
|
|
13440
|
-
});
|
|
13441
|
-
// 上报事件
|
|
13442
|
-
bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
|
|
13443
|
-
eventName: 'AddToCart',
|
|
13444
|
-
product: product ? [product] : undefined,
|
|
13445
|
-
contentType: 'product',
|
|
13446
|
-
data,
|
|
13447
|
-
position,
|
|
13448
|
-
content_id: (_a = product === null || product === void 0 ? void 0 : product.itemId) !== null && _a !== void 0 ? _a : '',
|
|
13449
|
-
value: parseFloat(selectedVariant.price.amount) * quantity,
|
|
13450
|
-
currency: selectedVariant.price.currencyCode,
|
|
13451
|
-
contents: [{
|
|
13452
|
-
id: variantId,
|
|
13453
|
-
quantity
|
|
13454
|
-
}]
|
|
13455
|
-
});
|
|
13456
|
-
// 跳转到Shopify购物车页面
|
|
13457
|
-
window.location.href = cartUrl;
|
|
13458
|
-
}, [selectedVariant, quantity, finalShopifyDomain, bffFbReport, product, data, position]);
|
|
13459
|
-
// 计算总价
|
|
13460
|
-
const totalPrice = React.useMemo(() => {
|
|
13461
|
-
if (!selectedVariant)
|
|
13462
|
-
return null;
|
|
13463
|
-
const price = parseFloat(selectedVariant.price.amount);
|
|
13464
|
-
const total = price * quantity;
|
|
13465
|
-
return total.toFixed(2);
|
|
13466
|
-
}, [selectedVariant, quantity]);
|
|
13467
|
-
// 初始化时间
|
|
13468
|
-
React.useEffect(() => {
|
|
13469
|
-
const initTime = () => {
|
|
13470
|
-
curTimeRef.current = new Date();
|
|
13471
|
-
};
|
|
13472
|
-
initTime();
|
|
13473
|
-
window.addEventListener('pageshow', initTime);
|
|
13474
|
-
return () => {
|
|
13475
|
-
window.removeEventListener('pageshow', initTime);
|
|
13476
|
-
};
|
|
13477
|
-
}, []);
|
|
13478
|
-
// 加载中
|
|
13479
|
-
if (loading) {
|
|
13480
|
-
return (React.createElement("div", { className: "add-to-cart-popup-loading", style: style },
|
|
13481
|
-
React.createElement("div", null, finalTexts.loading)));
|
|
13482
|
-
}
|
|
13483
|
-
// 错误状态
|
|
13484
|
-
if (error || !productData) {
|
|
13485
|
-
return (React.createElement("div", { className: "add-to-cart-popup-error", style: style },
|
|
13486
|
-
React.createElement("div", null,
|
|
13487
|
-
finalTexts.error,
|
|
13488
|
-
": ",
|
|
13489
|
-
error || 'Product not found')));
|
|
13490
|
-
}
|
|
13491
|
-
const mainImage = ((_h = selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.image) === null || _h === void 0 ? void 0 : _h.url) || ((_j = productData.images.edges[0]) === null || _j === void 0 ? void 0 : _j.node.url) || ((_k = product === null || product === void 0 ? void 0 : product.homePage) === null || _k === void 0 ? void 0 : _k[0]) || '';
|
|
13492
|
-
const hasAllOptionsSelected = productData.options.length === Object.keys(selectedOptions).length;
|
|
13493
|
-
const isAddToCartDisabled = !selectedVariant || quantity === 0;
|
|
13494
|
-
return (React.createElement("div", Object.assign({ className: "add-to-cart-popup-container", style: style }, props),
|
|
13495
|
-
React.createElement("div", { className: "variant-detail-section" },
|
|
13496
|
-
React.createElement("div", { className: "variant-image-wrapper" },
|
|
13497
|
-
React.createElement("img", { src: mainImage, alt: productData.title, className: "variant-image" })),
|
|
13498
|
-
React.createElement("div", { className: "variant-info-wrapper" },
|
|
13499
|
-
React.createElement("h2", { className: "product-title-text", style: variantStyles.title, dangerouslySetInnerHTML: {
|
|
13500
|
-
__html: setFontForText(productData.title, variantStyles.title)
|
|
13501
|
-
} }),
|
|
13502
|
-
selectedVariant && (React.createElement(React.Fragment, null,
|
|
13503
|
-
React.createElement("div", { className: "selected-options-tags" }, selectedVariant.selectedOptions.map(option => (React.createElement("span", { key: option.name, className: "option-tag", style: variantStyles.selectedOption },
|
|
13504
|
-
option.name,
|
|
13505
|
-
": ",
|
|
13506
|
-
option.value)))),
|
|
13507
|
-
React.createElement("div", { className: "price-display" },
|
|
13508
|
-
React.createElement("span", { className: "price-value", style: variantStyles.price, dangerouslySetInnerHTML: {
|
|
13509
|
-
__html: setFontForText(`${selectedVariant.price.currencyCode} $${totalPrice}`, variantStyles.price)
|
|
13510
|
-
} })),
|
|
13511
|
-
React.createElement("div", { className: "quantity-selector-wrapper", style: quantityStyle },
|
|
13512
|
-
React.createElement("button", { className: "quantity-btn quantity-decrease", onClick: () => handleQuantityChange(-1), disabled: quantity <= 1, "aria-label": "Decrease quantity" }, "-"),
|
|
13513
|
-
React.createElement("input", { type: "number", value: quantity, readOnly: true, className: "quantity-input-field", "aria-label": "Quantity" }),
|
|
13514
|
-
React.createElement("button", { className: "quantity-btn quantity-increase", onClick: () => handleQuantityChange(1), disabled: quantity >= ((_l = selectedVariant.quantityAvailable) !== null && _l !== void 0 ? _l : 999), "aria-label": "Increase quantity" }, "+")))),
|
|
13515
|
-
!hasAllOptionsSelected && (React.createElement("div", { className: "no-selection-hint", style: variantStyles.option }, finalTexts.selectOptions)))),
|
|
13516
|
-
React.createElement("div", { className: "variant-options-section" }, productData.options.map(option => (React.createElement("div", { key: option.name, className: "option-group-wrapper" },
|
|
13517
|
-
React.createElement("h3", { className: "option-group-name", style: variantStyles.option, dangerouslySetInnerHTML: {
|
|
13518
|
-
__html: setFontForText(option.name, variantStyles.option)
|
|
13519
|
-
} }),
|
|
13520
|
-
React.createElement("div", { className: "option-values-grid" }, option.values.map(value => {
|
|
13521
|
-
const isSelected = selectedOptions[option.name] === value;
|
|
13522
|
-
const isAvailable = isOptionValueAvailable(option.name, value);
|
|
13523
|
-
return (React.createElement("button", { key: value, className: `option-value-button ${isSelected ? 'selected' : ''} ${!isAvailable ? 'disabled' : ''}`, onClick: () => isAvailable && handleOptionSelect(option.name, value), disabled: !isAvailable, "aria-label": `${option.name}: ${value}`, "aria-pressed": isSelected }, value));
|
|
13524
|
-
})))))),
|
|
13525
|
-
React.createElement("button", { className: `add-to-cart-button ${isAddToCartDisabled ? 'disabled' : ''}`, style: buttonStyle, onClick: handleAddToCart, disabled: isAddToCartDisabled, "aria-label": finalTexts.addToCart },
|
|
13526
|
-
React.createElement("span", { dangerouslySetInnerHTML: {
|
|
13527
|
-
__html: setFontForText(finalTexts.addToCart, buttonStyle)
|
|
13528
|
-
} }))));
|
|
13529
|
-
};
|
|
13530
|
-
|
|
13531
13473
|
/*
|
|
13532
13474
|
* @Author: tao
|
|
13533
13475
|
* @Date: 2026-01-12
|
|
@@ -13543,60 +13485,7 @@ Made in Italy` })));
|
|
|
13543
13485
|
interactionRender: interactionRender$d
|
|
13544
13486
|
},
|
|
13545
13487
|
defaulSetting: {
|
|
13546
|
-
props: {
|
|
13547
|
-
shopifyDomain: '',
|
|
13548
|
-
storefrontAccessToken: '',
|
|
13549
|
-
variantStyles: {
|
|
13550
|
-
title: {
|
|
13551
|
-
color: '#000',
|
|
13552
|
-
fontSize: 20,
|
|
13553
|
-
fontWeight: 600,
|
|
13554
|
-
marginBottom: 12
|
|
13555
|
-
},
|
|
13556
|
-
price: {
|
|
13557
|
-
color: '#000',
|
|
13558
|
-
fontSize: 24,
|
|
13559
|
-
fontWeight: 700,
|
|
13560
|
-
marginBottom: 16
|
|
13561
|
-
},
|
|
13562
|
-
option: {
|
|
13563
|
-
color: '#111',
|
|
13564
|
-
fontSize: 16,
|
|
13565
|
-
fontWeight: 600,
|
|
13566
|
-
marginBottom: 12
|
|
13567
|
-
},
|
|
13568
|
-
selectedOption: {
|
|
13569
|
-
fontSize: 14,
|
|
13570
|
-
color: '#374151'
|
|
13571
|
-
}
|
|
13572
|
-
},
|
|
13573
|
-
buttonStyle: {
|
|
13574
|
-
backgroundColor: '#000',
|
|
13575
|
-
color: '#fff',
|
|
13576
|
-
fontSize: 16,
|
|
13577
|
-
height: 52,
|
|
13578
|
-
fontWeight: 600,
|
|
13579
|
-
textAlign: 'center',
|
|
13580
|
-
textTransform: 'uppercase'
|
|
13581
|
-
},
|
|
13582
|
-
quantityStyle: {
|
|
13583
|
-
gap: 12
|
|
13584
|
-
},
|
|
13585
|
-
texts: {
|
|
13586
|
-
addToCart: 'Add to Cart',
|
|
13587
|
-
selectOptions: 'Please select options',
|
|
13588
|
-
loading: 'Loading...',
|
|
13589
|
-
error: 'Failed to load product',
|
|
13590
|
-
color: 'Color',
|
|
13591
|
-
size: 'Size',
|
|
13592
|
-
material: 'Material',
|
|
13593
|
-
style: 'Style'
|
|
13594
|
-
},
|
|
13595
|
-
popupBg: {
|
|
13596
|
-
horizontalMargin: 0,
|
|
13597
|
-
bottomMargin: 0
|
|
13598
|
-
}
|
|
13599
|
-
},
|
|
13488
|
+
props: {},
|
|
13600
13489
|
style: {}
|
|
13601
13490
|
},
|
|
13602
13491
|
w: 100,
|
|
@@ -19692,7 +19581,7 @@ Made in Italy` })));
|
|
|
19692
19581
|
return res.json();
|
|
19693
19582
|
})
|
|
19694
19583
|
.then((result) => {
|
|
19695
|
-
var _a, _b, _c, _d;
|
|
19584
|
+
var _a, _b, _c, _d, _e;
|
|
19696
19585
|
if (result.code === '0' || result.code === '00000') {
|
|
19697
19586
|
// 判断数据结构:CMS 模式和普通模式可能不同
|
|
19698
19587
|
let multiCtaData = null;
|
|
@@ -19711,6 +19600,14 @@ Made in Italy` })));
|
|
|
19711
19600
|
console.error('[StructurePage] No multiCta data found in response:', result);
|
|
19712
19601
|
setError(result.message || 'No multiCta data found');
|
|
19713
19602
|
}
|
|
19603
|
+
// 存储 Shopify 配置信息到 window 对象,供 AddToCart 弹窗使用
|
|
19604
|
+
if ((_e = result.data) === null || _e === void 0 ? void 0 : _e.shopify) {
|
|
19605
|
+
window.__SHOPIFY_CONFIG__ = {
|
|
19606
|
+
domain: result.data.shopify.domain,
|
|
19607
|
+
storefrontAccessToken: result.data.shopify.storefrontAccessToken
|
|
19608
|
+
};
|
|
19609
|
+
console.log('[StructurePage] Shopify config stored:', window.__SHOPIFY_CONFIG__);
|
|
19610
|
+
}
|
|
19714
19611
|
}
|
|
19715
19612
|
else {
|
|
19716
19613
|
setError(result.message || 'Failed to load data');
|