pb-sxp-ui 1.20.27 → 1.20.29

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 (35) hide show
  1. package/dist/index.cjs +353 -39
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +353 -39
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.min.cjs +9 -9
  6. package/dist/index.min.cjs.map +1 -1
  7. package/dist/index.min.js +9 -9
  8. package/dist/index.min.js.map +1 -1
  9. package/dist/pb-ui.js +353 -39
  10. package/dist/pb-ui.js.map +1 -1
  11. package/dist/pb-ui.min.js +9 -9
  12. package/dist/pb-ui.min.js.map +1 -1
  13. package/es/core/context/SxpDataSourceProvider.d.ts +1 -1
  14. package/es/core/index.d.ts +6 -0
  15. package/es/core/index.js +10 -0
  16. package/es/core/utils/materials.js +30 -7
  17. package/es/core/utils/tool.d.ts +1 -0
  18. package/es/core/utils/tool.js +43 -0
  19. package/es/materials/sxp/popup/AddToCart/index.js +27 -8
  20. package/es/materials/sxp/popup/AddToCart/index.new.js +27 -6
  21. package/es/materials/sxp/popup/AddToCart/index.old.js +13 -2
  22. package/es/materials/sxp/popup/CommodityDetail/index.js +21 -16
  23. package/es/materials/sxp/popup/CommodityDetailDiroNew/index.js +25 -0
  24. package/lib/core/context/SxpDataSourceProvider.d.ts +1 -1
  25. package/lib/core/index.d.ts +6 -0
  26. package/lib/core/index.js +10 -5
  27. package/lib/core/utils/materials.js +29 -6
  28. package/lib/core/utils/tool.d.ts +1 -0
  29. package/lib/core/utils/tool.js +45 -1
  30. package/lib/materials/sxp/popup/AddToCart/index.js +27 -8
  31. package/lib/materials/sxp/popup/AddToCart/index.new.js +27 -6
  32. package/lib/materials/sxp/popup/AddToCart/index.old.js +12 -1
  33. package/lib/materials/sxp/popup/CommodityDetail/index.js +21 -16
  34. package/lib/materials/sxp/popup/CommodityDetailDiroNew/index.js +25 -0
  35. 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);
@@ -314,6 +413,73 @@
314
413
  }
315
414
  return (_b = params[key]) !== null && _b !== void 0 ? _b : '';
316
415
  }
416
+ /**
417
+ * 货币代码到货币符号的映射
418
+ * 根据 Shopify 返回的 currencyCode 获取对应的货币符号
419
+ */
420
+ function getCurrencySymbol(currencyCode) {
421
+ const currencySymbolMap = {
422
+ // 主要货币
423
+ USD: '$', // 美元
424
+ EUR: '€', // 欧元
425
+ GBP: '£', // 英镑
426
+ JPY: '¥', // 日元
427
+ CNY: '¥', // 人民币
428
+ KRW: '₩', // 韩元
429
+ INR: '₹', // 印度卢比
430
+ RUB: '₽', // 俄罗斯卢布
431
+ BRL: 'R$', // 巴西雷亚尔
432
+ CAD: 'CA$', // 加拿大元
433
+ AUD: 'A$', // 澳元
434
+ CHF: 'CHF', // 瑞士法郎
435
+ SEK: 'kr', // 瑞典克朗
436
+ NOK: 'kr', // 挪威克朗
437
+ DKK: 'kr', // 丹麦克朗
438
+ PLN: 'zł', // 波兰兹罗提
439
+ THB: '฿', // 泰铢
440
+ IDR: 'Rp', // 印尼盾
441
+ MYR: 'RM', // 马来西亚林吉特
442
+ PHP: '₱', // 菲律宾比索
443
+ SGD: 'S$', // 新加坡元
444
+ HKD: 'HK$', // 港币
445
+ TWD: 'NT$', // 新台币
446
+ NZD: 'NZ$', // 新西兰元
447
+ MXN: 'MX$', // 墨西哥比索
448
+ ZAR: 'R', // 南非兰特
449
+ TRY: '₺', // 土耳其里拉
450
+ AED: 'AED', // 阿联酋迪拉姆
451
+ SAR: 'SAR', // 沙特里亚尔
452
+ ILS: '₪', // 以色列新谢克尔
453
+ ARS: 'AR$', // 阿根廷比索
454
+ CLP: 'CL$', // 智利比索
455
+ COP: 'CO$', // 哥伦比亚比索
456
+ VND: '₫', // 越南盾
457
+ EGP: 'E£', // 埃及镑
458
+ NGN: '₦', // 尼日利亚奈拉
459
+ PKR: '₨', // 巴基斯坦卢比
460
+ BDT: '৳', // 孟加拉塔卡
461
+ };
462
+ return currencySymbolMap[currencyCode.toUpperCase()] || currencyCode;
463
+ }
464
+
465
+ var tool = /*#__PURE__*/Object.freeze({
466
+ __proto__: null,
467
+ deleteCookie: deleteCookie,
468
+ generateRandomString: generateRandomString,
469
+ getBrowserInfo: getBrowserInfo,
470
+ getCookie: getCookie,
471
+ getCurrencySymbol: getCurrencySymbol,
472
+ getDevice: getDevice$1,
473
+ getIndexByblockType: getIndexByblockType,
474
+ getScreenReader: getScreenReader,
475
+ getSystem: getSystem,
476
+ getUid: getUid,
477
+ getUrlParamByKey: getUrlParamByKey,
478
+ setCookie: setCookie,
479
+ setFontForText: setFontForText,
480
+ splitUrlParams: splitUrlParams,
481
+ uuid: uuid
482
+ });
317
483
 
318
484
  function unzip(b64Data) {
319
485
  const strData = atob(b64Data);
@@ -499,6 +665,18 @@
499
665
  const getFeSessionId = () => {
500
666
  return window.localStorage.getItem(feRealSessionIdKey);
501
667
  };
668
+ // 删除sessionID
669
+ const removeFeSessionId = () => {
670
+ window.localStorage.removeItem(feRealSessionIdKey);
671
+ };
672
+
673
+ var sessionStore = /*#__PURE__*/Object.freeze({
674
+ __proto__: null,
675
+ getFeSessionId: getFeSessionId,
676
+ refreshFeSessionId: refreshFeSessionId,
677
+ removeFeSessionId: removeFeSessionId,
678
+ storeAndLoadFeSessionId: storeAndLoadFeSessionId
679
+ });
502
680
 
503
681
  /*
504
682
  * @Author: binruan@chatlabs.com
@@ -522,6 +700,9 @@
522
700
  }
523
701
  return fakeUserId;
524
702
  };
703
+ const removeFeUserId = () => {
704
+ window.localStorage.removeItem(FAKE_USER_KEY);
705
+ };
525
706
  const getFeUserState = () => {
526
707
  const fakeUserState = window.localStorage.getItem(FAKE_USER_STATE);
527
708
  if (lodash.isEmpty(fakeUserState)) {
@@ -551,6 +732,24 @@
551
732
  window.localStorage.setItem(USER_CONSENT_RESULT_KEY, 'true');
552
733
  };
553
734
 
735
+ var localStore = /*#__PURE__*/Object.freeze({
736
+ __proto__: null,
737
+ AGREE_POLICY: AGREE_POLICY,
738
+ CCONTSENT_STATE: CCONTSENT_STATE,
739
+ FAKE_USER_KEY: FAKE_USER_KEY,
740
+ FAKE_USER_STATE: FAKE_USER_STATE,
741
+ SLIDE_SKIP_STATE: SLIDE_SKIP_STATE,
742
+ USER_CONSENT_RESULT_KEY: USER_CONSENT_RESULT_KEY,
743
+ getContsentState: getContsentState,
744
+ getFeUserState: getFeUserState,
745
+ getSlideSkipState: getSlideSkipState,
746
+ getUserConsentResult: getUserConsentResult,
747
+ removeFeUserId: removeFeUserId,
748
+ setSlideSkipState: setSlideSkipState,
749
+ setUserConsentResult: setUserConsentResult,
750
+ storeAndLoadFeUserId: storeAndLoadFeUserId
751
+ });
752
+
554
753
  /*
555
754
  * @Author: binruan@chatlabs.com
556
755
  * @Date: 2024-03-20 10:27:31
@@ -1759,6 +1958,23 @@
1759
1958
  DATA_TYPE["ARRAY_NUMBER"] = "array-number";
1760
1959
  })(DATA_TYPE || (DATA_TYPE = {}));
1761
1960
 
1961
+ /*
1962
+ * @Author: binruan@chatlabs.com
1963
+ * @Date: 2024-03-20 10:27:31
1964
+ * @LastEditors: binruan@chatlabs.com
1965
+ * @LastEditTime: 2024-03-20 13:56:49
1966
+ * @FilePath: \pb-sxp-ui\src\core\hooks\index.ts
1967
+ *
1968
+ */
1969
+
1970
+ var index$4 = /*#__PURE__*/Object.freeze({
1971
+ __proto__: null,
1972
+ get DATA_TYPE () { return DATA_TYPE; },
1973
+ useDataSource: useDataSource,
1974
+ useEditor: useEditor,
1975
+ useSxpDataSource: useSxpDataSource
1976
+ });
1977
+
1762
1978
  const DataSourceContext = React.createContext({ $store: {}, options: [], configs: [] });
1763
1979
  const DataSourceProvider = ({ children, isSsr, enable }) => {
1764
1980
  const [options, setOptions] = React.useState([]);
@@ -10830,7 +11046,7 @@
10830
11046
  : '';
10831
11047
  };
10832
11048
  const getPriceText = ({ product, enableFormattedPrice, globalConfig, isHiddenDef, style }) => {
10833
- var _a, _b, _c, _d, _e, _f, _g, _h;
11049
+ var _a, _b, _c, _d, _e;
10834
11050
  let text = '';
10835
11051
  if ((!(product === null || product === void 0 ? void 0 : product.currency) || !(product === null || product === void 0 ? void 0 : product.price)) && isHiddenDef)
10836
11052
  return null;
@@ -10838,18 +11054,51 @@
10838
11054
  if (typeof price !== 'number')
10839
11055
  return text;
10840
11056
  let priceSymbol = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.priceSymbol;
10841
- let currency = (product === null || product === void 0 ? void 0 : product.currency) ? (_c = (_b = (_a = product === null || product === void 0 ? void 0 : product.currency) === null || _a === void 0 ? void 0 : _a.split('-')[1]) === null || _b === void 0 ? void 0 : _b.toUpperCase()) !== null && _c !== void 0 ? _c : '' : '$';
11057
+ // product.currency 中提取货币代码
11058
+ // 支持多种格式:
11059
+ // 1. "EUR" - 直接是货币代码
11060
+ // 2. "USD-$" - 货币代码-货币符号
11061
+ // 3. "$-USD" - 货币符号-货币代码 (不常见)
11062
+ let currencyCode = '';
11063
+ if (product === null || product === void 0 ? void 0 : product.currency) {
11064
+ const parts = product.currency.split('-');
11065
+ if (parts.length > 1) {
11066
+ // 判断哪一部分是货币代码(通常是3个大写字母)
11067
+ // 货币代码通常是3个字母,如 USD, EUR, GBP
11068
+ const firstPart = parts[0].toUpperCase();
11069
+ const secondPart = parts[1].toUpperCase();
11070
+ // 如果第一部分是3个字母,则认为是货币代码
11071
+ if (/^[A-Z]{3}$/.test(firstPart)) {
11072
+ currencyCode = firstPart;
11073
+ }
11074
+ else if (/^[A-Z]{3}$/.test(secondPart)) {
11075
+ currencyCode = secondPart;
11076
+ }
11077
+ else {
11078
+ // 都不是标准格式,取第一部分
11079
+ currencyCode = firstPart;
11080
+ }
11081
+ }
11082
+ else {
11083
+ currencyCode = parts[0].toUpperCase();
11084
+ }
11085
+ }
11086
+ else {
11087
+ currencyCode = 'USD'; // 默认美元
11088
+ }
11089
+ // 使用货币代码映射获取货币符号
11090
+ let currency = getCurrencySymbol(currencyCode);
10842
11091
  const isToLocStr = enableFormattedPrice === undefined || enableFormattedPrice;
10843
11092
  let decPic = price === null || price === void 0 ? void 0 : price.toString();
10844
11093
  if (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.showTwoDecimalPoint) {
10845
11094
  decPic = price === null || price === void 0 ? void 0 : price.toFixed(2);
10846
11095
  }
10847
- let decInd = (_d = decPic === null || decPic === void 0 ? void 0 : decPic.indexOf('.')) !== null && _d !== void 0 ? _d : -1;
11096
+ let decInd = (_a = decPic === null || decPic === void 0 ? void 0 : decPic.indexOf('.')) !== null && _a !== void 0 ? _a : -1;
10848
11097
  if (isToLocStr) {
10849
11098
  text =
10850
- (_e = price === null || price === void 0 ? void 0 : price.toLocaleString('zh', {
11099
+ (_b = price === null || price === void 0 ? void 0 : price.toLocaleString('zh', {
10851
11100
  minimumFractionDigits: (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.showTwoDecimalPoint) ? 2 : 0
10852
- })) !== null && _e !== void 0 ? _e : '';
11101
+ })) !== null && _b !== void 0 ? _b : '';
10853
11102
  let startIndex = 0;
10854
11103
  let endIndex = decInd !== null && decInd !== void 0 ? decInd : text === null || text === void 0 ? void 0 : text.length;
10855
11104
  if ((priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.millesimalSymbol) === '.') {
@@ -10880,7 +11129,7 @@
10880
11129
  }
10881
11130
  });
10882
11131
  }
10883
- currency = `<span style="font-family:${(_h = (_g = (_f = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.priceSymbol) === null || _f === void 0 ? void 0 : _f.fontFamily) !== null && _g !== void 0 ? _g : style === null || style === void 0 ? void 0 : style['fontFamily-en']) !== null && _h !== void 0 ? _h : 'inherit'}">${currency}</span>`;
11132
+ currency = `<span style="font-family:${(_e = (_d = (_c = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.priceSymbol) === null || _c === void 0 ? void 0 : _c.fontFamily) !== null && _d !== void 0 ? _d : style === null || style === void 0 ? void 0 : style['fontFamily-en']) !== null && _e !== void 0 ? _e : 'inherit'}">${currency}</span>`;
10884
11133
  text = setFontForText(text, style);
10885
11134
  if ((priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) && (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) !== 'none') {
10886
11135
  text = (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) === 'left' ? currency + text : text + currency;
@@ -10916,30 +11165,37 @@
10916
11165
  cta = p === null || p === void 0 ? void 0 : p.bindCta;
10917
11166
  }
10918
11167
  const handleLink = (e) => {
10919
- // 如果启用了加购功能且配置了加购弹窗ID,则打开加购弹窗
11168
+ // 如果启用了加购功能且配置了加购弹窗ID,检查是否是 Shopify 商品
10920
11169
  if (enableAddToCart && addToCartPopupId) {
10921
- // 设置弹窗数据
10922
- setPopupDetailData === null || setPopupDetailData === void 0 ? void 0 : setPopupDetailData(Object.assign(Object.assign({}, data), { index: position }));
10923
- // 上报点击事件
10924
- bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
10925
- eventName: 'ClickCTA',
10926
- product: product ? [product] : undefined,
10927
- contentType: 'product',
10928
- data,
10929
- position,
10930
- cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
10931
- cta_action_type: 'open_internal_popup',
10932
- target_content_id: product === null || product === void 0 ? void 0 : product.itemId
10933
- });
10934
- console.log('[CommodityDetail] 打开加购弹窗:', addToCartPopupId);
10935
- // 打开加购弹窗
10936
- if (typeof window !== 'undefined' && window.sxpPopup) {
10937
- window.sxpPopup(addToCartPopupId);
11170
+ // 问题3:只有 Shopify 商品(有 shopifyId)才打开加购弹窗
11171
+ if (!(product === null || product === void 0 ? void 0 : product.shopifyId)) {
11172
+ console.warn('[CommodityDetail] 非 Shopify 商品,跳过加购弹窗');
11173
+ // 继续执行默认行为(跳转链接)
10938
11174
  }
10939
11175
  else {
10940
- console.warn('[CommodityDetail] sxpPopup 方法不存在');
11176
+ // 设置弹窗数据
11177
+ setPopupDetailData === null || setPopupDetailData === void 0 ? void 0 : setPopupDetailData(Object.assign(Object.assign({}, data), { index: position }));
11178
+ // 上报点击事件
11179
+ bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
11180
+ eventName: 'ClickCTA',
11181
+ product: product ? [product] : undefined,
11182
+ contentType: 'product',
11183
+ data,
11184
+ position,
11185
+ cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
11186
+ cta_action_type: 'open_internal_popup',
11187
+ target_content_id: product === null || product === void 0 ? void 0 : product.itemId
11188
+ });
11189
+ console.log('[CommodityDetail] 打开加购弹窗:', addToCartPopupId);
11190
+ // 打开加购弹窗
11191
+ if (typeof window !== 'undefined' && window.sxpPopup) {
11192
+ window.sxpPopup(addToCartPopupId);
11193
+ }
11194
+ else {
11195
+ console.warn('[CommodityDetail] sxpPopup 方法不存在');
11196
+ }
11197
+ return;
10941
11198
  }
10942
- return;
10943
11199
  }
10944
11200
  // 默认行为:跳转到商品链接
10945
11201
  if (product === null || product === void 0 ? void 0 : product.link) {
@@ -11909,7 +12165,7 @@
11909
12165
 
11910
12166
  const AddToCartPopup$1 = ({ isActive = true }) => {
11911
12167
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
11912
- const { popupDetailData, globalConfig } = useSxpDataSource();
12168
+ const { popupDetailData, globalConfig, bffFbReport } = useSxpDataSource();
11913
12169
  const [productData, setProductData] = React.useState(null);
11914
12170
  const [selectedOptions, setSelectedOptions] = React.useState({});
11915
12171
  const [selectedVariant, setSelectedVariant] = React.useState(null);
@@ -12049,6 +12305,18 @@
12049
12305
  shopifyDomain,
12050
12306
  selectedVariant
12051
12307
  });
12308
+ // 上报 sessionCompleted 事件(问题4)
12309
+ bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
12310
+ eventName: 'sessionCompleted',
12311
+ product: product ? [product] : undefined,
12312
+ contentType: 'product',
12313
+ rec: data,
12314
+ position: data === null || data === void 0 ? void 0 : data.index,
12315
+ cta_text: 'Add To Cart',
12316
+ cta_action_type: 'add_to_cart',
12317
+ target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
12318
+ target_url: `https://${shopifyDomain}/cart/add`
12319
+ });
12052
12320
  // 使用 Shopify 的 /cart/add 接口,通过查询参数添加商品
12053
12321
  // 这种方式会跳转到购物车页面而不是结算页面
12054
12322
  const params = new URLSearchParams({
@@ -12063,6 +12331,10 @@
12063
12331
  const totalPrice = selectedVariant
12064
12332
  ? (parseFloat(selectedVariant.price.amount) * quantity).toFixed(2)
12065
12333
  : '0.00';
12334
+ // 只有选择了 variant 后才显示货币符号
12335
+ const displayPrice = selectedVariant
12336
+ ? `${getCurrencySymbol(selectedVariant.price.currencyCode)}${totalPrice}`
12337
+ : totalPrice;
12066
12338
  if (loading) {
12067
12339
  return (React.createElement("div", { className: 'add-to-cart-popup' },
12068
12340
  React.createElement("div", { className: 'loading' }, "Loading...")));
@@ -12096,9 +12368,7 @@
12096
12368
  "Available: ",
12097
12369
  selectedVariant.quantityAvailable))),
12098
12370
  React.createElement("div", { className: 'variant-price-row' },
12099
- React.createElement("div", { className: 'price' },
12100
- "$",
12101
- totalPrice),
12371
+ React.createElement("div", { className: 'price' }, displayPrice),
12102
12372
  React.createElement("div", { className: 'quantity-selector' },
12103
12373
  React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1 }, "\u2212"),
12104
12374
  React.createElement("span", { className: 'qty-value' }, quantity),
@@ -12106,16 +12376,26 @@
12106
12376
  React.createElement("div", { className: 'variant-options' }, productData.options.map(option => (React.createElement("div", { key: option.name, className: 'option-group' },
12107
12377
  React.createElement("div", { className: 'option-label' }, option.name),
12108
12378
  React.createElement("div", { className: 'option-values' }, option.values.map(value => {
12109
- // 检查这个选项是否可选(availableForSale = true,如果有 quantityAvailable 则还需 > 0)
12379
+ // 检查这个选项值与当前已选择的其他选项组合后是否可用
12110
12380
  const isAvailable = productData.variants.edges.some(({ node: variant }) => {
12381
+ // 检查这个variant是否匹配当前选项值
12111
12382
  const hasThisOption = variant.selectedOptions.some(opt => opt.name === option.name && opt.value === value);
12112
- if (!hasThisOption || !variant.availableForSale)
12383
+ if (!hasThisOption)
12113
12384
  return false;
12114
- // 如果有 quantityAvailable 字段,则需要检查库存
12115
- if (variant.quantityAvailable !== undefined) {
12116
- return variant.quantityAvailable > 0;
12117
- }
12118
- // 没有 quantityAvailable 字段时,只要 availableForSale 为 true 就可选
12385
+ // 检查这个variant是否匹配其他已选择的选项
12386
+ const matchesOtherSelections = Object.entries(selectedOptions).every(([key, val]) => {
12387
+ // 跳过当前正在检查的选项
12388
+ if (key === option.name)
12389
+ return true;
12390
+ return variant.selectedOptions.some(opt => opt.name === key && opt.value === val);
12391
+ });
12392
+ if (!matchesOtherSelections)
12393
+ return false;
12394
+ // 检查是否可售
12395
+ if (!variant.availableForSale)
12396
+ return false;
12397
+ // 如果有 quantityAvailable 字段且为0,但 availableForSale 为 true,仍然可选(问题2)
12398
+ // 如果 quantityAvailable 不存在,只要 availableForSale 为 true 就可选
12119
12399
  return true;
12120
12400
  });
12121
12401
  const isSelected = selectedOptions[option.name] === value;
@@ -12166,7 +12446,35 @@
12166
12446
  }
12167
12447
  const handleLink = (e) => {
12168
12448
  e.preventDefault();
12169
- // 上报点击事件
12449
+ // 问题3:只有 Shopify 商品(有 shopifyId)才打开加购弹窗
12450
+ if (!(product === null || product === void 0 ? void 0 : product.shopifyId)) {
12451
+ console.warn('[CommodityDetailDiroNew] 非 Shopify 商品,跳转到外链');
12452
+ // 上报点击事件
12453
+ ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
12454
+ eventSubject: 'clickCta',
12455
+ eventDescription: 'User clicked the CTA'
12456
+ }, data, product, position);
12457
+ bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
12458
+ eventName: 'ClickCTA',
12459
+ product: product ? [product] : undefined,
12460
+ contentType: 'product',
12461
+ data,
12462
+ position,
12463
+ cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
12464
+ cta_action_type: 'open_external_link',
12465
+ target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
12466
+ target_url: product === null || product === void 0 ? void 0 : product.link
12467
+ });
12468
+ if (!isPost) {
12469
+ productView(data, product, cta, viewTime || curTimeRef.current, position);
12470
+ }
12471
+ // 跳转到商品链接
12472
+ if (product === null || product === void 0 ? void 0 : product.link) {
12473
+ window.location.href = window.getJointUtmLink(product.link);
12474
+ }
12475
+ return;
12476
+ }
12477
+ // Shopify 商品:上报点击事件
12170
12478
  ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
12171
12479
  eventSubject: 'clickCta',
12172
12480
  eventDescription: 'User clicked the CTA'
@@ -19789,7 +20097,13 @@ Made in Italy` })));
19789
20097
  var index$3 = /*#__PURE__*/Object.freeze({
19790
20098
  __proto__: null,
19791
20099
  EditorCore: EditorCore,
19792
- StructurePage: StructurePage
20100
+ Pagebuilder: Pagebuilder,
20101
+ StructurePage: StructurePage,
20102
+ createMaterial: createMaterial,
20103
+ hooks: index$4,
20104
+ localStore: localStore,
20105
+ sessionStore: sessionStore,
20106
+ tool: tool
19793
20107
  });
19794
20108
 
19795
20109
  /*