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