pb-sxp-ui 1.20.14 → 1.20.16

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