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/index.js CHANGED
@@ -165,6 +165,14 @@ function uuid(len, radix) {
165
165
  }
166
166
  return uuid.join('');
167
167
  }
168
+ const getIndexByblockType = (type, index) => {
169
+ if (type === 'CommodityCarouselBlock' || type === 'CopyBlock') {
170
+ return 'initial';
171
+ }
172
+ else {
173
+ return index;
174
+ }
175
+ };
168
176
  const generateRandomString = (length) => {
169
177
  let result = '';
170
178
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
@@ -224,6 +232,70 @@ const setFontForText = (textContent, style) => {
224
232
  }
225
233
  return content;
226
234
  };
235
+ function getBrowserInfo() {
236
+ var _a, _b, _c, _d, _e, _f, _g;
237
+ const userAgent = self.navigator.userAgent;
238
+ if (!userAgent)
239
+ return null;
240
+ if (/edge\/([\d\.]+)/i.exec(userAgent))
241
+ return `Edge ${(_a = /edge\/([\d\.]+)/i.exec(userAgent)) === null || _a === void 0 ? void 0 : _a[1]}`;
242
+ if (/edg\/([\d\.]+)/i.exec(userAgent))
243
+ return `Edge(Chromium) ${(_b = /edge\/([\d\.]+)/i.exec(userAgent)) === null || _b === void 0 ? void 0 : _b[1]}`;
244
+ if (/msie/i.test(userAgent))
245
+ return `Internet Explorer ${(_c = /msie ([\d\.]+)/i.exec(userAgent)) === null || _c === void 0 ? void 0 : _c[1]}`;
246
+ if (/Trident/i.test(userAgent))
247
+ return `Internet Explorer ${(_d = /rv:([\d\.]+)/i.exec(userAgent)) === null || _d === void 0 ? void 0 : _d[1]}`;
248
+ if (/chrome/i.test(userAgent))
249
+ return `Chrome ${(_e = /chrome\/([\d\.]+)/i.exec(userAgent)) === null || _e === void 0 ? void 0 : _e[1]}`;
250
+ if (/firefox/i.test(userAgent))
251
+ return `Firefox ${(_f = /firefox\/([\d\.]+)/i.exec(userAgent)) === null || _f === void 0 ? void 0 : _f[1]}`;
252
+ if (/safari/i.test(userAgent))
253
+ return `Safari ${(_g = /version\/([\d\.]+)/i.exec(userAgent)) === null || _g === void 0 ? void 0 : _g[1]}`;
254
+ return null;
255
+ }
256
+ function getSystem() {
257
+ var _a, _b, _c;
258
+ const userAgent = self.navigator.userAgent;
259
+ if (!userAgent)
260
+ return null;
261
+ if (/iphone/i.test(userAgent))
262
+ return `IOS ${(_a = userAgent.match(/OS\s(.*?)\slike/)) === null || _a === void 0 ? void 0 : _a[1]}`;
263
+ if (/android/i.test(userAgent))
264
+ return `Android ${(_b = userAgent.match(/Android\s(.*?)\;/)) === null || _b === void 0 ? void 0 : _b[1]}`;
265
+ if (/windows/i.test(userAgent))
266
+ return `Windows ${(_c = userAgent.match(/Windows\s(.*?)\;/)) === null || _c === void 0 ? void 0 : _c[1]}`;
267
+ if (/mac/i.test(userAgent))
268
+ return 'Mac OS';
269
+ return null;
270
+ }
271
+ function getDevice$1() {
272
+ const userAgent = self.navigator.userAgent;
273
+ if (!userAgent)
274
+ return null;
275
+ if (/iphone/i.test(userAgent))
276
+ return 'iPhone';
277
+ if (/android/i.test(userAgent)) {
278
+ // var index1 = userAgent.indexOf(';');
279
+ // var index2 = userAgent.indexOf(';', index1 + 1);
280
+ // var index3 = userAgent.indexOf(';', index2 + 1);
281
+ // var index4 = userAgent.indexOf(';', index3 + 1);
282
+ // if (index2 !== -1 && index3 !== -1) {
283
+ // var value1 = userAgent.substring(index3 + 1, index4);
284
+ // return `${value1}`;
285
+ // }
286
+ const index1 = userAgent.indexOf('(');
287
+ const index2 = userAgent.indexOf(')');
288
+ if (index1 !== -1 && index2 !== -1) {
289
+ const value = userAgent.substring(index1 + 1, index2);
290
+ return `${value}`;
291
+ }
292
+ }
293
+ if (/windows/i.test(userAgent))
294
+ return 'Windows';
295
+ if (/mac/i.test(userAgent))
296
+ return 'Mac';
297
+ return null;
298
+ }
227
299
  function getCookie(val) {
228
300
  // const expirationDate = new Date();
229
301
  // expirationDate.setDate(expirationDate.getDate() + 100);
@@ -285,6 +357,33 @@ function deleteCookie(name, path = '/', domain = '') {
285
357
  document.cookie = `${name}=; ${expiration}${pathPart}${domainPart}`;
286
358
  console.log(`已尝试删除Cookie: ${name}`);
287
359
  }
360
+ function setCookie(name, value, days = 0, path = '/', domain = '', secure = false, sameSite = 'Lax') {
361
+ let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
362
+ // 设置过期时间
363
+ if (days) {
364
+ const date = new Date();
365
+ date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
366
+ cookieString += `; expires=${date.toUTCString()}`;
367
+ }
368
+ // 设置路径
369
+ if (path) {
370
+ cookieString += `; path=${path}`;
371
+ }
372
+ // 设置域名
373
+ if (domain) {
374
+ cookieString += `; domain=${domain}`;
375
+ }
376
+ // 设置Secure标志
377
+ if (secure) {
378
+ cookieString += '; secure';
379
+ }
380
+ // 设置SameSite属性
381
+ if (sameSite) {
382
+ cookieString += `; samesite=${sameSite}`;
383
+ }
384
+ // 设置Cookie
385
+ document.cookie = cookieString;
386
+ }
288
387
  function getUrlParamByKey(key) {
289
388
  var _a, _b;
290
389
  const queryString = location.search.slice(1);
@@ -300,6 +399,24 @@ function getUrlParamByKey(key) {
300
399
  return (_b = params[key]) !== null && _b !== void 0 ? _b : '';
301
400
  }
302
401
 
402
+ var tool = /*#__PURE__*/Object.freeze({
403
+ __proto__: null,
404
+ deleteCookie: deleteCookie,
405
+ generateRandomString: generateRandomString,
406
+ getBrowserInfo: getBrowserInfo,
407
+ getCookie: getCookie,
408
+ getDevice: getDevice$1,
409
+ getIndexByblockType: getIndexByblockType,
410
+ getScreenReader: getScreenReader,
411
+ getSystem: getSystem,
412
+ getUid: getUid,
413
+ getUrlParamByKey: getUrlParamByKey,
414
+ setCookie: setCookie,
415
+ setFontForText: setFontForText,
416
+ splitUrlParams: splitUrlParams,
417
+ uuid: uuid
418
+ });
419
+
303
420
  function unzip(b64Data) {
304
421
  const strData = atob(b64Data);
305
422
  const charData = strData.split('').map(function (x) {
@@ -484,6 +601,18 @@ const refreshFeSessionId = () => {
484
601
  const getFeSessionId = () => {
485
602
  return window.localStorage.getItem(feRealSessionIdKey);
486
603
  };
604
+ // 删除sessionID
605
+ const removeFeSessionId = () => {
606
+ window.localStorage.removeItem(feRealSessionIdKey);
607
+ };
608
+
609
+ var sessionStore = /*#__PURE__*/Object.freeze({
610
+ __proto__: null,
611
+ getFeSessionId: getFeSessionId,
612
+ refreshFeSessionId: refreshFeSessionId,
613
+ removeFeSessionId: removeFeSessionId,
614
+ storeAndLoadFeSessionId: storeAndLoadFeSessionId
615
+ });
487
616
 
488
617
  /*
489
618
  * @Author: binruan@chatlabs.com
@@ -507,6 +636,9 @@ const storeAndLoadFeUserId = () => {
507
636
  }
508
637
  return fakeUserId;
509
638
  };
639
+ const removeFeUserId = () => {
640
+ window.localStorage.removeItem(FAKE_USER_KEY);
641
+ };
510
642
  const getFeUserState = () => {
511
643
  const fakeUserState = window.localStorage.getItem(FAKE_USER_STATE);
512
644
  if (isEmpty(fakeUserState)) {
@@ -536,6 +668,24 @@ const setUserConsentResult = () => {
536
668
  window.localStorage.setItem(USER_CONSENT_RESULT_KEY, 'true');
537
669
  };
538
670
 
671
+ var localStore = /*#__PURE__*/Object.freeze({
672
+ __proto__: null,
673
+ AGREE_POLICY: AGREE_POLICY,
674
+ CCONTSENT_STATE: CCONTSENT_STATE,
675
+ FAKE_USER_KEY: FAKE_USER_KEY,
676
+ FAKE_USER_STATE: FAKE_USER_STATE,
677
+ SLIDE_SKIP_STATE: SLIDE_SKIP_STATE,
678
+ USER_CONSENT_RESULT_KEY: USER_CONSENT_RESULT_KEY,
679
+ getContsentState: getContsentState,
680
+ getFeUserState: getFeUserState,
681
+ getSlideSkipState: getSlideSkipState,
682
+ getUserConsentResult: getUserConsentResult,
683
+ removeFeUserId: removeFeUserId,
684
+ setSlideSkipState: setSlideSkipState,
685
+ setUserConsentResult: setUserConsentResult,
686
+ storeAndLoadFeUserId: storeAndLoadFeUserId
687
+ });
688
+
539
689
  /*
540
690
  * @Author: binruan@chatlabs.com
541
691
  * @Date: 2024-03-20 10:27:31
@@ -1744,6 +1894,23 @@ var DATA_TYPE;
1744
1894
  DATA_TYPE["ARRAY_NUMBER"] = "array-number";
1745
1895
  })(DATA_TYPE || (DATA_TYPE = {}));
1746
1896
 
1897
+ /*
1898
+ * @Author: binruan@chatlabs.com
1899
+ * @Date: 2024-03-20 10:27:31
1900
+ * @LastEditors: binruan@chatlabs.com
1901
+ * @LastEditTime: 2024-03-20 13:56:49
1902
+ * @FilePath: \pb-sxp-ui\src\core\hooks\index.ts
1903
+ *
1904
+ */
1905
+
1906
+ var index$4 = /*#__PURE__*/Object.freeze({
1907
+ __proto__: null,
1908
+ get DATA_TYPE () { return DATA_TYPE; },
1909
+ useDataSource: useDataSource,
1910
+ useEditor: useEditor,
1911
+ useSxpDataSource: useSxpDataSource
1912
+ });
1913
+
1747
1914
  const DataSourceContext = createContext({ $store: {}, options: [], configs: [] });
1748
1915
  const DataSourceProvider = ({ children, isSsr, enable }) => {
1749
1916
  const [options, setOptions] = useState([]);
@@ -10523,7 +10690,7 @@ function useVisibleHeight() {
10523
10690
  *
10524
10691
  */
10525
10692
  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 }) => {
10693
+ const Modal = ({ visible, onClose, children, modalStyle, padding, popup, schema, fullHeight, isFullScreen = false, openState, showCloseButton = true }) => {
10527
10694
  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
10695
  const { visibleHeight, bottomHeight } = useVisibleHeight();
10529
10696
  const touchRef = useRef(null);
@@ -10703,8 +10870,8 @@ const Modal = ({ visible, onClose, children, modalStyle, padding, popup, schema,
10703
10870
  setScrollTop(15 - ((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.scrollTop));
10704
10871
  }
10705
10872
  })), 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);
10873
+ showCloseButton && (React.createElement("button", { className: 'modal-icon-wrapper', role: 'button', "aria-label": 'close button', onClick: onClose, style: { top: scrollTop } },
10874
+ React.createElement("img", { src: (globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.popupCloseIcon) || closeIcon$1, alt: 'close button', className: 'modal-icon' })))))))), modalEleRef.current);
10708
10875
  };
10709
10876
  var Modal$1 = memo(Modal);
10710
10877
 
@@ -11892,18 +12059,248 @@ var settingRender$d = [
11892
12059
  }
11893
12060
  ];
11894
12061
 
12062
+ const AddToCartPopup$1 = ({ isActive = true }) => {
12063
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
12064
+ const { popupDetailData, globalConfig } = useSxpDataSource();
12065
+ const [productData, setProductData] = useState(null);
12066
+ const [selectedOptions, setSelectedOptions] = useState({});
12067
+ const [selectedVariant, setSelectedVariant] = useState(null);
12068
+ const [quantity, setQuantity] = useState(1);
12069
+ const [loading, setLoading] = useState(true);
12070
+ const [error, setError] = useState(null);
12071
+ const [showImagePreview, setShowImagePreview] = useState(false);
12072
+ const [previewImageUrl, setPreviewImageUrl] = useState('');
12073
+ // 获取商品数据
12074
+ const data = popupDetailData;
12075
+ 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;
12076
+ // Shopify 配置
12077
+ const shopifyConfig = window.__SHOPIFY_CONFIG__;
12078
+ 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';
12079
+ 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';
12080
+ const productId = (product === null || product === void 0 ? void 0 : product.shopifyId) || (product === null || product === void 0 ? void 0 : product.itemId) || '';
12081
+ // 查询 Shopify 商品数据
12082
+ const fetchProductData = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
12083
+ var _k;
12084
+ if (!productId || !shopifyDomain || !storefrontToken) {
12085
+ setLoading(false);
12086
+ return;
12087
+ }
12088
+ setLoading(true);
12089
+ setError(null);
12090
+ try {
12091
+ const query = `
12092
+ query getProduct($id: ID!) {
12093
+ product(id: $id) {
12094
+ id
12095
+ title
12096
+ images(first: 10) {
12097
+ edges {
12098
+ node {
12099
+ url
12100
+ }
12101
+ }
12102
+ }
12103
+ options {
12104
+ name
12105
+ values
12106
+ }
12107
+ variants(first: 100) {
12108
+ edges {
12109
+ node {
12110
+ id
12111
+ title
12112
+ availableForSale
12113
+ quantityAvailable
12114
+ price {
12115
+ amount
12116
+ currencyCode
12117
+ }
12118
+ image {
12119
+ url
12120
+ }
12121
+ selectedOptions {
12122
+ name
12123
+ value
12124
+ }
12125
+ }
12126
+ }
12127
+ }
12128
+ }
12129
+ }
12130
+ `;
12131
+ const fullProductId = productId.startsWith('gid://') ? productId : `gid://shopify/Product/${productId}`;
12132
+ const response = yield fetch(`https://${shopifyDomain}/api/2024-01/graphql.json`, {
12133
+ method: 'POST',
12134
+ headers: {
12135
+ 'Content-Type': 'application/json',
12136
+ 'X-Shopify-Storefront-Access-Token': storefrontToken
12137
+ },
12138
+ body: JSON.stringify({
12139
+ query,
12140
+ variables: { id: fullProductId }
12141
+ })
12142
+ });
12143
+ const result = yield response.json();
12144
+ if (result.errors) {
12145
+ throw new Error(result.errors[0].message);
12146
+ }
12147
+ console.log('[AddToCart] Shopify Product Data:', result.data.product);
12148
+ console.log('[AddToCart] Options:', (_k = result.data.product) === null || _k === void 0 ? void 0 : _k.options);
12149
+ setProductData(result.data.product);
12150
+ }
12151
+ catch (err) {
12152
+ setError(err instanceof Error ? err.message : 'Failed to load product');
12153
+ console.error('[AddToCartPopup] 加载失败:', err);
12154
+ }
12155
+ finally {
12156
+ setLoading(false);
12157
+ }
12158
+ }), [productId, shopifyDomain, storefrontToken]);
12159
+ useEffect(() => {
12160
+ if (isActive) {
12161
+ fetchProductData();
12162
+ }
12163
+ }, [isActive, fetchProductData]);
12164
+ // 根据选中的规格匹配 variant
12165
+ useEffect(() => {
12166
+ if (!productData)
12167
+ return;
12168
+ const variants = productData.variants.edges.map(edge => edge.node);
12169
+ const optionsCount = productData.options.length;
12170
+ const selectedCount = Object.keys(selectedOptions).length;
12171
+ if (selectedCount === 0 || selectedCount < optionsCount) {
12172
+ setSelectedVariant(null);
12173
+ return;
12174
+ }
12175
+ const matchedVariant = variants.find(variant => {
12176
+ return variant.selectedOptions.every(option => {
12177
+ return selectedOptions[option.name] === option.value;
12178
+ });
12179
+ });
12180
+ setSelectedVariant(matchedVariant || null);
12181
+ // 当 variant 改变时,如果有库存数量限制,确保数量不超过库存
12182
+ if ((matchedVariant === null || matchedVariant === void 0 ? void 0 : matchedVariant.quantityAvailable) !== undefined && matchedVariant.quantityAvailable > 0) {
12183
+ setQuantity(prev => Math.min(prev, matchedVariant.quantityAvailable));
12184
+ }
12185
+ }, [selectedOptions, productData]);
12186
+ // 处理规格选择
12187
+ const handleOptionSelect = (optionName, value) => {
12188
+ setSelectedOptions(prev => (Object.assign(Object.assign({}, prev), { [optionName]: value })));
12189
+ };
12190
+ // 处理加购
12191
+ const handleAddToCart = () => {
12192
+ if (!selectedVariant) {
12193
+ alert('Please select all options');
12194
+ return;
12195
+ }
12196
+ // 提取 variant ID(去掉 gid://shopify/ProductVariant/ 前缀)
12197
+ const variantId = selectedVariant.id.replace('gid://shopify/ProductVariant/', '');
12198
+ console.log('[AddToCart] 添加到购物车:', {
12199
+ variantId,
12200
+ quantity,
12201
+ shopifyDomain,
12202
+ selectedVariant
12203
+ });
12204
+ // 使用 Shopify 的 /cart/add 接口,通过查询参数添加商品
12205
+ // 这种方式会跳转到购物车页面而不是结算页面
12206
+ const params = new URLSearchParams({
12207
+ id: variantId,
12208
+ quantity: quantity.toString()
12209
+ });
12210
+ const cartUrl = `https://${shopifyDomain}/cart/add?${params.toString()}`;
12211
+ console.log('[AddToCart] 跳转到购物车 URL:', cartUrl);
12212
+ window.location.href = cartUrl;
12213
+ };
12214
+ // 计算总价
12215
+ const totalPrice = selectedVariant
12216
+ ? (parseFloat(selectedVariant.price.amount) * quantity).toFixed(2)
12217
+ : '0.00';
12218
+ if (loading) {
12219
+ return (React.createElement("div", { className: 'add-to-cart-popup' },
12220
+ React.createElement("div", { className: 'loading' }, "Loading...")));
12221
+ }
12222
+ if (error) {
12223
+ return (React.createElement("div", { className: 'add-to-cart-popup' },
12224
+ React.createElement("div", { className: 'error' }, error)));
12225
+ }
12226
+ if (!productData) {
12227
+ return null;
12228
+ }
12229
+ const mainImage = ((_h = productData.images.edges[0]) === null || _h === void 0 ? void 0 : _h.node.url) || '';
12230
+ const variantImage = ((_j = selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.image) === null || _j === void 0 ? void 0 : _j.url) || mainImage;
12231
+ const maxQuantity = (selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.quantityAvailable) || 999; // 如果没有库存数据,默认允许最多 999
12232
+ return (React.createElement("div", { className: 'add-to-cart-popup' },
12233
+ React.createElement("div", { className: 'popup-content' },
12234
+ React.createElement("div", { className: 'product-header' },
12235
+ React.createElement("div", { className: 'product-title' }, productData.title)),
12236
+ React.createElement("div", { className: 'variant-detail' },
12237
+ React.createElement("div", { className: 'variant-image-container', onClick: () => {
12238
+ if (variantImage) {
12239
+ setPreviewImageUrl(variantImage);
12240
+ setShowImagePreview(true);
12241
+ }
12242
+ }, style: { cursor: 'pointer' } },
12243
+ React.createElement("img", { src: variantImage, alt: 'Selected variant', className: 'variant-image' })),
12244
+ React.createElement("div", { className: 'variant-info' },
12245
+ React.createElement("div", { className: 'variant-specs-row' },
12246
+ 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"))),
12247
+ selectedVariant && selectedVariant.quantityAvailable !== undefined && (React.createElement("div", { className: 'stock-info' },
12248
+ "Available: ",
12249
+ selectedVariant.quantityAvailable))),
12250
+ React.createElement("div", { className: 'variant-price-row' },
12251
+ React.createElement("div", { className: 'price' },
12252
+ "$",
12253
+ totalPrice),
12254
+ React.createElement("div", { className: 'quantity-selector' },
12255
+ React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1 }, "\u2212"),
12256
+ React.createElement("span", { className: 'qty-value' }, quantity),
12257
+ React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(quantity + 1), disabled: !selectedVariant || quantity >= maxQuantity }, "+"))))),
12258
+ React.createElement("div", { className: 'variant-options' }, productData.options.map(option => (React.createElement("div", { key: option.name, className: 'option-group' },
12259
+ React.createElement("div", { className: 'option-label' }, option.name),
12260
+ React.createElement("div", { className: 'option-values' }, option.values.map(value => {
12261
+ // 检查这个选项是否可选(availableForSale = true,如果有 quantityAvailable 则还需 > 0)
12262
+ const isAvailable = productData.variants.edges.some(({ node: variant }) => {
12263
+ const hasThisOption = variant.selectedOptions.some(opt => opt.name === option.name && opt.value === value);
12264
+ if (!hasThisOption || !variant.availableForSale)
12265
+ return false;
12266
+ // 如果有 quantityAvailable 字段,则需要检查库存
12267
+ if (variant.quantityAvailable !== undefined) {
12268
+ return variant.quantityAvailable > 0;
12269
+ }
12270
+ // 没有 quantityAvailable 字段时,只要 availableForSale 为 true 就可选
12271
+ return true;
12272
+ });
12273
+ const isSelected = selectedOptions[option.name] === value;
12274
+ return (React.createElement("button", { key: value, className: `option-btn ${isSelected ? 'selected' : ''} ${!isAvailable ? 'disabled' : ''}`, onClick: () => isAvailable && handleOptionSelect(option.name, value), disabled: !isAvailable }, value));
12275
+ }))))))),
12276
+ React.createElement("div", { className: 'popup-footer' },
12277
+ React.createElement("button", { className: 'add-to-cart-btn', onClick: handleAddToCart, disabled: !selectedVariant }, "Add To Cart")),
12278
+ showImagePreview && previewImageUrl && (React.createElement(Modal$1, { visible: showImagePreview, padding: 0, isFullScreen: true, onClose: () => setShowImagePreview(false) },
12279
+ React.createElement("div", { style: {
12280
+ width: '100%',
12281
+ height: '100%',
12282
+ display: 'flex',
12283
+ alignItems: 'center',
12284
+ justifyContent: 'center',
12285
+ backgroundColor: 'rgba(0, 0, 0, 0.9)'
12286
+ }, onClick: () => setShowImagePreview(false) },
12287
+ React.createElement("img", { src: previewImageUrl, alt: 'Preview', style: {
12288
+ maxWidth: '100%',
12289
+ maxHeight: '100%',
12290
+ objectFit: 'contain'
12291
+ } }))))));
12292
+ };
12293
+
11895
12294
  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);
12295
+ 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;
12296
+ 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"]);
12297
+ const { sxpParameter, popupCurTimeRef, popupDetailData, setPopupDetailData, isPreview, bffFbReport, checkCommodityIndexRef, globalConfig, ctaEvent } = useSxpDataSource();
12298
+ useEditor();
12299
+ const { productView } = useEventReport();
11904
12300
  const [showModal, setShowModal] = useState(false);
11905
12301
  const curTimeRef = useRef(null);
11906
12302
  const [show3DModal, setShow3DModal] = useState(false);
12303
+ const [showAddToCart, setShowAddToCart] = useState(false);
11907
12304
  const [checkCommodityIndex, setCheckCommodityIndex] = useState((_b = popupDetailData === null || popupDetailData === void 0 ? void 0 : popupDetailData.multiCheckIndex) !== null && _b !== void 0 ? _b : 0);
11908
12305
  const swiperRef = useRef();
11909
12306
  const [swiperActiveIndex, setSwiperActiveIndex] = useState(0);
@@ -11920,30 +12317,30 @@ const CommodityDetailDiroNew$1 = (_a) => {
11920
12317
  cta = p === null || p === void 0 ? void 0 : p.bindCta;
11921
12318
  }
11922
12319
  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);
12320
+ e.preventDefault();
12321
+ // 上报点击事件
12322
+ ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
12323
+ eventSubject: 'clickCta',
12324
+ eventDescription: 'User clicked the CTA'
12325
+ }, data, product, position);
12326
+ bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
12327
+ eventName: 'ClickCTA',
12328
+ product: product ? [product] : undefined,
12329
+ contentType: 'product',
12330
+ data,
12331
+ position,
12332
+ cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
12333
+ cta_action_type: 'open_internal_popup',
12334
+ target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
12335
+ target_url: product === null || product === void 0 ? void 0 : product.link
12336
+ });
12337
+ if (!isPost) {
12338
+ productView(data, product, cta, viewTime || curTimeRef.current, position);
11946
12339
  }
12340
+ // 更新 popupDetailData,确保 AddToCart 组件能获取到商品数据
12341
+ 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 }));
12342
+ // 打开 AddToCart 弹窗
12343
+ setShowAddToCart(true);
11947
12344
  };
11948
12345
  useEffect(() => {
11949
12346
  var _a, _b;
@@ -11964,7 +12361,7 @@ const CommodityDetailDiroNew$1 = (_a) => {
11964
12361
  rec: recData,
11965
12362
  position
11966
12363
  });
11967
- }, [isActive, bffFbReport, isPost]);
12364
+ }, [isActive, bffFbReport, isPost, data, product, position]);
11968
12365
  useEffect(() => {
11969
12366
  if (!isActive || isPost)
11970
12367
  return;
@@ -12092,13 +12489,13 @@ Made in Italy` })));
12092
12489
  swiperRef.current.swiper.slideTo(0);
12093
12490
  swiperRef.current.swiper.autoplay.start();
12094
12491
  }
12095
- }, []);
12492
+ }, [popupCurTimeRef, checkCommodityIndexRef]);
12096
12493
  const renderCommodityGroup = useCallback(() => {
12097
12494
  var _a, _b, _c;
12098
12495
  if (isPost)
12099
12496
  return;
12100
12497
  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]);
12498
+ }, [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
12499
  const getDotsAlign = useMemo(() => {
12103
12500
  const dotsAlignClass = {
12104
12501
  left: 'commondityDetail-swiper-clickable-left',
@@ -12108,24 +12505,24 @@ Made in Italy` })));
12108
12505
  return dotsAlignClass === null || dotsAlignClass === void 0 ? void 0 : dotsAlignClass[swiper === null || swiper === void 0 ? void 0 : swiper.dotsAlign];
12109
12506
  }, [swiper === null || swiper === void 0 ? void 0 : swiper.dotsAlign]);
12110
12507
  const iframeUrl = product === null || product === void 0 ? void 0 : product.remark;
12508
+ const isAlly = useMemo(() => getScreenReader(), []);
12111
12509
  const handleMouseEnter = useCallback(() => {
12112
12510
  if (swiperRef.current && swiperRef.current.swiper && isAlly) {
12113
12511
  swiperRef.current.swiper.autoplay.stop();
12114
12512
  }
12115
- }, []);
12513
+ }, [isAlly]);
12116
12514
  const handleMouseLeave = useCallback(() => {
12117
12515
  if (swiperRef.current && swiperRef.current.swiper && isAlly) {
12118
12516
  swiperRef.current.swiper.autoplay.start();
12119
12517
  }
12120
- }, []);
12518
+ }, [isAlly]);
12121
12519
  const handleSlideChange = useCallback((swiper) => {
12122
12520
  setSwiperActiveIndex(swiper.activeIndex);
12123
12521
  }, []);
12124
- const isAlly = useMemo(() => getScreenReader(), []);
12125
12522
  return (React.createElement("div", { className: 'pb-commondityDiroNew' },
12126
12523
  React.createElement("div", Object.assign({ className: css(Object.assign(Object.assign({}, style), { transform: 'translate3d(0px, 0px, 0px)' })) }, props),
12127
12524
  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: {
12525
+ 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
12526
  clickable: true,
12130
12527
  bulletActiveClass: 'swipe-item-active-bullet',
12131
12528
  clickableClass: getDotsAlign,
@@ -12142,7 +12539,7 @@ Made in Italy` })));
12142
12539
  : {}), { loop: true, ref: swiperRef, onSlideChange: handleSlideChange, autoplay: {
12143
12540
  delay: (swiper === null || swiper === void 0 ? void 0 : swiper.delay) * 1000
12144
12541
  }, 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,
12542
+ bottom: (_y = swiper === null || swiper === void 0 ? void 0 : swiper.dotsMarginBottom) !== null && _y !== void 0 ? _y : 0,
12146
12543
  fontSize: '14px'
12147
12544
  } }, ((swiper === null || swiper === void 0 ? void 0 : swiper.dotsBgColor) && {
12148
12545
  '.swiper-pagination-bullet': {
@@ -12154,7 +12551,7 @@ Made in Italy` })));
12154
12551
  backgroundColor: `${swiper === null || swiper === void 0 ? void 0 : swiper.dotsActiveColor}!important`,
12155
12552
  opacity: 1
12156
12553
  }
12157
- }))) }), (_y = product === null || product === void 0 ? void 0 : product.homePage) === null || _y === void 0 ? void 0 : _y.map((src, srcKey) => {
12554
+ }))) }), (_z = product === null || product === void 0 ? void 0 : product.homePage) === null || _z === void 0 ? void 0 : _z.map((src, srcKey) => {
12158
12555
  var _a;
12159
12556
  return (React.createElement(SwiperSlide, { key: srcKey, "aria-hidden": srcKey !== swiperActiveIndex },
12160
12557
  React.createElement("div", { style: {
@@ -12170,7 +12567,7 @@ Made in Italy` })));
12170
12567
  objectPosition: `50% ${(swiper === null || swiper === void 0 ? void 0 : swiper.translateY) ? (swiper === null || swiper === void 0 ? void 0 : swiper.translateY) + 50 : 50}%`
12171
12568
  }, 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
12569
  }))),
12173
- !((_z = product === null || product === void 0 ? void 0 : product.homePage) === null || _z === void 0 ? void 0 : _z.length) && (React.createElement("div", { className: css({
12570
+ !((_0 = product === null || product === void 0 ? void 0 : product.homePage) === null || _0 === void 0 ? void 0 : _0.length) && (React.createElement("div", { className: css({
12174
12571
  height,
12175
12572
  width
12176
12573
  }) },
@@ -12178,7 +12575,7 @@ Made in Italy` })));
12178
12575
  objectFit: 'cover',
12179
12576
  width: '100%',
12180
12577
  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' }))),
12578
+ }), src: (_1 = sxpParameter === null || sxpParameter === void 0 ? void 0 : sxpParameter.bottom_image) !== null && _1 !== void 0 ? _1 : bottom_image, alt: 'pdp image' }))),
12182
12579
  (iframeUrl || !product) && iframeIcon && (React.createElement("div", { style: {
12183
12580
  display: 'flex',
12184
12581
  alignItems: 'center',
@@ -12195,7 +12592,7 @@ Made in Italy` })));
12195
12592
  React.createElement("div", { className: 'pb-commondityDiroNew-content-top' },
12196
12593
  React.createElement("div", { className: 'pb-commondityDiroNew-content-top-left' },
12197
12594
  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)
12595
+ __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
12596
  } }),
12200
12597
  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
12598
  __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 +12602,11 @@ Made in Italy` })));
12205
12602
  __html: priceText !== null && priceText !== void 0 ? priceText : ''
12206
12603
  } }),
12207
12604
  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)
12605
+ __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
12606
  } }))),
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 },
12607
+ 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
12608
  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)
12609
+ __html: setFontForText((_5 = cta === null || cta === void 0 ? void 0 : cta.enTitle) !== null && _5 !== void 0 ? _5 : 'Shop now', buttonStyle)
12213
12610
  } })),
12214
12611
  productInfoText({ isPost }))),
12215
12612
  React.createElement(Modal$1, { visible: showModal, onClose: () => setShowModal(false) },
@@ -12221,7 +12618,9 @@ Made in Italy` })));
12221
12618
  height: 'calc(100% - 50px)',
12222
12619
  marginTop: '50px',
12223
12620
  border: 'none'
12224
- } })))));
12621
+ } }))),
12622
+ showAddToCart && (React.createElement(Modal$1, { visible: showAddToCart, padding: 0, isFullScreen: false, onClose: () => setShowAddToCart(false) },
12623
+ React.createElement(AddToCartPopup$1, { isActive: true })))));
12225
12624
  };
12226
12625
  var CommodityDetailDiroNewComponent = memo(CommodityDetailDiroNew$1);
12227
12626
 
@@ -13223,296 +13622,6 @@ var interactionRender$d = () => {
13223
13622
  React.createElement("li", null, "\u65E0\u5E93\u5B58\u6216\u4E0D\u53EF\u552E\u5356\u7684\u89C4\u683C\u81EA\u52A8\u7F6E\u7070\u4E0D\u53EF\u9009"))));
13224
13623
  };
13225
13624
 
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
13625
  /*
13517
13626
  * @Author: tao
13518
13627
  * @Date: 2026-01-12
@@ -13528,60 +13637,7 @@ const AddToCartPopup = createMaterial(AddToCartPopup$1, {
13528
13637
  interactionRender: interactionRender$d
13529
13638
  },
13530
13639
  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
- },
13640
+ props: {},
13585
13641
  style: {}
13586
13642
  },
13587
13643
  w: 100,
@@ -19677,7 +19733,7 @@ const StructurePage = (_a) => {
19677
19733
  return res.json();
19678
19734
  })
19679
19735
  .then((result) => {
19680
- var _a, _b, _c, _d;
19736
+ var _a, _b, _c, _d, _e;
19681
19737
  if (result.code === '0' || result.code === '00000') {
19682
19738
  // 判断数据结构:CMS 模式和普通模式可能不同
19683
19739
  let multiCtaData = null;
@@ -19696,6 +19752,14 @@ const StructurePage = (_a) => {
19696
19752
  console.error('[StructurePage] No multiCta data found in response:', result);
19697
19753
  setError(result.message || 'No multiCta data found');
19698
19754
  }
19755
+ // 存储 Shopify 配置信息到 window 对象,供 AddToCart 弹窗使用
19756
+ if ((_e = result.data) === null || _e === void 0 ? void 0 : _e.shopify) {
19757
+ window.__SHOPIFY_CONFIG__ = {
19758
+ domain: result.data.shopify.domain,
19759
+ storefrontAccessToken: result.data.shopify.storefrontAccessToken
19760
+ };
19761
+ console.log('[StructurePage] Shopify config stored:', window.__SHOPIFY_CONFIG__);
19762
+ }
19699
19763
  }
19700
19764
  else {
19701
19765
  setError(result.message || 'Failed to load data');
@@ -19877,7 +19941,13 @@ const StructurePage = (_a) => {
19877
19941
  var index$3 = /*#__PURE__*/Object.freeze({
19878
19942
  __proto__: null,
19879
19943
  EditorCore: EditorCore,
19880
- StructurePage: StructurePage
19944
+ Pagebuilder: Pagebuilder,
19945
+ StructurePage: StructurePage,
19946
+ createMaterial: createMaterial,
19947
+ hooks: index$4,
19948
+ localStore: localStore,
19949
+ sessionStore: sessionStore,
19950
+ tool: tool
19881
19951
  });
19882
19952
 
19883
19953
  /*