kupos-ui-components-lib 9.6.6 → 9.6.8

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.
@@ -0,0 +1 @@
1
+ {"nm":"t","ddd":0,"h":500,"w":500,"meta":{"g":"@lottiefiles/toolkit-js 0.33.2"},"layers":[{"ty":4,"nm":"t","sr":1,"st":60,"op":90,"ip":60,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[256.655,268,0]},"s":{"a":0,"k":[100,100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256.655,268,0]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":89},{"s":[0],"t":90}]}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"nm":"0","it":[{"ty":"sh","bm":0,"hd":false,"nm":"パ","d":1,"ks":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-35.799,-108.024],[135.03,-108.024],[135.015,-107.976],[-35.905,-107.905]]}],"t":60},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-35.799,-108.024],[135.03,-108.024],[-48.36,108.024],[-135.03,96.72]]}],"t":66}]}},{"ty":"fl","bm":0,"hd":false,"nm":"塗","c":{"a":0,"k":[1,1,1]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":60},{"s":[100],"t":61}]}},{"ty":"tr","a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[245.351,170.024]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}}]},{"ty":"gr","bm":0,"hd":false,"nm":"0","it":[{"ty":"sh","bm":0,"hd":false,"nm":"パ","d":1,"ks":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-146.335,21.917],[-146.203,22.157],[-111.091,-49.844],[-111.165,-49.681]]}],"t":66},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-146.335,21.917],[66.749,49.681],[146.335,-25.815],[-111.165,-49.681]]}],"t":72}]}},{"ty":"fl","bm":0,"hd":false,"nm":"塗","c":{"a":0,"k":[1,1,1]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":66},{"s":[100],"t":67}]}},{"ty":"tr","a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256.655,244.827]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}}]},{"ty":"gr","bm":0,"hd":false,"nm":"0","it":[{"ty":"sh","bm":0,"hd":false,"nm":"パ","d":1,"ks":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[85.348,-127.61],[40.195,-131.89],[134.402,-123.098]]}],"t":66},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[54.848,-47.61],[40.195,-131.89],[134.402,-123.098]]}],"t":72},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-134.402,131.89],[40.195,-131.89],[134.402,-123.098]]}],"t":78}]}},{"ty":"fl","bm":0,"hd":false,"nm":"塗","c":{"a":0,"k":[1,1,1]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":72},{"s":[100],"t":73}]}},{"ty":"tr","a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[268.588,342.11]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}}]}],"ind":1},{"ty":4,"nm":"t","sr":1,"st":30,"op":60,"ip":30,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[256.655,268,0]},"s":{"a":0,"k":[100,100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256.655,268,0]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":59},{"s":[0],"t":60}]}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"nm":"0","it":[{"ty":"sh","bm":0,"hd":false,"nm":"パ","d":1,"ks":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-35.799,-108.024],[135.03,-108.024],[135.015,-107.976],[-35.905,-107.905]]}],"t":30},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-35.799,-108.024],[135.03,-108.024],[-48.36,108.024],[-135.03,96.72]]}],"t":36}]}},{"ty":"fl","bm":0,"hd":false,"nm":"塗","c":{"a":0,"k":[1,1,1]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":30},{"s":[100],"t":31}]}},{"ty":"tr","a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[245.351,170.024]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}}]},{"ty":"gr","bm":0,"hd":false,"nm":"0","it":[{"ty":"sh","bm":0,"hd":false,"nm":"パ","d":1,"ks":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-146.335,21.917],[-146.203,22.157],[-111.091,-49.844],[-111.165,-49.681]]}],"t":36},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-146.335,21.917],[66.749,49.681],[146.335,-25.815],[-111.165,-49.681]]}],"t":42}]}},{"ty":"fl","bm":0,"hd":false,"nm":"塗","c":{"a":0,"k":[1,1,1]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":36},{"s":[100],"t":37}]}},{"ty":"tr","a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256.655,244.827]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}}]},{"ty":"gr","bm":0,"hd":false,"nm":"0","it":[{"ty":"sh","bm":0,"hd":false,"nm":"パ","d":1,"ks":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[85.348,-127.61],[40.195,-131.89],[134.402,-123.098]]}],"t":36},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[54.848,-47.61],[40.195,-131.89],[134.402,-123.098]]}],"t":42},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-134.402,131.89],[40.195,-131.89],[134.402,-123.098]]}],"t":48}]}},{"ty":"fl","bm":0,"hd":false,"nm":"塗","c":{"a":0,"k":[1,1,1]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":42},{"s":[100],"t":43}]}},{"ty":"tr","a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[268.588,342.11]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}}]}],"ind":2},{"ty":4,"nm":"t","sr":1,"st":0,"op":30,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[256.655,268,0]},"s":{"a":0,"k":[100,100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256.655,268,0]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":29},{"s":[0],"t":30}]}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"nm":"0","it":[{"ty":"sh","bm":0,"hd":false,"nm":"パ","d":1,"ks":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-35.799,-108.024],[135.03,-108.024],[135.015,-107.976],[-35.905,-107.905]]}],"t":0},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-35.799,-108.024],[135.03,-108.024],[-48.36,108.024],[-135.03,96.72]]}],"t":6}]}},{"ty":"fl","bm":0,"hd":false,"nm":"塗","c":{"a":0,"k":[1,1,1]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":0},{"s":[100],"t":1}]}},{"ty":"tr","a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[245.351,170.024]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}}]},{"ty":"gr","bm":0,"hd":false,"nm":"0","it":[{"ty":"sh","bm":0,"hd":false,"nm":"パ","d":1,"ks":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-146.335,21.917],[-146.203,22.157],[-111.091,-49.844],[-111.165,-49.681]]}],"t":6},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-146.335,21.917],[66.749,49.681],[146.335,-25.815],[-111.165,-49.681]]}],"t":12}]}},{"ty":"fl","bm":0,"hd":false,"nm":"塗","c":{"a":0,"k":[1,1,1]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":6},{"s":[100],"t":7}]}},{"ty":"tr","a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[256.655,244.827]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}}]},{"ty":"gr","bm":0,"hd":false,"nm":"0","it":[{"ty":"sh","bm":0,"hd":false,"nm":"パ","d":1,"ks":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[85.348,-127.61],[40.195,-131.89],[134.402,-123.098]]}],"t":6},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[{"c":true,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[54.848,-47.61],[40.195,-131.89],[134.402,-123.098]]}],"t":12},{"s":[{"c":true,"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-134.402,131.89],[40.195,-131.89],[134.402,-123.098]]}],"t":18}]}},{"ty":"fl","bm":0,"hd":false,"nm":"塗","c":{"a":0,"k":[1,1,1]},"r":1,"o":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[0],"t":12},{"s":[100],"t":13}]}},{"ty":"tr","a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[268.588,342.11]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}}]}],"ind":3}],"v":"5.9.0","fr":30,"op":90,"ip":0,"assets":[]}
@@ -37,6 +37,9 @@ import KuposButton from "../../ui/KuposButton/KuposButton";
37
37
  import BottomAmenities from "../../ui/BottomAmenities/BottomAmenities";
38
38
  import SeatSection from "../../ui/SeatSection/SeatSection";
39
39
  import DateTimeSection from "../../ui/DateTimeSection/DateTimeSection";
40
+ import FeatureServiceUi from "../../ui/FeatureServiceUI/FeatureServiceUi";
41
+
42
+ import thunderAnimation from "../../assets/images/anims/service_list/thunder_icon.json";
40
43
  import ServiceBadges from "../../ui/ServiceBadges/ServiceBadges";
41
44
 
42
45
  const SEAT_EXCEPTIONS = ["Asiento mascota"];
@@ -71,6 +74,9 @@ const ANIMATION_MAP: Record<string, Record<string, any>> = {
71
74
  bombAnimation: {
72
75
  kupos: bombAnimation,
73
76
  },
77
+ thunderAnimation: {
78
+ kupos: thunderAnimation,
79
+ },
74
80
  dotAnimation: {
75
81
  kupos: dotAnimation,
76
82
  },
@@ -113,9 +119,10 @@ function ServiceItemPB({
113
119
  setIsExpand,
114
120
  coachKey,
115
121
  viewersConfig,
122
+ isNewUi,
116
123
  showLoginModal,
117
124
  isLoggedIn,
118
- showLoginOption
125
+ showLoginOption,
119
126
  }: ServiceItemProps & { currencySign?: string }): React.ReactElement {
120
127
  const getAnimationIcon = (icon: string) => {
121
128
  const animation = ANIMATION_MAP[icon];
@@ -415,6 +422,18 @@ function ServiceItemPB({
415
422
  siteType={siteType}
416
423
  isAllinBus={isAllinBus}
417
424
  />
425
+ ) : isNewUi ? (
426
+ <FeatureServiceUi
427
+ serviceItem={serviceItem}
428
+ showTopLabel={showTopLabel}
429
+ colors={colors}
430
+ isSoldOut={isSoldOut}
431
+ getAnimationIcon={getAnimationIcon}
432
+ cityOrigin={cityOrigin}
433
+ cityDestination={cityDestination}
434
+ renderIcon={renderIcon}
435
+ viewersConfig={viewersConfig}
436
+ />
418
437
  ) : (
419
438
  <div
420
439
  className={`relative hover:z-[150] ${hasOfferText || hasDpEnabled ? "mb-[55px]" : "mb-[10px]"} ${
@@ -132,6 +132,13 @@ export interface ServiceItemProps {
132
132
  whiteFireIcon?: string
133
133
  fireIcon?: string
134
134
 
135
+ whiteOrigin?: string,
136
+ whiteDestination?: string,
137
+ userIcon?: string,
138
+ sheildIcon?: string,
139
+ busIcon?: string,
140
+ whiteDownArrow?: string,
141
+
135
142
  [key: string]: string | Record<string, string | undefined> | undefined;
136
143
  };
137
144
  useLottieFor?: string[];
@@ -223,6 +230,7 @@ export interface ServiceItemProps {
223
230
  label?: string; // e.g. "personas están viendo este viaje"
224
231
  icon?: string; // optional icon URL
225
232
  };
233
+ isNewUi?: boolean
226
234
  showLoginModal?: any
227
235
  isLoggedIn?: any
228
236
  showLoginOption?: boolean
@@ -0,0 +1,549 @@
1
+ import React from "react";
2
+ import LottiePlayer from "../../assets/LottiePlayer";
3
+ import commonService from "../../utils/CommonService";
4
+
5
+ const HARDCODED_OPERATORS = [
6
+ {
7
+ logo: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Turbus_logo.svg/320px-Turbus_logo.svg.png",
8
+ name: "Turbus",
9
+ time: "7:00 am",
10
+ seatsAvailable: "3 disponibles",
11
+ },
12
+ {
13
+ logo: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Pullman_Bus_logo.svg/320px-Pullman_Bus_logo.svg.png",
14
+ name: "Pullmanbus",
15
+ time: "8:00 am",
16
+ seatsAvailable: "5 disponibles",
17
+ },
18
+ {
19
+ logo: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Turbus_logo.svg/320px-Turbus_logo.svg.png",
20
+ name: "Expreso Santa C...",
21
+ time: "9:00 am",
22
+ seatsAvailable: "3 disponibles",
23
+ },
24
+ ];
25
+
26
+ const HARDCODED_COUNTDOWN = "09:55";
27
+
28
+ const HOW_IT_WORKS_STEPS = [
29
+ {
30
+ icon: "flexible",
31
+ name: "1. Salida flexible",
32
+ text: "Viajas en un horario entre las 07:00 y las 10:00 AM del día elegido.",
33
+ },
34
+ {
35
+ icon: "bus",
36
+ name: "2. Empresa asignada",
37
+ text: "Una de las empresas disponibles confirma tu viaje una vez pagado.",
38
+ },
39
+ {
40
+ icon: "price",
41
+ name: "3. Precio garantizado",
42
+ text: "Al seleccionar este servicio aseguras el precio reducido.",
43
+ },
44
+ {
45
+ icon: "ticket",
46
+ name: "4. ¡Listo!",
47
+ text: "Recibe todos los detalles de tu viaje al instante tras la compra.",
48
+ },
49
+ ];
50
+
51
+ const FeatureStepIcon = ({ icon }) => {
52
+ const iconClassName = "h-[30px] w-[30px] text-[#171717]";
53
+
54
+ switch (icon) {
55
+ case "flexible":
56
+ return (
57
+ <svg
58
+ className={iconClassName}
59
+ viewBox="0 0 40 40"
60
+ fill="none"
61
+ aria-hidden="true"
62
+ >
63
+ <path
64
+ d="M31.5 13.4A13 13 0 0 0 8 12.3"
65
+ stroke="currentColor"
66
+ strokeWidth="2.2"
67
+ strokeLinecap="round"
68
+ />
69
+ <path
70
+ d="m7.4 7.7.2 5.2 5.1-1.2M8.5 26.6A13 13 0 0 0 32 27.7"
71
+ stroke="currentColor"
72
+ strokeWidth="2.2"
73
+ strokeLinecap="round"
74
+ strokeLinejoin="round"
75
+ />
76
+ <path
77
+ d="m32.6 32.3-.2-5.2-5.1 1.2"
78
+ stroke="currentColor"
79
+ strokeWidth="2.2"
80
+ strokeLinecap="round"
81
+ strokeLinejoin="round"
82
+ />
83
+ </svg>
84
+ );
85
+ case "bus":
86
+ return (
87
+ <svg
88
+ className={iconClassName}
89
+ viewBox="0 0 40 40"
90
+ fill="none"
91
+ aria-hidden="true"
92
+ >
93
+ <rect
94
+ x="8"
95
+ y="4.5"
96
+ width="24"
97
+ height="27"
98
+ rx="2.5"
99
+ stroke="currentColor"
100
+ strokeWidth="2.2"
101
+ />
102
+ <path
103
+ d="M8 18.5h24M12 9h16M12 26h4m8 0h4M11 31.5v3h5v-3m8 0v3h5v-3M5.5 10v7m29-7v7"
104
+ stroke="currentColor"
105
+ strokeWidth="2.2"
106
+ strokeLinecap="round"
107
+ />
108
+ </svg>
109
+ );
110
+ case "price":
111
+ return (
112
+ <svg
113
+ className={iconClassName}
114
+ viewBox="0 0 40 40"
115
+ fill="none"
116
+ aria-hidden="true"
117
+ >
118
+ <circle
119
+ cx="20"
120
+ cy="20"
121
+ r="14"
122
+ stroke="currentColor"
123
+ strokeWidth="2.2"
124
+ />
125
+ <path
126
+ d="M23.7 15.4c-1-.7-2.2-1-3.6-1-2.2 0-3.8 1.1-3.8 2.8 0 4.2 7.4 1.8 7.4 5.8 0 1.8-1.6 2.8-4 2.8-1.5 0-2.9-.4-4-1.2M20 11.7v2.5m0 11.8v2.4"
127
+ stroke="currentColor"
128
+ strokeWidth="2.2"
129
+ strokeLinecap="round"
130
+ />
131
+ </svg>
132
+ );
133
+ default:
134
+ return (
135
+ <svg
136
+ className={iconClassName}
137
+ viewBox="0 0 40 40"
138
+ fill="none"
139
+ aria-hidden="true"
140
+ >
141
+ <path
142
+ d="M7 11h26v6a3.5 3.5 0 0 0 0 7v6H7v-6a3.5 3.5 0 0 0 0-7v-6Z"
143
+ stroke="currentColor"
144
+ strokeWidth="2.2"
145
+ strokeLinejoin="round"
146
+ />
147
+ <path
148
+ d="M22 12.5v3m0 3v3m0 3v4"
149
+ stroke="currentColor"
150
+ strokeWidth="2.2"
151
+ strokeLinecap="round"
152
+ />
153
+ </svg>
154
+ );
155
+ }
156
+ };
157
+
158
+ const AssuranceIcon = ({ type }) => {
159
+ const iconClassName = "h-[18px] w-[18px] shrink-0 text-white";
160
+
161
+ if (type === "pending") {
162
+ return (
163
+ <svg
164
+ className={iconClassName}
165
+ viewBox="0 0 20 20"
166
+ fill="none"
167
+ aria-hidden="true"
168
+ >
169
+ <path
170
+ d="M4.2 8.2a6.2 6.2 0 1 1 .5 5.1"
171
+ stroke="currentColor"
172
+ strokeWidth="1.8"
173
+ strokeLinecap="round"
174
+ />
175
+ <path
176
+ d="M4.2 4.8v3.4h3.4"
177
+ stroke="currentColor"
178
+ strokeWidth="1.8"
179
+ strokeLinecap="round"
180
+ strokeLinejoin="round"
181
+ />
182
+ </svg>
183
+ );
184
+ }
185
+
186
+ return (
187
+ <svg
188
+ className={iconClassName}
189
+ viewBox="0 0 20 20"
190
+ fill="none"
191
+ aria-hidden="true"
192
+ >
193
+ <path
194
+ d="M10 2.2 16.3 4v5c0 4-2.4 6.8-6.3 8.7C6.1 15.8 3.7 13 3.7 9V4L10 2.2Z"
195
+ stroke="currentColor"
196
+ strokeWidth="1.6"
197
+ strokeLinejoin="round"
198
+ />
199
+ <path
200
+ d="m6.9 9.7 2.1 2.1 4.3-4.4"
201
+ stroke="currentColor"
202
+ strokeWidth="1.7"
203
+ strokeLinecap="round"
204
+ strokeLinejoin="round"
205
+ />
206
+ </svg>
207
+ );
208
+ };
209
+
210
+ const FeatureServiceUi = ({
211
+ serviceItem,
212
+ showTopLabel,
213
+ colors,
214
+ isSoldOut,
215
+ getAnimationIcon,
216
+ cityOrigin,
217
+ cityDestination,
218
+ renderIcon,
219
+ viewersConfig,
220
+ }) => {
221
+ const operators =
222
+ serviceItem?.operators?.length > 0
223
+ ? serviceItem.operators
224
+ : HARDCODED_OPERATORS;
225
+
226
+ return (
227
+ <div
228
+ // ${
229
+ // serviceItem.offer_text ? "mb-[55px]" : "mb-[10px]"
230
+ // }
231
+ className={`relative mb-[10px]
232
+ ${
233
+ serviceItem?.is_direct_trip ||
234
+ serviceItem?.train_type_label === "Tren Express (Nuevo)" ||
235
+ showTopLabel
236
+ ? "mt-[24px]"
237
+ : "mt-[20px]"
238
+ }`}
239
+ >
240
+ <div
241
+ className=""
242
+ style={{
243
+ border: "1px solid #c0c0c0",
244
+ padding: "14px",
245
+ borderRadius: "14px",
246
+ }}
247
+ >
248
+ <div className="flex justify-between items-center px-[14px] pb-[10px] text-[13.33px]">
249
+ <div className="flex items-center gap-[10px]">
250
+ <span>Salida flexible</span>
251
+ <div
252
+ className="bold-text font-[9px]"
253
+ style={{
254
+ backgroundColor: "#FF5C60",
255
+ padding: "1px 8px",
256
+ borderRadius: "4px",
257
+ color: "#fff",
258
+ }}
259
+ >
260
+ <span>AHORRAS 60%</span>
261
+ </div>
262
+ </div>
263
+ <div>
264
+ <span>
265
+ {renderIcon("fireIcon", "14px")}{" "}
266
+ <span className="bold-text">Remate</span> términa en{" "}
267
+ <span
268
+ className="bold-text text-end"
269
+ ref={(node) => commonService.startCountdown(node, 599)}
270
+ style={{
271
+ fontVariantNumeric: "tabular-nums",
272
+ display: "inline-block",
273
+ color: "#FF5C60",
274
+ }}
275
+ />
276
+ </span>
277
+ </div>
278
+ </div>
279
+ <div
280
+ id={`service-card-${serviceItem.id}`}
281
+ className="bg-[#0C1421] text-white mx-auto relative rounded-[14px] p-[14px] text-[13.33px]"
282
+ >
283
+ <div className="grid grid-cols-[1.3fr_2fr_1.2fr] gap-[16px] items-stretch">
284
+ {/* LEFT: origin, destination, flexible, time, confirmed seat */}
285
+ <div className="flex flex-col justify-between gap-[20px] py-[2px] ">
286
+ <div className="flex flex-col gap-[8px]">
287
+ <div className="flex items-center gap-[8px]">
288
+ <img
289
+ src={serviceItem.icons?.whiteOrigin}
290
+ alt="origin"
291
+ className={`w-[14px] h-[14px] shrink-0 ${
292
+ isSoldOut ? "grayscale" : ""
293
+ }`}
294
+ />
295
+ <span className="text-[13px] bold-text">
296
+ {cityOrigin?.label.split(",")[0]}
297
+ </span>
298
+ </div>
299
+ <div className="flex items-center gap-[8px]">
300
+ <img
301
+ src={serviceItem.icons?.whiteDestination}
302
+ alt="destination"
303
+ className={`w-[16px] h-[16px] shrink-0 ${
304
+ isSoldOut ? "grayscale" : ""
305
+ }`}
306
+ style={{ opacity: isSoldOut ? 0.5 : 1 }}
307
+ />
308
+ <span className="text-[13px] bold-text">
309
+ {cityDestination?.label.split(",")[0]}
310
+ </span>
311
+ </div>
312
+ </div>
313
+
314
+ <div className="flex flex-col gap-[8px]">
315
+ {/* Salida flexible badge — uses flexibleIcon */}
316
+ {/* <div
317
+ className="flex items-center gap-[6px] rounded-[8px] px-[8px] py-[4px] w-fit mb-[6px]"
318
+ style={{
319
+ border: "1px solid #363c48",
320
+ backgroundColor: "#1a202e",
321
+ }}
322
+ >
323
+ <img
324
+ src={serviceItem.icons?.busIcon}
325
+ alt="bus"
326
+ style={{ width: "20px", height: "20px" }}
327
+ />
328
+ <span className="text-[12px] whitespace-nowrap">
329
+ Salida flexible
330
+ </span>
331
+ </div> */}
332
+ <div className="text-[12px] bold-text whitespace-nowrap">
333
+ Entre 07:00 AM y 10:00 AM
334
+ </div>
335
+ <div className="text-[11px] bold-text">Viernes 23 de mayo</div>
336
+ </div>
337
+
338
+ <div className="flex flex-col items-start gap-[10px] text-[12px] ">
339
+ <div className="flex items-center gap-[8px]">
340
+ <AssuranceIcon type="pending" />
341
+
342
+ <span
343
+ className="text-[10px]"
344
+ style={{
345
+ lineHeight: 1.3,
346
+ }}
347
+ >
348
+ Empresa y hora a confirmar luego del pago.
349
+ </span>
350
+ </div>
351
+ <div className="flex items-center gap-[8px]">
352
+ <AssuranceIcon type="secured" />
353
+
354
+ <span
355
+ className="text-[10px]"
356
+ style={{
357
+ lineHeight: 1.3,
358
+ }}
359
+ >
360
+ Tu compra está 100% asegurada.
361
+ </span>
362
+ </div>
363
+ </div>
364
+ </div>
365
+
366
+ {/* MIDDLE: competing operators + viewers */}
367
+ <div className="px-[16px] flex flex-col items-center justify-between gap-[12px] py-[2px] border-r border-[#363c48] border-l border-[#363c48]">
368
+ <div className="text-center">
369
+ <div className="bold-text text-[14px]">
370
+ 3 operadores compitiendo por tu compra
371
+ </div>
372
+ {/* <div className="text-[12px] mt-[8px]">
373
+ Empresa a confirmar después de tu pago
374
+ </div> */}
375
+ </div>
376
+
377
+ <div className="flex items-stretch justify-center gap-[8px] w-full mb-[16px]">
378
+ {operators.map((op, idx) => (
379
+ <div
380
+ key={idx}
381
+ className="flex flex-col items-center justify-center gap-[8px] rounded-[8px]"
382
+ style={{
383
+ width: "140px",
384
+ // height: "80px",
385
+ border: "1px solid #363c48",
386
+ backgroundColor: "#1a202e",
387
+ padding: "14px",
388
+ }}
389
+ >
390
+ <img
391
+ src={serviceItem.operator_details[0]}
392
+ alt={op.name}
393
+ className={`h-[24px] w-auto object-contain ${
394
+ isSoldOut ? "grayscale" : ""
395
+ }`}
396
+ />
397
+ <span className="text-[11px] truncate max-w-full text-center">
398
+ {serviceItem.operator_details[2]}
399
+ </span>
400
+ <div className="bg-[#FF8F45] text-white text-[12px] font-bold px-[16px] py-[4px] rounded-[4px] bold-text">
401
+ <span>{op?.time}</span>
402
+ </div>
403
+ <span className="text-[10px] mt-[6px]">
404
+ {op?.seatsAvailable}
405
+ </span>
406
+ </div>
407
+ ))}
408
+ </div>
409
+
410
+ <div
411
+ className="flex items-center justify-center gap-[6px] text-[12px]"
412
+ style={{
413
+ border: "1px solid #363c48",
414
+ backgroundColor: "#1a202e",
415
+ padding: "8px 14px",
416
+ borderRadius: "24px",
417
+ width: "430px",
418
+ }}
419
+ >
420
+ <img
421
+ src={serviceItem.icons?.userIcon}
422
+ alt="eye"
423
+ style={{ width: "16px", height: "16px" }}
424
+ />
425
+ <span>
426
+ <span className="bold-text text-white">
427
+ {" "}
428
+ <span
429
+ className="bold-text"
430
+ ref={(node) =>
431
+ commonService.startViewerCount(node, viewersConfig)
432
+ }
433
+ style={{
434
+ fontVariantNumeric: "tabular-nums",
435
+ color: "#FF5C60",
436
+ }}
437
+ />{" "}
438
+ <span
439
+ style={{
440
+ color: "#FF5C60",
441
+ }}
442
+ >
443
+ personas
444
+ </span>
445
+ </span>{" "}
446
+ viendo este viaje |{" "}
447
+ <span
448
+ className="bold-text"
449
+ ref={(node) =>
450
+ commonService.startComprandoCount(node, 4, 16)
451
+ }
452
+ style={{ fontVariantNumeric: "tabular-nums" }}
453
+ />{" "}
454
+ han comprado
455
+ </span>
456
+ </div>
457
+ </div>
458
+
459
+ {/* RIGHT: price + button */}
460
+ <div className="flex flex-col justify-center gap-[12px] py-[2px] relative mb-[16px]">
461
+ <div
462
+ className="flex flex-col gap-[6px] "
463
+ style={{
464
+ alignItems: "center",
465
+ }}
466
+ >
467
+ <span className="text-[#FF8F45] bold-text text-[26px] leading-tight">
468
+ 60% OFF
469
+ </span>
470
+ <span className="text-[#666] text-[14px] line-through">
471
+ $10.000
472
+ </span>
473
+ <span className="text-white bold-text text-[28px] leading-none">
474
+ $4.000
475
+ </span>
476
+ </div>
477
+
478
+ <button
479
+ className="flex items-center gap-[6px] px-[20px] py-[10px] rounded-[12px] text-white bold-text text-[13px] mt-[4px] justify-center border-none cursor-pointer"
480
+ style={{
481
+ backgroundColor: "#FF5C60",
482
+ }}
483
+ >
484
+ <LottiePlayer
485
+ // animationData={serviceItem.icons.flexibleAnim}
486
+ animationData={getAnimationIcon("thunderAnimation")}
487
+ width="18px"
488
+ height="18px"
489
+ />
490
+ <span className="whitespace-nowrap">¡Lo quiero!</span>
491
+ </button>
492
+ </div>
493
+
494
+ <div className="absolute bottom-[11px] right-[18px]">
495
+ <img
496
+ src={serviceItem.icons?.downArrow}
497
+ alt="down arrow"
498
+ style={{
499
+ width: "14px",
500
+ height: "8px",
501
+ filter: "brightness(0) invert(1)",
502
+ }}
503
+ />
504
+ </div>
505
+ </div>
506
+ </div>
507
+ <div className="px-[16px] pt-[14px] pb-[6px] text-[13.33px]">
508
+ <span className="bold-text">¿Cómo funciona?</span>
509
+
510
+ <div className="mt-[14px] grid grid-cols-4 gap-[20px] px-[16px] ">
511
+ {HOW_IT_WORKS_STEPS.map((step) => (
512
+ <div
513
+ key={step.name}
514
+ className="flex flex-col items-center text-center text-[#272727]"
515
+ >
516
+ <FeatureStepIcon icon={step.icon} />
517
+ <span className="bold-text mt-[10px] text-[12px] leading-[14px]">
518
+ {step.name}
519
+ </span>
520
+ <span className="mt-[2px] max-w-[220px] text-[12px] leading-[14px] text-[#4a4a4a]">
521
+ {step.text}
522
+ </span>
523
+ </div>
524
+ ))}
525
+ </div>
526
+ </div>
527
+ </div>
528
+
529
+ {/* TOP BADGE — "Remate | Termina en 09:55 min" hardcoded, no countdown hook */}
530
+ {/* {showTopLabel && (
531
+ <div className="absolute -top-[11px] left-0 w-full flex items-center justify-end gap-[12px] pr-[15px] z-10 ">
532
+ <div className="flex items-center gap-[6px] py-[5px] px-[14px] rounded-[38px] text-[12.5px] bg-[#FF8F45] text-white whitespace-nowrap">
533
+ <LottiePlayer
534
+ animationData={getAnimationIcon("bombAnimation")}
535
+ width="14px"
536
+ height="14px"
537
+ />
538
+ <span>
539
+ <strong>Remate</strong> | Termina en{" "}
540
+ <strong>{HARDCODED_COUNTDOWN}</strong> min
541
+ </span>
542
+ </div>
543
+ </div>
544
+ )} */}
545
+ </div>
546
+ );
547
+ };
548
+
549
+ export default FeatureServiceUi;
@@ -33,11 +33,7 @@ const StageTooltip = ({
33
33
  terminals?.[arr[i].split("||")[0].split("|")[0]] || "";
34
34
  let time = arr[i].split("||")[0].split("|")[1];
35
35
 
36
- if (direction !== 1 && i > 0) {
37
- // skip logic (same as yours)
38
- } else {
39
- formattedStages.push(`${locationName} ${time}`);
40
- }
36
+ formattedStages.push(`${locationName || terminal} ${time}`);
41
37
  }
42
38
 
43
39
  const extractTiming = (location: string) => {