pb-sxp-ui 1.20.13 → 1.20.15

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 (62) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +111 -111
  3. package/dist/index.cjs +1187 -383
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.css +73 -72
  6. package/dist/index.js +1187 -384
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.min.cjs +7 -7
  9. package/dist/index.min.cjs.map +1 -1
  10. package/dist/index.min.js +7 -7
  11. package/dist/index.min.js.map +1 -1
  12. package/dist/pb-ui.js +1187 -383
  13. package/dist/pb-ui.js.map +1 -1
  14. package/dist/pb-ui.min.js +7 -7
  15. package/dist/pb-ui.min.js.map +1 -1
  16. package/es/core/components/DiyPortalPreview/VideoWidget.js +10 -8
  17. package/es/core/components/DiyStoryPreview/index.js +10 -4
  18. package/es/core/components/StructurePage/index.d.ts +89 -0
  19. package/es/core/components/StructurePage/index.js +700 -0
  20. package/es/core/components/SxpPageRender/LikeButton/index.js +20 -18
  21. package/es/core/components/SxpPageRender/PictureGroup/index.d.ts +5 -0
  22. package/es/core/components/SxpPageRender/PictureGroup/index.js +39 -13
  23. package/es/core/components/SxpPageRender/VideoWidget/index.js +33 -46
  24. package/es/core/components/SxpPageRender/WaterFall/index.js +4 -3
  25. package/es/core/components/SxpPageRender/fakeData.js +1 -1
  26. package/es/core/components/SxpPageRender/index.js +66 -44
  27. package/es/core/context/SxpDataSourceProvider.d.ts +5 -12
  28. package/es/core/context/SxpDataSourceProvider.js +84 -38
  29. package/es/core/hooks/useEventReport.js +6 -5
  30. package/es/core/hooks/useVisibleHeight.js +7 -7
  31. package/es/core/index.d.ts +2 -0
  32. package/es/core/index.js +1 -0
  33. package/es/core/utils/materials.d.ts +1 -1
  34. package/es/index.d.ts +1 -0
  35. package/es/index.js +1 -0
  36. package/es/materials/sxp/MultiPosts/index.js +4 -4
  37. package/es/materials/sxp/popup/CommodityDetail/index.js +4 -4
  38. package/es/materials/sxp/popup/CommodityDetailDiroNew/index.js +1 -1
  39. package/lib/core/components/DiyPortalPreview/VideoWidget.js +10 -8
  40. package/lib/core/components/DiyStoryPreview/index.js +10 -4
  41. package/lib/core/components/StructurePage/index.d.ts +89 -0
  42. package/lib/core/components/StructurePage/index.js +702 -0
  43. package/lib/core/components/SxpPageRender/LikeButton/index.js +20 -18
  44. package/lib/core/components/SxpPageRender/PictureGroup/index.d.ts +5 -0
  45. package/lib/core/components/SxpPageRender/PictureGroup/index.js +38 -12
  46. package/lib/core/components/SxpPageRender/VideoWidget/index.js +33 -46
  47. package/lib/core/components/SxpPageRender/WaterFall/index.js +4 -3
  48. package/lib/core/components/SxpPageRender/fakeData.js +1 -1
  49. package/lib/core/components/SxpPageRender/index.js +66 -44
  50. package/lib/core/context/SxpDataSourceProvider.d.ts +5 -12
  51. package/lib/core/context/SxpDataSourceProvider.js +84 -38
  52. package/lib/core/hooks/useEventReport.js +6 -5
  53. package/lib/core/hooks/useVisibleHeight.js +7 -7
  54. package/lib/core/index.d.ts +2 -0
  55. package/lib/core/index.js +6 -1
  56. package/lib/core/utils/materials.d.ts +1 -1
  57. package/lib/index.d.ts +1 -0
  58. package/lib/index.js +3 -1
  59. package/lib/materials/sxp/MultiPosts/index.js +4 -4
  60. package/lib/materials/sxp/popup/CommodityDetail/index.js +4 -4
  61. package/lib/materials/sxp/popup/CommodityDetailDiroNew/index.js +1 -1
  62. package/package.json +111 -111
@@ -0,0 +1,702 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importStar(require("react"));
5
+ const hooks_1 = require("../../hooks");
6
+ const FormatImage_1 = tslib_1.__importDefault(require("../SxpPageRender/FormatImage"));
7
+ const RESOLVER = {};
8
+ try {
9
+ const materialsModule = require('../../materials/sxp');
10
+ Object.values(materialsModule).forEach((v) => {
11
+ var _a;
12
+ if ((_a = v === null || v === void 0 ? void 0 : v.extend) === null || _a === void 0 ? void 0 : _a.type) {
13
+ RESOLVER[v.extend.type] = v;
14
+ }
15
+ });
16
+ }
17
+ catch (error) {
18
+ console.warn('Failed to load materials for StructurePage:', error);
19
+ }
20
+ const baseStyles = {
21
+ container: {
22
+ backgroundColor: '#000',
23
+ overflowY: 'auto',
24
+ overflowX: 'hidden',
25
+ padding: 0,
26
+ boxSizing: 'border-box'
27
+ },
28
+ section: {
29
+ width: '100%',
30
+ position: 'relative',
31
+ boxSizing: 'border-box'
32
+ },
33
+ heroSection: {
34
+ width: '100%',
35
+ height: 'auto',
36
+ position: 'relative',
37
+ overflow: 'hidden',
38
+ backgroundColor: '#000'
39
+ },
40
+ heroTopText: {
41
+ width: '100%',
42
+ padding: '20px',
43
+ backgroundColor: '#fff',
44
+ color: '#000',
45
+ fontSize: '16px',
46
+ fontWeight: 'bold',
47
+ textAlign: 'center',
48
+ boxSizing: 'border-box'
49
+ },
50
+ heroImageContainer: {
51
+ width: '100%',
52
+ position: 'relative',
53
+ overflow: 'hidden'
54
+ },
55
+ heroImage: {
56
+ width: '100%',
57
+ height: 'auto',
58
+ display: 'block',
59
+ objectFit: 'cover'
60
+ },
61
+ heroVideo: {
62
+ width: '100%',
63
+ height: 'auto',
64
+ display: 'block',
65
+ objectFit: 'cover'
66
+ },
67
+ heroOverlay: {
68
+ position: 'absolute',
69
+ bottom: 0,
70
+ left: 0,
71
+ right: 0,
72
+ padding: '40px 20px',
73
+ background: 'linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 100%)',
74
+ color: '#fff',
75
+ display: 'flex',
76
+ justifyContent: 'center',
77
+ alignItems: 'center'
78
+ },
79
+ heroButton: {
80
+ padding: '12px 30px',
81
+ backgroundColor: '#fff',
82
+ color: '#000',
83
+ border: 'none',
84
+ fontSize: '14px',
85
+ fontWeight: 500,
86
+ cursor: 'pointer',
87
+ textTransform: 'uppercase'
88
+ },
89
+ carouselSection: {
90
+ width: '100%',
91
+ position: 'relative'
92
+ },
93
+ carouselImageContainer: {
94
+ width: '100%',
95
+ height: 'auto',
96
+ position: 'relative',
97
+ overflow: 'hidden'
98
+ },
99
+ carouselContainer: {
100
+ display: 'flex',
101
+ transition: 'transform 0.5s ease-in-out',
102
+ width: '100%'
103
+ },
104
+ carouselSlide: {
105
+ minWidth: '100%',
106
+ position: 'relative'
107
+ },
108
+ carouselImage: {
109
+ width: '100%',
110
+ height: 'auto',
111
+ display: 'block',
112
+ objectFit: 'cover'
113
+ },
114
+ carouselVideo: {
115
+ width: '100%',
116
+ height: 'auto',
117
+ display: 'block',
118
+ objectFit: 'cover'
119
+ },
120
+ carouselInfoSection: {
121
+ width: '100%',
122
+ padding: '20px',
123
+ backgroundColor: '#000',
124
+ color: '#fff',
125
+ textAlign: 'center'
126
+ },
127
+ carouselText: {
128
+ fontSize: '16px',
129
+ fontWeight: 'normal',
130
+ marginBottom: '15px',
131
+ color: '#fff'
132
+ },
133
+ carouselButton: {
134
+ padding: '10px 25px',
135
+ backgroundColor: '#fff',
136
+ color: '#000',
137
+ border: '1px solid #fff',
138
+ fontSize: '13px',
139
+ fontWeight: 500,
140
+ cursor: 'pointer',
141
+ textTransform: 'uppercase'
142
+ },
143
+ arrowButton: {
144
+ position: 'absolute',
145
+ top: '50%',
146
+ transform: 'translateY(-50%)',
147
+ width: '40px',
148
+ height: '40px',
149
+ backgroundColor: 'rgba(255,255,255,0.8)',
150
+ border: 'none',
151
+ borderRadius: '50%',
152
+ fontSize: '18px',
153
+ cursor: 'pointer',
154
+ zIndex: 10,
155
+ display: 'flex',
156
+ alignItems: 'center',
157
+ justifyContent: 'center'
158
+ },
159
+ highlightSection: {
160
+ width: '100%',
161
+ position: 'relative',
162
+ backgroundColor: '#000'
163
+ },
164
+ highlightImageContainer: {
165
+ width: '100%',
166
+ aspectRatio: '1/1',
167
+ position: 'relative',
168
+ overflow: 'hidden'
169
+ },
170
+ highlightImage: {
171
+ width: '100%',
172
+ height: '100%',
173
+ objectFit: 'cover',
174
+ display: 'block'
175
+ },
176
+ highlightInfoSection: {
177
+ width: '100%',
178
+ padding: '20px',
179
+ backgroundColor: '#000',
180
+ color: '#fff',
181
+ textAlign: 'center'
182
+ },
183
+ highlightTitle: {
184
+ fontSize: '18px',
185
+ fontWeight: 'bold',
186
+ marginBottom: '10px',
187
+ textAlign: 'center',
188
+ color: '#fff'
189
+ },
190
+ highlightDesc: {
191
+ fontSize: '14px',
192
+ marginBottom: '15px',
193
+ textAlign: 'center',
194
+ lineHeight: '1.5',
195
+ color: '#ccc'
196
+ },
197
+ highlightButton: {
198
+ padding: '10px 25px',
199
+ backgroundColor: 'transparent',
200
+ color: '#fff',
201
+ border: '1px solid #fff',
202
+ fontSize: '13px',
203
+ fontWeight: 500,
204
+ cursor: 'pointer',
205
+ textTransform: 'uppercase'
206
+ },
207
+ productGrid: {
208
+ display: 'grid',
209
+ gridTemplateColumns: '50% 50%',
210
+ gridAutoRows: 'auto',
211
+ gap: '0',
212
+ width: '100%',
213
+ backgroundColor: '#000',
214
+ boxSizing: 'border-box',
215
+ margin: 0,
216
+ padding: 0,
217
+ overflow: 'hidden'
218
+ },
219
+ productItem: {
220
+ position: 'relative',
221
+ backgroundColor: '#000',
222
+ display: 'block',
223
+ boxSizing: 'border-box',
224
+ width: '100%',
225
+ minWidth: 0,
226
+ overflow: 'hidden'
227
+ },
228
+ productImageContainer: {
229
+ width: '100%',
230
+ paddingBottom: '100%',
231
+ position: 'relative',
232
+ overflow: 'hidden'
233
+ },
234
+ productImage: {
235
+ position: 'absolute',
236
+ top: 0,
237
+ left: 0,
238
+ width: '100%',
239
+ height: '100%',
240
+ objectFit: 'cover',
241
+ display: 'block'
242
+ },
243
+ productCtaContainer: {
244
+ width: '100%',
245
+ padding: '15px',
246
+ backgroundColor: '#000',
247
+ textAlign: 'center',
248
+ boxSizing: 'border-box'
249
+ },
250
+ productText: {
251
+ width: '100%',
252
+ padding: '15px',
253
+ backgroundColor: '#000',
254
+ color: '#fff',
255
+ textAlign: 'center',
256
+ fontSize: '14px',
257
+ fontWeight: 'normal',
258
+ boxSizing: 'border-box'
259
+ },
260
+ productButton: {
261
+ padding: '8px 20px',
262
+ backgroundColor: 'transparent',
263
+ color: '#fff',
264
+ border: '1px solid #fff',
265
+ fontSize: '12px',
266
+ fontWeight: 500,
267
+ cursor: 'pointer',
268
+ textTransform: 'uppercase',
269
+ whiteSpace: 'nowrap'
270
+ },
271
+ footerSection: {
272
+ width: '100%',
273
+ position: 'relative',
274
+ backgroundColor: '#000'
275
+ },
276
+ footerInfoSection: {
277
+ width: '100%',
278
+ padding: '20px',
279
+ backgroundColor: '#000',
280
+ color: '#fff',
281
+ textAlign: 'center'
282
+ },
283
+ footerText: {
284
+ fontSize: '18px',
285
+ fontWeight: 'normal',
286
+ marginBottom: '15px',
287
+ lineHeight: '1.4',
288
+ color: '#fff'
289
+ },
290
+ footerButton: {
291
+ padding: '10px 25px',
292
+ backgroundColor: 'transparent',
293
+ color: '#fff',
294
+ border: '1px solid #fff',
295
+ fontSize: '13px',
296
+ fontWeight: 500,
297
+ cursor: 'pointer',
298
+ textTransform: 'uppercase',
299
+ marginBottom: '20px',
300
+ display: 'inline-block'
301
+ },
302
+ footerImageContainer: {
303
+ width: '100%',
304
+ aspectRatio: '1/1',
305
+ overflow: 'hidden'
306
+ },
307
+ footerImage: {
308
+ width: '100%',
309
+ height: '100%',
310
+ objectFit: 'cover',
311
+ display: 'block'
312
+ }
313
+ };
314
+ const StructurePage = (_a) => {
315
+ var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
316
+ var { containerStyle, containerHeight = 664, containerWidth = 375, className = '', apiUrl = 'https://bff-be-dev.chatlabs.net/api/v1/recommend/list', requestBody, editorMode = false, multiCTAConfig: propMultiCTAConfig, videoPlayIcon: propVideoPlayIcon, isCmsMode = false, storyId, customHeaders } = _a, rest = tslib_1.__rest(_a, ["containerStyle", "containerHeight", "containerWidth", "className", "apiUrl", "requestBody", "editorMode", "multiCTAConfig", "videoPlayIcon", "isCmsMode", "storyId", "customHeaders"]);
317
+ const [data, setData] = (0, react_1.useState)(null);
318
+ const [loading, setLoading] = (0, react_1.useState)(true);
319
+ const [error, setError] = (0, react_1.useState)(null);
320
+ const [carouselIndex, setCarouselIndex] = (0, react_1.useState)(0);
321
+ const heroVideoRef = (0, react_1.useRef)(null);
322
+ const carouselVideoRefs = (0, react_1.useRef)([]);
323
+ const [isHeroVideoPaused, setIsHeroVideoPaused] = (0, react_1.useState)(false);
324
+ const [carouselVideoPausedStates, setCarouselVideoPausedStates] = (0, react_1.useState)([]);
325
+ const { schema } = (0, hooks_1.useEditor)();
326
+ const multiCTAConfig = (0, react_1.useMemo)(() => {
327
+ var _a;
328
+ return propMultiCTAConfig || ((_a = schema === null || schema === void 0 ? void 0 : schema.sxpPageConf) === null || _a === void 0 ? void 0 : _a.multiCTAConfig) || {};
329
+ }, [propMultiCTAConfig, (_b = schema === null || schema === void 0 ? void 0 : schema.sxpPageConf) === null || _b === void 0 ? void 0 : _b.multiCTAConfig]);
330
+ const DEFAULT_PAUSE_ICON = 'https://sxph5-uat.chatlabs.net/pb_static/06f28a2025c74c1cb49be6767316d827.png';
331
+ const videoPlayIcon = (0, react_1.useMemo)(() => {
332
+ var _a, _b;
333
+ if (propVideoPlayIcon)
334
+ return propVideoPlayIcon;
335
+ const configIcon = (_b = (_a = schema === null || schema === void 0 ? void 0 : schema.sxpPageConf) === null || _a === void 0 ? void 0 : _a.globalConfig) === null || _b === void 0 ? void 0 : _b.videoPlayIcon;
336
+ if (configIcon) {
337
+ if (configIcon.startsWith('http://') || configIcon.startsWith('https://')) {
338
+ return configIcon;
339
+ }
340
+ if (configIcon.startsWith('/')) {
341
+ return `${window.location.origin}${configIcon}`;
342
+ }
343
+ return configIcon;
344
+ }
345
+ return DEFAULT_PAUSE_ICON;
346
+ }, [propVideoPlayIcon, (_d = (_c = schema === null || schema === void 0 ? void 0 : schema.sxpPageConf) === null || _c === void 0 ? void 0 : _c.globalConfig) === null || _d === void 0 ? void 0 : _d.videoPlayIcon]);
347
+ const handleCtaClick = (0, react_1.useCallback)((link, interaction, productData, ctaData) => {
348
+ if (interaction) {
349
+ const { linkType, popupType, popupAni } = interaction;
350
+ if (linkType === 'popup' && popupType) {
351
+ if (productData && typeof window !== 'undefined' && window.setPopupDetailData) {
352
+ const popupData = {
353
+ video: {
354
+ bindProduct: productData,
355
+ bindProducts: [productData],
356
+ bindCta: ctaData
357
+ }
358
+ };
359
+ window.setPopupDetailData(popupData);
360
+ }
361
+ if (typeof window !== 'undefined' && window.sxpPopup) {
362
+ if (popupAni && popupAni.name) {
363
+ window.sxpPopup(popupType, popupAni);
364
+ }
365
+ else {
366
+ window.sxpPopup(popupType);
367
+ }
368
+ }
369
+ return;
370
+ }
371
+ }
372
+ if (link) {
373
+ window.open(link, '_blank');
374
+ }
375
+ }, []);
376
+ const mergeStyles = (0, react_1.useCallback)((baseStyle, configKey) => {
377
+ if (!editorMode || !multiCTAConfig[configKey]) {
378
+ return baseStyle;
379
+ }
380
+ const config = multiCTAConfig[configKey];
381
+ const styleKeys = [
382
+ 'fontSize', 'color', 'textAlign', 'fontWeight',
383
+ 'backgroundColor', 'padding', 'margin', 'borderRadius',
384
+ 'showBorder', 'borderWidth', 'borderColor',
385
+ 'buttonBackgroundColor', 'buttonTextColor', 'buttonWidth', 'buttonHeight'
386
+ ];
387
+ const styleConfig = Object.keys(config)
388
+ .filter(key => styleKeys.includes(key))
389
+ .reduce((obj, key) => {
390
+ obj[key] = config[key];
391
+ return obj;
392
+ }, {});
393
+ if (Object.keys(styleConfig).length === 0) {
394
+ return baseStyle;
395
+ }
396
+ const customStyle = {};
397
+ if (styleConfig.fontSize && typeof styleConfig.fontSize === 'number') {
398
+ customStyle.fontSize = `${styleConfig.fontSize}px`;
399
+ }
400
+ if (styleConfig.color && typeof styleConfig.color === 'string') {
401
+ customStyle.color = styleConfig.color;
402
+ }
403
+ if (styleConfig.textAlign && typeof styleConfig.textAlign === 'string') {
404
+ customStyle.textAlign = styleConfig.textAlign;
405
+ }
406
+ if (styleConfig.fontWeight && typeof styleConfig.fontWeight === 'number') {
407
+ customStyle.fontWeight = styleConfig.fontWeight;
408
+ }
409
+ if (styleConfig.backgroundColor && typeof styleConfig.backgroundColor === 'string') {
410
+ customStyle.backgroundColor = styleConfig.backgroundColor;
411
+ }
412
+ if (styleConfig.padding && typeof styleConfig.padding === 'string') {
413
+ customStyle.padding = styleConfig.padding;
414
+ }
415
+ if (styleConfig.margin && typeof styleConfig.margin === 'string') {
416
+ customStyle.margin = styleConfig.margin;
417
+ }
418
+ if (styleConfig.borderRadius && typeof styleConfig.borderRadius === 'number') {
419
+ customStyle.borderRadius = `${styleConfig.borderRadius}px`;
420
+ }
421
+ if (styleConfig.showBorder && styleConfig.borderWidth && typeof styleConfig.borderWidth === 'number') {
422
+ customStyle.border = `${styleConfig.borderWidth}px solid ${styleConfig.borderColor || '#d9d9d9'}`;
423
+ }
424
+ if (styleConfig.buttonBackgroundColor && typeof styleConfig.buttonBackgroundColor === 'string') {
425
+ customStyle.backgroundColor = styleConfig.buttonBackgroundColor;
426
+ }
427
+ if (styleConfig.buttonTextColor && typeof styleConfig.buttonTextColor === 'string') {
428
+ customStyle.color = styleConfig.buttonTextColor;
429
+ }
430
+ if (styleConfig.buttonWidth && typeof styleConfig.buttonWidth === 'number') {
431
+ customStyle.width = `${styleConfig.buttonWidth}px`;
432
+ }
433
+ if (styleConfig.buttonHeight && typeof styleConfig.buttonHeight === 'number') {
434
+ customStyle.height = `${styleConfig.buttonHeight}px`;
435
+ }
436
+ return Object.assign(Object.assign({}, baseStyle), customStyle);
437
+ }, [editorMode, multiCTAConfig]);
438
+ const renderCTA = (0, react_1.useCallback)((buttonKey, ctaData, productData, fallbackStyle) => {
439
+ var _a, _b, _c;
440
+ if (!ctaData) {
441
+ return null;
442
+ }
443
+ const config = multiCTAConfig[buttonKey];
444
+ const templateType = config === null || config === void 0 ? void 0 : config.templateType;
445
+ const interaction = config === null || config === void 0 ? void 0 : config.interaction;
446
+ if (editorMode && templateType && RESOLVER[templateType]) {
447
+ const TemplateComponent = RESOLVER[templateType];
448
+ const templateExtend = TemplateComponent === null || TemplateComponent === void 0 ? void 0 : TemplateComponent.extend;
449
+ if (templateExtend) {
450
+ const templateProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (_a = templateExtend.defaulSetting) === null || _a === void 0 ? void 0 : _a.props), { style: Object.assign(Object.assign(Object.assign({}, (_b = templateExtend.defaulSetting) === null || _b === void 0 ? void 0 : _b.style), mergeStyles(fallbackStyle || {}, buttonKey)), { marginBottom: 0, width: '100%' }), textStyle: (_c = templateExtend.defaulSetting) === null || _c === void 0 ? void 0 : _c.textStyle }), (productData && { bindProduct: productData })), { isTel: true }), rest);
451
+ return react_1.default.createElement(TemplateComponent, templateProps);
452
+ }
453
+ }
454
+ return (react_1.default.createElement("button", { style: mergeStyles(fallbackStyle || baseStyles.heroButton, buttonKey), onClick: () => handleCtaClick(ctaData === null || ctaData === void 0 ? void 0 : ctaData.link, interaction, productData, ctaData) }, ctaData.title));
455
+ }, [multiCTAConfig, editorMode, handleCtaClick, mergeStyles, rest]);
456
+ (0, react_1.useEffect)(() => {
457
+ const hasActualData = propMultiCTAConfig && (propMultiCTAConfig.heroSection ||
458
+ propMultiCTAConfig.carouselSection ||
459
+ propMultiCTAConfig.highlightRevealSection ||
460
+ propMultiCTAConfig.productGridSection ||
461
+ propMultiCTAConfig.footerSection);
462
+ if (editorMode && hasActualData && !isCmsMode) {
463
+ setLoading(false);
464
+ setError(null);
465
+ setData(propMultiCTAConfig);
466
+ return;
467
+ }
468
+ if (editorMode && data && !isCmsMode) {
469
+ return;
470
+ }
471
+ setLoading(true);
472
+ setError(null);
473
+ let finalApiUrl = apiUrl;
474
+ let bodyToSend = {};
475
+ if (isCmsMode) {
476
+ if (!storyId) {
477
+ console.error('[StructurePage CMS Mode] storyId is required but not provided');
478
+ setError('storyId is required in CMS mode');
479
+ setLoading(false);
480
+ return;
481
+ }
482
+ finalApiUrl = `${apiUrl}/api/console/ad/multiCta/rec/detail`;
483
+ bodyToSend = { storyId };
484
+ }
485
+ else {
486
+ const defaultBody = {
487
+ maxSize: 20,
488
+ defaultSize: 10,
489
+ type: 'story'
490
+ };
491
+ bodyToSend = requestBody ? Object.assign(Object.assign({}, defaultBody), requestBody) : defaultBody;
492
+ }
493
+ const headers = {
494
+ 'Content-Type': 'application/json'
495
+ };
496
+ if (isCmsMode) {
497
+ if (customHeaders) {
498
+ Object.assign(headers, customHeaders);
499
+ }
500
+ }
501
+ else {
502
+ if (bodyToSend['x-app-id']) {
503
+ headers['x-app-id'] = bodyToSend['x-app-id'];
504
+ delete bodyToSend['x-app-id'];
505
+ }
506
+ if (bodyToSend['x-user-id']) {
507
+ headers['x-user-id'] = bodyToSend['x-user-id'];
508
+ delete bodyToSend['x-user-id'];
509
+ }
510
+ if (bodyToSend['tenant-id']) {
511
+ headers['tenant-id'] = bodyToSend['tenant-id'];
512
+ delete bodyToSend['tenant-id'];
513
+ }
514
+ }
515
+ fetch(finalApiUrl, {
516
+ method: 'POST',
517
+ headers,
518
+ body: JSON.stringify(bodyToSend),
519
+ credentials: 'include'
520
+ })
521
+ .then((res) => {
522
+ if (!res.ok) {
523
+ throw new Error(`HTTP error! status: ${res.status}`);
524
+ }
525
+ return res.json();
526
+ })
527
+ .then((result) => {
528
+ var _a, _b, _c, _d;
529
+ if (result.code === '0' || result.code === '00000') {
530
+ let multiCtaData = null;
531
+ if (isCmsMode) {
532
+ multiCtaData = (_a = result.data) === null || _a === void 0 ? void 0 : _a.multiCta;
533
+ }
534
+ else {
535
+ multiCtaData = (_d = (_c = (_b = result.data) === null || _b === void 0 ? void 0 : _b.recList) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.multiCta;
536
+ }
537
+ if (multiCtaData) {
538
+ setData(multiCtaData);
539
+ }
540
+ else {
541
+ console.error('[StructurePage] No multiCta data found in response:', result);
542
+ setError(result.message || 'No multiCta data found');
543
+ }
544
+ }
545
+ else {
546
+ setError(result.message || 'Failed to load data');
547
+ }
548
+ setLoading(false);
549
+ })
550
+ .catch((err) => {
551
+ console.error('[StructurePage] Failed to fetch data:', {
552
+ error: err,
553
+ message: err.message,
554
+ url: finalApiUrl,
555
+ body: bodyToSend,
556
+ isCmsMode,
557
+ storyId
558
+ });
559
+ setError(err.message || 'Network error');
560
+ setLoading(false);
561
+ });
562
+ }, [apiUrl, isCmsMode, storyId, customHeaders]);
563
+ (0, react_1.useEffect)(() => {
564
+ var _a;
565
+ if (heroVideoRef.current && ((_a = data === null || data === void 0 ? void 0 : data.heroSection) === null || _a === void 0 ? void 0 : _a.url)) {
566
+ heroVideoRef.current.play().catch((err) => console.log('Video autoplay failed:', err));
567
+ setIsHeroVideoPaused(false);
568
+ }
569
+ }, [data === null || data === void 0 ? void 0 : data.heroSection]);
570
+ (0, react_1.useEffect)(() => {
571
+ if (data === null || data === void 0 ? void 0 : data.carouselSection) {
572
+ setCarouselVideoPausedStates(new Array(data.carouselSection.length).fill(true));
573
+ }
574
+ }, [data === null || data === void 0 ? void 0 : data.carouselSection]);
575
+ const handleHeroVideoClick = (0, react_1.useCallback)(() => {
576
+ if (heroVideoRef.current) {
577
+ if (heroVideoRef.current.paused) {
578
+ heroVideoRef.current.play();
579
+ setIsHeroVideoPaused(false);
580
+ }
581
+ else {
582
+ heroVideoRef.current.pause();
583
+ setIsHeroVideoPaused(true);
584
+ }
585
+ }
586
+ }, []);
587
+ const handleCarouselVideoClick = (0, react_1.useCallback)((index) => {
588
+ const videoRef = carouselVideoRefs.current[index];
589
+ if (videoRef) {
590
+ if (videoRef.paused) {
591
+ videoRef.play();
592
+ setCarouselVideoPausedStates(prev => {
593
+ const newStates = [...prev];
594
+ newStates[index] = false;
595
+ return newStates;
596
+ });
597
+ }
598
+ else {
599
+ videoRef.pause();
600
+ setCarouselVideoPausedStates(prev => {
601
+ const newStates = [...prev];
602
+ newStates[index] = true;
603
+ return newStates;
604
+ });
605
+ }
606
+ }
607
+ }, []);
608
+ const handleCarouselPrev = () => {
609
+ if (data === null || data === void 0 ? void 0 : data.carouselSection) {
610
+ setCarouselIndex((prev) => (prev === 0 ? data.carouselSection.length - 1 : prev - 1));
611
+ }
612
+ };
613
+ const handleCarouselNext = () => {
614
+ if (data === null || data === void 0 ? void 0 : data.carouselSection) {
615
+ setCarouselIndex((prev) => (prev === data.carouselSection.length - 1 ? 0 : prev + 1));
616
+ }
617
+ };
618
+ if (loading) {
619
+ return (react_1.default.createElement("div", { style: Object.assign(Object.assign({}, baseStyles.container), { height: containerHeight, width: containerWidth, display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: '16px' }) }, "Loading..."));
620
+ }
621
+ if (error) {
622
+ return (react_1.default.createElement("div", { style: Object.assign(Object.assign({}, baseStyles.container), { height: containerHeight, width: containerWidth, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', color: '#fff', padding: '20px', textAlign: 'center' }) },
623
+ react_1.default.createElement("div", { style: { fontSize: '18px', marginBottom: '10px' } }, "\u26A0\uFE0F Error"),
624
+ react_1.default.createElement("div", { style: { fontSize: '14px', opacity: 0.8 } }, error)));
625
+ }
626
+ if (!data) {
627
+ return (react_1.default.createElement("div", { style: Object.assign(Object.assign({}, baseStyles.container), { height: containerHeight, width: containerWidth, display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: '16px' }) }, "No data available"));
628
+ }
629
+ return (react_1.default.createElement("div", { className: className, style: Object.assign(Object.assign(Object.assign({}, baseStyles.container), { height: containerHeight, width: containerWidth }), containerStyle) },
630
+ data.heroSection && (react_1.default.createElement("div", { style: baseStyles.heroSection },
631
+ data.heroSection.text && (react_1.default.createElement("div", { style: mergeStyles(baseStyles.heroTopText, 'heroTopText') }, data.heroSection.text)),
632
+ react_1.default.createElement("div", { style: baseStyles.heroImageContainer },
633
+ data.heroSection.url ? (react_1.default.createElement("div", { style: { position: 'relative', width: '100%', height: '100%' }, onClick: handleHeroVideoClick },
634
+ react_1.default.createElement("video", { ref: heroVideoRef, src: data.heroSection.url, style: baseStyles.heroVideo, autoPlay: true, muted: true, loop: true, playsInline: true, controls: false }),
635
+ isHeroVideoPaused && (react_1.default.createElement(FormatImage_1.default, { className: 'clc-pb-video-pause', src: videoPlayIcon, alt: 'play' })))) : ((_e = data.heroSection.imgUrls) === null || _e === void 0 ? void 0 : _e[0]) ? (react_1.default.createElement("img", { src: data.heroSection.imgUrls[0], alt: 'Hero', style: baseStyles.heroImage })) : null,
636
+ react_1.default.createElement("div", { style: baseStyles.heroOverlay }, renderCTA('heroButton', (_g = (_f = data.heroSection.bindProducts) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g.bindCta, (_h = data.heroSection.bindProducts) === null || _h === void 0 ? void 0 : _h[0], baseStyles.heroButton))))),
637
+ data.carouselSection && data.carouselSection.length > 0 && (react_1.default.createElement("div", { style: mergeStyles(baseStyles.carouselSection, 'carouselSection') },
638
+ react_1.default.createElement("div", { style: baseStyles.carouselImageContainer },
639
+ react_1.default.createElement("div", { style: Object.assign(Object.assign({}, baseStyles.carouselContainer), { transform: `translateX(-${carouselIndex * 100}%)` }) }, data.carouselSection.map((item, index) => {
640
+ var _a;
641
+ return (react_1.default.createElement("div", { key: item.itemId, style: baseStyles.carouselSlide }, item.url ? (react_1.default.createElement("div", { style: { position: 'relative', width: '100%', height: '100%' }, onClick: () => handleCarouselVideoClick(index) },
642
+ react_1.default.createElement("video", { ref: (el) => {
643
+ carouselVideoRefs.current[index] = el;
644
+ }, src: item.url, style: baseStyles.carouselVideo, muted: true, loop: true, playsInline: true, controls: false }),
645
+ carouselVideoPausedStates[index] && (react_1.default.createElement(FormatImage_1.default, { className: 'clc-pb-video-pause', src: videoPlayIcon, alt: 'play' })))) : ((_a = item.imgUrls) === null || _a === void 0 ? void 0 : _a[0]) ? (react_1.default.createElement("img", { src: item.imgUrls[0], alt: item.text || 'Carousel', style: baseStyles.carouselImage })) : null));
646
+ })),
647
+ react_1.default.createElement("button", { style: Object.assign(Object.assign({}, baseStyles.arrowButton), { left: '10px' }), onClick: handleCarouselPrev }, "\u2039"),
648
+ react_1.default.createElement("button", { style: Object.assign(Object.assign({}, baseStyles.arrowButton), { right: '10px' }), onClick: handleCarouselNext }, "\u203A")),
649
+ react_1.default.createElement("div", { style: mergeStyles(baseStyles.carouselInfoSection, 'carouselSection') },
650
+ ((_j = data.carouselSection[carouselIndex]) === null || _j === void 0 ? void 0 : _j.text) && (react_1.default.createElement("div", { style: mergeStyles(baseStyles.carouselText, 'carouselSection') }, (_k = data.carouselSection[carouselIndex]) === null || _k === void 0 ? void 0 : _k.text)),
651
+ renderCTA('carouselButton', (_o = (_m = (_l = data.carouselSection[carouselIndex]) === null || _l === void 0 ? void 0 : _l.bindProducts) === null || _m === void 0 ? void 0 : _m[0]) === null || _o === void 0 ? void 0 : _o.bindCta, (_q = (_p = data.carouselSection[carouselIndex]) === null || _p === void 0 ? void 0 : _p.bindProducts) === null || _q === void 0 ? void 0 : _q[0], baseStyles.carouselButton)))),
652
+ data.highlightRevealSection && (react_1.default.createElement("div", { style: mergeStyles(baseStyles.highlightSection, 'highlightSection') },
653
+ react_1.default.createElement("div", { style: baseStyles.highlightImageContainer },
654
+ react_1.default.createElement("img", { src: data.highlightRevealSection.landingImageUrl || data.highlightRevealSection.cover, alt: data.highlightRevealSection.title, style: baseStyles.highlightImage })),
655
+ react_1.default.createElement("div", { style: mergeStyles(baseStyles.highlightInfoSection, 'highlightSection') },
656
+ react_1.default.createElement("div", { style: mergeStyles(baseStyles.highlightTitle, 'highlightSection') }, data.highlightRevealSection.title),
657
+ renderCTA('highlightButton', data.highlightRevealSection.bindCta, data.highlightRevealSection, baseStyles.highlightButton)))),
658
+ data.productGridSection && data.productGridSection.length > 0 && (react_1.default.createElement("div", { style: mergeStyles(baseStyles.productGrid, 'productGrid') }, (() => {
659
+ const gridItems = [null, null, null, null, null, null];
660
+ const productIndexMap = {};
661
+ data.productGridSection.forEach((product, idx) => {
662
+ var _a;
663
+ const pos = (_a = product.position) === null || _a === void 0 ? void 0 : _a.toLowerCase();
664
+ let gridIndex = -1;
665
+ if (pos === 'top_right') {
666
+ gridIndex = 1;
667
+ }
668
+ else if (pos === 'top_left') {
669
+ gridIndex = 0;
670
+ }
671
+ else if (pos === 'center_left') {
672
+ gridIndex = 2;
673
+ }
674
+ else if (pos === 'center_right') {
675
+ gridIndex = 3;
676
+ }
677
+ else if (pos === 'bottom_left') {
678
+ gridIndex = 4;
679
+ }
680
+ else if (pos === 'bottom_right') {
681
+ gridIndex = 5;
682
+ }
683
+ if (gridIndex >= 0) {
684
+ gridItems[gridIndex] = product;
685
+ productIndexMap[gridIndex] = idx + 1;
686
+ }
687
+ });
688
+ return gridItems.map((product, gridIndex) => {
689
+ const productDataIndex = productIndexMap[gridIndex];
690
+ const buttonKey = `productButton${productDataIndex || gridIndex + 1}`;
691
+ return (react_1.default.createElement("div", { key: (product === null || product === void 0 ? void 0 : product.itemId) || `empty-${gridIndex}`, style: baseStyles.productItem }, product ? (react_1.default.createElement(react_1.default.Fragment, null,
692
+ react_1.default.createElement("div", { style: baseStyles.productImageContainer },
693
+ react_1.default.createElement("img", { src: product.landingImageUrl || product.cover, style: baseStyles.productImage })),
694
+ product.bindCta && (react_1.default.createElement("div", { style: baseStyles.productCtaContainer }, renderCTA(buttonKey, product.bindCta, product, baseStyles.productButton))))) : (react_1.default.createElement("div", { style: { width: '100%', paddingBottom: '100%' } }))));
695
+ });
696
+ })())),
697
+ data.footerSection && (react_1.default.createElement("div", { style: mergeStyles(baseStyles.footerSection, 'footerSection') },
698
+ react_1.default.createElement("div", { style: mergeStyles(baseStyles.footerInfoSection, 'footerSection') }, renderCTA('footerButton', data.footerSection.bindCta, data.footerSection, baseStyles.footerButton)),
699
+ react_1.default.createElement("div", { style: baseStyles.footerImageContainer },
700
+ react_1.default.createElement("img", { src: data.footerSection.landingImageUrl || data.footerSection.cover, alt: data.footerSection.title, style: baseStyles.footerImage }))))));
701
+ };
702
+ exports.default = StructurePage;