kupos-ui-components-lib 9.6.3 → 9.6.4

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