pb-sxp-ui 1.20.26 → 1.20.28

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 (46) hide show
  1. package/dist/index.cjs +466 -396
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +355 -291
  4. package/dist/index.js +466 -396
  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 +466 -396
  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/core/index.d.ts +6 -0
  21. package/es/core/index.js +10 -0
  22. package/es/materials/sxp/popup/AddToCart/index.d.ts +1 -27
  23. package/es/materials/sxp/popup/AddToCart/index.js +117 -173
  24. package/es/materials/sxp/popup/AddToCart/index.new.d.ts +8 -0
  25. package/es/materials/sxp/popup/AddToCart/index.new.js +174 -0
  26. package/es/materials/sxp/popup/AddToCart/index.old.d.ts +33 -0
  27. package/es/materials/sxp/popup/AddToCart/index.old.js +299 -0
  28. package/es/materials/sxp/popup/AddToCart/material.js +1 -54
  29. package/es/materials/sxp/popup/CommodityDetailDiroNew/index.js +48 -53
  30. package/lib/core/components/StructurePage/index.d.ts +4 -0
  31. package/lib/core/components/StructurePage/index.js +8 -1
  32. package/lib/core/components/SxpPageRender/Modal/index.d.ts +1 -0
  33. package/lib/core/components/SxpPageRender/Modal/index.js +3 -3
  34. package/lib/core/components/SxpPageRender/index.d.ts +1 -0
  35. package/lib/core/components/SxpPageRender/typing.d.ts +1 -0
  36. package/lib/core/index.d.ts +6 -0
  37. package/lib/core/index.js +10 -5
  38. package/lib/materials/sxp/popup/AddToCart/index.d.ts +1 -27
  39. package/lib/materials/sxp/popup/AddToCart/index.js +115 -171
  40. package/lib/materials/sxp/popup/AddToCart/index.new.d.ts +8 -0
  41. package/lib/materials/sxp/popup/AddToCart/index.new.js +176 -0
  42. package/lib/materials/sxp/popup/AddToCart/index.old.d.ts +33 -0
  43. package/lib/materials/sxp/popup/AddToCart/index.old.js +301 -0
  44. package/lib/materials/sxp/popup/AddToCart/material.js +1 -54
  45. package/lib/materials/sxp/popup/CommodityDetailDiroNew/index.js +48 -53
  46. package/package.json +1 -1
package/dist/pb-ui.js CHANGED
@@ -180,6 +180,14 @@
180
180
  }
181
181
  return uuid.join('');
182
182
  }
183
+ const getIndexByblockType = (type, index) => {
184
+ if (type === 'CommodityCarouselBlock' || type === 'CopyBlock') {
185
+ return 'initial';
186
+ }
187
+ else {
188
+ return index;
189
+ }
190
+ };
183
191
  const generateRandomString = (length) => {
184
192
  let result = '';
185
193
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
@@ -239,6 +247,70 @@
239
247
  }
240
248
  return content;
241
249
  };
250
+ function getBrowserInfo() {
251
+ var _a, _b, _c, _d, _e, _f, _g;
252
+ const userAgent = self.navigator.userAgent;
253
+ if (!userAgent)
254
+ return null;
255
+ if (/edge\/([\d\.]+)/i.exec(userAgent))
256
+ return `Edge ${(_a = /edge\/([\d\.]+)/i.exec(userAgent)) === null || _a === void 0 ? void 0 : _a[1]}`;
257
+ if (/edg\/([\d\.]+)/i.exec(userAgent))
258
+ return `Edge(Chromium) ${(_b = /edge\/([\d\.]+)/i.exec(userAgent)) === null || _b === void 0 ? void 0 : _b[1]}`;
259
+ if (/msie/i.test(userAgent))
260
+ return `Internet Explorer ${(_c = /msie ([\d\.]+)/i.exec(userAgent)) === null || _c === void 0 ? void 0 : _c[1]}`;
261
+ if (/Trident/i.test(userAgent))
262
+ return `Internet Explorer ${(_d = /rv:([\d\.]+)/i.exec(userAgent)) === null || _d === void 0 ? void 0 : _d[1]}`;
263
+ if (/chrome/i.test(userAgent))
264
+ return `Chrome ${(_e = /chrome\/([\d\.]+)/i.exec(userAgent)) === null || _e === void 0 ? void 0 : _e[1]}`;
265
+ if (/firefox/i.test(userAgent))
266
+ return `Firefox ${(_f = /firefox\/([\d\.]+)/i.exec(userAgent)) === null || _f === void 0 ? void 0 : _f[1]}`;
267
+ if (/safari/i.test(userAgent))
268
+ return `Safari ${(_g = /version\/([\d\.]+)/i.exec(userAgent)) === null || _g === void 0 ? void 0 : _g[1]}`;
269
+ return null;
270
+ }
271
+ function getSystem() {
272
+ var _a, _b, _c;
273
+ const userAgent = self.navigator.userAgent;
274
+ if (!userAgent)
275
+ return null;
276
+ if (/iphone/i.test(userAgent))
277
+ return `IOS ${(_a = userAgent.match(/OS\s(.*?)\slike/)) === null || _a === void 0 ? void 0 : _a[1]}`;
278
+ if (/android/i.test(userAgent))
279
+ return `Android ${(_b = userAgent.match(/Android\s(.*?)\;/)) === null || _b === void 0 ? void 0 : _b[1]}`;
280
+ if (/windows/i.test(userAgent))
281
+ return `Windows ${(_c = userAgent.match(/Windows\s(.*?)\;/)) === null || _c === void 0 ? void 0 : _c[1]}`;
282
+ if (/mac/i.test(userAgent))
283
+ return 'Mac OS';
284
+ return null;
285
+ }
286
+ function getDevice$1() {
287
+ const userAgent = self.navigator.userAgent;
288
+ if (!userAgent)
289
+ return null;
290
+ if (/iphone/i.test(userAgent))
291
+ return 'iPhone';
292
+ if (/android/i.test(userAgent)) {
293
+ // var index1 = userAgent.indexOf(';');
294
+ // var index2 = userAgent.indexOf(';', index1 + 1);
295
+ // var index3 = userAgent.indexOf(';', index2 + 1);
296
+ // var index4 = userAgent.indexOf(';', index3 + 1);
297
+ // if (index2 !== -1 && index3 !== -1) {
298
+ // var value1 = userAgent.substring(index3 + 1, index4);
299
+ // return `${value1}`;
300
+ // }
301
+ const index1 = userAgent.indexOf('(');
302
+ const index2 = userAgent.indexOf(')');
303
+ if (index1 !== -1 && index2 !== -1) {
304
+ const value = userAgent.substring(index1 + 1, index2);
305
+ return `${value}`;
306
+ }
307
+ }
308
+ if (/windows/i.test(userAgent))
309
+ return 'Windows';
310
+ if (/mac/i.test(userAgent))
311
+ return 'Mac';
312
+ return null;
313
+ }
242
314
  function getCookie(val) {
243
315
  // const expirationDate = new Date();
244
316
  // expirationDate.setDate(expirationDate.getDate() + 100);
@@ -300,6 +372,33 @@
300
372
  document.cookie = `${name}=; ${expiration}${pathPart}${domainPart}`;
301
373
  console.log(`已尝试删除Cookie: ${name}`);
302
374
  }
375
+ function setCookie(name, value, days = 0, path = '/', domain = '', secure = false, sameSite = 'Lax') {
376
+ let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
377
+ // 设置过期时间
378
+ if (days) {
379
+ const date = new Date();
380
+ date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
381
+ cookieString += `; expires=${date.toUTCString()}`;
382
+ }
383
+ // 设置路径
384
+ if (path) {
385
+ cookieString += `; path=${path}`;
386
+ }
387
+ // 设置域名
388
+ if (domain) {
389
+ cookieString += `; domain=${domain}`;
390
+ }
391
+ // 设置Secure标志
392
+ if (secure) {
393
+ cookieString += '; secure';
394
+ }
395
+ // 设置SameSite属性
396
+ if (sameSite) {
397
+ cookieString += `; samesite=${sameSite}`;
398
+ }
399
+ // 设置Cookie
400
+ document.cookie = cookieString;
401
+ }
303
402
  function getUrlParamByKey(key) {
304
403
  var _a, _b;
305
404
  const queryString = location.search.slice(1);
@@ -315,6 +414,24 @@
315
414
  return (_b = params[key]) !== null && _b !== void 0 ? _b : '';
316
415
  }
317
416
 
417
+ var tool = /*#__PURE__*/Object.freeze({
418
+ __proto__: null,
419
+ deleteCookie: deleteCookie,
420
+ generateRandomString: generateRandomString,
421
+ getBrowserInfo: getBrowserInfo,
422
+ getCookie: getCookie,
423
+ getDevice: getDevice$1,
424
+ getIndexByblockType: getIndexByblockType,
425
+ getScreenReader: getScreenReader,
426
+ getSystem: getSystem,
427
+ getUid: getUid,
428
+ getUrlParamByKey: getUrlParamByKey,
429
+ setCookie: setCookie,
430
+ setFontForText: setFontForText,
431
+ splitUrlParams: splitUrlParams,
432
+ uuid: uuid
433
+ });
434
+
318
435
  function unzip(b64Data) {
319
436
  const strData = atob(b64Data);
320
437
  const charData = strData.split('').map(function (x) {
@@ -499,6 +616,18 @@
499
616
  const getFeSessionId = () => {
500
617
  return window.localStorage.getItem(feRealSessionIdKey);
501
618
  };
619
+ // 删除sessionID
620
+ const removeFeSessionId = () => {
621
+ window.localStorage.removeItem(feRealSessionIdKey);
622
+ };
623
+
624
+ var sessionStore = /*#__PURE__*/Object.freeze({
625
+ __proto__: null,
626
+ getFeSessionId: getFeSessionId,
627
+ refreshFeSessionId: refreshFeSessionId,
628
+ removeFeSessionId: removeFeSessionId,
629
+ storeAndLoadFeSessionId: storeAndLoadFeSessionId
630
+ });
502
631
 
503
632
  /*
504
633
  * @Author: binruan@chatlabs.com
@@ -522,6 +651,9 @@
522
651
  }
523
652
  return fakeUserId;
524
653
  };
654
+ const removeFeUserId = () => {
655
+ window.localStorage.removeItem(FAKE_USER_KEY);
656
+ };
525
657
  const getFeUserState = () => {
526
658
  const fakeUserState = window.localStorage.getItem(FAKE_USER_STATE);
527
659
  if (lodash.isEmpty(fakeUserState)) {
@@ -551,6 +683,24 @@
551
683
  window.localStorage.setItem(USER_CONSENT_RESULT_KEY, 'true');
552
684
  };
553
685
 
686
+ var localStore = /*#__PURE__*/Object.freeze({
687
+ __proto__: null,
688
+ AGREE_POLICY: AGREE_POLICY,
689
+ CCONTSENT_STATE: CCONTSENT_STATE,
690
+ FAKE_USER_KEY: FAKE_USER_KEY,
691
+ FAKE_USER_STATE: FAKE_USER_STATE,
692
+ SLIDE_SKIP_STATE: SLIDE_SKIP_STATE,
693
+ USER_CONSENT_RESULT_KEY: USER_CONSENT_RESULT_KEY,
694
+ getContsentState: getContsentState,
695
+ getFeUserState: getFeUserState,
696
+ getSlideSkipState: getSlideSkipState,
697
+ getUserConsentResult: getUserConsentResult,
698
+ removeFeUserId: removeFeUserId,
699
+ setSlideSkipState: setSlideSkipState,
700
+ setUserConsentResult: setUserConsentResult,
701
+ storeAndLoadFeUserId: storeAndLoadFeUserId
702
+ });
703
+
554
704
  /*
555
705
  * @Author: binruan@chatlabs.com
556
706
  * @Date: 2024-03-20 10:27:31
@@ -1759,6 +1909,23 @@
1759
1909
  DATA_TYPE["ARRAY_NUMBER"] = "array-number";
1760
1910
  })(DATA_TYPE || (DATA_TYPE = {}));
1761
1911
 
1912
+ /*
1913
+ * @Author: binruan@chatlabs.com
1914
+ * @Date: 2024-03-20 10:27:31
1915
+ * @LastEditors: binruan@chatlabs.com
1916
+ * @LastEditTime: 2024-03-20 13:56:49
1917
+ * @FilePath: \pb-sxp-ui\src\core\hooks\index.ts
1918
+ *
1919
+ */
1920
+
1921
+ var index$4 = /*#__PURE__*/Object.freeze({
1922
+ __proto__: null,
1923
+ get DATA_TYPE () { return DATA_TYPE; },
1924
+ useDataSource: useDataSource,
1925
+ useEditor: useEditor,
1926
+ useSxpDataSource: useSxpDataSource
1927
+ });
1928
+
1762
1929
  const DataSourceContext = React.createContext({ $store: {}, options: [], configs: [] });
1763
1930
  const DataSourceProvider = ({ children, isSsr, enable }) => {
1764
1931
  const [options, setOptions] = React.useState([]);
@@ -10538,7 +10705,7 @@
10538
10705
  *
10539
10706
  */
10540
10707
  const closeIcon$1 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAjhJREFUWEfFlztOw0AQhmeWiJ4CCmpQ5DiRQsIJyAWg5A0lR0AIChDiCJS8ER0cADgBeRSxt4CCDgkaKiq8i+zYeWx2413HEWmiJJv9v535Z2aN8M8vFPT9z3zETD0aAUChUJjwvPFHAJhBhB3Hqd6OAsK2yyucwykAvP38eJX398Z3AJDLlVYR8ToU9Rhj25TWr9KEsKy5dULIGQCMtfZly45TvwsAstm56UwG6wA4FUFwzrdctxZBDcWSy5XWEPG8I84/GcMipdWPtgcsaz5PCHtKG0IuTiqUvjT9U/WYMG2IOPE+AP+LtCB0xKUAAyA2Xbd2o2OG0NQXvTnvhL17D7EPtH9TRCIWwkRcGYGIQgYBABuqPuHXOQBc6pw80lBGwBQiiXhsBHQhkoprA6iM6acjhDQKu5YJZW6XeOI3XJdpvfsdTu52VfXEekD8owQiXGIubpSCbhDbLu8DwKEAd+A41SOdPpE4BS0viFOtvV2iKWqUgn5x/tmS70xR01GuDSCKc86/OCcLgTyyZ0ScDGNhFAktAJV4NFJ9YyaFiAWIE+9uVkkgBgLoig8DMWAa9ro9ynkUdlW5maZDCmB6clmz0k1HH4Cs1Ezbq2p2yEpUuBOKTSZZex00RUWIrltxuuK6EOGDSbGIOPZicpMx6fny650377qNRgBgWeVFQuA+6UjVgREhGIMlSqsPUQqIbZdOOIdZQmCv2axRnU1N1+TzJYsxOEaEV8ep7frPZ7Gd0FTEdP0ft0/kMNdg0eoAAAAASUVORK5CYII=';
10541
- const Modal = ({ visible, onClose, children, modalStyle, padding, popup, schema, fullHeight, isFullScreen = false, openState }) => {
10708
+ const Modal = ({ visible, onClose, children, modalStyle, padding, popup, schema, fullHeight, isFullScreen = false, openState, showCloseButton = true }) => {
10542
10709
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
10543
10710
  const { visibleHeight, bottomHeight } = useVisibleHeight();
10544
10711
  const touchRef = React.useRef(null);
@@ -10718,8 +10885,8 @@
10718
10885
  setScrollTop(15 - ((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.scrollTop));
10719
10886
  }
10720
10887
  })), child()),
10721
- React.createElement("button", { className: 'modal-icon-wrapper', role: 'button', "aria-label": 'close button', onClick: onClose, style: { top: scrollTop } },
10722
- React.createElement("img", { src: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.popupCloseIcon) || closeIcon$1, alt: 'close button', className: 'modal-icon' }))))))), modalEleRef.current);
10888
+ showCloseButton && (React.createElement("button", { className: 'modal-icon-wrapper', role: 'button', "aria-label": 'close button', onClick: onClose, style: { top: scrollTop } },
10889
+ React.createElement("img", { src: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.popupCloseIcon) || closeIcon$1, alt: 'close button', className: 'modal-icon' })))))))), modalEleRef.current);
10723
10890
  };
10724
10891
  var Modal$1 = React.memo(Modal);
10725
10892
 
@@ -11907,18 +12074,248 @@
11907
12074
  }
11908
12075
  ];
11909
12076
 
12077
+ const AddToCartPopup$1 = ({ isActive = true }) => {
12078
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
12079
+ const { popupDetailData, globalConfig } = useSxpDataSource();
12080
+ const [productData, setProductData] = React.useState(null);
12081
+ const [selectedOptions, setSelectedOptions] = React.useState({});
12082
+ const [selectedVariant, setSelectedVariant] = React.useState(null);
12083
+ const [quantity, setQuantity] = React.useState(1);
12084
+ const [loading, setLoading] = React.useState(true);
12085
+ const [error, setError] = React.useState(null);
12086
+ const [showImagePreview, setShowImagePreview] = React.useState(false);
12087
+ const [previewImageUrl, setPreviewImageUrl] = React.useState('');
12088
+ // 获取商品数据
12089
+ const data = popupDetailData;
12090
+ 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;
12091
+ // Shopify 配置
12092
+ const shopifyConfig = window.__SHOPIFY_CONFIG__;
12093
+ 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';
12094
+ 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';
12095
+ const productId = (product === null || product === void 0 ? void 0 : product.shopifyId) || (product === null || product === void 0 ? void 0 : product.itemId) || '';
12096
+ // 查询 Shopify 商品数据
12097
+ const fetchProductData = React.useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
12098
+ var _k;
12099
+ if (!productId || !shopifyDomain || !storefrontToken) {
12100
+ setLoading(false);
12101
+ return;
12102
+ }
12103
+ setLoading(true);
12104
+ setError(null);
12105
+ try {
12106
+ const query = `
12107
+ query getProduct($id: ID!) {
12108
+ product(id: $id) {
12109
+ id
12110
+ title
12111
+ images(first: 10) {
12112
+ edges {
12113
+ node {
12114
+ url
12115
+ }
12116
+ }
12117
+ }
12118
+ options {
12119
+ name
12120
+ values
12121
+ }
12122
+ variants(first: 100) {
12123
+ edges {
12124
+ node {
12125
+ id
12126
+ title
12127
+ availableForSale
12128
+ quantityAvailable
12129
+ price {
12130
+ amount
12131
+ currencyCode
12132
+ }
12133
+ image {
12134
+ url
12135
+ }
12136
+ selectedOptions {
12137
+ name
12138
+ value
12139
+ }
12140
+ }
12141
+ }
12142
+ }
12143
+ }
12144
+ }
12145
+ `;
12146
+ const fullProductId = productId.startsWith('gid://') ? productId : `gid://shopify/Product/${productId}`;
12147
+ const response = yield fetch(`https://${shopifyDomain}/api/2024-01/graphql.json`, {
12148
+ method: 'POST',
12149
+ headers: {
12150
+ 'Content-Type': 'application/json',
12151
+ 'X-Shopify-Storefront-Access-Token': storefrontToken
12152
+ },
12153
+ body: JSON.stringify({
12154
+ query,
12155
+ variables: { id: fullProductId }
12156
+ })
12157
+ });
12158
+ const result = yield response.json();
12159
+ if (result.errors) {
12160
+ throw new Error(result.errors[0].message);
12161
+ }
12162
+ console.log('[AddToCart] Shopify Product Data:', result.data.product);
12163
+ console.log('[AddToCart] Options:', (_k = result.data.product) === null || _k === void 0 ? void 0 : _k.options);
12164
+ setProductData(result.data.product);
12165
+ }
12166
+ catch (err) {
12167
+ setError(err instanceof Error ? err.message : 'Failed to load product');
12168
+ console.error('[AddToCartPopup] 加载失败:', err);
12169
+ }
12170
+ finally {
12171
+ setLoading(false);
12172
+ }
12173
+ }), [productId, shopifyDomain, storefrontToken]);
12174
+ React.useEffect(() => {
12175
+ if (isActive) {
12176
+ fetchProductData();
12177
+ }
12178
+ }, [isActive, fetchProductData]);
12179
+ // 根据选中的规格匹配 variant
12180
+ React.useEffect(() => {
12181
+ if (!productData)
12182
+ return;
12183
+ const variants = productData.variants.edges.map(edge => edge.node);
12184
+ const optionsCount = productData.options.length;
12185
+ const selectedCount = Object.keys(selectedOptions).length;
12186
+ if (selectedCount === 0 || selectedCount < optionsCount) {
12187
+ setSelectedVariant(null);
12188
+ return;
12189
+ }
12190
+ const matchedVariant = variants.find(variant => {
12191
+ return variant.selectedOptions.every(option => {
12192
+ return selectedOptions[option.name] === option.value;
12193
+ });
12194
+ });
12195
+ setSelectedVariant(matchedVariant || null);
12196
+ // 当 variant 改变时,如果有库存数量限制,确保数量不超过库存
12197
+ if ((matchedVariant === null || matchedVariant === void 0 ? void 0 : matchedVariant.quantityAvailable) !== undefined && matchedVariant.quantityAvailable > 0) {
12198
+ setQuantity(prev => Math.min(prev, matchedVariant.quantityAvailable));
12199
+ }
12200
+ }, [selectedOptions, productData]);
12201
+ // 处理规格选择
12202
+ const handleOptionSelect = (optionName, value) => {
12203
+ setSelectedOptions(prev => (Object.assign(Object.assign({}, prev), { [optionName]: value })));
12204
+ };
12205
+ // 处理加购
12206
+ const handleAddToCart = () => {
12207
+ if (!selectedVariant) {
12208
+ alert('Please select all options');
12209
+ return;
12210
+ }
12211
+ // 提取 variant ID(去掉 gid://shopify/ProductVariant/ 前缀)
12212
+ const variantId = selectedVariant.id.replace('gid://shopify/ProductVariant/', '');
12213
+ console.log('[AddToCart] 添加到购物车:', {
12214
+ variantId,
12215
+ quantity,
12216
+ shopifyDomain,
12217
+ selectedVariant
12218
+ });
12219
+ // 使用 Shopify 的 /cart/add 接口,通过查询参数添加商品
12220
+ // 这种方式会跳转到购物车页面而不是结算页面
12221
+ const params = new URLSearchParams({
12222
+ id: variantId,
12223
+ quantity: quantity.toString()
12224
+ });
12225
+ const cartUrl = `https://${shopifyDomain}/cart/add?${params.toString()}`;
12226
+ console.log('[AddToCart] 跳转到购物车 URL:', cartUrl);
12227
+ window.location.href = cartUrl;
12228
+ };
12229
+ // 计算总价
12230
+ const totalPrice = selectedVariant
12231
+ ? (parseFloat(selectedVariant.price.amount) * quantity).toFixed(2)
12232
+ : '0.00';
12233
+ if (loading) {
12234
+ return (React.createElement("div", { className: 'add-to-cart-popup' },
12235
+ React.createElement("div", { className: 'loading' }, "Loading...")));
12236
+ }
12237
+ if (error) {
12238
+ return (React.createElement("div", { className: 'add-to-cart-popup' },
12239
+ React.createElement("div", { className: 'error' }, error)));
12240
+ }
12241
+ if (!productData) {
12242
+ return null;
12243
+ }
12244
+ const mainImage = ((_h = productData.images.edges[0]) === null || _h === void 0 ? void 0 : _h.node.url) || '';
12245
+ const variantImage = ((_j = selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.image) === null || _j === void 0 ? void 0 : _j.url) || mainImage;
12246
+ const maxQuantity = (selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.quantityAvailable) || 999; // 如果没有库存数据,默认允许最多 999
12247
+ return (React.createElement("div", { className: 'add-to-cart-popup' },
12248
+ React.createElement("div", { className: 'popup-content' },
12249
+ React.createElement("div", { className: 'product-header' },
12250
+ React.createElement("div", { className: 'product-title' }, productData.title)),
12251
+ React.createElement("div", { className: 'variant-detail' },
12252
+ React.createElement("div", { className: 'variant-image-container', onClick: () => {
12253
+ if (variantImage) {
12254
+ setPreviewImageUrl(variantImage);
12255
+ setShowImagePreview(true);
12256
+ }
12257
+ }, style: { cursor: 'pointer' } },
12258
+ React.createElement("img", { src: variantImage, alt: 'Selected variant', className: 'variant-image' })),
12259
+ React.createElement("div", { className: 'variant-info' },
12260
+ React.createElement("div", { className: 'variant-specs-row' },
12261
+ 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"))),
12262
+ selectedVariant && selectedVariant.quantityAvailable !== undefined && (React.createElement("div", { className: 'stock-info' },
12263
+ "Available: ",
12264
+ selectedVariant.quantityAvailable))),
12265
+ React.createElement("div", { className: 'variant-price-row' },
12266
+ React.createElement("div", { className: 'price' },
12267
+ "$",
12268
+ totalPrice),
12269
+ React.createElement("div", { className: 'quantity-selector' },
12270
+ React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1 }, "\u2212"),
12271
+ React.createElement("span", { className: 'qty-value' }, quantity),
12272
+ React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(quantity + 1), disabled: !selectedVariant || quantity >= maxQuantity }, "+"))))),
12273
+ React.createElement("div", { className: 'variant-options' }, productData.options.map(option => (React.createElement("div", { key: option.name, className: 'option-group' },
12274
+ React.createElement("div", { className: 'option-label' }, option.name),
12275
+ React.createElement("div", { className: 'option-values' }, option.values.map(value => {
12276
+ // 检查这个选项是否可选(availableForSale = true,如果有 quantityAvailable 则还需 > 0)
12277
+ const isAvailable = productData.variants.edges.some(({ node: variant }) => {
12278
+ const hasThisOption = variant.selectedOptions.some(opt => opt.name === option.name && opt.value === value);
12279
+ if (!hasThisOption || !variant.availableForSale)
12280
+ return false;
12281
+ // 如果有 quantityAvailable 字段,则需要检查库存
12282
+ if (variant.quantityAvailable !== undefined) {
12283
+ return variant.quantityAvailable > 0;
12284
+ }
12285
+ // 没有 quantityAvailable 字段时,只要 availableForSale 为 true 就可选
12286
+ return true;
12287
+ });
12288
+ const isSelected = selectedOptions[option.name] === value;
12289
+ return (React.createElement("button", { key: value, className: `option-btn ${isSelected ? 'selected' : ''} ${!isAvailable ? 'disabled' : ''}`, onClick: () => isAvailable && handleOptionSelect(option.name, value), disabled: !isAvailable }, value));
12290
+ }))))))),
12291
+ React.createElement("div", { className: 'popup-footer' },
12292
+ React.createElement("button", { className: 'add-to-cart-btn', onClick: handleAddToCart, disabled: !selectedVariant }, "Add To Cart")),
12293
+ showImagePreview && previewImageUrl && (React.createElement(Modal$1, { visible: showImagePreview, padding: 0, isFullScreen: true, onClose: () => setShowImagePreview(false) },
12294
+ React.createElement("div", { style: {
12295
+ width: '100%',
12296
+ height: '100%',
12297
+ display: 'flex',
12298
+ alignItems: 'center',
12299
+ justifyContent: 'center',
12300
+ backgroundColor: 'rgba(0, 0, 0, 0.9)'
12301
+ }, onClick: () => setShowImagePreview(false) },
12302
+ React.createElement("img", { src: previewImageUrl, alt: 'Preview', style: {
12303
+ maxWidth: '100%',
12304
+ maxHeight: '100%',
12305
+ objectFit: 'contain'
12306
+ } }))))));
12307
+ };
12308
+
11910
12309
  const CommodityDetailDiroNew$1 = (_a) => {
11911
- var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4;
11912
- var { style, 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"]);
11913
- React.useState(true);
11914
- const { sxpParameter, popupCurTimeRef, popupDetailData, isPreview, bffFbReport, checkCommodityIndexRef, globalConfig, ctaEvent } = useSxpDataSource();
11915
- const { jumpToWeb, productView } = useEventReport();
11916
- React.useState(false);
11917
- React.useState(false);
11918
- React.useState(true);
12310
+ 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;
12311
+ 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"]);
12312
+ const { sxpParameter, popupCurTimeRef, popupDetailData, setPopupDetailData, isPreview, bffFbReport, checkCommodityIndexRef, globalConfig, ctaEvent } = useSxpDataSource();
12313
+ useEditor();
12314
+ const { productView } = useEventReport();
11919
12315
  const [showModal, setShowModal] = React.useState(false);
11920
12316
  const curTimeRef = React.useRef(null);
11921
12317
  const [show3DModal, setShow3DModal] = React.useState(false);
12318
+ const [showAddToCart, setShowAddToCart] = React.useState(false);
11922
12319
  const [checkCommodityIndex, setCheckCommodityIndex] = React.useState((_b = popupDetailData === null || popupDetailData === void 0 ? void 0 : popupDetailData.multiCheckIndex) !== null && _b !== void 0 ? _b : 0);
11923
12320
  const swiperRef = React.useRef();
11924
12321
  const [swiperActiveIndex, setSwiperActiveIndex] = React.useState(0);
@@ -11935,30 +12332,30 @@
11935
12332
  cta = p === null || p === void 0 ? void 0 : p.bindCta;
11936
12333
  }
11937
12334
  const handleLink = (e) => {
11938
- if (product === null || product === void 0 ? void 0 : product.link) {
11939
- jumpToWeb(e, data, product, cta, position);
11940
- if (!isPost) {
11941
- productView(data, product, cta, viewTime || curTimeRef.current, position);
11942
- }
11943
- else {
11944
- ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
11945
- eventSubject: 'clickCta',
11946
- eventDescription: 'User clicked the CTA'
11947
- }, data, product, position);
11948
- bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
11949
- eventName: 'ClickCTA',
11950
- product: product ? [product] : undefined,
11951
- contentType: 'product',
11952
- data,
11953
- position,
11954
- cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
11955
- cta_action_type: 'open_external_link',
11956
- target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
11957
- target_url: product.link
11958
- });
11959
- }
11960
- window.location.href = window.getJointUtmLink(product.link);
12335
+ e.preventDefault();
12336
+ // 上报点击事件
12337
+ ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
12338
+ eventSubject: 'clickCta',
12339
+ eventDescription: 'User clicked the CTA'
12340
+ }, data, product, position);
12341
+ bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
12342
+ eventName: 'ClickCTA',
12343
+ product: product ? [product] : undefined,
12344
+ contentType: 'product',
12345
+ data,
12346
+ position,
12347
+ cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
12348
+ cta_action_type: 'open_internal_popup',
12349
+ target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
12350
+ target_url: product === null || product === void 0 ? void 0 : product.link
12351
+ });
12352
+ if (!isPost) {
12353
+ productView(data, product, cta, viewTime || curTimeRef.current, position);
11961
12354
  }
12355
+ // 更新 popupDetailData,确保 AddToCart 组件能获取到商品数据
12356
+ 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 }));
12357
+ // 打开 AddToCart 弹窗
12358
+ setShowAddToCart(true);
11962
12359
  };
11963
12360
  React.useEffect(() => {
11964
12361
  var _a, _b;
@@ -11979,7 +12376,7 @@
11979
12376
  rec: recData,
11980
12377
  position
11981
12378
  });
11982
- }, [isActive, bffFbReport, isPost]);
12379
+ }, [isActive, bffFbReport, isPost, data, product, position]);
11983
12380
  React.useEffect(() => {
11984
12381
  if (!isActive || isPost)
11985
12382
  return;
@@ -12107,13 +12504,13 @@ Made in Italy` })));
12107
12504
  swiperRef.current.swiper.slideTo(0);
12108
12505
  swiperRef.current.swiper.autoplay.start();
12109
12506
  }
12110
- }, []);
12507
+ }, [popupCurTimeRef, checkCommodityIndexRef]);
12111
12508
  const renderCommodityGroup = React.useCallback(() => {
12112
12509
  var _a, _b, _c;
12113
12510
  if (isPost)
12114
12511
  return;
12115
12512
  return (React.createElement(CommodityGroup$1, { products: (_a = data === null || data === void 0 ? void 0 : data.video) === null || _a === void 0 ? void 0 : _a.bindProducts, data: commodityGroup, defImg: (_c = (_b = sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.bottom_image) !== null && _b !== void 0 ? _b : bottom_image) !== null && _c !== void 0 ? _c : '', style: { padding: '0 19px' }, onCLick: handleClick, popupDetailData: popupDetailData, check: checkCommodityIndex }));
12116
- }, [checkCommodityIndex]);
12513
+ }, [checkCommodityIndex, isPost, (_w = data === null || data === void 0 ? void 0 : data.video) === null || _w === void 0 ? void 0 : _w.bindProducts, commodityGroup, sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.bottom_image, bottom_image, handleClick, popupDetailData]);
12117
12514
  const getDotsAlign = React.useMemo(() => {
12118
12515
  const dotsAlignClass = {
12119
12516
  left: 'commondityDetail-swiper-clickable-left',
@@ -12123,24 +12520,24 @@ Made in Italy` })));
12123
12520
  return dotsAlignClass === null || dotsAlignClass === void 0 ? void 0 : dotsAlignClass[swiper === null || swiper === void 0 ? void 0 : swiper.dotsAlign];
12124
12521
  }, [swiper === null || swiper === void 0 ? void 0 : swiper.dotsAlign]);
12125
12522
  const iframeUrl = product === null || product === void 0 ? void 0 : product.remark;
12523
+ const isAlly = React.useMemo(() => getScreenReader(), []);
12126
12524
  const handleMouseEnter = React.useCallback(() => {
12127
12525
  if (swiperRef.current && swiperRef.current.swiper && isAlly) {
12128
12526
  swiperRef.current.swiper.autoplay.stop();
12129
12527
  }
12130
- }, []);
12528
+ }, [isAlly]);
12131
12529
  const handleMouseLeave = React.useCallback(() => {
12132
12530
  if (swiperRef.current && swiperRef.current.swiper && isAlly) {
12133
12531
  swiperRef.current.swiper.autoplay.start();
12134
12532
  }
12135
- }, []);
12533
+ }, [isAlly]);
12136
12534
  const handleSlideChange = React.useCallback((swiper) => {
12137
12535
  setSwiperActiveIndex(swiper.activeIndex);
12138
12536
  }, []);
12139
- const isAlly = React.useMemo(() => getScreenReader(), []);
12140
12537
  return (React.createElement("div", { className: 'pb-commondityDiroNew' },
12141
12538
  React.createElement("div", Object.assign({ className: css.css(Object.assign(Object.assign({}, style), { transform: 'translate3d(0px, 0px, 0px)' })) }, props),
12142
12539
  React.createElement("div", { style: { position: 'relative' }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave },
12143
- 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: {
12540
+ product && ((_x = product === null || product === void 0 ? void 0 : product.homePage) === null || _x === void 0 ? void 0 : _x.length) > 0 && (React.createElement(Swiper, Object.assign({ height: height, modules: [Pagination, Autoplay, ...(isAlly ? [Navigation, A11y, Mousewheel, Keyboard] : [])], pagination: {
12144
12541
  clickable: true,
12145
12542
  bulletActiveClass: 'swipe-item-active-bullet',
12146
12543
  clickableClass: getDotsAlign,
@@ -12157,7 +12554,7 @@ Made in Italy` })));
12157
12554
  : {}), { loop: true, ref: swiperRef, onSlideChange: handleSlideChange, autoplay: {
12158
12555
  delay: (swiper === null || swiper === void 0 ? void 0 : swiper.delay) * 1000
12159
12556
  }, className: css.css(Object.assign(Object.assign({ '.swiper-pagination': {
12160
- bottom: (_x = swiper === null || swiper === void 0 ? void 0 : swiper.dotsMarginBottom) !== null && _x !== void 0 ? _x : 0,
12557
+ bottom: (_y = swiper === null || swiper === void 0 ? void 0 : swiper.dotsMarginBottom) !== null && _y !== void 0 ? _y : 0,
12161
12558
  fontSize: '14px'
12162
12559
  } }, ((swiper === null || swiper === void 0 ? void 0 : swiper.dotsBgColor) && {
12163
12560
  '.swiper-pagination-bullet': {
@@ -12169,7 +12566,7 @@ Made in Italy` })));
12169
12566
  backgroundColor: `${swiper === null || swiper === void 0 ? void 0 : swiper.dotsActiveColor}!important`,
12170
12567
  opacity: 1
12171
12568
  }
12172
- }))) }), (_y = product === null || product === void 0 ? void 0 : product.homePage) === null || _y === void 0 ? void 0 : _y.map((src, srcKey) => {
12569
+ }))) }), (_z = product === null || product === void 0 ? void 0 : product.homePage) === null || _z === void 0 ? void 0 : _z.map((src, srcKey) => {
12173
12570
  var _a;
12174
12571
  return (React.createElement(SwiperSlide, { key: srcKey, "aria-hidden": srcKey !== swiperActiveIndex },
12175
12572
  React.createElement("div", { style: {
@@ -12185,7 +12582,7 @@ Made in Italy` })));
12185
12582
  objectPosition: `50% ${(swiper === null || swiper === void 0 ? void 0 : swiper.translateY) ? (swiper === null || swiper === void 0 ? void 0 : swiper.translateY) + 50 : 50}%`
12186
12583
  }, src: (_a = src !== null && src !== void 0 ? src : sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.bottom_image) !== null && _a !== void 0 ? _a : bottom_image }))));
12187
12584
  }))),
12188
- !((_z = product === null || product === void 0 ? void 0 : product.homePage) === null || _z === void 0 ? void 0 : _z.length) && (React.createElement("div", { className: css.css({
12585
+ !((_0 = product === null || product === void 0 ? void 0 : product.homePage) === null || _0 === void 0 ? void 0 : _0.length) && (React.createElement("div", { className: css.css({
12189
12586
  height,
12190
12587
  width
12191
12588
  }) },
@@ -12193,7 +12590,7 @@ Made in Italy` })));
12193
12590
  objectFit: 'cover',
12194
12591
  width: '100%',
12195
12592
  height: '100%'
12196
- }), src: (_0 = sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.bottom_image) !== null && _0 !== void 0 ? _0 : bottom_image, alt: 'pdp image' }))),
12593
+ }), src: (_1 = sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.bottom_image) !== null && _1 !== void 0 ? _1 : bottom_image, alt: 'pdp image' }))),
12197
12594
  (iframeUrl || !product) && iframeIcon && (React.createElement("div", { style: {
12198
12595
  display: 'flex',
12199
12596
  alignItems: 'center',
@@ -12210,7 +12607,7 @@ Made in Italy` })));
12210
12607
  React.createElement("div", { className: 'pb-commondityDiroNew-content-top' },
12211
12608
  React.createElement("div", { className: 'pb-commondityDiroNew-content-top-left' },
12212
12609
  React.createElement("div", { className: 'pb-commondityDiroNew-content-top-left-title', style: getStyle(commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.title), dangerouslySetInnerHTML: {
12213
- __html: setFontForText((_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)
12610
+ __html: setFontForText((_2 = product === null || product === void 0 ? void 0 : product.title) !== null && _2 !== void 0 ? _2 : 'Large Dior Toujours BagLarge', commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.title)
12214
12611
  } }),
12215
12612
  React.createElement("div", { className: 'pb-commondityDiroNew-content-collection', hidden: !!product && (!(product === null || product === void 0 ? void 0 : product.collection) || (product === null || product === void 0 ? void 0 : product.collection) === ''), style: getStyle(commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.collection), dangerouslySetInnerHTML: {
12216
12613
  __html: setFontForText((product === null || product === void 0 ? void 0 : product.collection) || 'Black Macrocannage CalfskinLarge', commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.collection)
@@ -12220,11 +12617,11 @@ Made in Italy` })));
12220
12617
  __html: priceText !== null && priceText !== void 0 ? priceText : ''
12221
12618
  } }),
12222
12619
  React.createElement("div", { className: 'pb-commondityDiroNew-content-top-right-price', hidden: !!product && !(product === null || product === void 0 ? void 0 : product.taxInfo), style: getStyle(commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.taxInfo), dangerouslySetInnerHTML: {
12223
- __html: setFontForText((_2 = product === null || product === void 0 ? void 0 : product.taxInfo) !== null && _2 !== void 0 ? _2 : '税费', commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.taxInfo)
12620
+ __html: setFontForText((_3 = product === null || product === void 0 ? void 0 : product.taxInfo) !== null && _3 !== void 0 ? _3 : '税费', commodityStyles === null || commodityStyles === void 0 ? void 0 : commodityStyles.taxInfo)
12224
12621
  } }))),
12225
- 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 },
12622
+ React.createElement("a", { "aria-label": (_4 = cta === null || cta === void 0 ? void 0 : cta.enTitle) !== null && _4 !== void 0 ? _4 : 'Shop now', role: 'button', tabIndex: 0, onClick: handleLink, className: 'pb-commondityDiroNew-btn', style: buttonStyle },
12226
12623
  React.createElement("span", { dangerouslySetInnerHTML: {
12227
- __html: setFontForText((_4 = cta === null || cta === void 0 ? void 0 : cta.enTitle) !== null && _4 !== void 0 ? _4 : 'Shop now', buttonStyle)
12624
+ __html: setFontForText((_5 = cta === null || cta === void 0 ? void 0 : cta.enTitle) !== null && _5 !== void 0 ? _5 : 'Shop now', buttonStyle)
12228
12625
  } })),
12229
12626
  productInfoText({ isPost }))),
12230
12627
  React.createElement(Modal$1, { visible: showModal, onClose: () => setShowModal(false) },
@@ -12236,7 +12633,9 @@ Made in Italy` })));
12236
12633
  height: 'calc(100% - 50px)',
12237
12634
  marginTop: '50px',
12238
12635
  border: 'none'
12239
- } })))));
12636
+ } }))),
12637
+ showAddToCart && (React.createElement(Modal$1, { visible: showAddToCart, padding: 0, isFullScreen: false, onClose: () => setShowAddToCart(false) },
12638
+ React.createElement(AddToCartPopup$1, { isActive: true })))));
12240
12639
  };
12241
12640
  var CommodityDetailDiroNewComponent = React.memo(CommodityDetailDiroNew$1);
12242
12641
 
@@ -13238,296 +13637,6 @@ Made in Italy` })));
13238
13637
  React.createElement("li", null, "\u65E0\u5E93\u5B58\u6216\u4E0D\u53EF\u552E\u5356\u7684\u89C4\u683C\u81EA\u52A8\u7F6E\u7070\u4E0D\u53EF\u9009"))));
13239
13638
  };
13240
13639
 
13241
- const AddToCartPopup$1 = (_a) => {
13242
- var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
13243
- var { style, isActive = true, index, shopifyDomain = '', storefrontAccessToken = '', variantStyles = {}, buttonStyle = {}, quantityStyle = {}, texts = {}, popupBg = {} } = _a, props = __rest(_a, ["style", "isActive", "index", "shopifyDomain", "storefrontAccessToken", "variantStyles", "buttonStyle", "quantityStyle", "texts", "popupBg"]);
13244
- const { sxpParameter, popupDetailData, isPreview, bffFbReport, globalConfig } = useSxpDataSource();
13245
- useEventReport();
13246
- const curTimeRef = React.useRef(null);
13247
- const [productData, setProductData] = React.useState(null);
13248
- const [selectedOptions, setSelectedOptions] = React.useState({});
13249
- const [selectedVariant, setSelectedVariant] = React.useState(null);
13250
- const [quantity, setQuantity] = React.useState(1);
13251
- const [loading, setLoading] = React.useState(true);
13252
- const [error, setError] = React.useState(null);
13253
- // 获取当前弹窗商品数据(自动从 popupDetailData 获取)
13254
- const data = popupDetailData;
13255
- const product = (_c = (_b = data === null || data === void 0 ? void 0 : data.video) === null || _b === void 0 ? void 0 : _b.bindProduct) !== null && _c !== void 0 ? _c : (_e = (_d = data === null || data === void 0 ? void 0 : data.video) === null || _d === void 0 ? void 0 : _d.bindProducts) === null || _e === void 0 ? void 0 : _e[0];
13256
- product === null || product === void 0 ? void 0 : product.bindCta;
13257
- const position = (_g = (_f = popupDetailData === null || popupDetailData === void 0 ? void 0 : popupDetailData.index) !== null && _f !== void 0 ? _f : index) !== null && _g !== void 0 ? _g : 0;
13258
- // Shopify配置 - 优先级:props > globalConfig > 默认值
13259
- const finalShopifyDomain = shopifyDomain || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.shopifyDomain) || 'dev-store-749237498237498636.myshopify.com';
13260
- const finalStorefrontToken = storefrontAccessToken || (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.storefrontAccessToken) || '77d894c490f79430ce7bd0a7efdff6b7';
13261
- // 自动从商品数据获取 Shopify Product ID
13262
- const productId = (product === null || product === void 0 ? void 0 : product.itemId) || '';
13263
- // 文案
13264
- const finalTexts = {
13265
- addToCart: texts.addToCart || 'Add to Cart',
13266
- selectOptions: texts.selectOptions || 'Please select options',
13267
- loading: texts.loading || 'Loading...',
13268
- error: texts.error || 'Failed to load product',
13269
- color: texts.color || 'Color',
13270
- size: texts.size || 'Size',
13271
- material: texts.material || 'Material',
13272
- style: texts.style || 'Style'
13273
- };
13274
- // 查询Shopify商品数据
13275
- const fetchProductData = React.useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
13276
- var _m;
13277
- if (!productId || !finalShopifyDomain || !finalStorefrontToken) {
13278
- console.log('[AddToCartPopup] 缺少必要配置:', {
13279
- productId,
13280
- shopifyDomain: finalShopifyDomain,
13281
- hasToken: !!finalStorefrontToken
13282
- });
13283
- setLoading(false);
13284
- return;
13285
- }
13286
- console.log('[AddToCartPopup] 开始加载商品数据:', {
13287
- productId,
13288
- shopifyDomain: finalShopifyDomain
13289
- });
13290
- setLoading(true);
13291
- setError(null);
13292
- try {
13293
- const query = `
13294
- query getProduct($id: ID!) {
13295
- product(id: $id) {
13296
- id
13297
- title
13298
- images(first: 10) {
13299
- edges {
13300
- node {
13301
- url
13302
- }
13303
- }
13304
- }
13305
- options {
13306
- name
13307
- values
13308
- }
13309
- variants(first: 100) {
13310
- edges {
13311
- node {
13312
- id
13313
- title
13314
- availableForSale
13315
- quantityAvailable
13316
- price {
13317
- amount
13318
- currencyCode
13319
- }
13320
- image {
13321
- url
13322
- }
13323
- selectedOptions {
13324
- name
13325
- value
13326
- }
13327
- }
13328
- }
13329
- }
13330
- }
13331
- }
13332
- `;
13333
- // 确保 Product ID 格式正确
13334
- const formattedProductId = productId.startsWith('gid://')
13335
- ? productId
13336
- : `gid://shopify/Product/${productId}`;
13337
- console.log('[AddToCartPopup] 使用的 Product ID:', formattedProductId);
13338
- const response = yield fetch(`https://${finalShopifyDomain}/api/2024-01/graphql.json`, {
13339
- method: 'POST',
13340
- headers: {
13341
- 'Content-Type': 'application/json',
13342
- 'X-Shopify-Storefront-Access-Token': finalStorefrontToken
13343
- },
13344
- body: JSON.stringify({
13345
- query,
13346
- variables: { id: formattedProductId }
13347
- })
13348
- });
13349
- if (!response.ok) {
13350
- throw new Error(`HTTP ${response.status}`);
13351
- }
13352
- const result = yield response.json();
13353
- if (result.errors) {
13354
- console.error('[AddToCartPopup] GraphQL 错误:', result.errors);
13355
- throw new Error(result.errors[0].message);
13356
- }
13357
- if (!((_m = result.data) === null || _m === void 0 ? void 0 : _m.product)) {
13358
- console.error('[AddToCartPopup] 未找到商品');
13359
- throw new Error('Product not found');
13360
- }
13361
- console.log('[AddToCartPopup] 商品数据加载成功:', result.data.product.title);
13362
- setProductData(result.data.product);
13363
- }
13364
- catch (err) {
13365
- const errorMessage = err instanceof Error ? err.message : finalTexts.error;
13366
- setError(errorMessage);
13367
- console.error('[AddToCartPopup] 加载失败:', err);
13368
- }
13369
- finally {
13370
- setLoading(false);
13371
- }
13372
- }), [productId, finalShopifyDomain, finalStorefrontToken, finalTexts.error]);
13373
- React.useEffect(() => {
13374
- if (isActive) {
13375
- fetchProductData();
13376
- }
13377
- }, [isActive, fetchProductData]);
13378
- // 根据选中的规格匹配variant
13379
- React.useEffect(() => {
13380
- if (!productData)
13381
- return;
13382
- const variants = productData.variants.edges.map(edge => edge.node);
13383
- const optionsCount = productData.options.length;
13384
- const selectedCount = Object.keys(selectedOptions).length;
13385
- if (selectedCount === 0 || selectedCount < optionsCount) {
13386
- setSelectedVariant(null);
13387
- return;
13388
- }
13389
- const matchedVariant = variants.find(variant => {
13390
- return variant.selectedOptions.every(option => selectedOptions[option.name] === option.value);
13391
- });
13392
- setSelectedVariant(matchedVariant || null);
13393
- setQuantity(1);
13394
- }, [selectedOptions, productData]);
13395
- // 处理规格选择
13396
- const handleOptionSelect = React.useCallback((optionName, value) => {
13397
- setSelectedOptions(prev => {
13398
- const newOptions = Object.assign({}, prev);
13399
- if (newOptions[optionName] === value) {
13400
- delete newOptions[optionName];
13401
- }
13402
- else {
13403
- newOptions[optionName] = value;
13404
- }
13405
- return newOptions;
13406
- });
13407
- }, []);
13408
- // 处理数量变化
13409
- const handleQuantityChange = React.useCallback((delta) => {
13410
- setQuantity(prev => {
13411
- var _a;
13412
- const newQuantity = prev + delta;
13413
- const maxQuantity = (_a = selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.quantityAvailable) !== null && _a !== void 0 ? _a : 999;
13414
- return Math.max(1, Math.min(newQuantity, maxQuantity));
13415
- });
13416
- }, [selectedVariant]);
13417
- // 检查某个规格值是否可用
13418
- const isOptionValueAvailable = React.useCallback((optionName, value) => {
13419
- if (!productData)
13420
- return false;
13421
- const variants = productData.variants.edges.map(edge => edge.node);
13422
- const tempOptions = Object.assign(Object.assign({}, selectedOptions), { [optionName]: value });
13423
- return variants.some(variant => {
13424
- const matches = variant.selectedOptions.every(option => !tempOptions[option.name] || tempOptions[option.name] === option.value);
13425
- const hasStock = variant.quantityAvailable === null || variant.quantityAvailable > 0;
13426
- return matches && variant.availableForSale && hasStock;
13427
- });
13428
- }, [productData, selectedOptions]);
13429
- // 处理加购
13430
- const handleAddToCart = React.useCallback(() => {
13431
- var _a;
13432
- if (!selectedVariant || quantity === 0)
13433
- return;
13434
- const variantId = selectedVariant.id.split('/').pop();
13435
- const cartUrl = `https://${finalShopifyDomain}/cart/add?id=${variantId}&quantity=${quantity}`;
13436
- console.log('[AddToCartPopup] 加购:', {
13437
- variantId,
13438
- quantity,
13439
- cartUrl
13440
- });
13441
- // 上报事件
13442
- bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
13443
- eventName: 'AddToCart',
13444
- product: product ? [product] : undefined,
13445
- contentType: 'product',
13446
- data,
13447
- position,
13448
- content_id: (_a = product === null || product === void 0 ? void 0 : product.itemId) !== null && _a !== void 0 ? _a : '',
13449
- value: parseFloat(selectedVariant.price.amount) * quantity,
13450
- currency: selectedVariant.price.currencyCode,
13451
- contents: [{
13452
- id: variantId,
13453
- quantity
13454
- }]
13455
- });
13456
- // 跳转到Shopify购物车页面
13457
- window.location.href = cartUrl;
13458
- }, [selectedVariant, quantity, finalShopifyDomain, bffFbReport, product, data, position]);
13459
- // 计算总价
13460
- const totalPrice = React.useMemo(() => {
13461
- if (!selectedVariant)
13462
- return null;
13463
- const price = parseFloat(selectedVariant.price.amount);
13464
- const total = price * quantity;
13465
- return total.toFixed(2);
13466
- }, [selectedVariant, quantity]);
13467
- // 初始化时间
13468
- React.useEffect(() => {
13469
- const initTime = () => {
13470
- curTimeRef.current = new Date();
13471
- };
13472
- initTime();
13473
- window.addEventListener('pageshow', initTime);
13474
- return () => {
13475
- window.removeEventListener('pageshow', initTime);
13476
- };
13477
- }, []);
13478
- // 加载中
13479
- if (loading) {
13480
- return (React.createElement("div", { className: "add-to-cart-popup-loading", style: style },
13481
- React.createElement("div", null, finalTexts.loading)));
13482
- }
13483
- // 错误状态
13484
- if (error || !productData) {
13485
- return (React.createElement("div", { className: "add-to-cart-popup-error", style: style },
13486
- React.createElement("div", null,
13487
- finalTexts.error,
13488
- ": ",
13489
- error || 'Product not found')));
13490
- }
13491
- const mainImage = ((_h = selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.image) === null || _h === void 0 ? void 0 : _h.url) || ((_j = productData.images.edges[0]) === null || _j === void 0 ? void 0 : _j.node.url) || ((_k = product === null || product === void 0 ? void 0 : product.homePage) === null || _k === void 0 ? void 0 : _k[0]) || '';
13492
- const hasAllOptionsSelected = productData.options.length === Object.keys(selectedOptions).length;
13493
- const isAddToCartDisabled = !selectedVariant || quantity === 0;
13494
- return (React.createElement("div", Object.assign({ className: "add-to-cart-popup-container", style: style }, props),
13495
- React.createElement("div", { className: "variant-detail-section" },
13496
- React.createElement("div", { className: "variant-image-wrapper" },
13497
- React.createElement("img", { src: mainImage, alt: productData.title, className: "variant-image" })),
13498
- React.createElement("div", { className: "variant-info-wrapper" },
13499
- React.createElement("h2", { className: "product-title-text", style: variantStyles.title, dangerouslySetInnerHTML: {
13500
- __html: setFontForText(productData.title, variantStyles.title)
13501
- } }),
13502
- selectedVariant && (React.createElement(React.Fragment, null,
13503
- React.createElement("div", { className: "selected-options-tags" }, selectedVariant.selectedOptions.map(option => (React.createElement("span", { key: option.name, className: "option-tag", style: variantStyles.selectedOption },
13504
- option.name,
13505
- ": ",
13506
- option.value)))),
13507
- React.createElement("div", { className: "price-display" },
13508
- React.createElement("span", { className: "price-value", style: variantStyles.price, dangerouslySetInnerHTML: {
13509
- __html: setFontForText(`${selectedVariant.price.currencyCode} $${totalPrice}`, variantStyles.price)
13510
- } })),
13511
- React.createElement("div", { className: "quantity-selector-wrapper", style: quantityStyle },
13512
- React.createElement("button", { className: "quantity-btn quantity-decrease", onClick: () => handleQuantityChange(-1), disabled: quantity <= 1, "aria-label": "Decrease quantity" }, "-"),
13513
- React.createElement("input", { type: "number", value: quantity, readOnly: true, className: "quantity-input-field", "aria-label": "Quantity" }),
13514
- React.createElement("button", { className: "quantity-btn quantity-increase", onClick: () => handleQuantityChange(1), disabled: quantity >= ((_l = selectedVariant.quantityAvailable) !== null && _l !== void 0 ? _l : 999), "aria-label": "Increase quantity" }, "+")))),
13515
- !hasAllOptionsSelected && (React.createElement("div", { className: "no-selection-hint", style: variantStyles.option }, finalTexts.selectOptions)))),
13516
- React.createElement("div", { className: "variant-options-section" }, productData.options.map(option => (React.createElement("div", { key: option.name, className: "option-group-wrapper" },
13517
- React.createElement("h3", { className: "option-group-name", style: variantStyles.option, dangerouslySetInnerHTML: {
13518
- __html: setFontForText(option.name, variantStyles.option)
13519
- } }),
13520
- React.createElement("div", { className: "option-values-grid" }, option.values.map(value => {
13521
- const isSelected = selectedOptions[option.name] === value;
13522
- const isAvailable = isOptionValueAvailable(option.name, value);
13523
- return (React.createElement("button", { key: value, className: `option-value-button ${isSelected ? 'selected' : ''} ${!isAvailable ? 'disabled' : ''}`, onClick: () => isAvailable && handleOptionSelect(option.name, value), disabled: !isAvailable, "aria-label": `${option.name}: ${value}`, "aria-pressed": isSelected }, value));
13524
- })))))),
13525
- React.createElement("button", { className: `add-to-cart-button ${isAddToCartDisabled ? 'disabled' : ''}`, style: buttonStyle, onClick: handleAddToCart, disabled: isAddToCartDisabled, "aria-label": finalTexts.addToCart },
13526
- React.createElement("span", { dangerouslySetInnerHTML: {
13527
- __html: setFontForText(finalTexts.addToCart, buttonStyle)
13528
- } }))));
13529
- };
13530
-
13531
13640
  /*
13532
13641
  * @Author: tao
13533
13642
  * @Date: 2026-01-12
@@ -13543,60 +13652,7 @@ Made in Italy` })));
13543
13652
  interactionRender: interactionRender$d
13544
13653
  },
13545
13654
  defaulSetting: {
13546
- props: {
13547
- shopifyDomain: '',
13548
- storefrontAccessToken: '',
13549
- variantStyles: {
13550
- title: {
13551
- color: '#000',
13552
- fontSize: 20,
13553
- fontWeight: 600,
13554
- marginBottom: 12
13555
- },
13556
- price: {
13557
- color: '#000',
13558
- fontSize: 24,
13559
- fontWeight: 700,
13560
- marginBottom: 16
13561
- },
13562
- option: {
13563
- color: '#111',
13564
- fontSize: 16,
13565
- fontWeight: 600,
13566
- marginBottom: 12
13567
- },
13568
- selectedOption: {
13569
- fontSize: 14,
13570
- color: '#374151'
13571
- }
13572
- },
13573
- buttonStyle: {
13574
- backgroundColor: '#000',
13575
- color: '#fff',
13576
- fontSize: 16,
13577
- height: 52,
13578
- fontWeight: 600,
13579
- textAlign: 'center',
13580
- textTransform: 'uppercase'
13581
- },
13582
- quantityStyle: {
13583
- gap: 12
13584
- },
13585
- texts: {
13586
- addToCart: 'Add to Cart',
13587
- selectOptions: 'Please select options',
13588
- loading: 'Loading...',
13589
- error: 'Failed to load product',
13590
- color: 'Color',
13591
- size: 'Size',
13592
- material: 'Material',
13593
- style: 'Style'
13594
- },
13595
- popupBg: {
13596
- horizontalMargin: 0,
13597
- bottomMargin: 0
13598
- }
13599
- },
13655
+ props: {},
13600
13656
  style: {}
13601
13657
  },
13602
13658
  w: 100,
@@ -19692,7 +19748,7 @@ Made in Italy` })));
19692
19748
  return res.json();
19693
19749
  })
19694
19750
  .then((result) => {
19695
- var _a, _b, _c, _d;
19751
+ var _a, _b, _c, _d, _e;
19696
19752
  if (result.code === '0' || result.code === '00000') {
19697
19753
  // 判断数据结构:CMS 模式和普通模式可能不同
19698
19754
  let multiCtaData = null;
@@ -19711,6 +19767,14 @@ Made in Italy` })));
19711
19767
  console.error('[StructurePage] No multiCta data found in response:', result);
19712
19768
  setError(result.message || 'No multiCta data found');
19713
19769
  }
19770
+ // 存储 Shopify 配置信息到 window 对象,供 AddToCart 弹窗使用
19771
+ if ((_e = result.data) === null || _e === void 0 ? void 0 : _e.shopify) {
19772
+ window.__SHOPIFY_CONFIG__ = {
19773
+ domain: result.data.shopify.domain,
19774
+ storefrontAccessToken: result.data.shopify.storefrontAccessToken
19775
+ };
19776
+ console.log('[StructurePage] Shopify config stored:', window.__SHOPIFY_CONFIG__);
19777
+ }
19714
19778
  }
19715
19779
  else {
19716
19780
  setError(result.message || 'Failed to load data');
@@ -19892,7 +19956,13 @@ Made in Italy` })));
19892
19956
  var index$3 = /*#__PURE__*/Object.freeze({
19893
19957
  __proto__: null,
19894
19958
  EditorCore: EditorCore,
19895
- StructurePage: StructurePage
19959
+ Pagebuilder: Pagebuilder,
19960
+ StructurePage: StructurePage,
19961
+ createMaterial: createMaterial,
19962
+ hooks: index$4,
19963
+ localStore: localStore,
19964
+ sessionStore: sessionStore,
19965
+ tool: tool
19896
19966
  });
19897
19967
 
19898
19968
  /*