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/index.cjs +179 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +179 -38
- package/dist/index.js.map +1 -1
- package/dist/index.min.cjs +9 -9
- package/dist/index.min.cjs.map +1 -1
- package/dist/index.min.js +9 -9
- package/dist/index.min.js.map +1 -1
- package/dist/pb-ui.js +179 -38
- package/dist/pb-ui.js.map +1 -1
- package/dist/pb-ui.min.js +9 -9
- package/dist/pb-ui.min.js.map +1 -1
- package/es/core/context/SxpDataSourceProvider.d.ts +1 -1
- package/es/core/utils/materials.js +30 -7
- package/es/core/utils/tool.d.ts +1 -0
- package/es/core/utils/tool.js +43 -0
- package/es/materials/sxp/popup/AddToCart/index.js +27 -8
- package/es/materials/sxp/popup/AddToCart/index.new.js +27 -6
- package/es/materials/sxp/popup/AddToCart/index.old.js +13 -2
- package/es/materials/sxp/popup/CommodityDetail/index.js +21 -16
- package/es/materials/sxp/popup/CommodityDetailDiroNew/index.js +25 -0
- package/lib/core/context/SxpDataSourceProvider.d.ts +1 -1
- package/lib/core/utils/materials.js +29 -6
- package/lib/core/utils/tool.d.ts +1 -0
- package/lib/core/utils/tool.js +45 -1
- package/lib/materials/sxp/popup/AddToCart/index.js +27 -8
- package/lib/materials/sxp/popup/AddToCart/index.new.js +27 -6
- package/lib/materials/sxp/popup/AddToCart/index.old.js +12 -1
- package/lib/materials/sxp/popup/CommodityDetail/index.js +21 -16
- package/lib/materials/sxp/popup/CommodityDetailDiroNew/index.js +25 -0
- package/package.json +1 -1
|
@@ -12,7 +12,7 @@ export interface IEventTimeType {
|
|
|
12
12
|
time: Date;
|
|
13
13
|
target: EventTarget;
|
|
14
14
|
}
|
|
15
|
-
export type ICapiEventNameType = 'PageView' | 'ProductView' | 'ViewContent' | 'ClickCTA' | 'ContentSwipe' | 'Engagement' | 'ExitFeed' | 'AddToCart';
|
|
15
|
+
export type ICapiEventNameType = 'PageView' | 'ProductView' | 'ViewContent' | 'ClickCTA' | 'ContentSwipe' | 'Engagement' | 'ExitFeed' | 'AddToCart' | 'sessionCompleted';
|
|
16
16
|
export interface ISxpDataSourceContext {
|
|
17
17
|
rtcList: RecItemType[];
|
|
18
18
|
setRtcList?: React.Dispatch<React.SetStateAction<RecItemType[]>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { setFontForText } from './tool';
|
|
1
|
+
import { setFontForText, getCurrencySymbol } from './tool';
|
|
2
2
|
export const getMediaValueByMode = (obj) => {
|
|
3
3
|
var _a;
|
|
4
4
|
if (!obj || typeof obj !== 'object') {
|
|
@@ -31,7 +31,7 @@ export const getBgStyleByImg = (data) => {
|
|
|
31
31
|
return getBgStyle(imgSrc);
|
|
32
32
|
};
|
|
33
33
|
export const getPriceText = ({ product, enableFormattedPrice, globalConfig, isHiddenDef, style }) => {
|
|
34
|
-
var _a, _b, _c, _d, _e
|
|
34
|
+
var _a, _b, _c, _d, _e;
|
|
35
35
|
let text = '';
|
|
36
36
|
if ((!(product === null || product === void 0 ? void 0 : product.currency) || !(product === null || product === void 0 ? void 0 : product.price)) && isHiddenDef)
|
|
37
37
|
return null;
|
|
@@ -39,18 +39,41 @@ export const getPriceText = ({ product, enableFormattedPrice, globalConfig, isHi
|
|
|
39
39
|
if (typeof price !== 'number')
|
|
40
40
|
return text;
|
|
41
41
|
let priceSymbol = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.priceSymbol;
|
|
42
|
-
let
|
|
42
|
+
let currencyCode = '';
|
|
43
|
+
if (product === null || product === void 0 ? void 0 : product.currency) {
|
|
44
|
+
const parts = product.currency.split('-');
|
|
45
|
+
if (parts.length > 1) {
|
|
46
|
+
const firstPart = parts[0].toUpperCase();
|
|
47
|
+
const secondPart = parts[1].toUpperCase();
|
|
48
|
+
if (/^[A-Z]{3}$/.test(firstPart)) {
|
|
49
|
+
currencyCode = firstPart;
|
|
50
|
+
}
|
|
51
|
+
else if (/^[A-Z]{3}$/.test(secondPart)) {
|
|
52
|
+
currencyCode = secondPart;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
currencyCode = firstPart;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
currencyCode = parts[0].toUpperCase();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
currencyCode = 'USD';
|
|
64
|
+
}
|
|
65
|
+
let currency = getCurrencySymbol(currencyCode);
|
|
43
66
|
const isToLocStr = enableFormattedPrice === undefined || enableFormattedPrice;
|
|
44
67
|
let decPic = price === null || price === void 0 ? void 0 : price.toString();
|
|
45
68
|
if (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.showTwoDecimalPoint) {
|
|
46
69
|
decPic = price === null || price === void 0 ? void 0 : price.toFixed(2);
|
|
47
70
|
}
|
|
48
|
-
let decInd = (
|
|
71
|
+
let decInd = (_a = decPic === null || decPic === void 0 ? void 0 : decPic.indexOf('.')) !== null && _a !== void 0 ? _a : -1;
|
|
49
72
|
if (isToLocStr) {
|
|
50
73
|
text =
|
|
51
|
-
(
|
|
74
|
+
(_b = price === null || price === void 0 ? void 0 : price.toLocaleString('zh', {
|
|
52
75
|
minimumFractionDigits: (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.showTwoDecimalPoint) ? 2 : 0
|
|
53
|
-
})) !== null &&
|
|
76
|
+
})) !== null && _b !== void 0 ? _b : '';
|
|
54
77
|
let startIndex = 0;
|
|
55
78
|
let endIndex = decInd !== null && decInd !== void 0 ? decInd : text === null || text === void 0 ? void 0 : text.length;
|
|
56
79
|
if ((priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.millesimalSymbol) === '.') {
|
|
@@ -80,7 +103,7 @@ export const getPriceText = ({ product, enableFormattedPrice, globalConfig, isHi
|
|
|
80
103
|
}
|
|
81
104
|
});
|
|
82
105
|
}
|
|
83
|
-
currency = `<span style="font-family:${(
|
|
106
|
+
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>`;
|
|
84
107
|
text = setFontForText(text, style);
|
|
85
108
|
if ((priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) && (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) !== 'none') {
|
|
86
109
|
text = (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) === 'left' ? currency + text : text + currency;
|
package/es/core/utils/tool.d.ts
CHANGED
|
@@ -16,4 +16,5 @@ declare function splitUrlParams(urlParams: string): string[] | undefined;
|
|
|
16
16
|
declare function deleteCookie(name: string, path?: string, domain?: string): void;
|
|
17
17
|
declare function setCookie(name: string, value: string, days?: number, path?: string, domain?: string, secure?: boolean, sameSite?: string): void;
|
|
18
18
|
declare function getUrlParamByKey(key: string): any;
|
|
19
|
+
export declare function getCurrencySymbol(currencyCode: string): string;
|
|
19
20
|
export { uuid, getIndexByblockType, getBrowserInfo, getDevice, getSystem, getCookie, getScreenReader, splitUrlParams, deleteCookie, setCookie, getUrlParamByKey };
|
package/es/core/utils/tool.js
CHANGED
|
@@ -233,4 +233,47 @@ function getUrlParamByKey(key) {
|
|
|
233
233
|
}
|
|
234
234
|
return (_b = params[key]) !== null && _b !== void 0 ? _b : '';
|
|
235
235
|
}
|
|
236
|
+
export function getCurrencySymbol(currencyCode) {
|
|
237
|
+
const currencySymbolMap = {
|
|
238
|
+
USD: '$',
|
|
239
|
+
EUR: '€',
|
|
240
|
+
GBP: '£',
|
|
241
|
+
JPY: '¥',
|
|
242
|
+
CNY: '¥',
|
|
243
|
+
KRW: '₩',
|
|
244
|
+
INR: '₹',
|
|
245
|
+
RUB: '₽',
|
|
246
|
+
BRL: 'R$',
|
|
247
|
+
CAD: 'CA$',
|
|
248
|
+
AUD: 'A$',
|
|
249
|
+
CHF: 'CHF',
|
|
250
|
+
SEK: 'kr',
|
|
251
|
+
NOK: 'kr',
|
|
252
|
+
DKK: 'kr',
|
|
253
|
+
PLN: 'zł',
|
|
254
|
+
THB: '฿',
|
|
255
|
+
IDR: 'Rp',
|
|
256
|
+
MYR: 'RM',
|
|
257
|
+
PHP: '₱',
|
|
258
|
+
SGD: 'S$',
|
|
259
|
+
HKD: 'HK$',
|
|
260
|
+
TWD: 'NT$',
|
|
261
|
+
NZD: 'NZ$',
|
|
262
|
+
MXN: 'MX$',
|
|
263
|
+
ZAR: 'R',
|
|
264
|
+
TRY: '₺',
|
|
265
|
+
AED: 'AED',
|
|
266
|
+
SAR: 'SAR',
|
|
267
|
+
ILS: '₪',
|
|
268
|
+
ARS: 'AR$',
|
|
269
|
+
CLP: 'CL$',
|
|
270
|
+
COP: 'CO$',
|
|
271
|
+
VND: '₫',
|
|
272
|
+
EGP: 'E£',
|
|
273
|
+
NGN: '₦',
|
|
274
|
+
PKR: '₨',
|
|
275
|
+
BDT: '৳',
|
|
276
|
+
};
|
|
277
|
+
return currencySymbolMap[currencyCode.toUpperCase()] || currencyCode;
|
|
278
|
+
}
|
|
236
279
|
export { uuid, getIndexByblockType, getBrowserInfo, getDevice, getSystem, getCookie, getScreenReader, splitUrlParams, deleteCookie, setCookie, getUrlParamByKey };
|
|
@@ -2,10 +2,11 @@ import { __awaiter } from "tslib";
|
|
|
2
2
|
import React, { useState, useEffect, useCallback } from 'react';
|
|
3
3
|
import { useSxpDataSource } from '../../../../core/hooks';
|
|
4
4
|
import Modal from '../../../../core/components/SxpPageRender/Modal';
|
|
5
|
+
import { getCurrencySymbol } from '../../../../core/utils/tool';
|
|
5
6
|
import './index.less';
|
|
6
7
|
const AddToCartPopup = ({ isActive = true }) => {
|
|
7
8
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
8
|
-
const { popupDetailData, globalConfig } = useSxpDataSource();
|
|
9
|
+
const { popupDetailData, globalConfig, bffFbReport } = useSxpDataSource();
|
|
9
10
|
const [productData, setProductData] = useState(null);
|
|
10
11
|
const [selectedOptions, setSelectedOptions] = useState({});
|
|
11
12
|
const [selectedVariant, setSelectedVariant] = useState(null);
|
|
@@ -137,6 +138,17 @@ const AddToCartPopup = ({ isActive = true }) => {
|
|
|
137
138
|
shopifyDomain,
|
|
138
139
|
selectedVariant
|
|
139
140
|
});
|
|
141
|
+
bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
|
|
142
|
+
eventName: 'sessionCompleted',
|
|
143
|
+
product: product ? [product] : undefined,
|
|
144
|
+
contentType: 'product',
|
|
145
|
+
rec: data,
|
|
146
|
+
position: data === null || data === void 0 ? void 0 : data.index,
|
|
147
|
+
cta_text: 'Add To Cart',
|
|
148
|
+
cta_action_type: 'add_to_cart',
|
|
149
|
+
target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
|
|
150
|
+
target_url: `https://${shopifyDomain}/cart/add`
|
|
151
|
+
});
|
|
140
152
|
const params = new URLSearchParams({
|
|
141
153
|
id: variantId,
|
|
142
154
|
quantity: quantity.toString()
|
|
@@ -148,6 +160,9 @@ const AddToCartPopup = ({ isActive = true }) => {
|
|
|
148
160
|
const totalPrice = selectedVariant
|
|
149
161
|
? (parseFloat(selectedVariant.price.amount) * quantity).toFixed(2)
|
|
150
162
|
: '0.00';
|
|
163
|
+
const displayPrice = selectedVariant
|
|
164
|
+
? `${getCurrencySymbol(selectedVariant.price.currencyCode)}${totalPrice}`
|
|
165
|
+
: totalPrice;
|
|
151
166
|
if (loading) {
|
|
152
167
|
return (React.createElement("div", { className: 'add-to-cart-popup' },
|
|
153
168
|
React.createElement("div", { className: 'loading' }, "Loading...")));
|
|
@@ -181,9 +196,7 @@ const AddToCartPopup = ({ isActive = true }) => {
|
|
|
181
196
|
"Available: ",
|
|
182
197
|
selectedVariant.quantityAvailable))),
|
|
183
198
|
React.createElement("div", { className: 'variant-price-row' },
|
|
184
|
-
React.createElement("div", { className: 'price' },
|
|
185
|
-
"$",
|
|
186
|
-
totalPrice),
|
|
199
|
+
React.createElement("div", { className: 'price' }, displayPrice),
|
|
187
200
|
React.createElement("div", { className: 'quantity-selector' },
|
|
188
201
|
React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1 }, "\u2212"),
|
|
189
202
|
React.createElement("span", { className: 'qty-value' }, quantity),
|
|
@@ -193,11 +206,17 @@ const AddToCartPopup = ({ isActive = true }) => {
|
|
|
193
206
|
React.createElement("div", { className: 'option-values' }, option.values.map(value => {
|
|
194
207
|
const isAvailable = productData.variants.edges.some(({ node: variant }) => {
|
|
195
208
|
const hasThisOption = variant.selectedOptions.some(opt => opt.name === option.name && opt.value === value);
|
|
196
|
-
if (!hasThisOption
|
|
209
|
+
if (!hasThisOption)
|
|
210
|
+
return false;
|
|
211
|
+
const matchesOtherSelections = Object.entries(selectedOptions).every(([key, val]) => {
|
|
212
|
+
if (key === option.name)
|
|
213
|
+
return true;
|
|
214
|
+
return variant.selectedOptions.some(opt => opt.name === key && opt.value === val);
|
|
215
|
+
});
|
|
216
|
+
if (!matchesOtherSelections)
|
|
217
|
+
return false;
|
|
218
|
+
if (!variant.availableForSale)
|
|
197
219
|
return false;
|
|
198
|
-
if (variant.quantityAvailable !== undefined) {
|
|
199
|
-
return variant.quantityAvailable > 0;
|
|
200
|
-
}
|
|
201
220
|
return true;
|
|
202
221
|
});
|
|
203
222
|
const isSelected = selectedOptions[option.name] === value;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
2
|
import React, { useState, useEffect, useCallback } from 'react';
|
|
3
3
|
import { useSxpDataSource } from '../../../../core/hooks';
|
|
4
|
+
import { getCurrencySymbol } from '../../../../core/utils/tool';
|
|
4
5
|
import './index.less';
|
|
5
6
|
const AddToCartPopup = ({ isActive = true, onClose }) => {
|
|
6
7
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
7
|
-
const { popupDetailData, globalConfig } = useSxpDataSource();
|
|
8
|
+
const { popupDetailData, globalConfig, bffFbReport } = useSxpDataSource();
|
|
8
9
|
const [productData, setProductData] = useState(null);
|
|
9
10
|
const [selectedOptions, setSelectedOptions] = useState({});
|
|
10
11
|
const [selectedVariant, setSelectedVariant] = useState(null);
|
|
@@ -120,6 +121,17 @@ const AddToCartPopup = ({ isActive = true, onClose }) => {
|
|
|
120
121
|
alert('Please select all options');
|
|
121
122
|
return;
|
|
122
123
|
}
|
|
124
|
+
bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
|
|
125
|
+
eventName: 'sessionCompleted',
|
|
126
|
+
product: product ? [product] : undefined,
|
|
127
|
+
contentType: 'product',
|
|
128
|
+
rec: data,
|
|
129
|
+
position: data === null || data === void 0 ? void 0 : data.index,
|
|
130
|
+
cta_text: 'Add To Cart',
|
|
131
|
+
cta_action_type: 'add_to_cart',
|
|
132
|
+
target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
|
|
133
|
+
target_url: `https://${shopifyDomain}/cart`
|
|
134
|
+
});
|
|
123
135
|
const variantId = selectedVariant.id.split('/').pop();
|
|
124
136
|
const checkoutUrl = `https://${shopifyDomain}/cart/${variantId}:${quantity}`;
|
|
125
137
|
window.location.href = checkoutUrl;
|
|
@@ -127,7 +139,9 @@ const AddToCartPopup = ({ isActive = true, onClose }) => {
|
|
|
127
139
|
const totalPrice = selectedVariant
|
|
128
140
|
? (parseFloat(selectedVariant.price.amount) * quantity).toFixed(2)
|
|
129
141
|
: '0.00';
|
|
130
|
-
const
|
|
142
|
+
const displayPrice = selectedVariant
|
|
143
|
+
? `${getCurrencySymbol(selectedVariant.price.currencyCode)}${totalPrice}`
|
|
144
|
+
: totalPrice;
|
|
131
145
|
if (loading) {
|
|
132
146
|
return (React.createElement("div", { className: "add-to-cart-popup" },
|
|
133
147
|
React.createElement("div", { className: "loading" }, "Loading...")));
|
|
@@ -152,9 +166,7 @@ const AddToCartPopup = ({ isActive = true, onClose }) => {
|
|
|
152
166
|
React.createElement("div", { className: "variant-info" },
|
|
153
167
|
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"))),
|
|
154
168
|
React.createElement("div", { className: "variant-price-row" },
|
|
155
|
-
React.createElement("div", { className: "price" },
|
|
156
|
-
"$",
|
|
157
|
-
totalPrice),
|
|
169
|
+
React.createElement("div", { className: "price" }, displayPrice),
|
|
158
170
|
React.createElement("div", { className: "quantity-selector" },
|
|
159
171
|
React.createElement("button", { className: "qty-btn", onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1 }, "\u2212"),
|
|
160
172
|
React.createElement("span", { className: "qty-value" }, quantity),
|
|
@@ -164,7 +176,16 @@ const AddToCartPopup = ({ isActive = true, onClose }) => {
|
|
|
164
176
|
React.createElement("div", { className: "option-values" }, option.values.map(value => {
|
|
165
177
|
const isAvailable = productData.variants.edges.some(({ node: variant }) => {
|
|
166
178
|
const hasThisOption = variant.selectedOptions.some(opt => opt.name === option.name && opt.value === value);
|
|
167
|
-
|
|
179
|
+
if (!hasThisOption)
|
|
180
|
+
return false;
|
|
181
|
+
const matchesOtherSelections = Object.entries(selectedOptions).every(([key, val]) => {
|
|
182
|
+
if (key === option.name)
|
|
183
|
+
return true;
|
|
184
|
+
return variant.selectedOptions.some(opt => opt.name === key && opt.value === val);
|
|
185
|
+
});
|
|
186
|
+
if (!matchesOtherSelections)
|
|
187
|
+
return false;
|
|
188
|
+
return variant.availableForSale;
|
|
168
189
|
});
|
|
169
190
|
const isSelected = selectedOptions[option.name] === value;
|
|
170
191
|
return (React.createElement("button", { key: value, className: `option-btn ${isSelected ? 'selected' : ''} ${!isAvailable ? 'disabled' : ''}`, onClick: () => isAvailable && handleOptionSelect(option.name, value), disabled: !isAvailable }, value));
|
|
@@ -2,7 +2,7 @@ import { __awaiter, __rest } from "tslib";
|
|
|
2
2
|
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
|
3
3
|
import { useSxpDataSource } from '../../../../core/hooks';
|
|
4
4
|
import { useEventReport } from '../../../../core/hooks/useEventReport';
|
|
5
|
-
import { setFontForText } from '../../../../core/utils/tool';
|
|
5
|
+
import { setFontForText, getCurrencySymbol } from '../../../../core/utils/tool';
|
|
6
6
|
import './index.less';
|
|
7
7
|
const AddToCartPopup = (_a) => {
|
|
8
8
|
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
@@ -227,6 +227,17 @@ const AddToCartPopup = (_a) => {
|
|
|
227
227
|
quantity
|
|
228
228
|
}]
|
|
229
229
|
});
|
|
230
|
+
bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
|
|
231
|
+
eventName: 'sessionCompleted',
|
|
232
|
+
product: product ? [product] : undefined,
|
|
233
|
+
contentType: 'product',
|
|
234
|
+
rec: data,
|
|
235
|
+
position,
|
|
236
|
+
cta_text: 'Add To Cart',
|
|
237
|
+
cta_action_type: 'add_to_cart',
|
|
238
|
+
target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
|
|
239
|
+
target_url: cartUrl
|
|
240
|
+
});
|
|
230
241
|
window.location.href = cartUrl;
|
|
231
242
|
}, [selectedVariant, quantity, finalShopifyDomain, bffFbReport, product, data, position]);
|
|
232
243
|
const totalPrice = useMemo(() => {
|
|
@@ -275,7 +286,7 @@ const AddToCartPopup = (_a) => {
|
|
|
275
286
|
option.value)))),
|
|
276
287
|
React.createElement("div", { className: "price-display" },
|
|
277
288
|
React.createElement("span", { className: "price-value", style: variantStyles.price, dangerouslySetInnerHTML: {
|
|
278
|
-
__html: setFontForText(`${selectedVariant.price.currencyCode}
|
|
289
|
+
__html: setFontForText(selectedVariant ? `${getCurrencySymbol(selectedVariant.price.currencyCode)}${totalPrice}` : totalPrice, variantStyles.price)
|
|
279
290
|
} })),
|
|
280
291
|
React.createElement("div", { className: "quantity-selector-wrapper", style: quantityStyle },
|
|
281
292
|
React.createElement("button", { className: "quantity-btn quantity-decrease", onClick: () => handleQuantityChange(-1), disabled: quantity <= 1, "aria-label": "Decrease quantity" }, "-"),
|
|
@@ -39,25 +39,30 @@ const CommodityDetail = (_a) => {
|
|
|
39
39
|
}
|
|
40
40
|
const handleLink = (e) => {
|
|
41
41
|
if (enableAddToCart && addToCartPopupId) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
eventName: 'ClickCTA',
|
|
45
|
-
product: product ? [product] : undefined,
|
|
46
|
-
contentType: 'product',
|
|
47
|
-
data,
|
|
48
|
-
position,
|
|
49
|
-
cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
|
|
50
|
-
cta_action_type: 'open_internal_popup',
|
|
51
|
-
target_content_id: product === null || product === void 0 ? void 0 : product.itemId
|
|
52
|
-
});
|
|
53
|
-
console.log('[CommodityDetail] 打开加购弹窗:', addToCartPopupId);
|
|
54
|
-
if (typeof window !== 'undefined' && window.sxpPopup) {
|
|
55
|
-
window.sxpPopup(addToCartPopupId);
|
|
42
|
+
if (!(product === null || product === void 0 ? void 0 : product.shopifyId)) {
|
|
43
|
+
console.warn('[CommodityDetail] 非 Shopify 商品,跳过加购弹窗');
|
|
56
44
|
}
|
|
57
45
|
else {
|
|
58
|
-
|
|
46
|
+
setPopupDetailData === null || setPopupDetailData === void 0 ? void 0 : setPopupDetailData(Object.assign(Object.assign({}, data), { index: position }));
|
|
47
|
+
bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
|
|
48
|
+
eventName: 'ClickCTA',
|
|
49
|
+
product: product ? [product] : undefined,
|
|
50
|
+
contentType: 'product',
|
|
51
|
+
data,
|
|
52
|
+
position,
|
|
53
|
+
cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
|
|
54
|
+
cta_action_type: 'open_internal_popup',
|
|
55
|
+
target_content_id: product === null || product === void 0 ? void 0 : product.itemId
|
|
56
|
+
});
|
|
57
|
+
console.log('[CommodityDetail] 打开加购弹窗:', addToCartPopupId);
|
|
58
|
+
if (typeof window !== 'undefined' && window.sxpPopup) {
|
|
59
|
+
window.sxpPopup(addToCartPopupId);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
console.warn('[CommodityDetail] sxpPopup 方法不存在');
|
|
63
|
+
}
|
|
64
|
+
return;
|
|
59
65
|
}
|
|
60
|
-
return;
|
|
61
66
|
}
|
|
62
67
|
if (product === null || product === void 0 ? void 0 : product.link) {
|
|
63
68
|
jumpToWeb(e, data, product, cta, position);
|
|
@@ -41,6 +41,31 @@ const CommodityDetailDiroNew = (_a) => {
|
|
|
41
41
|
}
|
|
42
42
|
const handleLink = (e) => {
|
|
43
43
|
e.preventDefault();
|
|
44
|
+
if (!(product === null || product === void 0 ? void 0 : product.shopifyId)) {
|
|
45
|
+
console.warn('[CommodityDetailDiroNew] 非 Shopify 商品,跳转到外链');
|
|
46
|
+
ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
|
|
47
|
+
eventSubject: 'clickCta',
|
|
48
|
+
eventDescription: 'User clicked the CTA'
|
|
49
|
+
}, data, product, position);
|
|
50
|
+
bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
|
|
51
|
+
eventName: 'ClickCTA',
|
|
52
|
+
product: product ? [product] : undefined,
|
|
53
|
+
contentType: 'product',
|
|
54
|
+
data,
|
|
55
|
+
position,
|
|
56
|
+
cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
|
|
57
|
+
cta_action_type: 'open_external_link',
|
|
58
|
+
target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
|
|
59
|
+
target_url: product === null || product === void 0 ? void 0 : product.link
|
|
60
|
+
});
|
|
61
|
+
if (!isPost) {
|
|
62
|
+
productView(data, product, cta, viewTime || curTimeRef.current, position);
|
|
63
|
+
}
|
|
64
|
+
if (product === null || product === void 0 ? void 0 : product.link) {
|
|
65
|
+
window.location.href = window.getJointUtmLink(product.link);
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
44
69
|
ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
|
|
45
70
|
eventSubject: 'clickCta',
|
|
46
71
|
eventDescription: 'User clicked the CTA'
|
|
@@ -12,7 +12,7 @@ export interface IEventTimeType {
|
|
|
12
12
|
time: Date;
|
|
13
13
|
target: EventTarget;
|
|
14
14
|
}
|
|
15
|
-
export type ICapiEventNameType = 'PageView' | 'ProductView' | 'ViewContent' | 'ClickCTA' | 'ContentSwipe' | 'Engagement' | 'ExitFeed' | 'AddToCart';
|
|
15
|
+
export type ICapiEventNameType = 'PageView' | 'ProductView' | 'ViewContent' | 'ClickCTA' | 'ContentSwipe' | 'Engagement' | 'ExitFeed' | 'AddToCart' | 'sessionCompleted';
|
|
16
16
|
export interface ISxpDataSourceContext {
|
|
17
17
|
rtcList: RecItemType[];
|
|
18
18
|
setRtcList?: React.Dispatch<React.SetStateAction<RecItemType[]>>;
|
|
@@ -37,7 +37,7 @@ const getBgStyleByImg = (data) => {
|
|
|
37
37
|
};
|
|
38
38
|
exports.getBgStyleByImg = getBgStyleByImg;
|
|
39
39
|
const getPriceText = ({ product, enableFormattedPrice, globalConfig, isHiddenDef, style }) => {
|
|
40
|
-
var _a, _b, _c, _d, _e
|
|
40
|
+
var _a, _b, _c, _d, _e;
|
|
41
41
|
let text = '';
|
|
42
42
|
if ((!(product === null || product === void 0 ? void 0 : product.currency) || !(product === null || product === void 0 ? void 0 : product.price)) && isHiddenDef)
|
|
43
43
|
return null;
|
|
@@ -45,18 +45,41 @@ const getPriceText = ({ product, enableFormattedPrice, globalConfig, isHiddenDef
|
|
|
45
45
|
if (typeof price !== 'number')
|
|
46
46
|
return text;
|
|
47
47
|
let priceSymbol = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.priceSymbol;
|
|
48
|
-
let
|
|
48
|
+
let currencyCode = '';
|
|
49
|
+
if (product === null || product === void 0 ? void 0 : product.currency) {
|
|
50
|
+
const parts = product.currency.split('-');
|
|
51
|
+
if (parts.length > 1) {
|
|
52
|
+
const firstPart = parts[0].toUpperCase();
|
|
53
|
+
const secondPart = parts[1].toUpperCase();
|
|
54
|
+
if (/^[A-Z]{3}$/.test(firstPart)) {
|
|
55
|
+
currencyCode = firstPart;
|
|
56
|
+
}
|
|
57
|
+
else if (/^[A-Z]{3}$/.test(secondPart)) {
|
|
58
|
+
currencyCode = secondPart;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
currencyCode = firstPart;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
currencyCode = parts[0].toUpperCase();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
currencyCode = 'USD';
|
|
70
|
+
}
|
|
71
|
+
let currency = (0, tool_1.getCurrencySymbol)(currencyCode);
|
|
49
72
|
const isToLocStr = enableFormattedPrice === undefined || enableFormattedPrice;
|
|
50
73
|
let decPic = price === null || price === void 0 ? void 0 : price.toString();
|
|
51
74
|
if (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.showTwoDecimalPoint) {
|
|
52
75
|
decPic = price === null || price === void 0 ? void 0 : price.toFixed(2);
|
|
53
76
|
}
|
|
54
|
-
let decInd = (
|
|
77
|
+
let decInd = (_a = decPic === null || decPic === void 0 ? void 0 : decPic.indexOf('.')) !== null && _a !== void 0 ? _a : -1;
|
|
55
78
|
if (isToLocStr) {
|
|
56
79
|
text =
|
|
57
|
-
(
|
|
80
|
+
(_b = price === null || price === void 0 ? void 0 : price.toLocaleString('zh', {
|
|
58
81
|
minimumFractionDigits: (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.showTwoDecimalPoint) ? 2 : 0
|
|
59
|
-
})) !== null &&
|
|
82
|
+
})) !== null && _b !== void 0 ? _b : '';
|
|
60
83
|
let startIndex = 0;
|
|
61
84
|
let endIndex = decInd !== null && decInd !== void 0 ? decInd : text === null || text === void 0 ? void 0 : text.length;
|
|
62
85
|
if ((priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.millesimalSymbol) === '.') {
|
|
@@ -86,7 +109,7 @@ const getPriceText = ({ product, enableFormattedPrice, globalConfig, isHiddenDef
|
|
|
86
109
|
}
|
|
87
110
|
});
|
|
88
111
|
}
|
|
89
|
-
currency = `<span style="font-family:${(
|
|
112
|
+
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>`;
|
|
90
113
|
text = (0, tool_1.setFontForText)(text, style);
|
|
91
114
|
if ((priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) && (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) !== 'none') {
|
|
92
115
|
text = (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) === 'left' ? currency + text : text + currency;
|
package/lib/core/utils/tool.d.ts
CHANGED
|
@@ -16,4 +16,5 @@ declare function splitUrlParams(urlParams: string): string[] | undefined;
|
|
|
16
16
|
declare function deleteCookie(name: string, path?: string, domain?: string): void;
|
|
17
17
|
declare function setCookie(name: string, value: string, days?: number, path?: string, domain?: string, secure?: boolean, sameSite?: string): void;
|
|
18
18
|
declare function getUrlParamByKey(key: string): any;
|
|
19
|
+
export declare function getCurrencySymbol(currencyCode: string): string;
|
|
19
20
|
export { uuid, getIndexByblockType, getBrowserInfo, getDevice, getSystem, getCookie, getScreenReader, splitUrlParams, deleteCookie, setCookie, getUrlParamByKey };
|
package/lib/core/utils/tool.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getUrlParamByKey = exports.setCookie = exports.deleteCookie = exports.splitUrlParams = exports.getScreenReader = exports.getCookie = exports.getSystem = exports.getDevice = exports.getBrowserInfo = exports.getIndexByblockType = exports.uuid = exports.setFontForText = exports.getUid = exports.generateRandomString = void 0;
|
|
3
|
+
exports.getUrlParamByKey = exports.setCookie = exports.deleteCookie = exports.splitUrlParams = exports.getScreenReader = exports.getCookie = exports.getSystem = exports.getDevice = exports.getBrowserInfo = exports.getIndexByblockType = exports.uuid = exports.getCurrencySymbol = exports.setFontForText = exports.getUid = exports.generateRandomString = void 0;
|
|
4
4
|
const uuid_1 = require("uuid");
|
|
5
5
|
function uuid(len, radix) {
|
|
6
6
|
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
|
|
@@ -250,3 +250,47 @@ function getUrlParamByKey(key) {
|
|
|
250
250
|
return (_b = params[key]) !== null && _b !== void 0 ? _b : '';
|
|
251
251
|
}
|
|
252
252
|
exports.getUrlParamByKey = getUrlParamByKey;
|
|
253
|
+
function getCurrencySymbol(currencyCode) {
|
|
254
|
+
const currencySymbolMap = {
|
|
255
|
+
USD: '$',
|
|
256
|
+
EUR: '€',
|
|
257
|
+
GBP: '£',
|
|
258
|
+
JPY: '¥',
|
|
259
|
+
CNY: '¥',
|
|
260
|
+
KRW: '₩',
|
|
261
|
+
INR: '₹',
|
|
262
|
+
RUB: '₽',
|
|
263
|
+
BRL: 'R$',
|
|
264
|
+
CAD: 'CA$',
|
|
265
|
+
AUD: 'A$',
|
|
266
|
+
CHF: 'CHF',
|
|
267
|
+
SEK: 'kr',
|
|
268
|
+
NOK: 'kr',
|
|
269
|
+
DKK: 'kr',
|
|
270
|
+
PLN: 'zł',
|
|
271
|
+
THB: '฿',
|
|
272
|
+
IDR: 'Rp',
|
|
273
|
+
MYR: 'RM',
|
|
274
|
+
PHP: '₱',
|
|
275
|
+
SGD: 'S$',
|
|
276
|
+
HKD: 'HK$',
|
|
277
|
+
TWD: 'NT$',
|
|
278
|
+
NZD: 'NZ$',
|
|
279
|
+
MXN: 'MX$',
|
|
280
|
+
ZAR: 'R',
|
|
281
|
+
TRY: '₺',
|
|
282
|
+
AED: 'AED',
|
|
283
|
+
SAR: 'SAR',
|
|
284
|
+
ILS: '₪',
|
|
285
|
+
ARS: 'AR$',
|
|
286
|
+
CLP: 'CL$',
|
|
287
|
+
COP: 'CO$',
|
|
288
|
+
VND: '₫',
|
|
289
|
+
EGP: 'E£',
|
|
290
|
+
NGN: '₦',
|
|
291
|
+
PKR: '₨',
|
|
292
|
+
BDT: '৳',
|
|
293
|
+
};
|
|
294
|
+
return currencySymbolMap[currencyCode.toUpperCase()] || currencyCode;
|
|
295
|
+
}
|
|
296
|
+
exports.getCurrencySymbol = getCurrencySymbol;
|
|
@@ -4,10 +4,11 @@ const tslib_1 = require("tslib");
|
|
|
4
4
|
const react_1 = tslib_1.__importStar(require("react"));
|
|
5
5
|
const hooks_1 = require("../../../../core/hooks");
|
|
6
6
|
const Modal_1 = tslib_1.__importDefault(require("../../../../core/components/SxpPageRender/Modal"));
|
|
7
|
+
const tool_1 = require("../../../../core/utils/tool");
|
|
7
8
|
require("./index.less");
|
|
8
9
|
const AddToCartPopup = ({ isActive = true }) => {
|
|
9
10
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
10
|
-
const { popupDetailData, globalConfig } = (0, hooks_1.useSxpDataSource)();
|
|
11
|
+
const { popupDetailData, globalConfig, bffFbReport } = (0, hooks_1.useSxpDataSource)();
|
|
11
12
|
const [productData, setProductData] = (0, react_1.useState)(null);
|
|
12
13
|
const [selectedOptions, setSelectedOptions] = (0, react_1.useState)({});
|
|
13
14
|
const [selectedVariant, setSelectedVariant] = (0, react_1.useState)(null);
|
|
@@ -139,6 +140,17 @@ const AddToCartPopup = ({ isActive = true }) => {
|
|
|
139
140
|
shopifyDomain,
|
|
140
141
|
selectedVariant
|
|
141
142
|
});
|
|
143
|
+
bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
|
|
144
|
+
eventName: 'sessionCompleted',
|
|
145
|
+
product: product ? [product] : undefined,
|
|
146
|
+
contentType: 'product',
|
|
147
|
+
rec: data,
|
|
148
|
+
position: data === null || data === void 0 ? void 0 : data.index,
|
|
149
|
+
cta_text: 'Add To Cart',
|
|
150
|
+
cta_action_type: 'add_to_cart',
|
|
151
|
+
target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
|
|
152
|
+
target_url: `https://${shopifyDomain}/cart/add`
|
|
153
|
+
});
|
|
142
154
|
const params = new URLSearchParams({
|
|
143
155
|
id: variantId,
|
|
144
156
|
quantity: quantity.toString()
|
|
@@ -150,6 +162,9 @@ const AddToCartPopup = ({ isActive = true }) => {
|
|
|
150
162
|
const totalPrice = selectedVariant
|
|
151
163
|
? (parseFloat(selectedVariant.price.amount) * quantity).toFixed(2)
|
|
152
164
|
: '0.00';
|
|
165
|
+
const displayPrice = selectedVariant
|
|
166
|
+
? `${(0, tool_1.getCurrencySymbol)(selectedVariant.price.currencyCode)}${totalPrice}`
|
|
167
|
+
: totalPrice;
|
|
153
168
|
if (loading) {
|
|
154
169
|
return (react_1.default.createElement("div", { className: 'add-to-cart-popup' },
|
|
155
170
|
react_1.default.createElement("div", { className: 'loading' }, "Loading...")));
|
|
@@ -183,9 +198,7 @@ const AddToCartPopup = ({ isActive = true }) => {
|
|
|
183
198
|
"Available: ",
|
|
184
199
|
selectedVariant.quantityAvailable))),
|
|
185
200
|
react_1.default.createElement("div", { className: 'variant-price-row' },
|
|
186
|
-
react_1.default.createElement("div", { className: 'price' },
|
|
187
|
-
"$",
|
|
188
|
-
totalPrice),
|
|
201
|
+
react_1.default.createElement("div", { className: 'price' }, displayPrice),
|
|
189
202
|
react_1.default.createElement("div", { className: 'quantity-selector' },
|
|
190
203
|
react_1.default.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1 }, "\u2212"),
|
|
191
204
|
react_1.default.createElement("span", { className: 'qty-value' }, quantity),
|
|
@@ -195,11 +208,17 @@ const AddToCartPopup = ({ isActive = true }) => {
|
|
|
195
208
|
react_1.default.createElement("div", { className: 'option-values' }, option.values.map(value => {
|
|
196
209
|
const isAvailable = productData.variants.edges.some(({ node: variant }) => {
|
|
197
210
|
const hasThisOption = variant.selectedOptions.some(opt => opt.name === option.name && opt.value === value);
|
|
198
|
-
if (!hasThisOption
|
|
211
|
+
if (!hasThisOption)
|
|
212
|
+
return false;
|
|
213
|
+
const matchesOtherSelections = Object.entries(selectedOptions).every(([key, val]) => {
|
|
214
|
+
if (key === option.name)
|
|
215
|
+
return true;
|
|
216
|
+
return variant.selectedOptions.some(opt => opt.name === key && opt.value === val);
|
|
217
|
+
});
|
|
218
|
+
if (!matchesOtherSelections)
|
|
219
|
+
return false;
|
|
220
|
+
if (!variant.availableForSale)
|
|
199
221
|
return false;
|
|
200
|
-
if (variant.quantityAvailable !== undefined) {
|
|
201
|
-
return variant.quantityAvailable > 0;
|
|
202
|
-
}
|
|
203
222
|
return true;
|
|
204
223
|
});
|
|
205
224
|
const isSelected = selectedOptions[option.name] === value;
|