pb-sxp-ui 1.20.28 → 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.
package/dist/pb-ui.js CHANGED
@@ -413,6 +413,54 @@
413
413
  }
414
414
  return (_b = params[key]) !== null && _b !== void 0 ? _b : '';
415
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
+ }
416
464
 
417
465
  var tool = /*#__PURE__*/Object.freeze({
418
466
  __proto__: null,
@@ -420,6 +468,7 @@
420
468
  generateRandomString: generateRandomString,
421
469
  getBrowserInfo: getBrowserInfo,
422
470
  getCookie: getCookie,
471
+ getCurrencySymbol: getCurrencySymbol,
423
472
  getDevice: getDevice$1,
424
473
  getIndexByblockType: getIndexByblockType,
425
474
  getScreenReader: getScreenReader,
@@ -10997,7 +11046,7 @@
10997
11046
  : '';
10998
11047
  };
10999
11048
  const getPriceText = ({ product, enableFormattedPrice, globalConfig, isHiddenDef, style }) => {
11000
- var _a, _b, _c, _d, _e, _f, _g, _h;
11049
+ var _a, _b, _c, _d, _e;
11001
11050
  let text = '';
11002
11051
  if ((!(product === null || product === void 0 ? void 0 : product.currency) || !(product === null || product === void 0 ? void 0 : product.price)) && isHiddenDef)
11003
11052
  return null;
@@ -11005,18 +11054,51 @@
11005
11054
  if (typeof price !== 'number')
11006
11055
  return text;
11007
11056
  let priceSymbol = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.priceSymbol;
11008
- 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);
11009
11091
  const isToLocStr = enableFormattedPrice === undefined || enableFormattedPrice;
11010
11092
  let decPic = price === null || price === void 0 ? void 0 : price.toString();
11011
11093
  if (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.showTwoDecimalPoint) {
11012
11094
  decPic = price === null || price === void 0 ? void 0 : price.toFixed(2);
11013
11095
  }
11014
- 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;
11015
11097
  if (isToLocStr) {
11016
11098
  text =
11017
- (_e = price === null || price === void 0 ? void 0 : price.toLocaleString('zh', {
11099
+ (_b = price === null || price === void 0 ? void 0 : price.toLocaleString('zh', {
11018
11100
  minimumFractionDigits: (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.showTwoDecimalPoint) ? 2 : 0
11019
- })) !== null && _e !== void 0 ? _e : '';
11101
+ })) !== null && _b !== void 0 ? _b : '';
11020
11102
  let startIndex = 0;
11021
11103
  let endIndex = decInd !== null && decInd !== void 0 ? decInd : text === null || text === void 0 ? void 0 : text.length;
11022
11104
  if ((priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.millesimalSymbol) === '.') {
@@ -11047,7 +11129,7 @@
11047
11129
  }
11048
11130
  });
11049
11131
  }
11050
- 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>`;
11051
11133
  text = setFontForText(text, style);
11052
11134
  if ((priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) && (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) !== 'none') {
11053
11135
  text = (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) === 'left' ? currency + text : text + currency;
@@ -11083,30 +11165,37 @@
11083
11165
  cta = p === null || p === void 0 ? void 0 : p.bindCta;
11084
11166
  }
11085
11167
  const handleLink = (e) => {
11086
- // 如果启用了加购功能且配置了加购弹窗ID,则打开加购弹窗
11168
+ // 如果启用了加购功能且配置了加购弹窗ID,检查是否是 Shopify 商品
11087
11169
  if (enableAddToCart && addToCartPopupId) {
11088
- // 设置弹窗数据
11089
- setPopupDetailData === null || setPopupDetailData === void 0 ? void 0 : setPopupDetailData(Object.assign(Object.assign({}, data), { index: position }));
11090
- // 上报点击事件
11091
- bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
11092
- eventName: 'ClickCTA',
11093
- product: product ? [product] : undefined,
11094
- contentType: 'product',
11095
- data,
11096
- position,
11097
- cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
11098
- cta_action_type: 'open_internal_popup',
11099
- target_content_id: product === null || product === void 0 ? void 0 : product.itemId
11100
- });
11101
- console.log('[CommodityDetail] 打开加购弹窗:', addToCartPopupId);
11102
- // 打开加购弹窗
11103
- if (typeof window !== 'undefined' && window.sxpPopup) {
11104
- window.sxpPopup(addToCartPopupId);
11170
+ // 问题3:只有 Shopify 商品(有 shopifyId)才打开加购弹窗
11171
+ if (!(product === null || product === void 0 ? void 0 : product.shopifyId)) {
11172
+ console.warn('[CommodityDetail] 非 Shopify 商品,跳过加购弹窗');
11173
+ // 继续执行默认行为(跳转链接)
11105
11174
  }
11106
11175
  else {
11107
- 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;
11108
11198
  }
11109
- return;
11110
11199
  }
11111
11200
  // 默认行为:跳转到商品链接
11112
11201
  if (product === null || product === void 0 ? void 0 : product.link) {
@@ -12076,7 +12165,7 @@
12076
12165
 
12077
12166
  const AddToCartPopup$1 = ({ isActive = true }) => {
12078
12167
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
12079
- const { popupDetailData, globalConfig } = useSxpDataSource();
12168
+ const { popupDetailData, globalConfig, bffFbReport } = useSxpDataSource();
12080
12169
  const [productData, setProductData] = React.useState(null);
12081
12170
  const [selectedOptions, setSelectedOptions] = React.useState({});
12082
12171
  const [selectedVariant, setSelectedVariant] = React.useState(null);
@@ -12216,6 +12305,18 @@
12216
12305
  shopifyDomain,
12217
12306
  selectedVariant
12218
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
+ });
12219
12320
  // 使用 Shopify 的 /cart/add 接口,通过查询参数添加商品
12220
12321
  // 这种方式会跳转到购物车页面而不是结算页面
12221
12322
  const params = new URLSearchParams({
@@ -12230,6 +12331,10 @@
12230
12331
  const totalPrice = selectedVariant
12231
12332
  ? (parseFloat(selectedVariant.price.amount) * quantity).toFixed(2)
12232
12333
  : '0.00';
12334
+ // 只有选择了 variant 后才显示货币符号
12335
+ const displayPrice = selectedVariant
12336
+ ? `${getCurrencySymbol(selectedVariant.price.currencyCode)}${totalPrice}`
12337
+ : totalPrice;
12233
12338
  if (loading) {
12234
12339
  return (React.createElement("div", { className: 'add-to-cart-popup' },
12235
12340
  React.createElement("div", { className: 'loading' }, "Loading...")));
@@ -12263,9 +12368,7 @@
12263
12368
  "Available: ",
12264
12369
  selectedVariant.quantityAvailable))),
12265
12370
  React.createElement("div", { className: 'variant-price-row' },
12266
- React.createElement("div", { className: 'price' },
12267
- "$",
12268
- totalPrice),
12371
+ React.createElement("div", { className: 'price' }, displayPrice),
12269
12372
  React.createElement("div", { className: 'quantity-selector' },
12270
12373
  React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1 }, "\u2212"),
12271
12374
  React.createElement("span", { className: 'qty-value' }, quantity),
@@ -12273,16 +12376,26 @@
12273
12376
  React.createElement("div", { className: 'variant-options' }, productData.options.map(option => (React.createElement("div", { key: option.name, className: 'option-group' },
12274
12377
  React.createElement("div", { className: 'option-label' }, option.name),
12275
12378
  React.createElement("div", { className: 'option-values' }, option.values.map(value => {
12276
- // 检查这个选项是否可选(availableForSale = true,如果有 quantityAvailable 则还需 > 0)
12379
+ // 检查这个选项值与当前已选择的其他选项组合后是否可用
12277
12380
  const isAvailable = productData.variants.edges.some(({ node: variant }) => {
12381
+ // 检查这个variant是否匹配当前选项值
12278
12382
  const hasThisOption = variant.selectedOptions.some(opt => opt.name === option.name && opt.value === value);
12279
- if (!hasThisOption || !variant.availableForSale)
12383
+ if (!hasThisOption)
12280
12384
  return false;
12281
- // 如果有 quantityAvailable 字段,则需要检查库存
12282
- if (variant.quantityAvailable !== undefined) {
12283
- return variant.quantityAvailable > 0;
12284
- }
12285
- // 没有 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 就可选
12286
12399
  return true;
12287
12400
  });
12288
12401
  const isSelected = selectedOptions[option.name] === value;
@@ -12333,7 +12446,35 @@
12333
12446
  }
12334
12447
  const handleLink = (e) => {
12335
12448
  e.preventDefault();
12336
- // 上报点击事件
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 商品:上报点击事件
12337
12478
  ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
12338
12479
  eventSubject: 'clickCta',
12339
12480
  eventDescription: 'User clicked the CTA'