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.
Files changed (42) hide show
  1. package/dist/index.cjs +292 -395
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +355 -291
  4. package/dist/index.js +292 -395
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.min.cjs +6 -6
  7. package/dist/index.min.cjs.map +1 -1
  8. package/dist/index.min.js +6 -6
  9. package/dist/index.min.js.map +1 -1
  10. package/dist/pb-ui.js +292 -395
  11. package/dist/pb-ui.js.map +1 -1
  12. package/dist/pb-ui.min.js +6 -6
  13. package/dist/pb-ui.min.js.map +1 -1
  14. package/es/core/components/StructurePage/index.d.ts +4 -0
  15. package/es/core/components/StructurePage/index.js +8 -1
  16. package/es/core/components/SxpPageRender/Modal/index.d.ts +1 -0
  17. package/es/core/components/SxpPageRender/Modal/index.js +3 -3
  18. package/es/core/components/SxpPageRender/index.d.ts +1 -0
  19. package/es/core/components/SxpPageRender/typing.d.ts +1 -0
  20. package/es/materials/sxp/popup/AddToCart/index.d.ts +1 -27
  21. package/es/materials/sxp/popup/AddToCart/index.js +117 -173
  22. package/es/materials/sxp/popup/AddToCart/index.new.d.ts +8 -0
  23. package/es/materials/sxp/popup/AddToCart/index.new.js +174 -0
  24. package/es/materials/sxp/popup/AddToCart/index.old.d.ts +33 -0
  25. package/es/materials/sxp/popup/AddToCart/index.old.js +299 -0
  26. package/es/materials/sxp/popup/AddToCart/material.js +1 -54
  27. package/es/materials/sxp/popup/CommodityDetailDiroNew/index.js +48 -53
  28. package/lib/core/components/StructurePage/index.d.ts +4 -0
  29. package/lib/core/components/StructurePage/index.js +8 -1
  30. package/lib/core/components/SxpPageRender/Modal/index.d.ts +1 -0
  31. package/lib/core/components/SxpPageRender/Modal/index.js +3 -3
  32. package/lib/core/components/SxpPageRender/index.d.ts +1 -0
  33. package/lib/core/components/SxpPageRender/typing.d.ts +1 -0
  34. package/lib/materials/sxp/popup/AddToCart/index.d.ts +1 -27
  35. package/lib/materials/sxp/popup/AddToCart/index.js +115 -171
  36. package/lib/materials/sxp/popup/AddToCart/index.new.d.ts +8 -0
  37. package/lib/materials/sxp/popup/AddToCart/index.new.js +176 -0
  38. package/lib/materials/sxp/popup/AddToCart/index.old.d.ts +33 -0
  39. package/lib/materials/sxp/popup/AddToCart/index.old.js +301 -0
  40. package/lib/materials/sxp/popup/AddToCart/material.js +1 -54
  41. package/lib/materials/sxp/popup/CommodityDetailDiroNew/index.js +48 -53
  42. 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, isDefault, rec, viewTime, isPost, bottom_image, tipText, swiper, commodityStyles, buttonStyle, index, commodityGroup, popupBg, iframeIcon, commodityImgRatio, isTel, iframeBgColor, isActive = true } = _a, props = __rest(_a, ["style", "isDefault", "rec", "viewTime", "isPost", "bottom_image", "tipText", "swiper", "commodityStyles", "buttonStyle", "index", "commodityGroup", "popupBg", "iframeIcon", "commodityImgRatio", "isTel", "iframeBgColor", "isActive"]);
11898
- useState(true);
11899
- const { sxpParameter, popupCurTimeRef, popupDetailData, isPreview, bffFbReport, checkCommodityIndexRef, globalConfig, ctaEvent } = useSxpDataSource();
11900
- const { jumpToWeb, productView } = useEventReport();
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
- if (product === null || product === void 0 ? void 0 : product.link) {
11924
- jumpToWeb(e, data, product, cta, position);
11925
- if (!isPost) {
11926
- productView(data, product, cta, viewTime || curTimeRef.current, position);
11927
- }
11928
- else {
11929
- ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
11930
- eventSubject: 'clickCta',
11931
- eventDescription: 'User clicked the CTA'
11932
- }, data, product, position);
11933
- bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
11934
- eventName: 'ClickCTA',
11935
- product: product ? [product] : undefined,
11936
- contentType: 'product',
11937
- data,
11938
- position,
11939
- cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
11940
- cta_action_type: 'open_external_link',
11941
- target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
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 && ((_w = product === null || product === void 0 ? void 0 : product.homePage) === null || _w === void 0 ? void 0 : _w.length) > 0 && (React.createElement(Swiper, Object.assign({ height: height, modules: [Pagination, Autoplay, ...(isAlly ? [Navigation, A11y, Mousewheel, Keyboard] : [])], pagination: {
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: (_x = swiper === null || swiper === void 0 ? void 0 : swiper.dotsMarginBottom) !== null && _x !== void 0 ? _x : 0,
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
- }))) }), (_y = product === null || product === void 0 ? void 0 : product.homePage) === null || _y === void 0 ? void 0 : _y.map((src, srcKey) => {
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
- !((_z = product === null || product === void 0 ? void 0 : product.homePage) === null || _z === void 0 ? void 0 : _z.length) && (React.createElement("div", { className: css({
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: (_0 = sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.bottom_image) !== null && _0 !== void 0 ? _0 : bottom_image, alt: 'pdp image' }))),
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((_1 = product === null || product === void 0 ? void 0 : product.title) !== null && _1 !== void 0 ? _1 : 'Large Dior Toujours BagLarge', commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.title)
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((_2 = product === null || product === void 0 ? void 0 : product.taxInfo) !== null && _2 !== void 0 ? _2 : '税费', commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.taxInfo)
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": (_3 = cta === null || cta === void 0 ? void 0 : cta.enTitle) !== null && _3 !== void 0 ? _3 : 'Shop now', role: 'button', tabIndex: 0, onClick: handleLink, className: 'pb-commondityDiroNew-btn', style: buttonStyle },
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((_4 = cta === null || cta === void 0 ? void 0 : cta.enTitle) !== null && _4 !== void 0 ? _4 : 'Shop now', buttonStyle)
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');