kupos-ui-components-lib 9.10.9 → 9.11.0

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 (29) hide show
  1. package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
  2. package/dist/components/ServiceItem/ServiceItemDesktop.js +3 -20
  3. package/dist/components/ServiceItem/ServiceItemMobile.d.ts +1 -1
  4. package/dist/components/ServiceItem/ServiceItemMobile.js +1 -1
  5. package/dist/components/ServiceItem/mobileTypes.d.ts +0 -1
  6. package/dist/components/ServiceItem/types.d.ts +0 -7
  7. package/dist/styles.css +10 -6
  8. package/dist/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.d.ts +1 -1
  9. package/dist/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.js +117 -33
  10. package/dist/ui/FeatureServiceUI/FeatureServiceUi.js +112 -36
  11. package/dist/ui/SeatSection/SeatSection.d.ts +1 -7
  12. package/dist/ui/SeatSection/SeatSection.js +20 -41
  13. package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +1 -2
  14. package/dist/ui/mobileweb/DateTimeSectionMobile.js +6 -12
  15. package/dist/ui/mobileweb/SeatSectionMobile.d.ts +1 -2
  16. package/dist/ui/mobileweb/SeatSectionMobile.js +23 -22
  17. package/dist/utils/CommonService.d.ts +9 -1
  18. package/dist/utils/CommonService.js +66 -7
  19. package/package.json +1 -1
  20. package/src/components/ServiceItem/ServiceItemDesktop.tsx +1 -43
  21. package/src/components/ServiceItem/ServiceItemMobile.tsx +1 -2
  22. package/src/components/ServiceItem/mobileTypes.ts +26 -31
  23. package/src/components/ServiceItem/types.ts +0 -12
  24. package/src/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.tsx +151 -70
  25. package/src/ui/FeatureServiceUI/FeatureServiceUi.tsx +132 -50
  26. package/src/ui/SeatSection/SeatSection.tsx +42 -89
  27. package/src/ui/mobileweb/DateTimeSectionMobile.tsx +35 -44
  28. package/src/ui/mobileweb/SeatSectionMobile.tsx +22 -27
  29. package/src/utils/CommonService.ts +84 -11
@@ -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, isTrain, selectedSeatKey, onSeatSelect, onTrainButtonClick, showSeatSelectionError, onShowSeatSelectionError, onClearSeatSelectionError, isFeatureDropDownExpand, setIsFeatureDropDownExpand, ticketQuantity, onIncreaseTicketQuantity, onDecreaseTicketQuantity, onRemateUiButtonClick, selectedTimeSlot, onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData, isFlores, operatorLabel, }: 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, onRemateUiButtonClick, selectedTimeSlot, onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData, isFlores, operatorLabel, }: ServiceItemProps & {
4
4
  currencySign?: string;
5
5
  }): React.ReactElement;
6
6
  export default ServiceItemPB;
@@ -87,12 +87,9 @@ const ANIMATION_MAP = {
87
87
  kupos: flameAnimation,
88
88
  },
89
89
  };
90
- 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, isTrain, selectedSeatKey, onSeatSelect, onTrainButtonClick, showSeatSelectionError, onShowSeatSelectionError, onClearSeatSelectionError, isFeatureDropDownExpand, setIsFeatureDropDownExpand, ticketQuantity, onIncreaseTicketQuantity, onDecreaseTicketQuantity, onRemateUiButtonClick, selectedTimeSlot, onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData, isFlores, operatorLabel, }) {
90
+ 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, onRemateUiButtonClick, selectedTimeSlot, onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData, isFlores, operatorLabel, }) {
91
91
  var _a, _b, _c;
92
- const handleSeatSelect = (key, price, seatKey, apiSeatType) => {
93
- onClearSeatSelectionError === null || onClearSeatSelectionError === void 0 ? void 0 : onClearSeatSelectionError();
94
- onSeatSelect === null || onSeatSelect === void 0 ? void 0 : onSeatSelect(key, price, seatKey, apiSeatType);
95
- };
92
+ console.log("🚀 ~ ServiceItemPB ~ serviceItem:", serviceItem);
96
93
  const getAnimationIcon = (icon) => {
97
94
  var _a;
98
95
  const animation = ANIMATION_MAP[icon];
@@ -231,16 +228,6 @@ function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, child
231
228
  });
232
229
  return;
233
230
  }
234
- if (isTrain) {
235
- if (!selectedSeatKey) {
236
- onShowSeatSelectionError === null || onShowSeatSelectionError === void 0 ? void 0 : onShowSeatSelectionError(serviceItem.id);
237
- return;
238
- }
239
- if (onTrainButtonClick) {
240
- onTrainButtonClick();
241
- return;
242
- }
243
- }
244
231
  onBookButtonPress();
245
232
  };
246
233
  const items = [
@@ -307,13 +294,9 @@ function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, child
307
294
  backgroundColor: "#ccc",
308
295
  } }),
309
296
  React.createElement("div", { className: "content-center" },
310
- React.createElement(SeatSection, { seatTypes: serviceItem.seat_types, serviceItem: serviceItem, availableSeats: serviceItem.available_seats, isSoldOut: isSoldOut, priceColor: colors.priceColor, dpSeatColor: colors.seatPriceColor, currencySign: currencySign, removeDuplicateSeats: removeDuplicateSeats, isPeru: isPeru, renderIcon: renderIcon, discountSeatPriceColor: colors.discountSeatPriceColor, isTrain: isTrain, selectedSeatKey: selectedSeatKey, onSeatSelect: handleSeatSelect, topLabelColor: colors.topLabelColor, tooltipColor: colors.tooltipColor })),
297
+ React.createElement(SeatSection, { seatTypes: serviceItem.seat_types, serviceItem: serviceItem, availableSeats: serviceItem.available_seats, isSoldOut: isSoldOut, priceColor: colors.priceColor, dpSeatColor: colors.seatPriceColor, currencySign: currencySign, removeDuplicateSeats: removeDuplicateSeats, isPeru: isPeru, renderIcon: renderIcon, discountSeatPriceColor: colors.discountSeatPriceColor, tooltipColor: colors.tooltipColor })),
311
298
  React.createElement("div", { className: "relative" },
312
299
  React.createElement(KuposButton, { isSoldOut: isSoldOut, isLoading: serviceDetailsLoading, buttonColor: colors.kuposButtonColor, buyLabel: translation === null || translation === void 0 ? void 0 : translation.buyButton, soldOutLabel: translation === null || translation === void 0 ? void 0 : translation.soldOutButton, soldOutIcon: renderIcon("soldOutIcon", "14px"), onClick: checkMidnight }),
313
- showSeatSelectionError === serviceItem.id && isTrain && (React.createElement("div", { className: "flex justify-center mr-[11px] w-[100%] right-[0px] absolute left-[0] top-[40px]" },
314
- React.createElement("div", { className: "text-[9px] text-center whitespace-nowrap", style: {
315
- color: colors.seatPriceColor,
316
- } }, "Selecciona el tipo de servicio"))),
317
300
  showLastSeats ? (React.createElement("div", { className: "flex justify-center mr-[11px] w-[100%] right-[0px] absolute left-[0] top-[40px]" }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.available_seats) < 10 &&
318
301
  (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.available_seats) > 0 && (React.createElement("div", { className: "text-[12px] mt-1 text-center", style: {
319
302
  color: colors.seatPriceColor,
@@ -1,4 +1,4 @@
1
1
  import React from "react";
2
2
  import { MobileServiceItemProps } from "./mobileTypes";
3
- declare function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, orignLabel, destinationLabel, amenitiesData, setShowDropdown, showDropdown, isExpanded, setIsExpanded, setAmenetiesAtomValue, isCiva, currencySign, isPeru, showRating, showLastSeats, removeDuplicateSeats, isLinatal, viewersConfig, operatorLabel, isTrain, isFeatureDropDownExpand, setIsFeatureDropDownExpand, ticketQuantity, onIncreaseTicketQuantity, onDecreaseTicketQuantity, cityOrigin, cityDestination, isNewUi, onRemateUiButtonClick, selectedTimeSlot, onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData, isFlores, }: MobileServiceItemProps): React.ReactElement;
3
+ declare function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, orignLabel, destinationLabel, amenitiesData, setShowDropdown, showDropdown, isExpanded, setIsExpanded, setAmenetiesAtomValue, isCiva, currencySign, isPeru, showRating, showLastSeats, removeDuplicateSeats, isLinatal, viewersConfig, isFeatureDropDownExpand, setIsFeatureDropDownExpand, ticketQuantity, onIncreaseTicketQuantity, onDecreaseTicketQuantity, cityOrigin, cityDestination, isNewUi, onRemateUiButtonClick, selectedTimeSlot, onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData, isFlores, operatorLabel }: MobileServiceItemProps): React.ReactElement;
4
4
  export default ServiceItemMobile;
@@ -18,7 +18,7 @@ const exceptions = [
18
18
  "blanco",
19
19
  "asiento_mascota",
20
20
  ];
21
- function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, orignLabel, destinationLabel, amenitiesData, setShowDropdown, showDropdown, isExpanded, setIsExpanded, setAmenetiesAtomValue, isCiva, currencySign, isPeru, showRating, showLastSeats, removeDuplicateSeats, isLinatal, viewersConfig, operatorLabel, isTrain, isFeatureDropDownExpand, setIsFeatureDropDownExpand, ticketQuantity, onIncreaseTicketQuantity, onDecreaseTicketQuantity, cityOrigin, cityDestination, isNewUi, onRemateUiButtonClick, selectedTimeSlot, onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData, isFlores, }) {
21
+ function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, orignLabel, destinationLabel, amenitiesData, setShowDropdown, showDropdown, isExpanded, setIsExpanded, setAmenetiesAtomValue, isCiva, currencySign, isPeru, showRating, showLastSeats, removeDuplicateSeats, isLinatal, viewersConfig, isFeatureDropDownExpand, setIsFeatureDropDownExpand, ticketQuantity, onIncreaseTicketQuantity, onDecreaseTicketQuantity, cityOrigin, cityDestination, isNewUi, onRemateUiButtonClick, selectedTimeSlot, onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData, isFlores, operatorLabel }) {
22
22
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
23
23
  const isItemExpanded = serviceItem.id === isExpanded;
24
24
  const isPetSeat = (Object.keys(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.pet_seat_info) || []).length > 0;
@@ -215,7 +215,6 @@ export interface MobileServiceItemProps {
215
215
  label?: string;
216
216
  icon?: string;
217
217
  };
218
- isTrain?: boolean;
219
218
  isFeatureDropDownExpand?: any;
220
219
  setIsFeatureDropDownExpand?: (value: any) => void;
221
220
  ticketQuantity?: number;
@@ -245,13 +245,6 @@ export interface ServiceItemProps {
245
245
  showLoginModal?: any;
246
246
  isLoggedIn?: any;
247
247
  showLoginOption?: boolean;
248
- isTrain?: boolean;
249
- selectedSeatKey?: any;
250
- onSeatSelect?: (key: any, price: number, seatKey: string, apiSeatType?: string) => void;
251
- onTrainButtonClick?: any;
252
- showSeatSelectionError?: string | null;
253
- onShowSeatSelectionError?: (serviceId: string) => void;
254
- onClearSeatSelectionError?: () => void;
255
248
  selectedTimeSlot?: string;
256
249
  onTimeSlotChange?: (slot: string) => void;
257
250
  isTimeDropdownOpen?: string | number | null;
package/dist/styles.css CHANGED
@@ -572,9 +572,6 @@
572
572
  .grid-cols-2 {
573
573
  grid-template-columns: repeat(2, minmax(0, 1fr));
574
574
  }
575
- .grid-cols-3 {
576
- grid-template-columns: repeat(3, minmax(0, 1fr));
577
- }
578
575
  .grid-cols-4 {
579
576
  grid-template-columns: repeat(4, minmax(0, 1fr));
580
577
  }
@@ -854,6 +851,9 @@
854
851
  .bg-\[lightgray\] {
855
852
  background-color: lightgray;
856
853
  }
854
+ .bg-\[white\] {
855
+ background-color: white;
856
+ }
857
857
  .bg-transparent {
858
858
  background-color: transparent;
859
859
  }
@@ -1023,9 +1023,6 @@
1023
1023
  .text-right {
1024
1024
  text-align: right;
1025
1025
  }
1026
- .text-\[9px\] {
1027
- font-size: 9px;
1028
- }
1029
1026
  .text-\[10px\] {
1030
1027
  font-size: 10px;
1031
1028
  }
@@ -1277,6 +1274,13 @@
1277
1274
  }
1278
1275
  }
1279
1276
  }
1277
+ .hover\:z-\[200\] {
1278
+ &:hover {
1279
+ @media (hover: hover) {
1280
+ z-index: 200;
1281
+ }
1282
+ }
1283
+ }
1280
1284
  .hover\:z-\[500\] {
1281
1285
  &:hover {
1282
1286
  @media (hover: hover) {
@@ -14,7 +14,7 @@ declare const FeatureServiceUiMobile: ({ serviceItem, showTopLabel, colors, isSo
14
14
  onIncreaseTicketQuantity: any;
15
15
  onDecreaseTicketQuantity: any;
16
16
  onBookButtonPress: any;
17
- selectedTimeSlot?: string;
17
+ selectedTimeSlot: any;
18
18
  onTimeSlotChange: any;
19
19
  isTimeDropdownOpen: any;
20
20
  onTimeDropdownToggle: any;
@@ -2,12 +2,6 @@ import React from "react";
2
2
  import LottiePlayer from "../../assets/LottiePlayer";
3
3
  import commonService from "../../utils/CommonService";
4
4
  import flameAnimation from "../../assets/images/anims/service_list/flame_anim.json";
5
- const TIME_SLOTS = [
6
- "Entre 07:00 AM y 10:00 AM",
7
- "Entre 11:00 AM y 14:00 AM",
8
- "Entre 15:00 PM y 18:00 PM",
9
- "Entre 19:00 PM y 22:00 PM",
10
- ];
11
5
  const HARDCODED_OPERATORS = [
12
6
  {
13
7
  logo: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Turbus_logo.svg/320px-Turbus_logo.svg.png",
@@ -28,8 +22,8 @@ const HARDCODED_OPERATORS = [
28
22
  seatsAvailable: "3 disponibles",
29
23
  },
30
24
  ];
31
- const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut, cityOrigin, cityDestination, renderIcon, viewersConfig, isFeatureDropDownExpand, onToggleExpand, ticketQuantity = 1, onIncreaseTicketQuantity, onDecreaseTicketQuantity, onBookButtonPress, selectedTimeSlot = TIME_SLOTS[0], onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData = undefined, }) => {
32
- var _a, _b, _c, _d, _e, _f, _g;
25
+ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut, cityOrigin, cityDestination, renderIcon, viewersConfig, isFeatureDropDownExpand, onToggleExpand, ticketQuantity = 1, onIncreaseTicketQuantity, onDecreaseTicketQuantity, onBookButtonPress, selectedTimeSlot, onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData = undefined, }) => {
26
+ var _a, _b, _c, _d, _e, _f;
33
27
  // Use wow_deal data if available, otherwise fall back to serviceItem operators or hardcoded
34
28
  const operators = ((_a = wowDealData === null || wowDealData === void 0 ? void 0 : wowDealData.services) === null || _a === void 0 ? void 0 : _a.length) > 0
35
29
  ? wowDealData.services.slice(0, 3).map((service) => ({
@@ -52,6 +46,7 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
52
46
  const dealWindowFrom = (wowDealData === null || wowDealData === void 0 ? void 0 : wowDealData.deal_window_from) || "07:00";
53
47
  const dealWindowTo = (wowDealData === null || wowDealData === void 0 ? void 0 : wowDealData.deal_window_to) || "10:00";
54
48
  const travelDate = wowDealData === null || wowDealData === void 0 ? void 0 : wowDealData.travel_date;
49
+ const serviceWindowHours = wowDealData === null || wowDealData === void 0 ? void 0 : wowDealData.service_window_hours;
55
50
  // Calculate countdown seconds from expires_at ISO timestamp
56
51
  const getCountdownSeconds = () => {
57
52
  if (!expiresAt)
@@ -61,23 +56,47 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
61
56
  const seconds = Math.max(0, Math.floor((expires - now) / 1000));
62
57
  return seconds;
63
58
  };
64
- // Generate time slot from deal window
65
- const dynamicTimeSlot = `Entre ${dealWindowFrom} y ${dealWindowTo}`;
66
- const displayTimeSlot = selectedTimeSlot || dynamicTimeSlot;
59
+ // Generate dynamic time slots from deal window + service window hours
60
+ const allTimeSlots = serviceWindowHours
61
+ ? commonService.generateTimeSlots(dealWindowFrom, dealWindowTo, serviceWindowHours)
62
+ : [];
63
+ // Filter slots to only those that have at least one service
64
+ const services = (wowDealData === null || wowDealData === void 0 ? void 0 : wowDealData.services) || [];
65
+ const availableTimeSlots = allTimeSlots.filter((slot) => services.some((s) => {
66
+ const depMin = commonService.timeToMinutes(s.departure_time);
67
+ return depMin >= slot.start && depMin < slot.end;
68
+ }));
69
+ // Active slot: the one matching selectedTimeSlot label, or the first available
70
+ const activeSlot = availableTimeSlots.find((s) => s.label === selectedTimeSlot) ||
71
+ availableTimeSlots[0];
72
+ // Services that fall within the active slot, sorted by final price ascending
73
+ const servicesInActiveSlot = activeSlot
74
+ ? services
75
+ .filter((s) => {
76
+ const depMin = commonService.timeToMinutes(s.departure_time);
77
+ return depMin >= activeSlot.start && depMin < activeSlot.end;
78
+ })
79
+ .sort((a, b) => a.final_price - b.final_price)
80
+ : services;
81
+ // The selected price (final and original) from the cheapest service in the active slot
82
+ const selectedSlotService = servicesInActiveSlot === null || servicesInActiveSlot === void 0 ? void 0 : servicesInActiveSlot[0];
83
+ const displayFinalPrice = selectedSlotService
84
+ ? selectedSlotService.final_price
85
+ : finalPrice;
86
+ const displayOriginalPrice = selectedSlotService
87
+ ? selectedSlotService.original_price
88
+ : originalPrice;
89
+ const displaySavingsPercent = selectedSlotService && selectedSlotService.original_price
90
+ ? Math.round(((selectedSlotService.original_price - selectedSlotService.final_price) /
91
+ selectedSlotService.original_price) *
92
+ 100)
93
+ : savingsPercent;
94
+ // The label shown on the dropdown button
95
+ const departureRange = (activeSlot === null || activeSlot === void 0 ? void 0 : activeSlot.label) || `Entre ${dealWindowFrom} y ${dealWindowTo}`;
67
96
  const isItemExpanded = serviceItem.id === isFeatureDropDownExpand ||
68
97
  isFeatureDropDownExpand === true;
69
98
  const isThisTimeDropdownOpen = isTimeDropdownOpen === serviceItem.id;
70
99
  const canDecreaseTicketQuantity = ticketQuantity > 1;
71
- const departures = (_d = (_c = wowDealData === null || wowDealData === void 0 ? void 0 : wowDealData.services) === null || _c === void 0 ? void 0 : _c.map((s) => s.departure_time)) === null || _d === void 0 ? void 0 : _d.filter(Boolean);
72
- let departureRange = `Entre ${dealWindowFrom} y ${dealWindowTo}`;
73
- if (departures === null || departures === void 0 ? void 0 : departures.length) {
74
- const sorted = [...departures].sort((a, b) => {
75
- const [ah, am] = a.split(":").map(Number);
76
- const [bh, bm] = b.split(":").map(Number);
77
- return ah * 60 + am - (bh * 60 + bm);
78
- });
79
- departureRange = `Entre ${sorted[0]} y ${sorted[sorted.length - 1]}`;
80
- }
81
100
  const HOW_IT_WORKS_STEPS = [
82
101
  {
83
102
  icon: "flexible",
@@ -145,28 +164,91 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
145
164
  } },
146
165
  React.createElement("span", null,
147
166
  "AHORRAS ",
148
- savingsPercent,
167
+ displaySavingsPercent,
149
168
  "%")))),
150
169
  React.createElement("div", { id: `service-card-${serviceItem.id}`, className: "bg-[#0C1421] text-white mx-auto relative rounded-[14px] p-[14px] text-[13.33px]" },
151
170
  React.createElement("div", { className: "flex flex-col gap-[10px]" },
152
171
  React.createElement("div", { className: " text-[white]" },
153
172
  React.createElement("div", { className: "flex flex-col gap-[10px] relative" },
154
173
  React.createElement("div", { className: "flex items-center gap-[6px]" },
155
- React.createElement("img", { src: (_e = serviceItem.icons) === null || _e === void 0 ? void 0 : _e.whiteOrigin, alt: "origin", className: `w-[13px] h-[13px] shrink-0 ${isSoldOut ? "grayscale" : ""}` }),
174
+ React.createElement("img", { src: (_c = serviceItem.icons) === null || _c === void 0 ? void 0 : _c.whiteOrigin, alt: "origin", className: `w-[13px] h-[13px] shrink-0 ${isSoldOut ? "grayscale" : ""}` }),
156
175
  React.createElement("span", { className: "text-[14px] bold-text" }, cityOrigin === null || cityOrigin === void 0 ? void 0 : cityOrigin.label.split(",")[0]),
157
176
  React.createElement("span", { className: "mx-[6px] text-[14px] bold-text" }, "\u2192"),
158
- React.createElement("img", { src: (_f = serviceItem.icons) === null || _f === void 0 ? void 0 : _f.whiteDestination, alt: "destination", className: `w-[13px] h-[13px] shrink-0 ${isSoldOut ? "grayscale" : ""}`, style: { opacity: isSoldOut ? 0.5 : 1 } }),
177
+ React.createElement("img", { src: (_d = serviceItem.icons) === null || _d === void 0 ? void 0 : _d.whiteDestination, alt: "destination", className: `w-[13px] h-[13px] shrink-0 ${isSoldOut ? "grayscale" : ""}`, style: { opacity: isSoldOut ? 0.5 : 1 } }),
159
178
  React.createElement("span", { className: "text-[14px] bold-text" }, cityDestination === null || cityDestination === void 0 ? void 0 : cityDestination.label.split(",")[0])),
160
179
  React.createElement("div", { className: "flex items-center gap-[6px]" },
161
- React.createElement("div", { className: "bold-text text-[12px] text-white" }, departureRange)))),
180
+ React.createElement("div", { className: "kupos-time-dd relative", tabIndex: 0, onBlur: (e) => {
181
+ if (!e.currentTarget.contains(e.relatedTarget)) {
182
+ onTimeDropdownToggle === null || onTimeDropdownToggle === void 0 ? void 0 : onTimeDropdownToggle(null);
183
+ }
184
+ }, style: { outline: "none" } },
185
+ React.createElement("button", { type: "button", onClick: () => onTimeDropdownToggle === null || onTimeDropdownToggle === void 0 ? void 0 : onTimeDropdownToggle(isThisTimeDropdownOpen ? null : serviceItem.id), className: "flex cursor-pointer select-none items-center gap-[6px] border-none bg-transparent p-0 bold-text text-[13px] text-[white]" },
186
+ React.createElement("span", null, departureRange),
187
+ React.createElement("img", { src: (_e = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _e === void 0 ? void 0 : _e.downArrow, alt: "down arrow", className: `kupos-time-chevron transition-transform duration-200 ${isThisTimeDropdownOpen ? "rotate-180" : "rotate-0"}`, style: {
188
+ width: "12px",
189
+ height: "8px",
190
+ filter: "brightness(0) invert(1)",
191
+ } })),
192
+ isThisTimeDropdownOpen && (React.createElement(React.Fragment, null,
193
+ React.createElement("div", { className: "absolute left-0 top-[calc(100%+10px)]", style: {
194
+ zIndex: 20,
195
+ backgroundColor: "#fff",
196
+ borderRadius: "14px",
197
+ minWidth: "190px",
198
+ boxShadow: "0 8px 32px rgba(0,0,0,0.28)",
199
+ overflow: "hidden",
200
+ padding: "6px 0",
201
+ } }, availableTimeSlots.map((slot) => {
202
+ const isActive = slot.label === selectedTimeSlot ||
203
+ slot === activeSlot;
204
+ // Count services in this slot
205
+ const count = services.filter((s) => {
206
+ const depMin = commonService.timeToMinutes(s.departure_time);
207
+ return depMin >= slot.start && depMin < slot.end;
208
+ }).length;
209
+ return (React.createElement("button", { key: slot.label, type: "button", onClick: () => {
210
+ onTimeSlotChange === null || onTimeSlotChange === void 0 ? void 0 : onTimeSlotChange(slot.label);
211
+ onTimeDropdownToggle === null || onTimeDropdownToggle === void 0 ? void 0 : onTimeDropdownToggle(null);
212
+ // const slotServices = services.filter((s) => {
213
+ // const depMin = commonService.timeToMinutes(
214
+ // s.departure_time,
215
+ // );
216
+ // return (
217
+ // depMin >= slot.start && depMin < slot.end
218
+ // );
219
+ // });
220
+ // console.log(
221
+ // "Selected slot label:",
222
+ // slot.label,
223
+ // );
224
+ // console.log(
225
+ // "Services in selected slot:",
226
+ // slotServices,
227
+ // );
228
+ }, className: `flex w-full cursor-pointer items-center justify-between gap-[10px] border-none px-[12px] py-[9px] text-left text-[13px] ${isActive ? "bg-[#FF5C60] font-bold text-[white]" : "bg-transparent font-normal text-[#1a1a1a]"}` },
229
+ React.createElement("span", null, slot.label),
230
+ count > 0 && (React.createElement("span", { className: `text-[11px] rounded-full px-[6px] py-[2px] font-bold ${isActive
231
+ ? "bg-[white] text-[#FF5C60]"
232
+ : "bg-[#FF5C60] text-[white]"}` }, count))));
233
+ })))))))),
162
234
  React.createElement("div", { className: "border-t border-[#363c48] my-[8px]" }),
163
235
  React.createElement("div", null,
164
236
  React.createElement("span", { className: "block w-full text-[14px] bold-text text-[white] mb-[10px]", style: { textAlign: "center" } },
165
- operatorsCompetingCount,
166
- " operadores compitiendo ",
237
+ servicesInActiveSlot.length > 0
238
+ ? servicesInActiveSlot.length
239
+ : operatorsCompetingCount,
240
+ " ",
241
+ "operadores compitiendo ",
167
242
  React.createElement("br", null),
168
243
  "por tu compra"),
169
- React.createElement("div", { className: "flex gap-[8px] text-[white]", style: { width: "100%" } }, 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: {
244
+ React.createElement("div", { className: "flex gap-[8px] text-[white]", style: { width: "100%" } }, (servicesInActiveSlot.length > 0
245
+ ? servicesInActiveSlot.slice(0, 3).map((s) => ({
246
+ logo: s.operator_logo_url,
247
+ name: s.operator_name,
248
+ time: s.departure_time,
249
+ seatsAvailable: `${s.available_seats} disponibles`,
250
+ }))
251
+ : 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: {
170
252
  flex: 1,
171
253
  minWidth: 0,
172
254
  height: "100px",
@@ -176,7 +258,9 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
176
258
  } },
177
259
  React.createElement("img", { src: op.logo, alt: op.name, onError: (e) => {
178
260
  var _a;
179
- e.currentTarget.src = ((_a = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_details) === null || _a === void 0 ? void 0 : _a[0]) || "/images/service-list/bus-icon.svg";
261
+ e.currentTarget.src =
262
+ ((_a = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_details) === null || _a === void 0 ? void 0 : _a[0]) ||
263
+ "/images/service-list/bus-icon.svg";
180
264
  }, className: `h-[24px] max-w-full object-contain ${isSoldOut ? "grayscale" : ""}` }),
181
265
  React.createElement("span", { className: "text-[12px] truncate max-w-full text-center " }, op.name),
182
266
  React.createElement("span", { className: "text-[11px] whitespace-nowrap" }, op === null || op === void 0 ? void 0 : op.seatsAvailable))))),
@@ -220,7 +304,7 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
220
304
  } },
221
305
  React.createElement("div", { className: "flex flex-col" },
222
306
  React.createElement("span", { className: "text-[18px] font-normal leading-[20px] text-[#9f9f9f] relative", style: { position: "relative" } },
223
- `$${((originalPrice * ticketQuantity)).toLocaleString()}`,
307
+ `$${(displayOriginalPrice * ticketQuantity).toLocaleString()}`,
224
308
  React.createElement("span", { style: {
225
309
  position: "absolute",
226
310
  left: "-2px",
@@ -231,12 +315,12 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
231
315
  transform: "rotate(-10deg)",
232
316
  transformOrigin: "center",
233
317
  } })),
234
- React.createElement("span", { className: "text-[white] bold-text text-[24px] leading-none mt-[4px]" }, `$${(finalPrice * ticketQuantity).toLocaleString()}`)),
318
+ React.createElement("span", { className: "text-[white] bold-text text-[24px] leading-none mt-[4px]" }, `$${(displayFinalPrice * ticketQuantity).toLocaleString()}`)),
235
319
  React.createElement("span", { className: "text-[#FF8F45] bold-text text-[22px] leading-tight", style: {
236
320
  animation: "pulse-zoom 2s ease-in-out infinite",
237
321
  whiteSpace: "nowrap",
238
322
  } },
239
- savingsPercent,
323
+ displaySavingsPercent,
240
324
  "% OFF")),
241
325
  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-[10px] justify-center border-none cursor-pointer", style: {
242
326
  backgroundColor: "#FF5C60",
@@ -246,7 +330,7 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
246
330
  React.createElement(LottiePlayer, { animationData: serviceItem.icons.thunderAnim, width: "16px", height: "16px" }),
247
331
  React.createElement("span", { className: "whitespace-nowrap" }, "\u00A1Lo quiero!")),
248
332
  React.createElement("div", { className: "flex justify-end mt-[10px]", onClick: onToggleExpand },
249
- React.createElement("img", { src: (_g = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _g === void 0 ? void 0 : _g.downArrow, alt: "down arrow", className: `transition-transform duration-300 ease-in-out ${isItemExpanded ? "rotate-180" : ""}`, style: {
333
+ React.createElement("img", { src: (_f = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _f === void 0 ? void 0 : _f.downArrow, alt: "down arrow", className: `transition-transform duration-300 ease-in-out ${isItemExpanded ? "rotate-180" : ""}`, style: {
250
334
  width: "14px",
251
335
  height: "8px",
252
336
  filter: "brightness(0) invert(1)",