tee3apps-cms-sdk-react 0.0.14 → 0.0.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.
@@ -49,7 +49,19 @@ interface TabContentGroup {
49
49
  dynamicImages?: any[];
50
50
  dynamicVideos?: any[];
51
51
  dynamicProducts?: any[];
52
+ staticImages?: any[];
53
+ staticVideos?: any[];
54
+ staticProducts?: any[];
52
55
  showItems?: Product[];
56
+ dynamic?: {
57
+ conditions: any[];
58
+ query: string;
59
+ list: any[];
60
+ pagination: number;
61
+ };
62
+ dynamicQueries?: {
63
+ selectedVariants: any[];
64
+ };
53
65
  }
54
66
 
55
67
  interface TabMode {
@@ -97,10 +109,6 @@ interface HeaderStyle {
97
109
  activeColorText: string;
98
110
  }
99
111
 
100
- interface TabsData {
101
- all: TabItem[];
102
- }
103
-
104
112
  export interface TabComponentProps {
105
113
  name: string;
106
114
  code: string;
@@ -109,7 +117,7 @@ export interface TabComponentProps {
109
117
  showTitle: boolean;
110
118
  title: TitleStyle;
111
119
  header: HeaderStyle;
112
- tabs: TabsData[];
120
+ tabs: TabItem[];
113
121
  }
114
122
 
115
123
  interface TabComponentMainProps {
@@ -157,27 +165,51 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
157
165
  const getImageUrl = (url: string) => {
158
166
  if (!url) return '';
159
167
  if (url.startsWith('http://') || url.startsWith('https://')) return url;
160
- return `${Linodeurl}${url}`;
168
+ // Ensure URL has leading slash if Linodeurl doesn't end with one
169
+ const cleanUrl = url.startsWith('/') ? url : `/${url}`;
170
+ const baseUrl = Linodeurl.endsWith('/') ? Linodeurl.slice(0, -1) : Linodeurl;
171
+ return `${baseUrl}${cleanUrl}`;
172
+ };
173
+
174
+ // Helper function to extract numeric value from price in any format
175
+ const getPriceValue = (price: any): number => {
176
+ console.error(price,"price-----")
177
+ if (price === null || price === undefined) return 0;
178
+
179
+ // If it's already a number
180
+ if (typeof price === 'number') {
181
+ return isNaN(price) ? 0 : price;
182
+ }
183
+
184
+ // If it's an object with $numberDecimal (but not an array)
185
+ if (typeof price === 'object' && price !== null && !Array.isArray(price)) {
186
+ if (price.$numberDecimal !== undefined && price.$numberDecimal !== null) {
187
+ const value = parseFloat(String(price.$numberDecimal));
188
+ return isNaN(value) ? 0 : value;
189
+ }
190
+ }
191
+
192
+ // If it's a string, try to parse it
193
+ if (typeof price === 'string') {
194
+ const value = parseFloat(price);
195
+ return isNaN(value) ? 0 : value;
196
+ }
197
+
198
+ return 0;
161
199
  };
162
200
 
163
201
  // Inline Product Card Component
164
202
  const ProductCard: React.FC<{ product: any; layout?: string }> = ({ product, layout = '1x1' }) => {
165
203
  const formatPrice = (price: any) => {
166
- if (typeof price === 'object' && price.$numberDecimal) {
167
- return parseFloat(price.$numberDecimal).toLocaleString('en-IN', {
168
- style: 'currency',
169
- currency: 'INR',
170
- minimumFractionDigits: 0,
171
- maximumFractionDigits: 0
172
- });
173
- }
174
- return price;
204
+ const priceValue = getPriceValue(price);
205
+ if (priceValue === 0 && !price) return '0';
206
+ return priceValue
175
207
  };
176
208
 
177
209
  const calculateOffer = (mrp: any, sp: any) => {
178
- const mrpValue = parseFloat(mrp.$numberDecimal || mrp);
179
- const spValue = parseFloat(sp.$numberDecimal || sp);
180
- if (mrpValue > spValue) {
210
+ const mrpValue = getPriceValue(mrp);
211
+ const spValue = getPriceValue(sp);
212
+ if (mrpValue > spValue && mrpValue > 0) {
181
213
  const discount = ((mrpValue - spValue) / mrpValue) * 100;
182
214
  return Math.round(discount);
183
215
  }
@@ -204,22 +236,39 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
204
236
  return variant.valueId?.name?.all || variant.valueId?.name || '';
205
237
  };
206
238
 
207
- const mrp = product.price?.MRP;
208
- const sp = product.price?.SP;
239
+ // Use pricing object first, fallback to price for backward compatibility
240
+ const mrp = product.pricing?.mrp ;
241
+ console.error(mrp,product,"mrp-----")
242
+ const sp = product.pricing?.costPrice;
243
+ console.error(sp,"sp-----")
209
244
  const offer = calculateOffer(mrp, sp);
210
245
 
211
246
  const cardMode = layout === '1x1' ? 'carousel-mode' : layout === '2x1' ? 'layout-2x1' : 'grid-mode';
212
247
  const productSlug = product.code;
213
248
  const productLink = `/${productSlug}`;
214
249
 
250
+ // Get product image URL - try multiple possible locations
251
+ const getProductImageUrl = () => {
252
+ return product.image?.all?.url ||
253
+ product.image?.url ||
254
+ product.model?.image?.url ||
255
+ product.model?.image?.all?.url ||
256
+ '';
257
+ };
258
+
215
259
  const cardContent = (
216
260
  <>
217
261
  {/* Product Image */}
218
262
  <div className="product-image-container">
219
263
  <img
220
- src={getImageUrl(product.image?.all?.url || product.model?.image?.url)}
221
- alt={product.name?.all || product.name?.displayName}
264
+ src={getImageUrl(getProductImageUrl())}
265
+ alt={product.name?.all || product.name?.displayName || 'Product image'}
222
266
  className="product-image"
267
+ onError={(e) => {
268
+ // Fallback if image fails to load
269
+ const target = e.target as HTMLImageElement;
270
+ target.style.display = 'none';
271
+ }}
223
272
  />
224
273
  </div>
225
274
 
@@ -266,10 +315,10 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
266
315
  <div className="product-pricing">
267
316
  <div className="price-row">
268
317
  <span className="current-price">{formatPrice(sp)}</span>
269
- {mrp && sp && parseFloat(mrp.$numberDecimal || mrp) > parseFloat(sp.$numberDecimal || sp) && (
318
+ {mrp && sp && offer > 0 && (
270
319
  <>
271
320
  <span className="original-price">{formatPrice(mrp)}</span>
272
- {offer > 0 && <span className="offer-badge">{offer}% OFF</span>}
321
+ <span className="offer-badge">{offer}% OFF</span>
273
322
  </>
274
323
  )}
275
324
  </div>
@@ -432,28 +481,56 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
432
481
 
433
482
  switch (tab.tabContentType) {
434
483
  case 'IMAGE':
435
- if (tab.tabContentImage) {
436
- console.warn(tab.tabContentImage, buildLinkForSlide(tab.tabContentImage));
437
- return (
438
- <a
439
- href={buildLinkForSlide(tab.tabContentImage) || undefined}
440
- target={
441
- tab.tabContentImage.link_type === 'external_link'
442
- ? tab.tabContentImage.external_link?.target
443
- : '_blank'
444
- }
445
- >
446
- <div style={contentStyle}>
447
- <div className="media-box">
448
- <img
449
- src={getImageUrl(tab.tabContentImage.image.url)}
450
- alt={tab.tabContentImage.image.alt}
451
- className="media-content"
452
- />
453
- </div>
484
+ if (tab.tabContentImage && tab.tabContentImage.image) {
485
+ const imageUrl = tab.tabContentImage.image.url;
486
+ const imageAlt = tab.tabContentImage.image.alt || 'Image';
487
+ const fullImageUrl = getImageUrl(imageUrl);
488
+ const linkUrl = buildLinkForSlide(tab.tabContentImage);
489
+ const linkTarget = tab.tabContentImage.link_type === 'EXTERNALLINK'
490
+ ? tab.tabContentImage.external_link?.target || '_blank'
491
+ : '_blank';
492
+
493
+ // Debug: Log image URL construction
494
+ if (!fullImageUrl) {
495
+ console.warn('Image URL is empty. Original URL:', imageUrl);
496
+ }
497
+
498
+ const imageElement = (
499
+ <div style={contentStyle}>
500
+ <div className="media-box" style={{ width: '100%', height: '100%', overflow: 'hidden' }}>
501
+ <img
502
+ src={fullImageUrl}
503
+ alt={imageAlt}
504
+ className="media-content"
505
+ style={{
506
+ width: '100%',
507
+ height: '100%',
508
+ objectFit: 'cover',
509
+ display: 'block'
510
+ }}
511
+ onError={(e) => {
512
+ const target = e.target as HTMLImageElement;
513
+ console.error('Image failed to load. URL:', fullImageUrl, 'Original:', imageUrl);
514
+ target.style.display = 'none';
515
+ }}
516
+ />
454
517
  </div>
518
+ </div>
519
+ );
520
+
521
+ if (linkUrl) {
522
+ return (
523
+ <a
524
+ href={linkUrl}
525
+ target={linkTarget}
526
+ style={{ textDecoration: 'none', color: 'inherit', display: 'contents' }}
527
+ >
528
+ {imageElement}
455
529
  </a>
456
530
  );
531
+ }
532
+
533
+ return imageElement;
457
534
  }
458
535
  break;
459
536
  case 'VIDEO':
@@ -478,7 +555,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
478
555
  // Handle both DYNAMIC and STATIC types
479
556
  const images = tab.tabContentGroupImage.type === 'DYNAMIC'
480
557
  ? tab.tabContentGroupImage.dynamicImages
481
- : tab.tabContentGroupImage.showItems;
558
+ : (tab.tabContentGroupImage.staticImages || tab.tabContentGroupImage.showItems);
482
559
 
483
560
  if (!images || images.length === 0) {
484
561
  return <div>No images available</div>;
@@ -642,6 +719,19 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
642
719
  const displayImages = displayIndices.map(idx => images[idx]);
643
720
  const needsCarousel = images.length > itemsPerView;
644
721
 
722
+ // Navigation handlers specific to this layout
723
+ const handleNextImage = () => {
724
+ if (carouselIndex < maxCarouselIndex) {
725
+ setCarouselIndex((prev) => Math.min(prev + 1, maxCarouselIndex));
726
+ }
727
+ };
728
+
729
+ const handlePrevImage = () => {
730
+ if (carouselIndex > 0) {
731
+ setCarouselIndex((prev) => Math.max(prev - 1, 0));
732
+ }
733
+ };
734
+
645
735
  // Create dynamic content style for GROUPIMAGE
646
736
  const groupImageContentStyle = {
647
737
  display: 'grid',
@@ -653,7 +743,17 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
653
743
  };
654
744
 
655
745
  return (
656
- <div style={{ position: 'relative', width: '100%' }}>
746
+ <div
747
+ style={{
748
+ position: 'relative',
749
+ width: '100%',
750
+ height: 'auto',
751
+ overflow: 'hidden',
752
+ display: 'flex',
753
+ alignItems: 'center',
754
+ justifyContent: 'center',
755
+ }}
756
+ >
657
757
  <div style={groupImageContentStyle} className='media-box'>
658
758
  {displayImages.map((image, displayIndex) => {
659
759
  const originalIndex = displayIndices[displayIndex];
@@ -702,7 +802,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
702
802
  <>
703
803
  {/* Previous Button */}
704
804
  <button
705
- onClick={prevCarouselItem}
805
+ onClick={handlePrevImage}
706
806
  disabled={carouselIndex === 0}
707
807
  style={{
708
808
  position: 'absolute',
@@ -729,7 +829,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
729
829
 
730
830
  {/* Next Button */}
731
831
  <button
732
- onClick={nextCarouselItem}
832
+ onClick={handleNextImage}
733
833
  disabled={carouselIndex >= maxCarouselIndex}
734
834
  style={{
735
835
  position: 'absolute',
@@ -795,7 +895,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
795
895
  // Handle both DYNAMIC and STATIC types
796
896
  const videos = tab.tabContentGroupVideo.type === 'DYNAMIC'
797
897
  ? tab.tabContentGroupVideo.dynamicVideos
798
- : tab.tabContentGroupVideo.showItems;
898
+ : (tab.tabContentGroupVideo.staticVideos || tab.tabContentGroupVideo.showItems);
799
899
 
800
900
  if (!videos || videos.length === 0) {
801
901
  return <div>No videos available</div>;
@@ -964,6 +1064,19 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
964
1064
  const displayVideos = displayIndices.map(idx => videos[idx]);
965
1065
  const needsCarousel = videos.length > itemsPerView;
966
1066
 
1067
+ // Navigation handlers specific to this layout
1068
+ const handleNextVideo = () => {
1069
+ if (carouselIndex < maxCarouselIndex) {
1070
+ setCarouselIndex((prev) => Math.min(prev + 1, maxCarouselIndex));
1071
+ }
1072
+ };
1073
+
1074
+ const handlePrevVideo = () => {
1075
+ if (carouselIndex > 0) {
1076
+ setCarouselIndex((prev) => Math.max(prev - 1, 0));
1077
+ }
1078
+ };
1079
+
967
1080
  // Create dynamic content style for GROUPVIDEO
968
1081
  const groupVideoContentStyle = {
969
1082
  display: 'grid',
@@ -975,7 +1088,17 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
975
1088
  };
976
1089
 
977
1090
  return (
978
- <div style={{ position: 'relative', width: '100%' }}>
1091
+ <div
1092
+ style={{
1093
+ position: 'relative',
1094
+ width: '100%',
1095
+ height: 'auto',
1096
+ overflow: 'hidden',
1097
+ display: 'flex',
1098
+ alignItems: 'center',
1099
+ justifyContent: 'center',
1100
+ }}
1101
+ >
979
1102
  <div style={groupVideoContentStyle} className='media-box'>
980
1103
  {displayVideos.map((video, displayIndex) => {
981
1104
  const originalIndex = displayIndices[displayIndex];
@@ -1027,7 +1150,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
1027
1150
  <>
1028
1151
  {/* Previous Button */}
1029
1152
  <button
1030
- onClick={prevCarouselItem}
1153
+ onClick={handlePrevVideo}
1031
1154
  disabled={carouselIndex === 0}
1032
1155
  style={{
1033
1156
  position: 'absolute',
@@ -1054,7 +1177,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
1054
1177
 
1055
1178
  {/* Next Button */}
1056
1179
  <button
1057
- onClick={nextCarouselItem}
1180
+ onClick={handleNextVideo}
1058
1181
  disabled={carouselIndex >= maxCarouselIndex}
1059
1182
  style={{
1060
1183
  position: 'absolute',
@@ -1116,8 +1239,15 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
1116
1239
  break;
1117
1240
 
1118
1241
  case 'GROUPPRODUCT':
1119
- if (tab.tabContentGroupProduct && tab.tabContentGroupProduct.showItems) {
1120
- const products = tab.tabContentGroupProduct.showItems;
1242
+ if (tab.tabContentGroupProduct) {
1243
+ // Handle both DYNAMIC and STATIC types
1244
+ const products = tab.tabContentGroupProduct.type === 'DYNAMIC'
1245
+ ? tab.tabContentGroupProduct.dynamicProducts
1246
+ : ( tab.tabContentGroupProduct.showItems || []);
1247
+
1248
+ if (!products || products.length === 0) {
1249
+ return <div>No products available</div>;
1250
+ }
1121
1251
 
1122
1252
  // 1x1 layout: Carousel view
1123
1253
  if (layout === '1x1') {
@@ -1254,6 +1384,40 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
1254
1384
  const displayProducts = displayIndices.map(idx => products[idx]);
1255
1385
  const needsCarousel = products.length > itemsPerView;
1256
1386
 
1387
+ // Debug logging
1388
+ console.log('GROUPPRODUCT Grid Layout:', {
1389
+ layout,
1390
+ totalProducts: products.length,
1391
+ itemsPerView,
1392
+ carouselIndex,
1393
+ maxCarouselIndex,
1394
+ displayIndices,
1395
+ needsCarousel
1396
+ });
1397
+
1398
+ // Navigation handlers specific to this layout
1399
+ const handleNextProduct = () => {
1400
+ console.log('Next clicked, current:', carouselIndex, 'max:', maxCarouselIndex);
1401
+ if (carouselIndex < maxCarouselIndex) {
1402
+ setCarouselIndex((prev) => {
1403
+ const next = Math.min(prev + 1, maxCarouselIndex);
1404
+ console.log('Setting carousel index to:', next);
1405
+ return next;
1406
+ });
1407
+ }
1408
+ };
1409
+
1410
+ const handlePrevProduct = () => {
1411
+ console.log('Prev clicked, current:', carouselIndex);
1412
+ if (carouselIndex > 0) {
1413
+ setCarouselIndex((prev) => {
1414
+ const next = Math.max(prev - 1, 0);
1415
+ console.log('Setting carousel index to:', next);
1416
+ return next;
1417
+ });
1418
+ }
1419
+ };
1420
+
1257
1421
  // Create dynamic content style for GROUPPRODUCT
1258
1422
  const groupProductContentStyle = {
1259
1423
  display: 'grid',
@@ -1267,7 +1431,17 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
1267
1431
  };
1268
1432
 
1269
1433
  return (
1270
- <div style={{ position: 'relative', width: '100%' }}>
1434
+ <div
1435
+ style={{
1436
+ position: 'relative',
1437
+ width: '100%',
1438
+ height: 'auto',
1439
+ overflow: 'hidden',
1440
+ display: 'flex',
1441
+ alignItems: 'center',
1442
+ justifyContent: 'center',
1443
+ }}
1444
+ >
1271
1445
  <div style={groupProductContentStyle}>
1272
1446
  {displayProducts.map((product, displayIndex) => {
1273
1447
  const originalIndex = displayIndices[displayIndex];
@@ -1294,14 +1468,18 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
1294
1468
  <>
1295
1469
  {/* Previous Button */}
1296
1470
  <button
1297
- onClick={prevCarouselItem}
1471
+ onClick={(e) => {
1472
+ e.preventDefault();
1473
+ e.stopPropagation();
1474
+ handlePrevProduct();
1475
+ }}
1298
1476
  disabled={carouselIndex === 0}
1299
1477
  style={{
1300
1478
  position: 'absolute',
1301
1479
  left: '10px',
1302
1480
  top: '50%',
1303
1481
  transform: 'translateY(-50%)',
1304
- background: 'rgba(0,0,0,0.5)',
1482
+ background: carouselIndex === 0 ? 'rgba(0,0,0,0.3)' : 'rgba(0,0,0,0.7)',
1305
1483
  color: 'white',
1306
1484
  border: 'none',
1307
1485
  borderRadius: '50%',
@@ -1312,8 +1490,11 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
1312
1490
  display: 'flex',
1313
1491
  alignItems: 'center',
1314
1492
  justifyContent: 'center',
1315
- fontSize: '18px',
1316
- zIndex: 10,
1493
+ fontSize: '24px',
1494
+ fontWeight: 'bold',
1495
+ zIndex: 100,
1496
+ pointerEvents: 'auto',
1497
+ transition: 'all 0.3s ease',
1317
1498
  }}
1318
1499
  >
1319
1500
 
@@ -1321,14 +1502,18 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
1321
1502
 
1322
1503
  {/* Next Button */}
1323
1504
  <button
1324
- onClick={nextCarouselItem}
1505
+ onClick={(e) => {
1506
+ e.preventDefault();
1507
+ e.stopPropagation();
1508
+ handleNextProduct();
1509
+ }}
1325
1510
  disabled={carouselIndex >= maxCarouselIndex}
1326
1511
  style={{
1327
1512
  position: 'absolute',
1328
1513
  right: '10px',
1329
1514
  top: '50%',
1330
1515
  transform: 'translateY(-50%)',
1331
- background: 'rgba(0,0,0,0.5)',
1516
+ background: carouselIndex >= maxCarouselIndex ? 'rgba(0,0,0,0.3)' : 'rgba(0,0,0,0.7)',
1332
1517
  color: 'white',
1333
1518
  border: 'none',
1334
1519
  borderRadius: '50%',
@@ -1339,8 +1524,11 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
1339
1524
  display: 'flex',
1340
1525
  alignItems: 'center',
1341
1526
  justifyContent: 'center',
1342
- fontSize: '18px',
1343
- zIndex: 10,
1527
+ fontSize: '24px',
1528
+ fontWeight: 'bold',
1529
+ zIndex: 100,
1530
+ pointerEvents: 'auto',
1531
+ transition: 'all 0.3s ease',
1344
1532
  }}
1345
1533
  >
1346
1534
 
@@ -1355,21 +1543,27 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
1355
1543
  transform: 'translateX(-50%)',
1356
1544
  display: 'flex',
1357
1545
  gap: '8px',
1358
- zIndex: 10,
1546
+ zIndex: 100,
1547
+ pointerEvents: 'auto',
1359
1548
  }}
1360
1549
  >
1361
1550
  {Array.from({ length: maxCarouselIndex + 1 }, (_, index) => (
1362
1551
  <button
1363
1552
  key={index}
1364
- onClick={() => goToCarouselItem(index)}
1553
+ onClick={(e) => {
1554
+ e.preventDefault();
1555
+ e.stopPropagation();
1556
+ goToCarouselItem(index);
1557
+ }}
1365
1558
  style={{
1366
1559
  width: index === carouselIndex ? '12px' : '8px',
1367
1560
  height: index === carouselIndex ? '12px' : '8px',
1368
1561
  borderRadius: '50%',
1369
- border: 'none',
1370
- background: index === carouselIndex ? 'white' : 'rgba(255,255,255,0.5)',
1562
+ border: '2px solid white',
1563
+ background: index === carouselIndex ? 'white' : 'rgba(255,255,255,0.6)',
1371
1564
  cursor: 'pointer',
1372
1565
  transition: 'all 0.3s ease',
1566
+ pointerEvents: 'auto',
1373
1567
  }}
1374
1568
  />
1375
1569
  ))}
@@ -1398,7 +1592,7 @@ const TabComponent: React.FC<TabComponentMainProps> = ({ props, deviceMode = 'we
1398
1592
  return null;
1399
1593
  };
1400
1594
 
1401
- const tabs = props.tabs[0]?.all || [];
1595
+ const tabs = props.tabs || [];
1402
1596
 
1403
1597
  return (
1404
1598
  <div style={{