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