kupos-ui-components-lib 9.9.6 → 9.9.7

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 (42) hide show
  1. package/dist/KuposUIComponent.d.ts +0 -3
  2. package/dist/components/ServiceItem/PeruServiceItemDesktop.d.ts +1 -1
  3. package/dist/components/ServiceItem/PeruServiceItemDesktop.js +176 -156
  4. package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
  5. package/dist/components/ServiceItem/ServiceItemDesktop.js +31 -29
  6. package/dist/components/ServiceItem/ServiceItemMobile.d.ts +1 -1
  7. package/dist/components/ServiceItem/ServiceItemMobile.js +17 -43
  8. package/dist/components/ServiceItem/mobileTypes.d.ts +2 -48
  9. package/dist/components/ServiceItem/types.d.ts +8 -27
  10. package/dist/styles.css +16 -219
  11. package/dist/ui/ExpendedDropDown/ExpandedDropdown.d.ts +2 -1
  12. package/dist/ui/ExpendedDropDown/ExpandedDropdown.js +4 -2
  13. package/dist/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.js +10 -3
  14. package/dist/ui/OfferBanner.d.ts +0 -2
  15. package/dist/ui/OfferBanner.js +15 -22
  16. package/dist/ui/SeatSection/SeatSection.d.ts +7 -1
  17. package/dist/ui/SeatSection/SeatSection.js +41 -12
  18. package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +2 -1
  19. package/dist/ui/mobileweb/DateTimeSectionMobile.js +12 -6
  20. package/dist/ui/mobileweb/SeatSectionMobile.d.ts +2 -1
  21. package/dist/ui/mobileweb/SeatSectionMobile.js +21 -14
  22. package/dist/utils/CommonService.d.ts +1 -4
  23. package/dist/utils/CommonService.js +6 -19
  24. package/package.json +1 -1
  25. package/src/KuposUIComponent.tsx +0 -3
  26. package/src/components/ServiceItem/PeruServiceItemDesktop.tsx +277 -404
  27. package/src/components/ServiceItem/ServiceItemDesktop.tsx +51 -71
  28. package/src/components/ServiceItem/ServiceItemMobile.tsx +290 -387
  29. package/src/components/ServiceItem/mobileTypes.ts +8 -50
  30. package/src/components/ServiceItem/types.ts +13 -32
  31. package/src/styles.css +0 -15
  32. package/src/ui/ExpendedDropDown/ExpandedDropdown.tsx +4 -2
  33. package/src/ui/OfferBanner.tsx +43 -71
  34. package/src/ui/SeatSection/SeatSection.tsx +86 -21
  35. package/src/ui/mobileweb/DateTimeSectionMobile.tsx +44 -35
  36. package/src/ui/mobileweb/SeatSectionMobile.tsx +23 -11
  37. package/src/utils/CommonService.ts +8 -27
  38. package/src/assets/images/anims/service_list/flame_anim.json +0 -1
  39. package/src/assets/images/anims/service_list/thunder_icon.json +0 -1
  40. package/src/assets/images/anims/service_list/users_anim.json +0 -1
  41. package/src/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.tsx +0 -575
  42. package/src/ui/FeatureServiceUI/FeatureServiceUi.tsx +0 -634
@@ -18,65 +18,31 @@ import pullmanFlexibleAnimation from "../../assets/images/anims/service_list/pul
18
18
  import pullmanPetFriendlyAnimation from "../../assets/images/anims/service_list/pullmanPetFriendly.json";
19
19
  import pullmanLocationAnimation from "../../assets/images/anims/service_list/pullmanLocation.json";
20
20
  import pullmanPriorityStageAnimation from "../../assets/images/anims/service_list/pullmanPriorityStage.json";
21
+ import pullmanPromoAnimation from "../../assets/images/anims/service_list/promocion.json";
22
+ import pullmanDirectoAnimation from "../../assets/images/anims/service_list/directo.json";
21
23
 
22
24
  import opsitesFlexibleAnimation from "../../assets/images/anims/service_list/opsitesFlexible.json";
23
25
  import opsitesPetFriendlyAnimation from "../../assets/images/anims/service_list/opsitesPetFriendly.json";
24
26
  import opsitesLocationAnimation from "../../assets/images/anims/service_list/opsitesLocation.json";
25
27
  import opsitesPriorityStageAnimation from "../../assets/images/anims/service_list/opsitesPriorityStage.json";
26
-
27
- import bombAnimation from "../../assets/images/anims/service_list/bomb.json";
28
- import dotAnimation from "../../assets/images/anims/service_list/dot_animation.json";
29
-
28
+ import opsitesPromoAnimation from "../../assets/images/anims/service_list/promocion.json";
29
+ import opsitesDirectoAnimation from "../../assets/images/anims/service_list/directo.json";
30
+
31
+ import linatalFlexibleAnimation from "../../assets/images/anims/service_list/flexible.json";
32
+ import linatalPromoAnimation from "../../assets/images/anims/service_list/promocion.json";
33
+ import linatalDirectoAnimation from "../../assets/images/anims/service_list/directo.json";
34
+ import linatalPriorityStageAnimation from "../../assets/images/anims/service_list/priority_stage.json";
35
+ import linatalPetFriendlyAnimation from "../../assets/images/anims/service_list/pet_friendly.json";
36
+ import linatalLocationAnimation from "../../assets/images/anims/service_list/location.json";
30
37
  import StageTooltip from "../../ui/StagesTooltip";
31
38
  import RatingBlock from "../../ui/RatingBlock";
32
39
  import DurationBlock from "../../ui/DurationBlock";
33
40
  import PetBlock from "../../ui/PetBlock";
34
41
  import FlexibleBlock from "../../ui/FlexibleBlock";
35
42
  import AmenitiesBlock from "../../ui/AmenitiesBlock";
36
- import SeatSection from "../../ui/SeatSection/SeatSection";
37
- import KuposButton from "../../ui/KuposButton/KuposButton";
38
- import BottomAmenities from "../../ui/BottomAmenities/BottomAmenities";
39
- import OfferBanner from "../../ui/OfferBanner";
40
- import ServiceBadges from "../../ui/ServiceBadges/ServiceBadges";
41
43
 
42
44
  const SEAT_EXCEPTIONS = ["Asiento mascota"];
43
45
 
44
- const ANIMATION_MAP: Record<string, Record<string, any>> = {
45
- promoAnim: {
46
- kupos: promoAnimation,
47
- },
48
- locationAnim: {
49
- kupos: locationAnimation,
50
- pullman: pullmanLocationAnimation,
51
- opsites: opsitesLocationAnimation,
52
- },
53
- directoAnim: {
54
- kupos: directoAnimation,
55
- },
56
- petFriendlyAnim: {
57
- kupos: petFriendlyAnimation,
58
- pullman: pullmanPetFriendlyAnimation,
59
- opsites: opsitesPetFriendlyAnimation,
60
- },
61
- priorityStageAnim: {
62
- kupos: priorityStageAnimation,
63
- pullman: pullmanPriorityStageAnimation,
64
- opsites: opsitesPriorityStageAnimation,
65
- },
66
- flexibleIcon: {
67
- kupos: flexibleAnimation,
68
- pullman: pullmanFlexibleAnimation,
69
- opsites: opsitesFlexibleAnimation,
70
- },
71
- bombAnimation: {
72
- kupos: bombAnimation,
73
- },
74
- dotAnimation: {
75
- kupos: dotAnimation,
76
- opsites: dotAnimation,
77
- },
78
- };
79
-
80
46
  function PeruServiceItemDesktop({
81
47
  serviceItem,
82
48
  onBookButtonPress,
@@ -101,21 +67,53 @@ function PeruServiceItemDesktop({
101
67
  isPeru,
102
68
  siteType,
103
69
  isAllinBus,
104
- viewersConfig,
105
- isExpand,
106
- setIsExpand,
107
- coachKey,
108
- isLoggedIn,
109
- showLoginModal,
110
70
  isFlores,
111
- isNewUiEnabled,
112
- showLoginOption,
113
71
  t = (key: string) => key,
114
72
  }: ServiceItemProps & { currencySign?: string }): React.ReactElement {
73
+ const animationMap: Record<string, Record<string, any>> = {
74
+ promoAnim: {
75
+ kupos: promoAnimation,
76
+ pullman: pullmanPromoAnimation,
77
+ opsites: opsitesPromoAnimation,
78
+ linatal: linatalPromoAnimation,
79
+ },
80
+ locationAnim: {
81
+ kupos: locationAnimation,
82
+ pullman: pullmanLocationAnimation,
83
+ opsites: opsitesLocationAnimation,
84
+ linatal: linatalLocationAnimation,
85
+ },
86
+ directoAnim: {
87
+ kupos: directoAnimation,
88
+ pullman: pullmanDirectoAnimation,
89
+ opsites: opsitesDirectoAnimation,
90
+ linatal: linatalDirectoAnimation,
91
+ },
92
+ petFriendlyAnim: {
93
+ kupos: petFriendlyAnimation,
94
+ pullman: pullmanPetFriendlyAnimation,
95
+ opsites: opsitesPetFriendlyAnimation,
96
+ linatal: linatalPetFriendlyAnimation,
97
+ },
98
+ priorityStageAnim: {
99
+ kupos: priorityStageAnimation,
100
+ pullman: pullmanPriorityStageAnimation,
101
+ opsites: opsitesPriorityStageAnimation,
102
+ linatal: linatalPriorityStageAnimation,
103
+ },
104
+ flexibleIcon: {
105
+ kupos: flexibleAnimation,
106
+ pullman: pullmanFlexibleAnimation,
107
+ opsites: opsitesFlexibleAnimation,
108
+ linatal: linatalFlexibleAnimation,
109
+ },
110
+ };
111
+
115
112
  const getAnimationIcon = (icon: string) => {
116
- const animation = ANIMATION_MAP[icon];
113
+ const animation = animationMap[icon];
117
114
  if (!animation) return null;
118
- return animation[siteType] ?? animation.kupos;
115
+ const currentSiteType = siteType || "kupos";
116
+ return animation[currentSiteType];
119
117
  };
120
118
  const SvgAmenities = ({
121
119
  moreAnemities,
@@ -151,9 +149,8 @@ function PeruServiceItemDesktop({
151
149
  style={{
152
150
  filter: color === "white" ? "brightness(0) invert(1)" : "",
153
151
  }}
154
- className={`object-contain ${
155
- moreAnemities ? "w-[16px] h-[16px]" : "w-[16px] h-[16px]"
156
- }`}
152
+ className={`object-contain ${moreAnemities ? "w-[16px] h-[16px]" : "w-[16px] h-[16px]"
153
+ }`}
157
154
  />
158
155
  );
159
156
  };
@@ -170,7 +167,6 @@ function PeruServiceItemDesktop({
170
167
  busStage[labelId].split("|")[0];
171
168
 
172
169
  let isSoldOut = serviceItem.available_seats <= 0;
173
- const hasDpEnabled = serviceItem?.is_dp_enabled === true;
174
170
 
175
171
  const renderIcon = (iconKey: string, size: string = "14px") => {
176
172
  const iconValue = serviceItem.icons?.[iconKey];
@@ -265,9 +261,8 @@ function PeruServiceItemDesktop({
265
261
  SEAT_EXCEPTIONS.includes(val.label) ? null : (
266
262
  <span
267
263
  key={key}
268
- className={`flex items-center justify-between text-[13.33px] ${
269
- isSoldOut ? "text-[#c0c0c0]" : ""
270
- }`}
264
+ className={`flex items-center justify-between text-[13.33px] ${isSoldOut ? "text-[#c0c0c0]" : ""
265
+ }`}
271
266
  >
272
267
  <div>
273
268
  <img
@@ -292,9 +287,8 @@ function PeruServiceItemDesktop({
292
287
  SEAT_EXCEPTIONS.includes(val.label) ? null : (
293
288
  <span
294
289
  key={key}
295
- className={`flex items-center justify-between text-[13.33px] ${
296
- isSoldOut ? "text-[#c0c0c0]" : ""
297
- }`}
290
+ className={`flex items-center justify-between text-[13.33px] ${isSoldOut ? "text-[#c0c0c0]" : ""
291
+ }`}
298
292
  >
299
293
  <div>
300
294
  <img
@@ -350,8 +344,6 @@ function PeruServiceItemDesktop({
350
344
  };
351
345
 
352
346
  const checkMidnight = () => {
353
- setIsExpand?.(null);
354
-
355
347
  if (
356
348
  cityOrigin?.label &&
357
349
  cityDestination?.label &&
@@ -456,56 +448,26 @@ function PeruServiceItemDesktop({
456
448
  ? extractStage(serviceItem.stage_details_arr, 1)
457
449
  : null;
458
450
 
459
- const countdownSeconds = 599;
460
-
461
- const startCountdown = (node: HTMLSpanElement | null) => {
462
- if (!node) return;
463
-
464
- const prevId = node.dataset.countdownId;
465
- if (prevId) clearInterval(Number(prevId));
466
-
467
- let remaining = countdownSeconds;
468
-
469
- const formatTime = (totalSecs: number) => {
470
- const m = Math.floor(totalSecs / 60);
471
- const s = totalSecs % 60;
472
- return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
473
- };
474
-
475
- node.textContent = formatTime(remaining);
476
-
477
- const id = setInterval(() => {
478
- remaining -= 1;
479
- if (remaining <= 0) {
480
- remaining = countdownSeconds;
481
- }
482
- node.textContent = formatTime(remaining);
483
- }, 1000);
484
-
485
- node.dataset.countdownId = String(id);
486
- };
487
-
488
451
  const items = [
489
452
  {
490
- key: "amenities",
491
- width: "20%",
492
- condition: true,
453
+ key: "rating",
454
+ width: "30%",
493
455
  render: (
494
- <AmenitiesBlock
456
+ <RatingBlock
457
+ showRating={showRating}
495
458
  serviceItem={serviceItem}
496
- metaData={metaData}
497
459
  isSoldOut={isSoldOut}
498
460
  colors={colors}
499
- getAnimationIcon={getAnimationIcon}
500
- getAmenityName={CommonService.getAmenityName}
501
- SvgAmenities={SvgAmenities}
461
+ t={t}
462
+ translation={translation}
502
463
  isPeru={isPeru}
503
464
  />
504
465
  ),
505
466
  },
467
+
506
468
  {
507
469
  key: "duration",
508
- width: "12%",
470
+ width: "20%",
509
471
  condition: serviceItem.duration,
510
472
  render: (
511
473
  <DurationBlock
@@ -518,20 +480,6 @@ function PeruServiceItemDesktop({
518
480
  ),
519
481
  },
520
482
 
521
- // {
522
- // key: "directo",
523
- // width: "12%",
524
- // condition: serviceItem?.is_direct_trip === true,
525
- // render: (
526
- // <DirectoBlock
527
- // translation={translation}
528
- // getAnimationIcon={getAnimationIcon}
529
- // colors={colors}
530
- // isSoldOut={isSoldOut}
531
- // />
532
- // ),
533
- // },
534
-
535
483
  {
536
484
  key: "pet",
537
485
  width: "20%",
@@ -551,7 +499,7 @@ function PeruServiceItemDesktop({
551
499
  {
552
500
  key: "flexible",
553
501
  width: "20%",
554
- condition: serviceItem.is_change_ticket === true,
502
+ condition: false,
555
503
  render: (
556
504
  <FlexibleBlock
557
505
  translation={translation}
@@ -562,145 +510,81 @@ function PeruServiceItemDesktop({
562
510
  />
563
511
  ),
564
512
  },
513
+
514
+ {
515
+ key: "amenities",
516
+ width: "20%",
517
+ render: (
518
+ <AmenitiesBlock
519
+ serviceItem={serviceItem}
520
+ metaData={metaData}
521
+ isSoldOut={isSoldOut}
522
+ colors={colors}
523
+ isPeru={isPeru}
524
+ getAnimationIcon={getAnimationIcon}
525
+ getAmenityName={CommonService.getAmenityName}
526
+ SvgAmenities={SvgAmenities}
527
+ />
528
+ ),
529
+ },
565
530
  ];
566
531
 
532
+ const amenitiesItem = items.find((i) => i.key === "amenities");
567
533
  const otherItems = items.filter(
568
- (i) => i.key !== "pet" && i.key !== "flexible" && !!i.condition,
569
- );
570
-
571
- const isItemExpanded = serviceItem.id === isExpand || isExpand === true;
572
- const grayscaleClass = isSoldOut ? "grayscale" : "";
573
-
574
- const hasOfferText = Boolean(serviceItem?.offer_text);
575
-
576
- const offerGradient = `linear-gradient(90deg, ${colors.rightGradiantColor || "#ff5964"} 0%, ${colors.leftGradiantColor || "#ff8842"} 100%)`;
577
- const offerGradientWithOpacity = `linear-gradient(90deg, ${colors.rightGradiantColor || "#ff5964"}80 0%, ${colors.leftGradiantColor || "#ff8842"}80 100%)`;
578
- const serviceCardStyle: React.CSSProperties =
579
- (hasOfferText && isNewUiEnabled) || hasDpEnabled
580
- ? {
581
- borderColor: "transparent",
582
- borderStyle: "solid",
583
- borderWidth: "3px 3px 0 3px",
584
- borderRadius: isItemExpanded || coachKey ? "18px 18px 0 0" : "18px",
585
- background: `linear-gradient(#fff, #fff) padding-box, ${isSoldOut ? offerGradientWithOpacity : offerGradient} border-box`,
586
- // zIndex: 1,
587
- }
588
- : {};
589
-
590
- const seats = removeDuplicateSeats
591
- ? serviceItem.seat_types?.filter(
592
- (seat, index, self) =>
593
- index === self.findIndex((s) => s.label === seat.label),
594
- ) || []
595
- : serviceItem.seat_types || [];
596
-
597
- const discountedSeats = seats.map((seat) => ({
598
- ...seat,
599
- ...CommonService.calculateDiscountedPrice(seat.fare, serviceItem as any),
600
- }));
601
-
602
- const hasDiscount = discountedSeats.some(
603
- (seat) => seat.originalPrice !== seat.discountedPrice,
534
+ (i) => i.key !== "amenities" && i.condition !== false,
604
535
  );
605
536
 
606
537
  return (
607
538
  <div
608
- className={`relative hover:z-[150] ${hasOfferText ? "mb-[55px]" : "mb-[10px]"} ${
609
- serviceItem?.is_direct_trip ||
610
- serviceItem?.train_type_label === "Tren Express (Nuevo)" ||
611
- showTopLabel
539
+ className={`relative ${serviceItem.offer_text ? "mb-[55px]" : "mb-[10px]"
540
+ } ${serviceItem?.is_direct_trip ||
541
+ serviceItem?.train_type_label === "Tren Express (Nuevo)" ||
542
+ showTopLabel
612
543
  ? "mt-[24px]"
613
544
  : "mt-[20px]"
614
- } `}
545
+ } `}
615
546
  >
616
- {(serviceItem?.offer_text || hasDpEnabled) && !isSoldOut && (
617
- <OfferBanner
618
- offerGradient={offerGradient}
619
- isSoldOut={isSoldOut}
620
- serviceItem={serviceItem}
621
- renderIcon={renderIcon}
622
- isLoggedIn={isLoggedIn}
623
- showLoginModal={showLoginModal}
624
- viewersConfig={viewersConfig}
625
- getAnimationIcon={getAnimationIcon}
626
- showLoginOption={showLoginOption}
627
- isNewUiEnabled={isNewUiEnabled}
628
- colors={colors}
629
- />
630
- )}
631
547
  <div
632
- id={`service-card-${serviceItem.id}`}
633
- className={`bg-white mx-auto relative ${
634
- (hasOfferText && isNewUiEnabled && !isSoldOut) || hasDpEnabled
635
- ? "z-[3] rounded-[18px]"
636
- : "rounded-[10px] border border-[#ccc]"
637
- }`}
638
- style={serviceCardStyle}
548
+ className={"bg-white rounded-[20px] shadow-service mx-auto relative"}
639
549
  >
640
- <div
641
- className=" pt-[20px]"
642
- style={{
643
- padding: hasOfferText
644
- ? "20px 15px 10px 15px"
645
- : coachKey
646
- ? "20px 15px 20px 15px"
647
- : "20px 15px 10px 15px",
648
-
649
- marginTop: hasDiscount || hasOfferText ? "14px" : "",
650
- }}
651
- >
652
- {/* <div className="grid grid-cols-[1.5fr_1fr_auto] gap-[3rem] sm:gap-[4rem] md:gap-[5rem] lg:gap-[6rem] xl:gap-[5rem] 2xl:gap-[7rem] text-[#464647]"> */}
653
- <div
654
- className="grid text-[#464647] w-full [grid-template-columns:14%_40%_0.5%_24%_13.5%] gap-x-[2%] items-center"
655
- // style={{ marginTop: showTopLabel ? "8px" : "" }}
656
- style={{
657
- marginTop:
658
- showTopLabel || serviceItem?.is_direct_trip ? "8px" : "",
659
- }}
660
- >
661
- {/* OPERATOR LOGO */}
662
- <div
663
- style={{
664
- display: "flex",
665
- flexDirection: "column",
666
- // gap: "5px",
667
- }}
668
- >
669
- <div
670
- // className="flex items-center justify-center m-[auto]"
671
- className=""
672
- >
550
+ <div className="p-[15px] pt-[20px]">
551
+ {/* Header with operator info and favorite */}
552
+ {/* <div className="flex justify-between items-center mb-[15px]">
553
+ <div className="flex items-center justify-between w-[250px]">
554
+ <div className="w-[120px] overflow-y-hidden">
673
555
  <img
674
556
  src={serviceItem.operator_details[0]}
675
557
  alt="service logo"
676
- className={`h-auto object-contain ${
677
- isFlores ? "w-[80%]" : "w-full"
678
- } ${isSoldOut ? "grayscale" : ""}`}
558
+ className={`w-[120px] h-auto object-contain ${
559
+ isSoldOut ? "grayscale" : ""
560
+ }`}
679
561
  />
562
+ </div>
563
+
564
+ <div>
565
+ {" "}
680
566
  {isCiva ? (
681
- <div className="text-[13.33px] black-text ml-2">
567
+ <div className="text-[13.33px] black-text">
682
568
  {serviceItem.operator_details[2]}
683
569
  </div>
684
570
  ) : null}
685
571
  </div>
686
- <RatingBlock
687
- showRating={showRating}
688
- serviceItem={serviceItem}
689
- isSoldOut={isSoldOut}
690
- colors={colors}
691
- t={t}
692
- translation={translation}
693
- isPeru={isPeru}
694
- />
695
572
  </div>
696
- {/* <div className="flex items-center justify-center m-[auto]">
573
+ </div> */}
574
+
575
+ {/* <div className="grid grid-cols-[1.5fr_1fr_auto] gap-[3rem] sm:gap-[4rem] md:gap-[5rem] lg:gap-[6rem] xl:gap-[5rem] 2xl:gap-[7rem] text-[#464647]"> */}
576
+ <div
577
+ className="grid text-[#464647] w-full [grid-template-columns:14%_40%_0.5%_24%_13.5%] gap-x-[2%] items-center"
578
+ style={{ marginTop: showTopLabel ? "8px" : "" }}
579
+ >
580
+ {/* OPERATOR LOGO */}
581
+ <div className="flex items-center justify-center m-[auto]">
697
582
  <div className=" ">
698
583
  <img
699
584
  src={serviceItem.operator_details[0]}
700
585
  alt="service logo"
701
- className={` h-auto object-contain ${
702
- isSoldOut ? "grayscale" : ""
703
- }`}
586
+ className={`h-auto object-contain ${isFlores ? "w-[80%]" : "w-full"
587
+ } ${isSoldOut ? "grayscale" : ""}`}
704
588
  />
705
589
  </div>
706
590
  {isCiva ? (
@@ -708,19 +592,18 @@ function PeruServiceItemDesktop({
708
592
  {serviceItem.operator_details[2]}
709
593
  </div>
710
594
  ) : null}
711
- </div> */}
595
+ </div>
712
596
 
713
597
  {/* DATE AND TIME - Grid Layout */}
714
598
  <div
715
- className={`min-h-[2.5rem] grid grid-cols-[0.8fr_auto_26%_1fr] gap-x-4 items-center text-[13.33px] ${
716
- isSoldOut ? "text-[#c0c0c0]" : ""
717
- }`}
599
+ className={`min-h-[2.5rem] grid grid-cols-[0.8fr_auto_26%_1fr] gap-x-4 items-center text-[13.33px] ${isSoldOut ? "text-[#c0c0c0]" : ""
600
+ }`}
718
601
  style={{
719
602
  gridTemplateRows: "1fr",
720
603
  }}
721
604
  >
722
605
  {/* ICONS COLUMN */}
723
- <div className="flex flex-col gap-[4px]">
606
+ <div className="flex flex-col gap-[10px]">
724
607
  {/* Origin Icon */}
725
608
  {orignLabel ? (
726
609
  <div className="w-[60px] h-[20px] flex items-center bold-text">
@@ -731,9 +614,8 @@ function PeruServiceItemDesktop({
731
614
  <img
732
615
  src={serviceItem.icons?.origin}
733
616
  alt="origin"
734
- className={`w-[18px] h-auto mr-[8px] ${
735
- isSoldOut ? "grayscale" : ""
736
- }`}
617
+ className={`w-[18px] h-auto mr-[8px] ${isSoldOut ? "grayscale" : ""
618
+ }`}
737
619
  />
738
620
  </div>
739
621
  )}
@@ -748,9 +630,8 @@ function PeruServiceItemDesktop({
748
630
  <div className="h-[20px] flex items-center">
749
631
  <img
750
632
  src={serviceItem.icons?.destination}
751
- className={`w-[18px] h-auto mr-[8px] ${
752
- isSoldOut ? "grayscale" : ""
753
- }`}
633
+ className={`w-[18px] h-auto mr-[8px] ${isSoldOut ? "grayscale" : ""
634
+ }`}
754
635
  style={{ opacity: isSoldOut ? 0.5 : 1 }}
755
636
  />
756
637
  </div>
@@ -758,7 +639,7 @@ function PeruServiceItemDesktop({
758
639
  </div>
759
640
 
760
641
  {/* DATES COLUMN */}
761
- <div className="flex flex-col gap-[4px]">
642
+ <div className="flex flex-col gap-[10px]">
762
643
  {/* Departure Date */}
763
644
  <StageTooltip
764
645
  stageData={serviceItem.boarding_stages}
@@ -791,7 +672,7 @@ function PeruServiceItemDesktop({
791
672
  </div>
792
673
 
793
674
  {/* DOTS COLUMN */}
794
- <div className="flex flex-col gap-[4px] items-center">
675
+ <div className="flex flex-col gap-[10px] items-center">
795
676
  {/* Departure Dot */}
796
677
  <div className="h-[20px] flex items-center justify-center">
797
678
  <div>•</div>
@@ -808,7 +689,7 @@ function PeruServiceItemDesktop({
808
689
  </div>
809
690
 
810
691
  {/* TIMES COLUMN */}
811
- <div className="flex flex-col gap-[4px]">
692
+ <div className="flex flex-col gap-[10px]">
812
693
  {/* Departure Time */}
813
694
  <StageTooltip
814
695
  stageData={serviceItem.boarding_stages}
@@ -854,180 +735,142 @@ function PeruServiceItemDesktop({
854
735
  ></div>
855
736
  {/* SEATS */}
856
737
  <div className="content-center">
857
- <SeatSection
858
- seatTypes={serviceItem.seat_types}
859
- serviceItem={serviceItem}
860
- availableSeats={serviceItem.available_seats}
861
- isSoldOut={isSoldOut}
862
- priceColor={colors.priceColor}
863
- currencySign={currencySign}
864
- removeDuplicateSeats={removeDuplicateSeats}
865
- isPeru={isPeru}
866
- renderIcon={renderIcon}
867
- discountSeatPriceColor={colors.discountSeatPriceColor}
868
- />
869
- </div>
738
+ <div
739
+ className={`relative flex gap-[10px] text-[13.33px] justify-between min-h-[2.5rem] ${getNumberOfSeats() < 3 ? "" : ""
740
+ }`}
741
+ style={
742
+ getNumberOfSeats() < 2
743
+ ? { alignItems: "center" }
744
+ : { alignItems: "center" }
745
+ }
746
+ >
747
+ <div className="flex flex-col justify-between">
748
+ {getSeatNames()}
749
+ </div>
870
750
 
871
- {/* BUTTON */}
872
- {/* {showLastSeats ? (
873
751
  <div
874
- className="flex justify-end mr-[11px] "
752
+ className="flex flex-col justify-between absolute inset-y-0 right-0 left-1/2 h-full"
875
753
  style={{
876
- position: "absolute",
877
- top: serviceDetailsLoading ? "7px" : "5px",
878
- right: "16px",
754
+ color: isSoldOut ? "#c0c0c0" : colors.priceColor,
755
+ top: 0,
756
+ bottom: 0,
757
+ left: "68%",
758
+ right: 0,
759
+ justifyContent:
760
+ getNumberOfSeats() < 2 ? "center" : "center",
761
+ gap: "5px",
879
762
  }}
880
763
  >
881
- {serviceItem?.available_seats < 10 &&
882
- serviceItem?.available_seats > 0 && (
883
- <div className="text-[12px] text-[#464647] mt-1 text-center">
884
- ¡Últimos Asientos!
885
- </div>
886
- )}
764
+ <span
765
+ style={{
766
+ position: "absolute",
767
+ top: getNumberOfSeats() > 1 ? -10 : -5,
768
+ fontWeight: "initial",
769
+ fontSize: "12px",
770
+ left: 0,
771
+ color: "#6a6a6a",
772
+ }}
773
+ >
774
+ Desde
775
+ </span>
776
+ {getSeatPrice()}
887
777
  </div>
888
- ) : null}
889
- <KuposButton
890
- isSoldOut={isSoldOut}
891
- isLoading={serviceDetailsLoading}
892
- buttonColor={colors.kuposButtonColor}
893
- buyLabel={translation?.buyButton}
894
- soldOutLabel={translation?.soldOutButton}
895
- soldOutIcon={renderIcon("soldOutIcon", "14px")}
896
- onClick={checkMidnight}
897
- /> */}
898
- <div className="relative">
899
- <KuposButton
900
- isSoldOut={isSoldOut}
901
- isLoading={serviceDetailsLoading}
902
- buttonColor={colors.kuposButtonColor}
903
- buyLabel={translation?.buyButton}
904
- soldOutLabel={translation?.soldOutButton}
905
- soldOutIcon={renderIcon("soldOutIcon", "14px")}
906
- onClick={checkMidnight}
907
- />
908
- {showLastSeats ? (
909
- <div className="flex justify-center mr-[11px] w-[100%] right-[0px] absolute left-[0] top-[40px]">
910
- {serviceItem?.available_seats < 10 &&
911
- serviceItem?.available_seats > 0 && (
912
- <div
913
- className="text-[12px] mt-1 text-center"
914
- style={{
915
- color: colors.seatPriceColor,
916
- }}
917
- >
918
- ¡Últimos Asientos!
919
- </div>
920
- )}
778
+ </div>
779
+ </div>
780
+
781
+ {/* BUTTON */}
782
+ <div>
783
+ <button
784
+ onClick={() => (!isSoldOut ? checkMidnight() : null)}
785
+ disabled={serviceDetailsLoading}
786
+ className={`w-full ${serviceDetailsLoading || isSoldOut ? "py-[12px]" : "py-[12px]"
787
+ } text-[13.33px] font-bold text-white rounded-[10px] border-none px-[20px] flex items-center justify-center`}
788
+ style={{
789
+ backgroundColor:
790
+ serviceDetailsLoading || isSoldOut
791
+ ? "lightgray"
792
+ : colors.kuposButtonColor,
793
+ cursor:
794
+ serviceDetailsLoading || isSoldOut
795
+ ? "not-allowed"
796
+ : "pointer",
797
+ }}
798
+ >
799
+ <span className="min-w-[75px] flex justify-center items-center bold-text uppercase">
800
+ {isSoldOut ? renderIcon("soldOutIcon", "14px") : null}
801
+
802
+ {serviceDetailsLoading ? (
803
+ <span className="loader-circle"></span>
804
+ ) : !isSoldOut ? (
805
+ translation?.buyButton
806
+ ) : (
807
+ translation?.soldOutButton
808
+ )}
809
+ </span>
810
+ </button>
811
+ </div>
812
+ </div>
813
+ {showLastSeats ? (
814
+ <div className="flex justify-end mr-[11px]">
815
+ {serviceItem?.available_seats < 10 &&
816
+ serviceItem?.available_seats > 0 && (
817
+ <div className="text-[12px] text-[red] mt-1 text-center">
818
+ ¡ Últimos Asientos!
819
+ </div>
820
+ )}
821
+ </div>
822
+ ) : null}
823
+
824
+ <div className="flex items-center mt-[15px] border-t border-[#eee] pt-[10px]">
825
+ {/* 🔹 LEFT SIDE (GRID ITEMS) */}
826
+ <div
827
+ className="grid items-center gap-[2%] flex-1"
828
+ style={{
829
+ gridTemplateColumns: "30% 18% 23% 23%",
830
+
831
+ // otherItems
832
+ // .map((i) => i.width)
833
+ // .join(" "),
834
+ }}
835
+ >
836
+ {otherItems.map((item) => (
837
+ <div key={item.key} className="flex items-center ">
838
+ {item.render}
921
839
  </div>
922
- ) : null}
840
+ ))}
841
+ </div>
842
+
843
+ {/* 🔹 RIGHT SIDE (ALWAYS END) */}
844
+ <div className="flex items-center ml-[12px] shrink-0 w-[130px] justify-end">
845
+ {amenitiesItem?.render}
923
846
  </div>
924
847
  </div>
925
- <BottomAmenities
926
- otherItems={otherItems}
927
- serviceItem={serviceItem}
928
- grayscaleClass={grayscaleClass}
929
- isSoldOut={isSoldOut}
930
- isItemExpanded={isItemExpanded}
931
- colors={colors}
932
- translation={translation}
933
- getAnimationIcon={getAnimationIcon}
934
- downArrowIcon={renderIcon("downArrow", "10px")}
935
- onToggleExpand={() =>
936
- setIsExpand && setIsExpand(isItemExpanded ? null : serviceItem.id)
937
- }
938
- isPeru={isPeru}
939
- />
940
848
  </div>
941
849
  </div>
942
850
 
943
851
  {children}
944
-
945
- {/* {serviceItem?.offer_text && (
852
+ {/* Bottom discount banner */}
853
+ {serviceItem?.offer_text && (
946
854
  <div
947
- className="text-white p-[10px_15px] text-left w-full flex items-center absolute -bottom-[36px] pt-[50px] rounded-b-[14px] text-[14px]"
855
+ className={` text-white p-[10px_15px] text-left w-full flex items-center absolute -bottom-[36px] pt-[50px] -z-10 rounded-b-[14px] text-[14px]`}
948
856
  style={{
949
- background: offerGradient,
857
+ backgroundColor: isSoldOut
858
+ ? colors?.bottomStripColor
859
+ : colors?.bottomStripColor,
950
860
  opacity: isSoldOut ? 0.5 : 1,
951
861
  }}
952
862
  >
953
- <div className="flex justify-between items-center w-full">
954
- <div className="flex items-center ">
955
- <div className="flex items-center">
956
- <LottiePlayer
957
- animationData={getAnimationIcon("bombAnimation")}
958
- width="18px"
959
- height="18px"
960
- />
961
- <div className="flex items-center mt-[2px]">
962
- <span className="bold-text ml-[6px]">
963
- {(serviceItem?.offer_text || "").length > 30
964
- ? (serviceItem?.offer_text || "").slice(0, 30) + "..."
965
- : serviceItem?.offer_text || ""}{" "}
966
- {isLoggedIn ? null : (
967
- <span onClick={showLoginModal} className="cursor-pointer">
968
- - registro
969
- </span>
970
- )}{" "}
971
- &nbsp;
972
- </span>{" "}
973
- | Termina en&nbsp;
974
- <span
975
- className="bold-text text-end"
976
- ref={(node) => CommonService.startCountdown(node, 599)}
977
- style={{
978
- fontVariantNumeric: "tabular-nums",
979
- display: "inline-block",
980
- }}
981
- />
982
- </div>
983
- </div>
984
- </div>
985
- <div className="flex items-center">
986
- <LottiePlayer
987
- animationData={getAnimationIcon("dotAnimation")}
988
- width="12px"
989
- height="12px"
990
- />
991
-
992
- <span className="ml-[6px]">
993
- <span
994
- className="bold-text"
995
- ref={(node) =>
996
- CommonService.startViewerCount(node, viewersConfig)
997
- }
998
- style={{ fontVariantNumeric: "tabular-nums" }}
999
- />{" "}
1000
- <span>
1001
- {" "}
1002
- {viewersConfig?.label || " viendo"} |{" "}
1003
- <span className="">
1004
- {serviceItem?.is_dp_enabled ? null : "Quedan pocos • "}
1005
- <span
1006
- className="bold-text"
1007
- ref={(node) =>
1008
- CommonService.startComprandoCount(node, 4, 16)
1009
- }
1010
- style={{ fontVariantNumeric: "tabular-nums" }}
1011
- />{" "}
1012
- comprando
1013
- </span>
1014
- </span>
1015
- </span>
1016
- </div>
1017
- </div>
863
+ <LottiePlayer
864
+ // animationData={serviceItem.icons.promoAnim}
865
+ animationData={getAnimationIcon("promoAnim")}
866
+ width="18px"
867
+ height="18px"
868
+ />
869
+ <span className="ml-[10px]">{serviceItem?.offer_text}</span>
1018
870
  </div>
1019
- )} */}
1020
-
1021
- <ServiceBadges
1022
- showTopLabel={showTopLabel}
1023
- isSoldOut={isSoldOut}
1024
- colors={colors}
1025
- renderIcon={renderIcon}
1026
- translation={translation}
1027
- serviceItem={serviceItem}
1028
- />
871
+ )}
1029
872
 
1030
- {/* <div className="absolute -top-[11px] left-0 w-full flex items-center justify-end gap-[12px] pr-[15px] z-10 ">
873
+ <div className="absolute -top-[11px] left-0 w-full flex items-center justify-end gap-[12px] pr-[15px] z-10 ">
1031
874
  {showTopLabel && (
1032
875
  <div
1033
876
  className={`flex items-center gap-[10px] py-[4px] px-[14px] rounded-[38px] text-[12.5px] z-20`}
@@ -1037,6 +880,7 @@ function PeruServiceItemDesktop({
1037
880
  >
1038
881
  <div className={isSoldOut ? "grayscale" : ""}>
1039
882
  <LottiePlayer
883
+ // animationData={serviceItem.icons.priorityStageAnim}
1040
884
  animationData={getAnimationIcon("priorityStageAnim")}
1041
885
  width="14px"
1042
886
  height="14px"
@@ -1061,6 +905,7 @@ function PeruServiceItemDesktop({
1061
905
  >
1062
906
  <div className={isSoldOut ? "grayscale" : ""}>
1063
907
  <LottiePlayer
908
+ // animationData={serviceItem.icons.priorityStageAnim}
1064
909
  animationData={getAnimationIcon("priorityStageAnim")}
1065
910
  width="14px"
1066
911
  height="14px"
@@ -1076,6 +921,30 @@ function PeruServiceItemDesktop({
1076
921
  </div>
1077
922
  )}
1078
923
 
924
+ {/* {dropoffName && (
925
+ <div
926
+ className={`flex items-center gap-[10px] py-[4px] px-[14px] rounded-[38px] text-[12.5px] z-20`}
927
+ style={{
928
+ backgroundColor: isSoldOut ? "#ddd" : colors.ratingBottomColor,
929
+ }}
930
+ >
931
+ <div className={isSoldOut ? "grayscale" : ""}>
932
+ <LottiePlayer
933
+ // animationData={serviceItem.icons.priorityStageAnim}
934
+ animationData={getAnimationIcon("priorityStageAnim")}
935
+ width="14px"
936
+ height="14px"
937
+ />
938
+ </div>
939
+ <div
940
+ className={
941
+ isSoldOut ? "text-white" : `text-[${colors.topLabelColor}]`
942
+ }
943
+ >
944
+ {dropoffName}
945
+ </div>
946
+ </div>
947
+ )} */}
1079
948
  {serviceItem?.is_transpordo && (
1080
949
  <div
1081
950
  className={`flex items-center gap-[10px] py-[4px] text-white px-[14px] rounded-[38px] text-[12.5px] z-20`}
@@ -1083,8 +952,11 @@ function PeruServiceItemDesktop({
1083
952
  backgroundColor: isSoldOut ? "#ddd" : colors.tooltipColor,
1084
953
  }}
1085
954
  >
1086
- {renderIcon("connectingServiceIcon", "12px")}
1087
-
955
+ <LottiePlayer
956
+ animationData={serviceItem.icons.connectingServiceIcon}
957
+ width="14px"
958
+ height="14px"
959
+ />
1088
960
  <div>{"Conexión"}</div>
1089
961
  </div>
1090
962
  )}
@@ -1111,6 +983,7 @@ function PeruServiceItemDesktop({
1111
983
  }}
1112
984
  >
1113
985
  <LottiePlayer
986
+ // animationData={serviceItem.icons.directoAnim}
1114
987
  animationData={getAnimationIcon("directoAnim")}
1115
988
  width="14px"
1116
989
  height="14px"
@@ -1118,7 +991,7 @@ function PeruServiceItemDesktop({
1118
991
  <div>{"Tren Express"}</div>
1119
992
  </div>
1120
993
  )}
1121
- </div> */}
994
+ </div>
1122
995
  </div>
1123
996
  );
1124
997
  }