tee3apps-cms-sdk-react 0.0.19 → 0.0.22

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 (27) hide show
  1. package/dist/index.js +2 -2
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +2 -2
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +1 -1
  6. package/src/Page.tsx +2 -2
  7. package/src/PageComponents/BoxComponent.tsx +142 -92
  8. package/src/PageComponents/Visual-Components/CarouselComponent.tsx +497 -364
  9. package/src/PageComponents/Visual-Components/GroupBrandComponent.tsx +396 -390
  10. package/src/PageComponents/Visual-Components/GroupCategoryComponent.tsx +21 -13
  11. package/src/PageComponents/Visual-Components/GroupImageList.tsx +642 -668
  12. package/src/PageComponents/Visual-Components/GroupProductComponent.tsx +46 -20
  13. package/src/PageComponents/Visual-Components/GroupVideoList.tsx +693 -589
  14. package/src/PageComponents/Visual-Components/ImageComponent.tsx +72 -17
  15. package/src/PageComponents/Visual-Components/LottieComponent.tsx +14 -8
  16. package/src/PageComponents/Visual-Components/NavigationComponent.tsx +74 -27
  17. package/src/PageComponents/Visual-Components/RichTextComponent.tsx +1 -1
  18. package/src/PageComponents/Visual-Components/TabComponent.tsx +1625 -875
  19. package/src/PageComponents/Visual-Components/TextComponent.tsx +24 -10
  20. package/src/PageComponents/Visual-Components/VideoComponent.tsx +33 -11
  21. package/src/PageComponents/Visual-Components/tab.css +645 -611
  22. package/src/index.css +126 -80
  23. package/src/Components/BoxRenderer.tsx +0 -108
  24. package/src/Components/ComponentRenderer.tsx +0 -29
  25. package/src/Components/ImageComponent.tsx +0 -68
  26. package/src/Components/RowComponent.tsx +0 -66
  27. package/src/Components/TextComponent.tsx +0 -47
@@ -1,669 +1,643 @@
1
- import React, { useState } from 'react';
2
- import { Linodeurl } from '../../const';
3
- interface ImageData {
4
- isDynamic: boolean;
5
- shape: string;
6
- url: string;
7
- alt: string;
8
- shapeImageId?: string;
9
- width?: number;
10
- height?: number;
11
- }
12
-
13
- interface ProductData {
14
- pd_type: string;
15
- pd_id?: {
16
- _id: string;
17
- code: string;
18
- name: {
19
- all: string;
20
- displayName?: string;
21
- };
22
- image?: ImageData;
23
- isActive: boolean;
24
- };
25
- product_data?: {
26
- _id: string;
27
- code: string;
28
- name: string;
29
- };
30
- }
31
-
32
-
33
-
34
- interface LinkData {
35
- url: string | null;
36
- target: string | null;
37
- }
38
-
39
- interface PageData {
40
- page_type: string | null;
41
- pg_type?: string | null;
42
-
43
- page_id?: any;
44
- page_data?:any;
45
- }
46
-
47
- interface ImageItem {
48
- id: number;
49
- attr: ImageData;
50
- title: string;
51
- subTitle: string;
52
- linktype: string;
53
- product?: ProductData;
54
- tag?: any;
55
- link?: LinkData;
56
- page?: PageData;
57
- }
58
-
59
- interface GroupImageStatic {
60
- _id: string;
61
- name: string;
62
- code: string;
63
- }
64
-
65
- interface GroupImageDynamic {
66
- code: string;
67
- name: { all: string };
68
- list: ImageItem[];
69
- isActive?: boolean;
70
- }
71
-
72
- interface GroupImageData {
73
- static: GroupImageStatic;
74
- dynamic: GroupImageDynamic;
75
- groupimagedata: ImageItem[];
76
- }
77
-
78
- interface HeaderTextStyle {
79
- fontSize: number;
80
- fontColor: string;
81
- isBold: boolean;
82
- isItalic: boolean;
83
- isUnderline: boolean;
84
- }
85
-
86
- interface DeviceBooleanProps {
87
- web: boolean;
88
- mobileweb: boolean;
89
- mobileapp: boolean;
90
- tablet: boolean;
91
- }
92
-
93
- interface DeviceLayoutProps {
94
- web: string;
95
- mobileweb: string;
96
- mobileapp: string;
97
- tablet: string;
98
- }
99
-
100
- export interface GroupImageListProps {
101
- nameData: any;
102
- data?: Array<{ id: string; type: string }>;
103
- types?: any[];
104
- type: string;
105
- groupimage: GroupImageData;
106
- headerText: any;
107
- activeStatus: boolean;
108
- headerImage: string;
109
- headerTextStyle: HeaderTextStyle;
110
- layout: DeviceLayoutProps;
111
- showHeader: DeviceBooleanProps;
112
- isHorizontalScroll: DeviceBooleanProps;
113
- headerBackground: string;
114
- carouselBackground: string;
115
- cardcolor: string;
116
- showSubtitle?: boolean;
117
- showTitle?: boolean;
118
- titleStyle?: {
119
- fontSize: number;
120
- fontColor: string;
121
- isBold: boolean;
122
- isItalic: boolean;
123
- isUnderline: boolean;
124
- };
125
- subtitleStyle?: {
126
- fontSize: number;
127
- fontColor: string;
128
- isBold: boolean;
129
- isItalic: boolean;
130
- isUnderline: boolean;
131
- };
132
- selectedChannel?: string;
133
- }
134
-
135
- interface GroupImageListMainProps {
136
- props: GroupImageListProps;
137
- deviceMode?: string;
138
- boxHeight?: string;
139
- }
140
-
141
- // Image Component Integration
142
- interface ImageComponentProps {
143
- imageData: ImageData;
144
- linkData: {
145
- linktype: string;
146
- product?: ProductData;
147
- tag?: any;
148
- link?: LinkData;
149
- page?: PageData;
150
- };
151
- borderRadius?: number;
152
- height?: string;
153
- width?: string;
154
- }
155
-
156
- const ImageComponentInternal: React.FC<ImageComponentProps> = ({
157
- imageData,
158
- linkData,
159
- borderRadius = 8,
160
- height = '100%',
161
- width = '100%'
162
- }) => {
163
- const getImageUrl = (url: string) => {
164
- if (!url) return '';
165
- if (url.startsWith('http://') || url.startsWith('https://')) return url;
166
- return `${Linodeurl}${url}`;
167
- };
168
-
169
- const buildLink = () => {
170
- console.warn(linkData)
171
- switch (linkData.linktype) {
172
-
173
- case 'NONE':
174
- return null;
175
- case 'EXTERNAL_LINK':
176
- case 'EXTERNAL':
177
- return linkData.link?.url || null;
178
- case 'PRODUCT':
179
- if (linkData.product?.pd_type === 'VARIANT') {
180
- return `/variant/${linkData.product.pd_id?.code || linkData.product.product_data?.code}`;
181
- } else {
182
- const code = linkData.product?.pd_id?.code || linkData.product?.product_data?.code;
183
- return `/model/${code}`;
184
- }
185
- case 'TAG':
186
- return `/tag/${linkData.tag?.tag_id?.code || linkData?.tag?.tag_data?.code}`;
187
- case 'PAGE':
188
- return `/page/${linkData.page?.page_id?._id || linkData.page?.page_data?._id }?type=${linkData.page?.page_type || linkData.page?.pg_type}`;
189
- default:
190
- return null;
191
- }
192
- };
193
-
194
- // const handleImageClick = () => {
195
- // const link = buildLink();
196
- // if (link === null) return;
197
-
198
- // if (link.startsWith('http')) {
199
- // window.open(link, linkData.link?.target || '_blank');
200
- // } else {
201
- // window.location.href = link;
202
- // }
203
- // };
204
-
205
- const imageStyle: React.CSSProperties = {
206
- width: width,
207
- height: height,
208
- objectFit: 'contain',
209
- borderRadius: `${borderRadius}px`,
210
- cursor: linkData.linktype !== 'NONE' ? 'pointer' : 'default',
211
- transition: 'transform 0.2s ease'
212
- };
213
-
214
- return (
215
- <a
216
- href={buildLink() ?? undefined}
217
- target={
218
- linkData?.linktype === 'EXTERNAL'
219
- ? (linkData?.link?.target ?? '_blank')
220
- : '_self'}
221
- >
222
- <div
223
- style={{
224
- width: '100%',
225
- height: '100%',
226
- borderRadius: `${borderRadius}px`,
227
- overflow: 'hidden'
228
- }}
229
- className='media-box'
230
- >
231
- <img
232
- className='media-content'
233
- src={getImageUrl(imageData.url)}
234
- alt={imageData.alt || ''}
235
- style={imageStyle}
236
- // onClick={linkData.linktype !== 'NONE' ? handleImageClick : undefined}
237
- onMouseOver={(e) => {
238
- if (linkData.linktype !== 'NONE') {
239
- (e.currentTarget as HTMLImageElement).style.transform = 'scale(1.02)';
240
- }
241
- }}
242
- onMouseOut={(e) => {
243
- (e.currentTarget as HTMLImageElement).style.transform = 'scale(1)';
244
- }}
245
- />
246
- </div>
247
- </a>
248
- );
249
- };
250
-
251
- // Main GroupImageList Component
252
- const GroupImageList: React.FC<GroupImageListMainProps> = ({
253
- props,
254
- deviceMode = 'web',
255
- boxHeight
256
- }) => {
257
- const getCurrentBooleanProp = (prop?: DeviceBooleanProps) => {
258
- if (!prop) return false;
259
- switch (deviceMode) {
260
- case 'mobileweb': return !!prop.mobileweb;
261
- case 'mobileapp': return !!prop.mobileapp;
262
- case 'tablet': return !!prop.tablet;
263
- case 'web':
264
- default: return !!prop.web;
265
- }
266
- };
267
-
268
- const getCurrentLayout = () => {
269
- if (!props.layout) return 'NONE';
270
- switch (deviceMode) {
271
- case 'mobileweb': return props.layout.mobileweb || 'NONE';
272
- case 'mobileapp': return props.layout.mobileapp || 'NONE';
273
- case 'tablet': return props.layout.tablet || 'NONE';
274
- case 'web':
275
- default: return props.layout.web || 'NONE';
276
- }
277
- };
278
-
279
- const showHeader = getCurrentBooleanProp(props.showHeader);
280
- const isHorizontalScroll = getCurrentBooleanProp(props.isHorizontalScroll);
281
- const currentLayout = getCurrentLayout();
282
-
283
- const getImages = (): ImageItem[] => {
284
- if (props.type === 'dynamic') {
285
- if (props.groupimage?.dynamic?.list?.length) return props.groupimage.dynamic.list;
286
- }
287
- if (props.groupimage?.groupimagedata?.length) return props.groupimage.groupimagedata;
288
- return [];
289
- };
290
-
291
- const images = getImages();
292
-
293
- // Carousel navigation buttons (layout NONE)
294
- const scrollLeft = () => {
295
- const scrollableContainer = document.querySelector('.scrollable-container');
296
- if (scrollableContainer) {
297
- (scrollableContainer as HTMLElement).scrollBy({ left: -200, behavior: 'smooth' });
298
- }
299
- };
300
-
301
- const scrollRight = () => {
302
- const scrollableContainer = document.querySelector('.scrollable-container');
303
- if (scrollableContainer) {
304
- (scrollableContainer as HTMLElement).scrollBy({ left: 200, behavior: 'smooth' });
305
- }
306
- };
307
-
308
- const ImageCard = ({ item, large = false }: { item: ImageItem; large?: boolean }) => {
309
- const [isHovered, setIsHovered] = useState(false);
310
-
311
- return (
312
- <div
313
- className="imageCard"
314
- style={{
315
- height: 'auto',
316
- borderRadius: '8px',
317
- overflow: 'hidden',
318
- border: '1px solid #eee',
319
- backgroundColor: props.cardcolor || '#fff',
320
- display: 'flex',
321
- flexDirection: 'column',
322
- padding: large ? '16px' : '12px',
323
- boxShadow: isHovered ? '0 4px 8px rgba(0,0,0,0.15)' : '0 2px 4px rgba(0,0,0,0.1)',
324
- transition: 'all 0.2s ease',
325
- cursor: item.linktype !== 'NONE' ? 'pointer' : 'default',
326
- transform: isHovered ? 'translateY(-2px)' : 'translateY(0px)',
327
- flex: 1
328
- }}
329
- onMouseOver={() => setIsHovered(true)}
330
- onMouseOut={() => setIsHovered(false)}
331
- >
332
- <div style={{ width: '100%', marginBottom: large ? '12px' : '8px' }}>
333
- <ImageComponentInternal
334
- imageData={item.attr}
335
- linkData={{
336
- linktype: item.linktype,
337
- product: item.product,
338
- tag: item.tag,
339
- link: item.link,
340
- page: item.page
341
- }}
342
- borderRadius={6}
343
- height={`${parseInt(boxHeight || '250') - 10}px`}
344
- />
345
- </div>
346
- {(props?.showTitle !== false) && item.title && (
347
- <div style={{
348
- textAlign: 'center',
349
- fontSize: props.titleStyle ? `${props.titleStyle.fontSize}px` : (large ? '16px' : '14px'),
350
- fontWeight: props.titleStyle?.isBold ? 'bold' : (large ? 600 : 500),
351
- color: props.titleStyle?.fontColor || '#333',
352
- fontStyle: props.titleStyle?.isItalic ? 'italic' : 'normal',
353
- textDecoration: props.titleStyle?.isUnderline ? 'underline' : 'none',
354
- lineHeight: '1.4',
355
- marginBottom: '4px'
356
- }}>
357
- {item.title}
358
- </div>
359
- )}
360
- {(props?.showSubtitle !== false) && item.subTitle && (
361
- <div style={{
362
- textAlign: 'center',
363
- fontSize: props.subtitleStyle ? `${props.subtitleStyle.fontSize}px` : (large ? '14px' : '12px'),
364
- fontWeight: props.subtitleStyle?.isBold ? 'bold' : 400,
365
- color: props.subtitleStyle?.fontColor || '#666',
366
- fontStyle: props.subtitleStyle?.isItalic ? 'italic' : 'normal',
367
- textDecoration: props.subtitleStyle?.isUnderline ? 'underline' : 'none',
368
- lineHeight: '1.3'
369
- }}>
370
- {item.subTitle}
371
- </div>
372
- )}
373
- </div>
374
- );
375
- };
376
-
377
- return (
378
- <>
379
- <style>
380
- {`
381
- .scrollable-container::-webkit-scrollbar {
382
- display: none;
383
- }
384
- `}
385
- </style>
386
- <div
387
- style={{
388
- border: '1px solid #e1e1e1',
389
- width: '100%',
390
- maxWidth: '100%',
391
- borderRadius: '0px',
392
- height: boxHeight || 'auto',
393
- minHeight: boxHeight ? boxHeight : '100px',
394
- position: 'relative',
395
- overflow: 'hidden',
396
- marginTop: '0px',
397
- display: 'flex',
398
- flexDirection: 'column'
399
- }}
400
- className='GroupImageListComponent'
401
- >
402
- {showHeader && (
403
- <div
404
- className="groupImageHeader"
405
- style={{
406
- backgroundColor: props.headerBackground,
407
- padding: '12px 16px',
408
- borderRadius: '0px',
409
- marginBottom: '4px',
410
- display: 'flex',
411
- alignItems: 'center',
412
- justifyContent: 'space-between',
413
- flexWrap: 'wrap',
414
- gap: '12px',
415
- }}
416
- >
417
- <p style={{
418
- color: props.headerTextStyle.fontColor,
419
- fontSize: `${props.headerTextStyle.fontSize}px`,
420
- fontWeight: props.headerTextStyle.isBold ? 'bold' : 'normal',
421
- fontStyle: props.headerTextStyle.isItalic ? 'italic' : 'normal',
422
- textDecoration: props.headerTextStyle.isUnderline ? 'underline' : 'none',
423
- margin: 0
424
- }}>
425
- {props.headerText || props.nameData || 'Image Gallery'}
426
- </p>
427
- {currentLayout === 'NONE' && images.length > 2 && (
428
- <div style={{ display: 'flex', gap: '8px' }}>
429
- <button
430
- onClick={scrollLeft}
431
- style={{
432
- width: '32px',
433
- height: '32px',
434
- borderRadius: '50%',
435
- border: '1px solid #ddd',
436
- backgroundColor: '#fff',
437
- cursor: 'pointer',
438
- display: 'flex',
439
- alignItems: 'center',
440
- justifyContent: 'center',
441
- fontSize: '16px',
442
- fontWeight: 'bold',
443
- boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
444
- }}
445
- onMouseOver={(e) => { e.currentTarget.style.backgroundColor = '#f8f9fa'; }}
446
- onMouseOut={(e) => { e.currentTarget.style.backgroundColor = '#fff'; }}
447
- >
448
-
449
- </button>
450
- <button
451
- onClick={scrollRight}
452
- style={{
453
- width: '32px',
454
- height: '32px',
455
- borderRadius: '50%',
456
- border: '1px solid #ddd',
457
- backgroundColor: '#fff',
458
- cursor: 'pointer',
459
- display: 'flex',
460
- alignItems: 'center',
461
- justifyContent: 'center',
462
- fontSize: '16px',
463
- fontWeight: 'bold',
464
- boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
465
- }}
466
- onMouseOver={(e) => { e.currentTarget.style.backgroundColor = '#f8f9fa'; }}
467
- onMouseOut={(e) => { e.currentTarget.style.backgroundColor = '#fff'; }}
468
- >
469
-
470
- </button>
471
- </div>
472
- )}
473
- </div>
474
- )}
475
-
476
-
477
- <div
478
- style={{
479
- display: currentLayout === 'NONE' ? 'flex' : 'block',
480
- overflowX: currentLayout === 'NONE' ? 'hidden' : 'visible',
481
- gap: currentLayout === 'NONE' ? '12px' : '0',
482
- padding: '12px',
483
- scrollBehavior: 'smooth',
484
- backgroundColor: props.carouselBackground || '#fff',
485
- borderRadius: '8px',
486
- position: 'relative',
487
- flex: 1,
488
- overflow: 'hidden'
489
- }}
490
- className="groupImageCarousel"
491
- >
492
- {/* Navigation buttons - positioned like carousel */}
493
- {!showHeader &&currentLayout === 'NONE' && images.length > 2 && (
494
- <>
495
- <button
496
- onClick={scrollLeft}
497
- style={{
498
- position: 'absolute',
499
- left: '10px',
500
- top: '50%',
501
- transform: 'translateY(-50%)',
502
- background: 'rgba(0,0,0,0.5)',
503
- color: 'white',
504
- border: 'none',
505
- borderRadius: '50%',
506
- width: '40px',
507
- height: '40px',
508
- cursor: 'pointer',
509
- display: 'flex',
510
- alignItems: 'center',
511
- justifyContent: 'center',
512
- fontSize: '18px',
513
- zIndex: 10,
514
- transition: 'all 0.2s ease'
515
- }}
516
- onMouseOver={(e) => {
517
- e.currentTarget.style.background = 'rgba(0,0,0,0.7)';
518
- e.currentTarget.style.transform = 'translateY(-50%) scale(1.1)';
519
- }}
520
- onMouseOut={(e) => {
521
- e.currentTarget.style.background = 'rgba(0,0,0,0.5)';
522
- e.currentTarget.style.transform = 'translateY(-50%) scale(1)';
523
- }}
524
- >
525
-
526
- </button>
527
- <button
528
- onClick={scrollRight}
529
- style={{
530
- position: 'absolute',
531
- right: '10px',
532
- top: '50%',
533
- transform: 'translateY(-50%)',
534
- background: 'rgba(0,0,0,0.5)',
535
- color: 'white',
536
- border: 'none',
537
- borderRadius: '50%',
538
- width: '40px',
539
- height: '40px',
540
- cursor: 'pointer',
541
- display: 'flex',
542
- alignItems: 'center',
543
- justifyContent: 'center',
544
- fontSize: '18px',
545
- zIndex: 10,
546
- transition: 'all 0.2s ease'
547
- }}
548
- onMouseOver={(e) => {
549
- e.currentTarget.style.background = 'rgba(0,0,0,0.7)';
550
- e.currentTarget.style.transform = 'translateY(-50%) scale(1.1)';
551
- }}
552
- onMouseOut={(e) => {
553
- e.currentTarget.style.background = 'rgba(0,0,0,0.5)';
554
- e.currentTarget.style.transform = 'translateY(-50%) scale(1)';
555
- }}
556
- >
557
-
558
- </button>
559
- </>
560
- )}
561
- {images.length > 0 ? (
562
- currentLayout === 'NONE' ? (
563
- <div
564
- className="scrollable-container"
565
- style={{
566
- display: 'flex',
567
- gap: '20px',
568
- overflowX: 'auto',
569
- scrollbarWidth: 'none', // Firefox
570
- msOverflowStyle: 'none' // IE and Edge
571
- }}>
572
- {images.map((image) => (
573
- <div
574
- key={image.id}
575
- style={{
576
- minWidth: '250px',
577
- height: boxHeight,
578
- flexShrink: 0,
579
- }}
580
- >
581
- <ImageCard item={image} />
582
- </div>
583
- ))}
584
- </div>
585
-
586
- ) : currentLayout === 'SMALL' ? (
587
- <div style={{
588
- display: 'grid',
589
- gridTemplateColumns: 'repeat(2, 1fr)',
590
- gap: '16px',
591
- padding: '8px',
592
- height: '100%'
593
- }}>
594
- {images.map((image) => (
595
- <div key={image.id} style={{
596
- height: '100%',
597
- display: 'flex',
598
- flexDirection: 'column'
599
- }}>
600
- <ImageCard item={image} />
601
- </div>
602
- ))}
603
- </div>
604
- ) : currentLayout === 'MEDIUM' ? (
605
- <div style={{
606
- display: 'grid',
607
- gridTemplateColumns: 'repeat(3, 1fr)',
608
- gap: '16px',
609
- padding: '8px',
610
- height: 'auto',
611
- overflowX: 'auto',
612
-
613
- }}>
614
- {images.map((image) => (
615
- <div key={image.id} style={{
616
- height: '100%',
617
- display: 'flex',
618
- flexDirection: 'column'
619
-
620
- }}>
621
- <ImageCard item={image} />
622
- </div>
623
- ))}
624
- </div>
625
- ) : currentLayout === 'MEDIUM_THREE' ? (
626
- <div style={{
627
- display: 'flex',
628
- flexDirection: 'column',
629
- gap: '16px',
630
- padding: '8px',
631
- height: '100%'
632
- }}>
633
- {images.length > 0 && (
634
- <div style={{ flex: '2', minHeight: '200px' }}>
635
- <ImageCard item={images[0]} large />
636
- </div>
637
- )}
638
- {images.length > 1 && (
639
- <div style={{
640
- display: 'grid',
641
- gridTemplateColumns: 'repeat(2, 1fr)',
642
- gap: '16px',
643
- flex: '1'
644
- }}>
645
- {images.slice(1).map((image) => (
646
- <div key={image.id} style={{
647
- height: '100%',
648
- display: 'flex',
649
- flexDirection: 'column'
650
- }}>
651
- <ImageCard item={image} />
652
- </div>
653
- ))}
654
- </div>
655
- )}
656
- </div>
657
- ) : null
658
- ) : (
659
- <div style={{ textAlign: 'center', color: '#666', padding: '40px', width: '100%', border: '2px dashed #ddd', borderRadius: '8px', backgroundColor: '#f9f9f9' }}>
660
- <p>No images available.</p>
661
- </div>
662
- )}
663
- </div>
664
- </div>
665
- </>
666
- );
667
- };
668
-
1
+ import React, { useState } from 'react';
2
+ import { Linodeurl } from '../../const';
3
+ interface ImageData {
4
+ isDynamic: boolean;
5
+ shape: string;
6
+ url: string;
7
+ alt: string;
8
+ shapeImageId?: string;
9
+ width?: number;
10
+ height?: number;
11
+ }
12
+
13
+ interface ProductData {
14
+ pd_type: string;
15
+ pd_id?: {
16
+ _id: string;
17
+ code: string;
18
+ name: {
19
+ all: string;
20
+ displayName?: string;
21
+ };
22
+ image?: ImageData;
23
+ isActive: boolean;
24
+ };
25
+ product_data?: {
26
+ _id: string;
27
+ code: string;
28
+ name: string;
29
+ };
30
+ }
31
+
32
+
33
+
34
+ interface LinkData {
35
+ url: string | null;
36
+ target: string | null;
37
+ }
38
+
39
+ interface PageData {
40
+ page_type: string | null;
41
+ pg_type?: string | null;
42
+
43
+ page_id?: any;
44
+ page_data?:any;
45
+ }
46
+
47
+ interface ImageItem {
48
+ id: number;
49
+ attr: ImageData;
50
+ title: string;
51
+ subTitle: string;
52
+ linktype: string;
53
+ product?: ProductData;
54
+ tag?: any;
55
+ link?: LinkData;
56
+ page?: PageData;
57
+ }
58
+
59
+ interface GroupImageStatic {
60
+ _id: string;
61
+ name: string;
62
+ code: string;
63
+ }
64
+
65
+ interface GroupImageDynamic {
66
+ code: string;
67
+ name: { all: string };
68
+ list: ImageItem[];
69
+ isActive?: boolean;
70
+ }
71
+
72
+ interface GroupImageData {
73
+ static: GroupImageStatic;
74
+ dynamic: GroupImageDynamic;
75
+ groupimagedata: ImageItem[];
76
+ }
77
+
78
+ interface HeaderTextStyle {
79
+ fontSize: number;
80
+ fontColor: string;
81
+ isBold: boolean;
82
+ isItalic: boolean;
83
+ isUnderline: boolean;
84
+ }
85
+
86
+ interface DeviceBooleanProps {
87
+ web: boolean;
88
+ mobileweb: boolean;
89
+ mobileapp: boolean;
90
+ tablet: boolean;
91
+ }
92
+
93
+ interface DeviceLayoutProps {
94
+ web: string;
95
+ mobileweb: string;
96
+ mobileapp: string;
97
+ tablet: string;
98
+ }
99
+
100
+ export interface GroupImageListProps {
101
+ nameData: any;
102
+ data?: Array<{ id: string; type: string }>;
103
+ types?: any[];
104
+ type: string;
105
+ groupimage: GroupImageData;
106
+ headerText: any;
107
+ activeStatus: boolean;
108
+ headerImage: string;
109
+ headerTextStyle: HeaderTextStyle;
110
+ layout: DeviceLayoutProps;
111
+ showHeader: DeviceBooleanProps;
112
+ isHorizontalScroll: DeviceBooleanProps;
113
+ headerBackground: string;
114
+ carouselBackground: string;
115
+ cardcolor: string;
116
+ showSubtitle?: DeviceBooleanProps;
117
+ showTitle?: DeviceBooleanProps;
118
+ titleStyle?: {
119
+ fontSize: number;
120
+ fontColor: string;
121
+ isBold: boolean;
122
+ isItalic: boolean;
123
+ isUnderline: boolean;
124
+ };
125
+ subtitleStyle?: {
126
+ fontSize: number;
127
+ fontColor: string;
128
+ isBold: boolean;
129
+ isItalic: boolean;
130
+ isUnderline: boolean;
131
+ };
132
+ selectedChannel?: string;
133
+ }
134
+
135
+ interface GroupImageListMainProps {
136
+ props: GroupImageListProps;
137
+ deviceMode?: string;
138
+ boxHeight?: string;
139
+ }
140
+
141
+ // Image Component Integration
142
+ interface ImageComponentProps {
143
+ imageData: ImageData;
144
+ linkData: {
145
+ linktype: string;
146
+ product?: ProductData;
147
+ tag?: any;
148
+ link?: LinkData;
149
+ page?: PageData;
150
+ };
151
+ borderRadius?: number;
152
+ height?: string;
153
+ width?: string;
154
+ }
155
+
156
+ const ImageComponentInternal: React.FC<ImageComponentProps> = ({
157
+ imageData,
158
+ linkData,
159
+ borderRadius = 8,
160
+ height = '100%',
161
+ width = '100%'
162
+ }) => {
163
+ const getImageUrl = (url: string) => {
164
+ if (!url) return '';
165
+ if (url.startsWith('http://') || url.startsWith('https://')) return url;
166
+ return `${Linodeurl}${url}`;
167
+ };
168
+
169
+ const buildLink = () => {
170
+ console.warn(linkData)
171
+ switch (linkData.linktype) {
172
+
173
+ case 'NONE':
174
+ return null;
175
+ case 'EXTERNAL_LINK':
176
+ case 'EXTERNAL':
177
+ return linkData.link?.url || null;
178
+ case 'PRODUCT': {
179
+ const pdType = linkData.product?.pd_type;
180
+ const code = linkData.product?.pd_id?.code || linkData.product?.product_data?.code;
181
+ if (!code) return null;
182
+
183
+ return pdType === 'VARIANT'
184
+ ? `/${code}`
185
+ : `/model/${code}`;
186
+ }
187
+ case 'TAG':
188
+ return `/tag/${linkData.tag?.tag_id?.code || linkData?.tag?.tag_data?.code}`;
189
+ case 'PAGE':
190
+ return `/page/${linkData.page?.page_id?._id || linkData.page?.page_data?._id }?type=${linkData.page?.page_type || linkData.page?.pg_type}`;
191
+ default:
192
+ return null;
193
+ }
194
+ };
195
+
196
+ // const handleImageClick = () => {
197
+ // const link = buildLink();
198
+ // if (link === null) return;
199
+
200
+ // if (link.startsWith('http')) {
201
+ // window.open(link, linkData.link?.target || '_blank');
202
+ // } else {
203
+ // window.location.href = link;
204
+ // }
205
+ // };
206
+
207
+ const imageStyle: React.CSSProperties = {
208
+ width: width,
209
+ height: height,
210
+ objectFit: 'contain',
211
+ borderRadius: `${borderRadius}px`,
212
+ cursor: linkData.linktype !== 'NONE' ? 'pointer' : 'default',
213
+ transition: 'transform 0.2s ease'
214
+ };
215
+
216
+ return (
217
+ <a
218
+ href={buildLink() ?? undefined}
219
+ target={
220
+ linkData?.linktype === 'EXTERNAL'
221
+ ? (linkData?.link?.target ?? '_blank')
222
+ : '_self'
223
+ }
224
+ style={{
225
+ display: 'block',
226
+ width: '100%',
227
+ height: '100%',
228
+ textDecoration: 'none',
229
+ color: 'inherit'
230
+ }}
231
+ >
232
+ <div
233
+ style={{
234
+ width: '100%',
235
+ height: '100%',
236
+ borderRadius: `${borderRadius}px`,
237
+ overflow: 'hidden',
238
+ display: 'flex',
239
+ alignItems: 'center',
240
+ justifyContent: 'center'
241
+ }}
242
+ className='media-box'
243
+ >
244
+ <img
245
+ className='media-content'
246
+ src={getImageUrl(imageData.url)}
247
+ alt={imageData.alt || ''}
248
+ style={imageStyle}
249
+ onMouseOver={(e) => {
250
+ if (linkData.linktype !== 'NONE') {
251
+ (e.currentTarget as HTMLImageElement).style.transform = 'scale(1.02)';
252
+ }
253
+ }}
254
+ onMouseOut={(e) => {
255
+ (e.currentTarget as HTMLImageElement).style.transform = 'scale(1)';
256
+ }}
257
+ />
258
+ </div>
259
+ </a>
260
+ );
261
+ };
262
+
263
+ // Main GroupImageList Component
264
+ const GroupImageList: React.FC<GroupImageListMainProps> = ({
265
+ props,
266
+ deviceMode = 'web',
267
+ boxHeight
268
+ }) => {
269
+ const getCurrentBooleanProp = (prop?: DeviceBooleanProps) => {
270
+ if (!prop) return false;
271
+ switch (deviceMode) {
272
+ case 'mobileweb': return !!prop.mobileweb;
273
+ case 'mobileapp': return !!prop.mobileapp;
274
+ case 'tablet': return !!prop.tablet;
275
+ case 'web':
276
+ default: return !!prop.web;
277
+ }
278
+ };
279
+
280
+ const getCurrentLayout = () => {
281
+ if (!props.layout) return 'NONE';
282
+ switch (deviceMode) {
283
+ case 'mobileweb': return props.layout.mobileweb || 'NONE';
284
+ case 'mobileapp': return props.layout.mobileapp || 'NONE';
285
+ case 'tablet': return props.layout.tablet || 'NONE';
286
+ case 'web':
287
+ default: return props.layout.web || 'NONE';
288
+ }
289
+ };
290
+
291
+ const showHeader = getCurrentBooleanProp(props.showHeader);
292
+ const isHorizontalScroll = getCurrentBooleanProp(props.isHorizontalScroll);
293
+ const showTitle = getCurrentBooleanProp(props.showTitle);
294
+ const showSubtitle = getCurrentBooleanProp(props.showSubtitle);
295
+ const currentLayout = getCurrentLayout();
296
+
297
+ const getImages = (): ImageItem[] => {
298
+ if (props.type === 'dynamic') {
299
+ if (props.groupimage?.dynamic?.list?.length) return props.groupimage.dynamic.list;
300
+ }
301
+ if (props.groupimage?.groupimagedata?.length) return props.groupimage.groupimagedata;
302
+ return [];
303
+ };
304
+
305
+ const images = getImages();
306
+
307
+ // Carousel navigation buttons (layout NONE)
308
+ const scrollLeft = () => {
309
+ const scrollableContainer = document.querySelector('.groupImageCarousel .scrollable-container');
310
+ if (scrollableContainer) {
311
+ (scrollableContainer as HTMLElement).scrollBy({ left: -200, behavior: 'smooth' });
312
+ }
313
+ };
314
+
315
+ const scrollRight = () => {
316
+ const scrollableContainer = document.querySelector('.groupImageCarousel .scrollable-container');
317
+ if (scrollableContainer) {
318
+ (scrollableContainer as HTMLElement).scrollBy({ left: 200, behavior: 'smooth' });
319
+ }
320
+ };
321
+
322
+ const ImageCard = ({ item, large = false }: { item: ImageItem; large?: boolean }) => {
323
+ const [isHovered, setIsHovered] = useState(false);
324
+
325
+ return (
326
+ <div
327
+ className="imageCard"
328
+ style={{
329
+ height: '100%',
330
+ minHeight: large ? '280px' : '260px',
331
+ borderRadius: '8px',
332
+ overflow: 'hidden',
333
+ border: '1px solid #eee',
334
+ backgroundColor: props.cardcolor || '#fff',
335
+ display: 'flex',
336
+ flexDirection: 'column',
337
+ padding: large ? '16px' : '12px',
338
+ boxShadow: isHovered ? '0 4px 8px rgba(0,0,0,0.15)' : '0 2px 4px rgba(0,0,0,0.1)',
339
+ transition: 'all 0.2s ease',
340
+ cursor: item.linktype !== 'NONE' ? 'pointer' : 'default',
341
+ transform: isHovered ? 'translateY(-2px)' : 'translateY(0px)',
342
+ }}
343
+ onMouseOver={() => setIsHovered(true)}
344
+ onMouseOut={() => setIsHovered(false)}
345
+ >
346
+ <div style={{
347
+ width: '100%',
348
+ height: large ? '200px' : '180px',
349
+ minHeight: large ? '200px' : '180px',
350
+ maxHeight: large ? '200px' : '180px',
351
+ marginBottom: large ? '12px' : '8px',
352
+ display: 'flex',
353
+ alignItems: 'center',
354
+ justifyContent: 'center',
355
+ overflow: 'hidden',
356
+ flexShrink: 0
357
+ }}>
358
+ <ImageComponentInternal
359
+ imageData={item.attr}
360
+ linkData={{
361
+ linktype: item.linktype,
362
+ product: item.product,
363
+ tag: item.tag,
364
+ link: item.link,
365
+ page: item.page
366
+ }}
367
+ borderRadius={6}
368
+ height="100%"
369
+ width="100%"
370
+ />
371
+ </div>
372
+ <div style={{
373
+ display: 'flex',
374
+ flexDirection: 'column',
375
+ flexShrink: 0,
376
+ minHeight: 0
377
+ }}>
378
+ {showTitle && item.title && (
379
+ <div style={{
380
+ textAlign: 'center',
381
+ fontSize: props.titleStyle ? `${props.titleStyle.fontSize}px` : (large ? '16px' : '14px'),
382
+ fontWeight: props.titleStyle?.isBold ? 'bold' : (large ? 600 : 500),
383
+ color: props.titleStyle?.fontColor || '#333',
384
+ fontStyle: props.titleStyle?.isItalic ? 'italic' : 'normal',
385
+ textDecoration: props.titleStyle?.isUnderline ? 'underline' : 'none',
386
+ lineHeight: '1.4',
387
+ marginBottom: showSubtitle && item.subTitle ? '4px' : '0',
388
+ overflow: 'hidden',
389
+ textOverflow: 'ellipsis',
390
+ display: '-webkit-box',
391
+ WebkitLineClamp: 2,
392
+ WebkitBoxOrient: 'vertical',
393
+ wordBreak: 'break-word'
394
+ }}>
395
+ {item.title}
396
+ </div>
397
+ )}
398
+ {showSubtitle && item.subTitle && (
399
+ <div style={{
400
+ textAlign: 'center',
401
+ fontSize: props.subtitleStyle ? `${props.subtitleStyle.fontSize}px` : (large ? '14px' : '12px'),
402
+ fontWeight: props.subtitleStyle?.isBold ? 'bold' : 400,
403
+ color: props.subtitleStyle?.fontColor || '#666',
404
+ fontStyle: props.subtitleStyle?.isItalic ? 'italic' : 'normal',
405
+ textDecoration: props.subtitleStyle?.isUnderline ? 'underline' : 'none',
406
+ lineHeight: '1.3',
407
+ overflow: 'hidden',
408
+ textOverflow: 'ellipsis',
409
+ display: '-webkit-box',
410
+ WebkitLineClamp: 2,
411
+ WebkitBoxOrient: 'vertical',
412
+ wordBreak: 'break-word'
413
+ }}>
414
+ {item.subTitle}
415
+ </div>
416
+ )}
417
+ </div>
418
+ </div>
419
+ );
420
+ };
421
+
422
+ return (
423
+ <div
424
+ style={{
425
+ border: '1px solid #e1e1e1',
426
+ width: '100%',
427
+ maxWidth: '100%',
428
+ borderRadius: '0px',
429
+ height: boxHeight || '100%',
430
+ minHeight: boxHeight ? boxHeight : '100px',
431
+ position: 'relative',
432
+ overflow: 'visible',
433
+ marginTop: '0px',
434
+ marginBottom: '20px',
435
+ display: 'flex',
436
+ flexDirection: 'column'
437
+ }}
438
+ className='GroupImageListComponent'
439
+ >
440
+ {showHeader && (
441
+ <div
442
+ className="groupImageHeader"
443
+ style={{
444
+ backgroundColor: props.headerBackground,
445
+ padding: '12px 16px',
446
+ borderRadius: '0px',
447
+ marginBottom: '4px',
448
+ display: 'flex',
449
+ alignItems: 'center',
450
+ justifyContent: 'space-between',
451
+ flexWrap: 'wrap',
452
+ gap: '12px',
453
+ }}
454
+ >
455
+ <p style={{
456
+ color: props.headerTextStyle.fontColor,
457
+ fontSize: `${props.headerTextStyle.fontSize}px`,
458
+ fontWeight: props.headerTextStyle.isBold ? 'bold' : 'normal',
459
+ fontStyle: props.headerTextStyle.isItalic ? 'italic' : 'normal',
460
+ textDecoration: props.headerTextStyle.isUnderline ? 'underline' : 'none',
461
+ margin: 0
462
+ }}>
463
+ {props.headerText || props.nameData || 'Image Gallery'}
464
+ </p>
465
+ {currentLayout === 'NONE' && images.length > 0 && (
466
+ <div style={{ display: 'flex', gap: '8px' }}>
467
+ <button
468
+ onClick={scrollLeft}
469
+ style={{
470
+ width: '32px',
471
+ height: '32px',
472
+ borderRadius: '50%',
473
+ border: '1px solid #ddd',
474
+ backgroundColor: '#fff',
475
+ cursor: 'pointer',
476
+ display: 'flex',
477
+ alignItems: 'center',
478
+ justifyContent: 'center',
479
+ fontSize: '16px',
480
+ fontWeight: 'bold',
481
+ boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
482
+ }}
483
+ onMouseOver={(e) => { e.currentTarget.style.backgroundColor = '#f8f9fa'; }}
484
+ onMouseOut={(e) => { e.currentTarget.style.backgroundColor = '#fff'; }}
485
+ >
486
+
487
+ </button>
488
+ <button
489
+ onClick={scrollRight}
490
+ style={{
491
+ width: '32px',
492
+ height: '32px',
493
+ borderRadius: '50%',
494
+ border: '1px solid #ddd',
495
+ backgroundColor: '#fff',
496
+ cursor: 'pointer',
497
+ display: 'flex',
498
+ alignItems: 'center',
499
+ justifyContent: 'center',
500
+ fontSize: '16px',
501
+ fontWeight: 'bold',
502
+ boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
503
+ }}
504
+ onMouseOver={(e) => { e.currentTarget.style.backgroundColor = '#f8f9fa'; }}
505
+ onMouseOut={(e) => { e.currentTarget.style.backgroundColor = '#fff'; }}
506
+ >
507
+
508
+ </button>
509
+ </div>
510
+ )}
511
+ </div>
512
+ )}
513
+
514
+
515
+ <div
516
+ style={{
517
+ display: currentLayout === 'NONE' ? 'flex' : 'block',
518
+ overflowX: currentLayout === 'NONE' ? 'hidden' : 'visible',
519
+ overflowY: currentLayout === 'NONE' ? 'hidden' : 'visible',
520
+ gap: currentLayout === 'NONE' ? '12px' : '0',
521
+ padding: '12px',
522
+ scrollBehavior: 'smooth',
523
+ backgroundColor: props.carouselBackground || '#fff',
524
+ borderRadius: '8px',
525
+ position: 'relative',
526
+ flex: 1,
527
+ minHeight: 0,
528
+ }}
529
+ className="groupImageCarousel"
530
+ >
531
+ {images.length > 0 ? (
532
+ currentLayout === 'NONE' ? (
533
+ <div
534
+ className="scrollable-container"
535
+ style={{
536
+ display: 'flex',
537
+ gap: '12px',
538
+ overflowX: isHorizontalScroll ? 'auto' : 'hidden',
539
+ overflowY: 'hidden',
540
+ alignItems: 'stretch',
541
+ width: '100%',
542
+ height: '100%',
543
+ }}>
544
+ {images.map((image) => (
545
+ <div
546
+ key={image.id}
547
+ style={{
548
+ minWidth: '250px',
549
+ width: '250px',
550
+ flexShrink: 0,
551
+ display: 'flex',
552
+ flexDirection: 'column',
553
+ height: '100%',
554
+ }}
555
+ >
556
+ <ImageCard item={image} />
557
+ </div>
558
+ ))}
559
+ </div>
560
+
561
+ ) : currentLayout === 'SMALL' ? (
562
+ <div style={{
563
+ display: 'grid',
564
+ gridTemplateColumns: 'repeat(2, 1fr)',
565
+ gap: '16px',
566
+ padding: '8px',
567
+ height: '100%'
568
+ }}>
569
+ {images.map((image) => (
570
+ <div key={image.id} style={{
571
+ height: '100%',
572
+ display: 'flex',
573
+ flexDirection: 'column'
574
+ }}>
575
+ <ImageCard item={image} />
576
+ </div>
577
+ ))}
578
+ </div>
579
+ ) : currentLayout === 'MEDIUM' ? (
580
+ <div style={{
581
+ display: 'grid',
582
+ gridTemplateColumns: 'repeat(3, 1fr)',
583
+ gap: '16px',
584
+ padding: '8px',
585
+ height: 'auto',
586
+ overflowX: 'auto',
587
+
588
+ }}>
589
+ {images.map((image) => (
590
+ <div key={image.id} style={{
591
+ height: '100%',
592
+ display: 'flex',
593
+ flexDirection: 'column'
594
+
595
+ }}>
596
+ <ImageCard item={image} />
597
+ </div>
598
+ ))}
599
+ </div>
600
+ ) : currentLayout === 'MEDIUM_THREE' ? (
601
+ <div style={{
602
+ display: 'flex',
603
+ flexDirection: 'column',
604
+ gap: '16px',
605
+ padding: '8px',
606
+ height: '100%'
607
+ }}>
608
+ {images.length > 0 && (
609
+ <div style={{ flex: '2', minHeight: '200px' }}>
610
+ <ImageCard item={images[0]} large />
611
+ </div>
612
+ )}
613
+ {images.length > 1 && (
614
+ <div style={{
615
+ display: 'grid',
616
+ gridTemplateColumns: 'repeat(2, 1fr)',
617
+ gap: '16px',
618
+ flex: '1'
619
+ }}>
620
+ {images.slice(1).map((image) => (
621
+ <div key={image.id} style={{
622
+ height: '100%',
623
+ display: 'flex',
624
+ flexDirection: 'column'
625
+ }}>
626
+ <ImageCard item={image} />
627
+ </div>
628
+ ))}
629
+ </div>
630
+ )}
631
+ </div>
632
+ ) : null
633
+ ) : (
634
+ <div style={{ textAlign: 'center', color: '#666', padding: '40px', width: '100%', border: '2px dashed #ddd', borderRadius: '8px', backgroundColor: '#f9f9f9' }}>
635
+ <p>No images available.</p>
636
+ </div>
637
+ )}
638
+ </div>
639
+ </div>
640
+ );
641
+ };
642
+
669
643
  export default GroupImageList;