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