kupos-ui-components-lib 9.7.0 → 9.7.1

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.
@@ -15,6 +15,9 @@ interface KuposUIComponentProps {
15
15
  orignLabel?: string;
16
16
  destinationLabel?: string;
17
17
  t?: (key: string) => string;
18
+ ticketQuantity?: number;
19
+ onIncreaseTicketQuantity?: (serviceItem: any) => void;
20
+ onDecreaseTicketQuantity?: (serviceItem: any) => void;
18
21
  id?: string;
19
22
  name?: string;
20
23
  description?: string;
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { ServiceItemProps } from "./types";
3
- declare function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, children, busStage, serviceDetailsLoading, cityOrigin, cityDestination, translation, orignLabel, destinationLabel, currencySign, isCiva, showRating, showLastSeats, removeArrivalTime, removeDuplicateSeats, isPeruSites, showAvailableSeats, isSeatIcon, isLinatal, isPeru, t, siteType, isAllinBus, isExpand, setIsExpand, coachKey, viewersConfig, isNewUi, showLoginModal, isLoggedIn, showLoginOption, }: ServiceItemProps & {
3
+ declare function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, children, busStage, serviceDetailsLoading, cityOrigin, cityDestination, translation, orignLabel, destinationLabel, currencySign, isCiva, showRating, showLastSeats, removeArrivalTime, removeDuplicateSeats, isPeruSites, showAvailableSeats, isSeatIcon, isLinatal, isPeru, t, siteType, isAllinBus, isExpand, setIsExpand, coachKey, viewersConfig, isNewUi, showLoginModal, isLoggedIn, showLoginOption, isFeatureDropDownExpand, setIsFeatureDropDownExpand, ticketQuantity, onIncreaseTicketQuantity, onDecreaseTicketQuantity, }: ServiceItemProps & {
4
4
  currencySign?: string;
5
5
  }): React.ReactElement;
6
6
  export default ServiceItemPB;
@@ -79,7 +79,7 @@ const ANIMATION_MAP = {
79
79
  kupos: femaleAnimation,
80
80
  },
81
81
  };
82
- function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, children, busStage, serviceDetailsLoading, cityOrigin, cityDestination, translation, orignLabel, destinationLabel, currencySign, isCiva, showRating, showLastSeats, removeArrivalTime, removeDuplicateSeats, isPeruSites, showAvailableSeats, isSeatIcon, isLinatal, isPeru, t = (key) => key, siteType, isAllinBus, isExpand, setIsExpand, coachKey, viewersConfig, isNewUi, showLoginModal, isLoggedIn, showLoginOption, }) {
82
+ function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, children, busStage, serviceDetailsLoading, cityOrigin, cityDestination, translation, orignLabel, destinationLabel, currencySign, isCiva, showRating, showLastSeats, removeArrivalTime, removeDuplicateSeats, isPeruSites, showAvailableSeats, isSeatIcon, isLinatal, isPeru, t = (key) => key, siteType, isAllinBus, isExpand, setIsExpand, coachKey, viewersConfig, isNewUi, showLoginModal, isLoggedIn, showLoginOption, isFeatureDropDownExpand, setIsFeatureDropDownExpand, ticketQuantity, onIncreaseTicketQuantity, onDecreaseTicketQuantity, }) {
83
83
  var _a;
84
84
  const getAnimationIcon = (icon) => {
85
85
  var _a;
@@ -248,7 +248,11 @@ function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, child
248
248
  },
249
249
  ];
250
250
  const otherItems = items.filter((i) => i.key !== "pet" && i.key !== "flexible" && !!i.condition);
251
- return (React.createElement(React.Fragment, null, isPeruSites ? (React.createElement(PeruServiceItemDesktop, { serviceItem: serviceItem, onBookButtonPress: onBookButtonPress, colors: colors, metaData: metaData, children: children, busStage: busStage, serviceDetailsLoading: serviceDetailsLoading, cityOrigin: cityOrigin, cityDestination: cityDestination, translation: translation, orignLabel: orignLabel, destinationLabel: destinationLabel, currencySign: currencySign, isCiva: isCiva, showRating: showRating, showLastSeats: showLastSeats, removeArrivalTime: removeArrivalTime, removeDuplicateSeats: removeDuplicateSeats, isPeruSites: isPeruSites, t: (key) => t(key), showAvailableSeats: showAvailableSeats, isSeatIcon: isSeatIcon, isPeru: isPeru, siteType: siteType, isAllinBus: isAllinBus })) : isNewUi ? (React.createElement(FeatureServiceUi, { serviceItem: serviceItem, showTopLabel: showTopLabel, colors: colors, isSoldOut: isSoldOut, getAnimationIcon: getAnimationIcon, cityOrigin: cityOrigin, cityDestination: cityDestination, renderIcon: renderIcon, viewersConfig: viewersConfig })) : (React.createElement("div", { className: `relative hover:z-[150] ${hasOfferText || hasDpEnabled ? "mb-[55px]" : "mb-[10px]"} ${(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_direct_trip) ||
251
+ return (React.createElement(React.Fragment, null, isPeruSites ? (React.createElement(PeruServiceItemDesktop, { serviceItem: serviceItem, onBookButtonPress: onBookButtonPress, colors: colors, metaData: metaData, children: children, busStage: busStage, serviceDetailsLoading: serviceDetailsLoading, cityOrigin: cityOrigin, cityDestination: cityDestination, translation: translation, orignLabel: orignLabel, destinationLabel: destinationLabel, currencySign: currencySign, isCiva: isCiva, showRating: showRating, showLastSeats: showLastSeats, removeArrivalTime: removeArrivalTime, removeDuplicateSeats: removeDuplicateSeats, isPeruSites: isPeruSites, t: (key) => t(key), showAvailableSeats: showAvailableSeats, isSeatIcon: isSeatIcon, isPeru: isPeru, siteType: siteType, isAllinBus: isAllinBus })) : isNewUi ? (React.createElement(FeatureServiceUi, { serviceItem: serviceItem, showTopLabel: showTopLabel, colors: colors, isSoldOut: isSoldOut, getAnimationIcon: getAnimationIcon, cityOrigin: cityOrigin, cityDestination: cityDestination, renderIcon: renderIcon, viewersConfig: viewersConfig, isFeatureDropDownExpand: isFeatureDropDownExpand, ticketQuantity: ticketQuantity, onIncreaseTicketQuantity: onIncreaseTicketQuantity, onDecreaseTicketQuantity: onDecreaseTicketQuantity, onBookButtonPress: onBookButtonPress, onToggleExpand: () => setIsFeatureDropDownExpand &&
252
+ setIsFeatureDropDownExpand(isFeatureDropDownExpand === serviceItem.id ||
253
+ isFeatureDropDownExpand === true
254
+ ? null
255
+ : serviceItem.id) })) : (React.createElement("div", { className: `relative hover:z-[150] ${hasOfferText || hasDpEnabled ? "mb-[55px]" : "mb-[10px]"} ${(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_direct_trip) ||
252
256
  (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.train_type_label) === "Tren Express (Nuevo)" ||
253
257
  showTopLabel
254
258
  ? "mt-[24px]"
@@ -219,6 +219,11 @@ export interface ServiceItemProps {
219
219
  isAllinBus?: boolean;
220
220
  isExpand?: any;
221
221
  setIsExpand?: (value: any) => void;
222
+ isFeatureDropDownExpand?: any;
223
+ setIsFeatureDropDownExpand?: (value: any) => void;
224
+ ticketQuantity?: number;
225
+ onIncreaseTicketQuantity?: (serviceItem: ServiceItemProps["serviceItem"]) => void;
226
+ onDecreaseTicketQuantity?: (serviceItem: ServiceItemProps["serviceItem"]) => void;
222
227
  coachKey?: number;
223
228
  viewersConfig?: {
224
229
  min: number;
package/dist/styles.css CHANGED
@@ -177,6 +177,9 @@
177
177
  .mx-auto {
178
178
  margin-inline: auto;
179
179
  }
180
+ .my-\[14px\] {
181
+ margin-block: 14px;
182
+ }
180
183
  .-mt-\[15px\] {
181
184
  margin-top: calc(15px * -1);
182
185
  }
@@ -249,9 +252,6 @@
249
252
  .mb-\[5px\] {
250
253
  margin-bottom: 5px;
251
254
  }
252
- .mb-\[6px\] {
253
- margin-bottom: 6px;
254
- }
255
255
  .mb-\[8px\] {
256
256
  margin-bottom: 8px;
257
257
  }
@@ -357,6 +357,9 @@
357
357
  .h-\[30px\] {
358
358
  height: 30px;
359
359
  }
360
+ .h-\[34px\] {
361
+ height: 34px;
362
+ }
360
363
  .h-\[100\%\] {
361
364
  height: 100%;
362
365
  }
@@ -396,6 +399,9 @@
396
399
  .w-\[30px\] {
397
400
  width: 30px;
398
401
  }
402
+ .w-\[34px\] {
403
+ width: 34px;
404
+ }
399
405
  .w-\[50\%\] {
400
406
  width: 50%;
401
407
  }
@@ -500,6 +506,9 @@
500
506
  .cursor-default {
501
507
  cursor: default;
502
508
  }
509
+ .cursor-not-allowed {
510
+ cursor: not-allowed;
511
+ }
503
512
  .cursor-pointer {
504
513
  cursor: pointer;
505
514
  }
@@ -512,18 +521,21 @@
512
521
  .grid-cols-2 {
513
522
  grid-template-columns: repeat(2, minmax(0, 1fr));
514
523
  }
524
+ .grid-cols-3 {
525
+ grid-template-columns: repeat(3, minmax(0, 1fr));
526
+ }
515
527
  .grid-cols-4 {
516
528
  grid-template-columns: repeat(4, minmax(0, 1fr));
517
529
  }
518
530
  .grid-cols-\[0\.8fr_auto_26\%_1fr\] {
519
531
  grid-template-columns: 0.8fr auto 26% 1fr;
520
532
  }
521
- .grid-cols-\[1\.3fr_2fr_1\.2fr\] {
522
- grid-template-columns: 1.3fr 2fr 1.2fr;
523
- }
524
533
  .grid-cols-\[1\.5fr_1fr_auto\] {
525
534
  grid-template-columns: 1.5fr 1fr auto;
526
535
  }
536
+ .grid-cols-\[23\%_50\%_27\%\] {
537
+ grid-template-columns: 23% 50% 27%;
538
+ }
527
539
  .grid-cols-\[26px_auto_26\%_1fr\] {
528
540
  grid-template-columns: 26px auto 26% 1fr;
529
541
  }
@@ -630,15 +642,15 @@
630
642
  .rounded-\[10px\] {
631
643
  border-radius: 10px;
632
644
  }
633
- .rounded-\[12px\] {
634
- border-radius: 12px;
635
- }
636
645
  .rounded-\[14px\] {
637
646
  border-radius: 14px;
638
647
  }
639
648
  .rounded-\[15px\] {
640
649
  border-radius: 15px;
641
650
  }
651
+ .rounded-\[16px\] {
652
+ border-radius: 16px;
653
+ }
642
654
  .rounded-\[18px\] {
643
655
  border-radius: 18px;
644
656
  }
@@ -758,6 +770,12 @@
758
770
  .bg-\[\#0C1421\] {
759
771
  background-color: #0C1421;
760
772
  }
773
+ .bg-\[\#2d374d\] {
774
+ background-color: #2d374d;
775
+ }
776
+ .bg-\[\#222b3d\] {
777
+ background-color: #222b3d;
778
+ }
761
779
  .bg-\[\#E6E6E6\] {
762
780
  background-color: #E6E6E6;
763
781
  }
@@ -846,6 +864,9 @@
846
864
  .px-\[20px\] {
847
865
  padding-inline: 20px;
848
866
  }
867
+ .px-\[22px\] {
868
+ padding-inline: 22px;
869
+ }
849
870
  .py-\[2px\] {
850
871
  padding-block: 2px;
851
872
  }
@@ -894,6 +915,9 @@
894
915
  .pt-\[50px\] {
895
916
  padding-top: 50px;
896
917
  }
918
+ .pr-\[10px\] {
919
+ padding-right: 10px;
920
+ }
897
921
  .pr-\[15px\] {
898
922
  padding-right: 15px;
899
923
  }
@@ -924,6 +948,9 @@
924
948
  .pl-\[6px\] {
925
949
  padding-left: 6px;
926
950
  }
951
+ .pl-\[22px\] {
952
+ padding-left: 22px;
953
+ }
927
954
  .text-center {
928
955
  text-align: center;
929
956
  }
@@ -969,9 +996,15 @@
969
996
  .text-\[18px\] {
970
997
  font-size: 18px;
971
998
  }
999
+ .text-\[20px\] {
1000
+ font-size: 20px;
1001
+ }
972
1002
  .text-\[22px\] {
973
1003
  font-size: 22px;
974
1004
  }
1005
+ .text-\[25px\] {
1006
+ font-size: 25px;
1007
+ }
975
1008
  .text-\[26px\] {
976
1009
  font-size: 26px;
977
1010
  }
@@ -1092,6 +1125,9 @@
1092
1125
  .opacity-0 {
1093
1126
  opacity: 0%;
1094
1127
  }
1128
+ .opacity-50 {
1129
+ opacity: 50%;
1130
+ }
1095
1131
  .opacity-100 {
1096
1132
  opacity: 100%;
1097
1133
  }
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- declare const FeatureServiceUi: ({ serviceItem, showTopLabel, colors, isSoldOut, getAnimationIcon, cityOrigin, cityDestination, renderIcon, viewersConfig, }: {
2
+ declare const FeatureServiceUi: ({ serviceItem, showTopLabel, colors, isSoldOut, getAnimationIcon, cityOrigin, cityDestination, renderIcon, viewersConfig, isFeatureDropDownExpand, onToggleExpand, ticketQuantity, onIncreaseTicketQuantity, onDecreaseTicketQuantity, onBookButtonPress, }: {
3
3
  serviceItem: any;
4
4
  showTopLabel: any;
5
5
  colors: any;
@@ -9,5 +9,11 @@ declare const FeatureServiceUi: ({ serviceItem, showTopLabel, colors, isSoldOut,
9
9
  cityDestination: any;
10
10
  renderIcon: any;
11
11
  viewersConfig: any;
12
+ isFeatureDropDownExpand: any;
13
+ onToggleExpand: any;
14
+ ticketQuantity?: number;
15
+ onIncreaseTicketQuantity: any;
16
+ onDecreaseTicketQuantity: any;
17
+ onBookButtonPress: any;
12
18
  }) => React.JSX.Element;
13
19
  export default FeatureServiceUi;
@@ -77,11 +77,14 @@ const AssuranceIcon = ({ type }) => {
77
77
  React.createElement("path", { 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", stroke: "currentColor", strokeWidth: "1.6", strokeLinejoin: "round" }),
78
78
  React.createElement("path", { d: "m6.9 9.7 2.1 2.1 4.3-4.4", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round" })));
79
79
  };
80
- const FeatureServiceUi = ({ serviceItem, showTopLabel, colors, isSoldOut, getAnimationIcon, cityOrigin, cityDestination, renderIcon, viewersConfig, }) => {
80
+ const FeatureServiceUi = ({ serviceItem, showTopLabel, colors, isSoldOut, getAnimationIcon, cityOrigin, cityDestination, renderIcon, viewersConfig, isFeatureDropDownExpand, onToggleExpand, ticketQuantity = 1, onIncreaseTicketQuantity, onDecreaseTicketQuantity, onBookButtonPress, }) => {
81
81
  var _a, _b, _c, _d, _e;
82
82
  const operators = ((_a = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operators) === null || _a === void 0 ? void 0 : _a.length) > 0
83
83
  ? serviceItem.operators
84
84
  : HARDCODED_OPERATORS;
85
+ const isItemExpanded = serviceItem.id === isFeatureDropDownExpand ||
86
+ isFeatureDropDownExpand === true;
87
+ const canDecreaseTicketQuantity = ticketQuantity > 1;
85
88
  return (React.createElement("div", {
86
89
  // ${
87
90
  // serviceItem.offer_text ? "mb-[55px]" : "mb-[10px]"
@@ -118,52 +121,51 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, colors, isSoldOut, getAni
118
121
  fontVariantNumeric: "tabular-nums",
119
122
  display: "inline-block",
120
123
  color: "#FF5C60",
124
+ minWidth: "40px",
121
125
  } })))),
122
126
  React.createElement("div", { id: `service-card-${serviceItem.id}`, className: "bg-[#0C1421] text-white mx-auto relative rounded-[14px] p-[14px] text-[13.33px]" },
123
- React.createElement("div", { className: "grid grid-cols-[1.3fr_2fr_1.2fr] gap-[16px] items-stretch" },
124
- React.createElement("div", { className: "flex flex-col justify-between gap-[20px] py-[2px] " },
127
+ React.createElement("div", { className: "grid grid-cols-[23%_50%_27%] items-stretch" },
128
+ React.createElement("div", { className: "flex flex-col justify-between gap-[20px] my-[14px] pr-[22px]" },
125
129
  React.createElement("div", { className: "flex flex-col gap-[8px]" },
126
130
  React.createElement("div", { className: "flex items-center gap-[8px]" },
127
131
  React.createElement("img", { src: (_b = serviceItem.icons) === null || _b === void 0 ? void 0 : _b.whiteOrigin, alt: "origin", className: `w-[14px] h-[14px] shrink-0 ${isSoldOut ? "grayscale" : ""}` }),
128
132
  React.createElement("span", { className: "text-[13px] bold-text" }, cityOrigin === null || cityOrigin === void 0 ? void 0 : cityOrigin.label.split(",")[0])),
129
133
  React.createElement("div", { className: "flex items-center gap-[8px]" },
130
- React.createElement("img", { src: (_c = serviceItem.icons) === null || _c === void 0 ? void 0 : _c.whiteDestination, alt: "destination", className: `w-[16px] h-[16px] shrink-0 ${isSoldOut ? "grayscale" : ""}`, style: { opacity: isSoldOut ? 0.5 : 1 } }),
134
+ React.createElement("img", { src: (_c = serviceItem.icons) === null || _c === void 0 ? void 0 : _c.whiteDestination, alt: "destination", className: `w-[14px] h-[14px] shrink-0 ${isSoldOut ? "grayscale" : ""}`, style: { opacity: isSoldOut ? 0.5 : 1 } }),
131
135
  React.createElement("span", { className: "text-[13px] bold-text" }, cityDestination === null || cityDestination === void 0 ? void 0 : cityDestination.label.split(",")[0]))),
132
136
  React.createElement("div", { className: "flex flex-col gap-[8px]" },
133
137
  React.createElement("div", { className: "text-[12px] bold-text whitespace-nowrap" }, "Entre 07:00 AM y 10:00 AM"),
134
138
  React.createElement("div", { className: "text-[11px] bold-text" }, "Viernes 23 de mayo")),
135
139
  React.createElement("div", { className: "flex flex-col items-start gap-[10px] text-[12px] " },
136
- React.createElement("div", { className: "flex items-center gap-[8px]" },
140
+ React.createElement("div", { className: "flex items-justify gap-[8px]" },
137
141
  React.createElement(AssuranceIcon, { type: "pending" }),
138
142
  React.createElement("span", { className: "text-[10px]", style: {
139
143
  lineHeight: 1.3,
140
144
  } }, "Empresa y hora a confirmar luego del pago.")),
141
- React.createElement("div", { className: "flex items-center gap-[8px]" },
145
+ React.createElement("div", { className: "flex items-justify gap-[8px]" },
142
146
  React.createElement(AssuranceIcon, { type: "secured" }),
143
147
  React.createElement("span", { className: "text-[10px]", style: {
144
148
  lineHeight: 1.3,
145
149
  } }, "Tu compra est\u00E1 100% asegurada.")))),
146
- React.createElement("div", { className: "px-[16px] flex flex-col items-center justify-between gap-[12px] py-[2px] border-r border-[#363c48] border-l border-[#363c48]" },
150
+ React.createElement("div", { className: "min-w-0 px-[22px] flex flex-col items-center justify-between gap-[16px] py-[2px] border-r border-[#363c48] border-l border-[#363c48]" },
147
151
  React.createElement("div", { className: "text-center" },
148
152
  React.createElement("div", { className: "bold-text text-[14px]" }, "3 operadores compitiendo por tu compra")),
149
- React.createElement("div", { className: "flex items-stretch justify-center gap-[8px] w-full mb-[16px]" }, operators.map((op, idx) => (React.createElement("div", { key: idx, className: "flex flex-col items-center justify-center gap-[8px] rounded-[8px]", style: {
150
- width: "140px",
153
+ React.createElement("div", { className: "grid w-full grid-cols-3 items-stretch gap-[14px] mb-[12px]" }, operators.map((op, idx) => (React.createElement("div", { key: idx, className: "flex min-w-0 flex-col items-center justify-center gap-[8px] rounded-[8px]", style: {
151
154
  // height: "80px",
152
155
  border: "1px solid #363c48",
153
156
  backgroundColor: "#1a202e",
154
- padding: "14px",
157
+ padding: "14px 10px",
155
158
  } },
156
- React.createElement("img", { src: serviceItem.operator_details[0], alt: op.name, className: `h-[24px] w-auto object-contain ${isSoldOut ? "grayscale" : ""}` }),
159
+ React.createElement("img", { src: serviceItem.operator_details[0], alt: op.name, className: `h-[24px] max-w-full object-contain ${isSoldOut ? "grayscale" : ""}` }),
157
160
  React.createElement("span", { className: "text-[11px] truncate max-w-full text-center" }, serviceItem.operator_details[2]),
158
- React.createElement("div", { className: "bg-[#FF8F45] text-white text-[12px] font-bold px-[16px] py-[4px] rounded-[4px] bold-text" },
161
+ React.createElement("div", { className: "bg-[#FF8F45] text-white text-[12px] font-bold px-[10px] py-[4px] rounded-[4px] bold-text whitespace-nowrap" },
159
162
  React.createElement("span", null, op === null || op === void 0 ? void 0 : op.time)),
160
163
  React.createElement("span", { className: "text-[10px] mt-[6px]" }, op === null || op === void 0 ? void 0 : op.seatsAvailable))))),
161
- React.createElement("div", { className: "flex items-center justify-center gap-[6px] text-[12px]", style: {
164
+ React.createElement("div", { className: "flex w-full items-center justify-center gap-[6px] text-[12px]", style: {
162
165
  border: "1px solid #363c48",
163
166
  backgroundColor: "#1a202e",
164
167
  padding: "8px 14px",
165
168
  borderRadius: "24px",
166
- width: "430px",
167
169
  } },
168
170
  React.createElement("img", { src: (_d = serviceItem.icons) === null || _d === void 0 ? void 0 : _d.userIcon, alt: "eye", style: { width: "16px", height: "16px" } }),
169
171
  React.createElement("span", null,
@@ -183,14 +185,38 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, colors, isSoldOut, getAni
183
185
  React.createElement("span", { className: "bold-text", ref: (node) => commonService.startComprandoCount(node, 4, 16), style: { fontVariantNumeric: "tabular-nums" } }),
184
186
  " ",
185
187
  "han comprado"))),
186
- React.createElement("div", { className: "flex flex-col justify-center gap-[12px] py-[2px] relative mb-[16px]" },
188
+ React.createElement("div", { className: "flex flex-col justify-center gap-[12px] py-[2px] pl-[22px] pr-[10px] relative mb-[16px]" },
187
189
  React.createElement("div", { className: "flex flex-col gap-[6px] ", style: {
188
190
  alignItems: "center",
189
191
  } },
190
192
  React.createElement("span", { className: "text-[#FF8F45] bold-text text-[26px] leading-tight" }, "60% OFF"),
191
- React.createElement("span", { className: "text-[#666] text-[14px] line-through" }, "$10.000"),
193
+ React.createElement("span", { className: "text-[13.33px] font-normal leading-[20px] text-[#9f9f9f] relative", style: { position: "relative" } },
194
+ "$10.000",
195
+ React.createElement("span", { style: {
196
+ position: "absolute",
197
+ left: "-2px",
198
+ top: "50%",
199
+ width: "calc(100% + 4px)",
200
+ height: "1px",
201
+ backgroundColor: "#FF5C60",
202
+ transform: "rotate(-10deg)",
203
+ transformOrigin: "center",
204
+ } })),
192
205
  React.createElement("span", { className: "text-white bold-text text-[28px] leading-none" }, "$4.000")),
193
- React.createElement("button", { 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", style: {
206
+ React.createElement("div", { className: "mt-[4px] flex flex-col items-center gap-[8px]" },
207
+ React.createElement("span", { className: "text-[12px] text-white" }, "\u00BFCu\u00E1ntos pasajes quieres?"),
208
+ React.createElement("div", { className: "flex w-full items-center justify-between", style: {
209
+ border: "1px solid #363c48",
210
+ backgroundColor: "#1a202e",
211
+ padding: "6px 14px",
212
+ borderRadius: "14px",
213
+ } },
214
+ React.createElement("button", { type: "button", "aria-label": "Disminuir pasajes", disabled: !canDecreaseTicketQuantity, onClick: () => onDecreaseTicketQuantity === null || onDecreaseTicketQuantity === void 0 ? void 0 : onDecreaseTicketQuantity(serviceItem), className: `flex h-[34px] w-[34px] items-center justify-center rounded-full border-none text-[25px] leading-none text-white ${canDecreaseTicketQuantity
215
+ ? "cursor-pointer bg-[#2d374d]"
216
+ : "cursor-not-allowed bg-[#222b3d] opacity-50"}` }, "-"),
217
+ React.createElement("span", { className: "bold-text text-[20px] text-white" }, ticketQuantity),
218
+ React.createElement("button", { type: "button", "aria-label": "Aumentar pasajes", onClick: () => onIncreaseTicketQuantity === null || onIncreaseTicketQuantity === void 0 ? void 0 : onIncreaseTicketQuantity(serviceItem), className: "flex h-[34px] w-[34px] cursor-pointer items-center justify-center rounded-full border-none bg-[#2d374d] text-[25px] leading-none text-white" }, "+"))),
219
+ React.createElement("button", { type: "button", onClick: onBookButtonPress, className: "flex items-center gap-[6px] px-[20px] py-[10px] rounded-[16px] text-white bold-text text-[13px] mt-[4px] justify-center border-none cursor-pointer", style: {
194
220
  backgroundColor: "#FF5C60",
195
221
  } },
196
222
  React.createElement(LottiePlayer
@@ -199,17 +225,22 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, colors, isSoldOut, getAni
199
225
  // animationData={serviceItem.icons.flexibleAnim}
200
226
  animationData: getAnimationIcon("thunderAnimation"), width: "18px", height: "18px" }),
201
227
  React.createElement("span", { className: "whitespace-nowrap" }, "\u00A1Lo quiero!"))),
202
- React.createElement("div", { className: "absolute bottom-[11px] right-[18px]" },
228
+ React.createElement("div", { className: `absolute bottom-[11px] right-[18px] cursor-pointer transition-transform duration-300 ease-in-out ${isItemExpanded ? "rotate-180" : ""}`, onClick: onToggleExpand },
203
229
  React.createElement("img", { src: (_e = serviceItem.icons) === null || _e === void 0 ? void 0 : _e.downArrow, alt: "down arrow", style: {
204
230
  width: "14px",
205
231
  height: "8px",
206
232
  filter: "brightness(0) invert(1)",
207
233
  } })))),
208
- React.createElement("div", { className: "px-[16px] pt-[14px] pb-[6px] text-[13.33px]" },
209
- React.createElement("span", { className: "bold-text" }, "\u00BFC\u00F3mo funciona?"),
210
- React.createElement("div", { className: "mt-[14px] grid grid-cols-4 gap-[20px] px-[16px] " }, HOW_IT_WORKS_STEPS.map((step) => (React.createElement("div", { key: step.name, className: "flex flex-col items-center text-center text-[#272727]" },
211
- React.createElement(FeatureStepIcon, { icon: step.icon }),
212
- React.createElement("span", { className: "bold-text mt-[10px] text-[12px] leading-[14px]" }, step.name),
213
- React.createElement("span", { className: "mt-[2px] max-w-[220px] text-[12px] leading-[14px] text-[#4a4a4a]" }, step.text)))))))));
234
+ React.createElement("div", { className: "grid", style: {
235
+ gridTemplateRows: isItemExpanded ? "1fr" : "0fr",
236
+ opacity: isItemExpanded ? 1 : 0,
237
+ transition: "grid-template-rows 300ms ease-in-out, opacity 250ms ease-in-out",
238
+ } },
239
+ React.createElement("div", { className: `min-h-0 overflow-hidden px-[16px] text-[13.33px] ${isItemExpanded ? "pt-[14px] pb-[6px]" : "py-0"}`, style: { transition: "padding 300ms ease-in-out" } },
240
+ React.createElement("span", { className: "bold-text" }, "\u00BFC\u00F3mo funciona?"),
241
+ React.createElement("div", { className: "mt-[14px] grid grid-cols-4 gap-[20px] px-[16px] " }, HOW_IT_WORKS_STEPS.map((step) => (React.createElement("div", { key: step.name, className: "flex flex-col items-center text-center text-[#272727]" },
242
+ React.createElement(FeatureStepIcon, { icon: step.icon }),
243
+ React.createElement("span", { className: "bold-text mt-[10px] text-[12px] leading-[14px]" }, step.name),
244
+ React.createElement("span", { className: "mt-[2px] max-w-[220px] text-[12px] leading-[14px] text-[#4a4a4a]" }, step.text))))))))));
214
245
  };
215
246
  export default FeatureServiceUi;
@@ -296,10 +296,14 @@ const commonService = {
296
296
  startViewerCount: (node, viewersConfig) => {
297
297
  if (!node || !viewersConfig)
298
298
  return;
299
+ const { min, max, interval = 5000 } = viewersConfig;
300
+ const configKey = `${min}-${max}-${interval}`;
301
+ if (node.dataset.viewerId && node.dataset.viewerConfig === configKey) {
302
+ return;
303
+ }
299
304
  const prevId = node.dataset.viewerId;
300
305
  if (prevId)
301
306
  clearInterval(Number(prevId));
302
- const { min, max, interval = 5000 } = viewersConfig;
303
307
  const clamp = (v) => Math.min(max, Math.max(min, v));
304
308
  const initialValue = Math.floor(Math.random() * (max - min + 1)) + min;
305
309
  node.textContent = String(initialValue);
@@ -310,6 +314,7 @@ const commonService = {
310
314
  node.textContent = String(clamp(Math.round(next)));
311
315
  }, interval);
312
316
  node.dataset.viewerId = String(id);
317
+ node.dataset.viewerConfig = configKey;
313
318
  },
314
319
  startCountdown: (node, countdownSeconds = 599) => {
315
320
  if (!node)
@@ -339,6 +344,10 @@ const commonService = {
339
344
  startComprandoCount: (node, min = 4, max = 16) => {
340
345
  if (!node)
341
346
  return;
347
+ const configKey = `${min}-${max}`;
348
+ if (node.dataset.comprandoId && node.dataset.comprandoConfig === configKey) {
349
+ return;
350
+ }
342
351
  const prevId = node.dataset.comprandoId;
343
352
  if (prevId)
344
353
  clearInterval(Number(prevId));
@@ -355,6 +364,7 @@ const commonService = {
355
364
  node.textContent = String(next);
356
365
  }, 5000); // Update every 5 seconds
357
366
  node.dataset.comprandoId = String(id);
367
+ node.dataset.comprandoConfig = configKey;
358
368
  },
359
369
  };
360
370
  export default commonService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kupos-ui-components-lib",
3
- "version": "9.7.0",
3
+ "version": "9.7.1",
4
4
  "description": "A reusable UI components package",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -32,6 +32,9 @@ interface KuposUIComponentProps {
32
32
  orignLabel?: string;
33
33
  destinationLabel?: string;
34
34
  t?: (key: string) => string;
35
+ ticketQuantity?: number;
36
+ onIncreaseTicketQuantity?: (serviceItem: any) => void;
37
+ onDecreaseTicketQuantity?: (serviceItem: any) => void;
35
38
 
36
39
  // New ServiceItem props
37
40
  id?: string;
@@ -123,6 +123,11 @@ function ServiceItemPB({
123
123
  showLoginModal,
124
124
  isLoggedIn,
125
125
  showLoginOption,
126
+ isFeatureDropDownExpand,
127
+ setIsFeatureDropDownExpand,
128
+ ticketQuantity,
129
+ onIncreaseTicketQuantity,
130
+ onDecreaseTicketQuantity,
126
131
  }: ServiceItemProps & { currencySign?: string }): React.ReactElement {
127
132
  const getAnimationIcon = (icon: string) => {
128
133
  const animation = ANIMATION_MAP[icon];
@@ -433,6 +438,20 @@ function ServiceItemPB({
433
438
  cityDestination={cityDestination}
434
439
  renderIcon={renderIcon}
435
440
  viewersConfig={viewersConfig}
441
+ isFeatureDropDownExpand={isFeatureDropDownExpand}
442
+ ticketQuantity={ticketQuantity}
443
+ onIncreaseTicketQuantity={onIncreaseTicketQuantity}
444
+ onDecreaseTicketQuantity={onDecreaseTicketQuantity}
445
+ onBookButtonPress={onBookButtonPress}
446
+ onToggleExpand={() =>
447
+ setIsFeatureDropDownExpand &&
448
+ setIsFeatureDropDownExpand(
449
+ isFeatureDropDownExpand === serviceItem.id ||
450
+ isFeatureDropDownExpand === true
451
+ ? null
452
+ : serviceItem.id,
453
+ )
454
+ }
436
455
  />
437
456
  ) : (
438
457
  <div
@@ -222,6 +222,11 @@ export interface ServiceItemProps {
222
222
  isAllinBus?: boolean;
223
223
  isExpand?: any;
224
224
  setIsExpand?: (value: any) => void;
225
+ isFeatureDropDownExpand?: any;
226
+ setIsFeatureDropDownExpand?: (value: any) => void;
227
+ ticketQuantity?: number;
228
+ onIncreaseTicketQuantity?: (serviceItem: ServiceItemProps["serviceItem"]) => void;
229
+ onDecreaseTicketQuantity?: (serviceItem: ServiceItemProps["serviceItem"]) => void;
225
230
  coachKey?: number
226
231
  viewersConfig?: {
227
232
  min: number;
@@ -217,12 +217,23 @@ const FeatureServiceUi = ({
217
217
  cityDestination,
218
218
  renderIcon,
219
219
  viewersConfig,
220
+ isFeatureDropDownExpand,
221
+ onToggleExpand,
222
+ ticketQuantity = 1,
223
+ onIncreaseTicketQuantity,
224
+ onDecreaseTicketQuantity,
225
+ onBookButtonPress,
220
226
  }) => {
221
227
  const operators =
222
228
  serviceItem?.operators?.length > 0
223
229
  ? serviceItem.operators
224
230
  : HARDCODED_OPERATORS;
225
231
 
232
+ const isItemExpanded =
233
+ serviceItem.id === isFeatureDropDownExpand ||
234
+ isFeatureDropDownExpand === true;
235
+ const canDecreaseTicketQuantity = ticketQuantity > 1;
236
+
226
237
  return (
227
238
  <div
228
239
  // ${
@@ -271,6 +282,7 @@ const FeatureServiceUi = ({
271
282
  fontVariantNumeric: "tabular-nums",
272
283
  display: "inline-block",
273
284
  color: "#FF5C60",
285
+ minWidth: "40px",
274
286
  }}
275
287
  />
276
288
  </span>
@@ -280,9 +292,9 @@ const FeatureServiceUi = ({
280
292
  id={`service-card-${serviceItem.id}`}
281
293
  className="bg-[#0C1421] text-white mx-auto relative rounded-[14px] p-[14px] text-[13.33px]"
282
294
  >
283
- <div className="grid grid-cols-[1.3fr_2fr_1.2fr] gap-[16px] items-stretch">
295
+ <div className="grid grid-cols-[23%_50%_27%] items-stretch">
284
296
  {/* LEFT: origin, destination, flexible, time, confirmed seat */}
285
- <div className="flex flex-col justify-between gap-[20px] py-[2px] ">
297
+ <div className="flex flex-col justify-between gap-[20px] my-[14px] pr-[22px]">
286
298
  <div className="flex flex-col gap-[8px]">
287
299
  <div className="flex items-center gap-[8px]">
288
300
  <img
@@ -300,7 +312,7 @@ const FeatureServiceUi = ({
300
312
  <img
301
313
  src={serviceItem.icons?.whiteDestination}
302
314
  alt="destination"
303
- className={`w-[16px] h-[16px] shrink-0 ${
315
+ className={`w-[14px] h-[14px] shrink-0 ${
304
316
  isSoldOut ? "grayscale" : ""
305
317
  }`}
306
318
  style={{ opacity: isSoldOut ? 0.5 : 1 }}
@@ -312,23 +324,6 @@ const FeatureServiceUi = ({
312
324
  </div>
313
325
 
314
326
  <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
327
  <div className="text-[12px] bold-text whitespace-nowrap">
333
328
  Entre 07:00 AM y 10:00 AM
334
329
  </div>
@@ -336,7 +331,7 @@ const FeatureServiceUi = ({
336
331
  </div>
337
332
 
338
333
  <div className="flex flex-col items-start gap-[10px] text-[12px] ">
339
- <div className="flex items-center gap-[8px]">
334
+ <div className="flex items-justify gap-[8px]">
340
335
  <AssuranceIcon type="pending" />
341
336
 
342
337
  <span
@@ -348,7 +343,7 @@ const FeatureServiceUi = ({
348
343
  Empresa y hora a confirmar luego del pago.
349
344
  </span>
350
345
  </div>
351
- <div className="flex items-center gap-[8px]">
346
+ <div className="flex items-justify gap-[8px]">
352
347
  <AssuranceIcon type="secured" />
353
348
 
354
349
  <span
@@ -364,7 +359,7 @@ const FeatureServiceUi = ({
364
359
  </div>
365
360
 
366
361
  {/* 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]">
362
+ <div className="min-w-0 px-[22px] flex flex-col items-center justify-between gap-[16px] py-[2px] border-r border-[#363c48] border-l border-[#363c48]">
368
363
  <div className="text-center">
369
364
  <div className="bold-text text-[14px]">
370
365
  3 operadores compitiendo por tu compra
@@ -374,30 +369,29 @@ const FeatureServiceUi = ({
374
369
  </div> */}
375
370
  </div>
376
371
 
377
- <div className="flex items-stretch justify-center gap-[8px] w-full mb-[16px]">
372
+ <div className="grid w-full grid-cols-3 items-stretch gap-[14px] mb-[12px]">
378
373
  {operators.map((op, idx) => (
379
374
  <div
380
375
  key={idx}
381
- className="flex flex-col items-center justify-center gap-[8px] rounded-[8px]"
376
+ className="flex min-w-0 flex-col items-center justify-center gap-[8px] rounded-[8px]"
382
377
  style={{
383
- width: "140px",
384
378
  // height: "80px",
385
379
  border: "1px solid #363c48",
386
380
  backgroundColor: "#1a202e",
387
- padding: "14px",
381
+ padding: "14px 10px",
388
382
  }}
389
383
  >
390
384
  <img
391
385
  src={serviceItem.operator_details[0]}
392
386
  alt={op.name}
393
- className={`h-[24px] w-auto object-contain ${
387
+ className={`h-[24px] max-w-full object-contain ${
394
388
  isSoldOut ? "grayscale" : ""
395
389
  }`}
396
390
  />
397
391
  <span className="text-[11px] truncate max-w-full text-center">
398
392
  {serviceItem.operator_details[2]}
399
393
  </span>
400
- <div className="bg-[#FF8F45] text-white text-[12px] font-bold px-[16px] py-[4px] rounded-[4px] bold-text">
394
+ <div className="bg-[#FF8F45] text-white text-[12px] font-bold px-[10px] py-[4px] rounded-[4px] bold-text whitespace-nowrap">
401
395
  <span>{op?.time}</span>
402
396
  </div>
403
397
  <span className="text-[10px] mt-[6px]">
@@ -408,13 +402,12 @@ const FeatureServiceUi = ({
408
402
  </div>
409
403
 
410
404
  <div
411
- className="flex items-center justify-center gap-[6px] text-[12px]"
405
+ className="flex w-full items-center justify-center gap-[6px] text-[12px]"
412
406
  style={{
413
407
  border: "1px solid #363c48",
414
408
  backgroundColor: "#1a202e",
415
409
  padding: "8px 14px",
416
410
  borderRadius: "24px",
417
- width: "430px",
418
411
  }}
419
412
  >
420
413
  <img
@@ -457,7 +450,7 @@ const FeatureServiceUi = ({
457
450
  </div>
458
451
 
459
452
  {/* RIGHT: price + button */}
460
- <div className="flex flex-col justify-center gap-[12px] py-[2px] relative mb-[16px]">
453
+ <div className="flex flex-col justify-center gap-[12px] py-[2px] pl-[22px] pr-[10px] relative mb-[16px]">
461
454
  <div
462
455
  className="flex flex-col gap-[6px] "
463
456
  style={{
@@ -467,16 +460,78 @@ const FeatureServiceUi = ({
467
460
  <span className="text-[#FF8F45] bold-text text-[26px] leading-tight">
468
461
  60% OFF
469
462
  </span>
470
- <span className="text-[#666] text-[14px] line-through">
463
+ {/* <span className="text-[#666] text-[14px] line-through">
464
+ $10.000
465
+ </span> */}
466
+ <span
467
+ className="text-[13.33px] font-normal leading-[20px] text-[#9f9f9f] relative"
468
+ style={{ position: "relative" }}
469
+ >
471
470
  $10.000
471
+ <span
472
+ style={{
473
+ position: "absolute",
474
+ left: "-2px",
475
+ top: "50%",
476
+ width: "calc(100% + 4px)",
477
+ height: "1px",
478
+
479
+ backgroundColor: "#FF5C60",
480
+
481
+ transform: "rotate(-10deg)",
482
+ transformOrigin: "center",
483
+ }}
484
+ />
472
485
  </span>
473
486
  <span className="text-white bold-text text-[28px] leading-none">
474
487
  $4.000
475
488
  </span>
476
489
  </div>
477
490
 
491
+ <div className="mt-[4px] flex flex-col items-center gap-[8px]">
492
+ <span className="text-[12px] text-white">
493
+ ¿Cuántos pasajes quieres?
494
+ </span>
495
+ <div
496
+ className="flex w-full items-center justify-between"
497
+ style={{
498
+ border: "1px solid #363c48",
499
+ backgroundColor: "#1a202e",
500
+ padding: "6px 14px",
501
+ borderRadius: "14px",
502
+ }}
503
+ >
504
+ <button
505
+ type="button"
506
+ aria-label="Disminuir pasajes"
507
+ disabled={!canDecreaseTicketQuantity}
508
+ onClick={() => onDecreaseTicketQuantity?.(serviceItem)}
509
+ className={`flex h-[34px] w-[34px] items-center justify-center rounded-full border-none text-[25px] leading-none text-white ${
510
+ canDecreaseTicketQuantity
511
+ ? "cursor-pointer bg-[#2d374d]"
512
+ : "cursor-not-allowed bg-[#222b3d] opacity-50"
513
+ }`}
514
+ >
515
+ -
516
+ </button>
517
+ <span className="bold-text text-[20px] text-white">
518
+ {ticketQuantity}
519
+ </span>
520
+ <button
521
+ type="button"
522
+ aria-label="Aumentar pasajes"
523
+ onClick={() => onIncreaseTicketQuantity?.(serviceItem)}
524
+ className="flex h-[34px] w-[34px] cursor-pointer items-center justify-center rounded-full border-none bg-[#2d374d] text-[25px] leading-none text-white"
525
+ >
526
+ +
527
+ </button>
528
+ </div>
529
+ </div>
530
+
478
531
  <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"
532
+ type="button"
533
+ onClick={onBookButtonPress}
534
+ className="flex items-center gap-[6px] px-[20px] py-[10px] rounded-[16px] text-white bold-text text-[13px] mt-[4px] justify-center border-none cursor-pointer"
480
535
  style={{
481
536
  backgroundColor: "#FF5C60",
482
537
  }}
@@ -491,7 +546,10 @@ const FeatureServiceUi = ({
491
546
  </button>
492
547
  </div>
493
548
 
494
- <div className="absolute bottom-[11px] right-[18px]">
549
+ <div
550
+ className={`absolute bottom-[11px] right-[18px] cursor-pointer transition-transform duration-300 ease-in-out ${isItemExpanded ? "rotate-180" : ""}`}
551
+ onClick={onToggleExpand}
552
+ >
495
553
  <img
496
554
  src={serviceItem.icons?.downArrow}
497
555
  alt="down arrow"
@@ -504,24 +562,39 @@ const FeatureServiceUi = ({
504
562
  </div>
505
563
  </div>
506
564
  </div>
507
- <div className="px-[16px] pt-[14px] pb-[6px] text-[13.33px]">
508
- <span className="bold-text">¿Cómo funciona?</span>
565
+ <div
566
+ className="grid"
567
+ style={{
568
+ gridTemplateRows: isItemExpanded ? "1fr" : "0fr",
569
+ opacity: isItemExpanded ? 1 : 0,
570
+ transition:
571
+ "grid-template-rows 300ms ease-in-out, opacity 250ms ease-in-out",
572
+ }}
573
+ >
574
+ <div
575
+ className={`min-h-0 overflow-hidden px-[16px] text-[13.33px] ${
576
+ isItemExpanded ? "pt-[14px] pb-[6px]" : "py-0"
577
+ }`}
578
+ style={{ transition: "padding 300ms ease-in-out" }}
579
+ >
580
+ <span className="bold-text">¿Cómo funciona?</span>
509
581
 
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
- ))}
582
+ <div className="mt-[14px] grid grid-cols-4 gap-[20px] px-[16px] ">
583
+ {HOW_IT_WORKS_STEPS.map((step) => (
584
+ <div
585
+ key={step.name}
586
+ className="flex flex-col items-center text-center text-[#272727]"
587
+ >
588
+ <FeatureStepIcon icon={step.icon} />
589
+ <span className="bold-text mt-[10px] text-[12px] leading-[14px]">
590
+ {step.name}
591
+ </span>
592
+ <span className="mt-[2px] max-w-[220px] text-[12px] leading-[14px] text-[#4a4a4a]">
593
+ {step.text}
594
+ </span>
595
+ </div>
596
+ ))}
597
+ </div>
525
598
  </div>
526
599
  </div>
527
600
  </div>
@@ -329,10 +329,15 @@ const commonService = {
329
329
  ) => {
330
330
  if (!node || !viewersConfig) return;
331
331
 
332
+ const { min, max, interval = 5000 } = viewersConfig;
333
+ const configKey = `${min}-${max}-${interval}`;
334
+ if (node.dataset.viewerId && node.dataset.viewerConfig === configKey) {
335
+ return;
336
+ }
337
+
332
338
  const prevId = node.dataset.viewerId;
333
339
  if (prevId) clearInterval(Number(prevId));
334
340
 
335
- const { min, max, interval = 5000 } = viewersConfig;
336
341
  const clamp = (v: number) => Math.min(max, Math.max(min, v));
337
342
  const initialValue = Math.floor(Math.random() * (max - min + 1)) + min;
338
343
 
@@ -347,6 +352,7 @@ const commonService = {
347
352
  }, interval);
348
353
 
349
354
  node.dataset.viewerId = String(id);
355
+ node.dataset.viewerConfig = configKey;
350
356
  },
351
357
 
352
358
  startCountdown: (
@@ -388,6 +394,11 @@ const commonService = {
388
394
  ) => {
389
395
  if (!node) return;
390
396
 
397
+ const configKey = `${min}-${max}`;
398
+ if (node.dataset.comprandoId && node.dataset.comprandoConfig === configKey) {
399
+ return;
400
+ }
401
+
391
402
  const prevId = node.dataset.comprandoId;
392
403
  if (prevId) clearInterval(Number(prevId));
393
404
 
@@ -408,6 +419,7 @@ const commonService = {
408
419
  }, 5000); // Update every 5 seconds
409
420
 
410
421
  node.dataset.comprandoId = String(id);
422
+ node.dataset.comprandoConfig = configKey;
411
423
  },
412
424
  };
413
425