kupos-ui-components-lib 9.8.7 → 9.8.9

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.
@@ -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, showLoginModal, isLoggedIn, showLoginOption, 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, showLoginModal, isLoggedIn, showLoginOption, isTrain, selectedSeatKey, onSeatSelect, onTrainButtonClick, showSeatSelectionError, onShowSeatSelectionError, onClearSeatSelectionError, isFlores, operatorLabel, }: ServiceItemProps & {
4
4
  currencySign?: string;
5
5
  }): React.ReactElement;
6
6
  export default ServiceItemPB;
@@ -74,8 +74,12 @@ const ANIMATION_MAP = {
74
74
  kupos: femaleAnimation,
75
75
  },
76
76
  };
77
- 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, showLoginModal, isLoggedIn, showLoginOption, isFlores, operatorLabel, }) {
77
+ 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, showLoginModal, isLoggedIn, showLoginOption, isTrain, selectedSeatKey, onSeatSelect, onTrainButtonClick, showSeatSelectionError, onShowSeatSelectionError, onClearSeatSelectionError, isFlores, operatorLabel, }) {
78
78
  var _a;
79
+ const handleSeatSelect = (key, price, seatKey, apiSeatType) => {
80
+ onClearSeatSelectionError === null || onClearSeatSelectionError === void 0 ? void 0 : onClearSeatSelectionError();
81
+ onSeatSelect === null || onSeatSelect === void 0 ? void 0 : onSeatSelect(key, price, seatKey, apiSeatType);
82
+ };
79
83
  const getAnimationIcon = (icon) => {
80
84
  var _a;
81
85
  const animation = ANIMATION_MAP[icon];
@@ -213,6 +217,16 @@ function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, child
213
217
  });
214
218
  return;
215
219
  }
220
+ if (isTrain) {
221
+ if (!selectedSeatKey) {
222
+ onShowSeatSelectionError === null || onShowSeatSelectionError === void 0 ? void 0 : onShowSeatSelectionError(serviceItem.id);
223
+ return;
224
+ }
225
+ if (onTrainButtonClick) {
226
+ onTrainButtonClick();
227
+ return;
228
+ }
229
+ }
216
230
  onBookButtonPress();
217
231
  };
218
232
  const items = [
@@ -275,9 +289,13 @@ function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, child
275
289
  backgroundColor: "#ccc",
276
290
  } }),
277
291
  React.createElement("div", { className: "content-center" },
278
- 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 })),
292
+ 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 })),
279
293
  React.createElement("div", { className: "relative" },
280
294
  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 }),
295
+ showSeatSelectionError === serviceItem.id && isTrain && (React.createElement("div", { className: "flex justify-center mr-[11px] w-[100%] right-[0px] absolute left-[0] top-[40px]" },
296
+ React.createElement("div", { className: "text-[9px] text-center whitespace-nowrap", style: {
297
+ color: colors.seatPriceColor,
298
+ } }, "Selecciona el tipo de servicio"))),
281
299
  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 &&
282
300
  (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.available_seats) > 0 && (React.createElement("div", { className: "text-[12px] mt-1 text-center", style: {
283
301
  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, }: 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, operatorLabel, }: MobileServiceItemProps): React.ReactElement;
4
4
  export default ServiceItemMobile;
@@ -17,7 +17,7 @@ const exceptions = [
17
17
  "blanco",
18
18
  "asiento_mascota",
19
19
  ];
20
- function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, orignLabel, destinationLabel, amenitiesData, setShowDropdown, showDropdown, isExpanded, setIsExpanded, setAmenetiesAtomValue, isCiva, currencySign, isPeru, showRating, showLastSeats, removeDuplicateSeats, isLinatal, viewersConfig, }) {
20
+ function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, orignLabel, destinationLabel, amenitiesData, setShowDropdown, showDropdown, isExpanded, setIsExpanded, setAmenetiesAtomValue, isCiva, currencySign, isPeru, showRating, showLastSeats, removeDuplicateSeats, isLinatal, viewersConfig, operatorLabel, }) {
21
21
  var _a, _b, _c, _d, _e, _f, _g;
22
22
  const isItemExpanded = serviceItem.id === isExpanded;
23
23
  const isPetSeat = (Object.keys(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.pet_seat_info) || []).length > 0;
@@ -180,6 +180,6 @@ function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, o
180
180
  zIndex: (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) ? -3 : undefined,
181
181
  marginTop: (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) ? "-15px" : "-10px",
182
182
  } },
183
- React.createElement(ExpandedDropdownMobile, { serviceItem: serviceItem, isPeru: isPeru, petSeatInfo: serviceItem.pet_seat_info, petFriendlyAnim: serviceItem.icons.petFriendlyAnim, isSoldOut: isSoldOut, isChangeTicket: serviceItem.is_change_ticket === true, ladiesBookedSeats: serviceItem.ladies_booked_seats, isDpEnabled: serviceItem.is_dp_enabled, femaleAnim: serviceItem.icons.femaleAnim, flexibleAnim: serviceItem.icons.flexibleAnim, renderIcon: renderIcon })))));
183
+ React.createElement(ExpandedDropdownMobile, { serviceItem: serviceItem, isPeru: isPeru, petSeatInfo: serviceItem.pet_seat_info, petFriendlyAnim: serviceItem.icons.petFriendlyAnim, isSoldOut: isSoldOut, isChangeTicket: serviceItem.is_change_ticket === true, ladiesBookedSeats: serviceItem.ladies_booked_seats, isDpEnabled: serviceItem.is_dp_enabled, femaleAnim: serviceItem.icons.femaleAnim, flexibleAnim: serviceItem.icons.flexibleAnim, renderIcon: renderIcon, operatorLabel: operatorLabel })))));
184
184
  }
185
185
  export default ServiceItemMobile;
@@ -187,4 +187,5 @@ export interface MobileServiceItemProps {
187
187
  label?: string;
188
188
  icon?: string;
189
189
  };
190
+ operatorLabel?: string;
190
191
  }
@@ -224,6 +224,13 @@ export interface ServiceItemProps {
224
224
  showLoginModal?: any;
225
225
  isLoggedIn?: any;
226
226
  showLoginOption?: boolean;
227
+ isTrain?: boolean;
228
+ selectedSeatKey?: any;
229
+ onSeatSelect?: (key: any, price: number, seatKey: string, apiSeatType?: string) => void;
230
+ onTrainButtonClick?: any;
231
+ showSeatSelectionError?: string | null;
232
+ onShowSeatSelectionError?: (serviceId: string) => void;
233
+ onClearSeatSelectionError?: () => void;
227
234
  isFlores?: boolean;
228
235
  operatorLabel?: string;
229
236
  }
package/dist/styles.css CHANGED
@@ -863,6 +863,9 @@
863
863
  .text-right {
864
864
  text-align: right;
865
865
  }
866
+ .text-\[9px\] {
867
+ font-size: 9px;
868
+ }
866
869
  .text-\[10px\] {
867
870
  font-size: 10px;
868
871
  }
@@ -3,6 +3,8 @@ interface SeatType {
3
3
  label: string;
4
4
  fare: number;
5
5
  key: any;
6
+ apiSeatType?: string;
7
+ api_seat_type?: string;
6
8
  }
7
9
  interface SeatSectionProps {
8
10
  seatTypes: SeatType[];
@@ -16,6 +18,10 @@ interface SeatSectionProps {
16
18
  serviceItem?: any;
17
19
  renderIcon?: (iconKey: string, size?: string) => React.ReactNode;
18
20
  discountSeatPriceColor?: string;
21
+ isTrain?: boolean;
22
+ selectedSeatKey?: any;
23
+ onSeatSelect?: (key: any, price: number, seatKey: string, apiSeatType?: string) => void;
24
+ topLabelColor?: string;
19
25
  }
20
- declare function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, }: SeatSectionProps): React.ReactElement;
26
+ declare function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, selectedSeatKey, onSeatSelect, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, isTrain, topLabelColor, }: SeatSectionProps): React.ReactElement;
21
27
  export default SeatSection;
@@ -8,11 +8,13 @@ function getAllSeatTypes(seatTypes) {
8
8
  let seatTypesWithPrices = seatTypes.filter(Boolean).map((val) => ({
9
9
  label: val === null || val === void 0 ? void 0 : val.label,
10
10
  price: val === null || val === void 0 ? void 0 : val.fare,
11
+ key: val === null || val === void 0 ? void 0 : val.key,
12
+ apiSeatType: (val === null || val === void 0 ? void 0 : val.apiSeatType) || (val === null || val === void 0 ? void 0 : val.api_seat_type),
11
13
  }));
12
14
  seatTypesWithPrices.sort((a, b) => a.price - b.price);
13
15
  return seatTypesWithPrices;
14
16
  }
15
- function getSortedSeatTypes(seatTypes) {
17
+ function getSortedSeatTypes(seatTypes, isTrain) {
16
18
  if (!(seatTypes === null || seatTypes === void 0 ? void 0 : seatTypes.length)) {
17
19
  return [{ label: "Salon cama", price: 0 }];
18
20
  }
@@ -21,7 +23,12 @@ function getSortedSeatTypes(seatTypes) {
21
23
  if (premiumIndex >= 3) {
22
24
  seatTypesWithPrices[2] = seatTypesWithPrices[premiumIndex];
23
25
  }
24
- seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
26
+ if (isTrain) {
27
+ seatTypesWithPrices = seatTypesWithPrices.slice(0, 4);
28
+ }
29
+ else {
30
+ seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
31
+ }
25
32
  const seenPrices = new Set();
26
33
  seatTypesWithPrices = seatTypesWithPrices.filter((seat) => {
27
34
  if (seenPrices.has(seat.price))
@@ -54,10 +61,10 @@ function getUniqueSeats(seatTypes) {
54
61
  function getNumberOfSeats(seatTypes) {
55
62
  return seatTypes.filter((val) => !SEAT_EXCEPTIONS.includes(val.label)).length;
56
63
  }
57
- function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, }) {
64
+ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, selectedSeatKey, onSeatSelect, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, isTrain, topLabelColor, }) {
58
65
  var _a;
59
66
  const uniqueSeats = getUniqueSeats(seatTypes);
60
- const sortedSeatTypes = getSortedSeatTypes(seatTypes);
67
+ const sortedSeatTypes = getSortedSeatTypes(seatTypes, isTrain);
61
68
  const numberOfSeats = getNumberOfSeats(seatTypes);
62
69
  const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
63
70
  const formatPrice = (price) => availableSeats <= 0
@@ -65,11 +72,34 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
65
72
  : CommonService.currency(price, currencySign);
66
73
  const renderSeatNames = () => {
67
74
  const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
68
- return seats.map((val, key) => SEAT_EXCEPTIONS.includes(val.label) ? null : (React.createElement("span", { key: key, className: `flex items-center justify-between text-[13.33px] ${isSoldOut ? "text-[#c0c0c0]" : ""}` }, typeof val.label === "string" || typeof val.label === "number"
69
- ? removeDuplicateSeats && isPeru
70
- ? CommonService.truncateSeatLabel(val.label)
71
- : val.label
72
- : null)));
75
+ return seats.map((val, key) => {
76
+ return SEAT_EXCEPTIONS.includes(val.label) ? null : (React.createElement("div", { className: "flex items-center", style: isTrain ? { cursor: "pointer" } : undefined, onClick: isTrain && !isSoldOut
77
+ ? () => val.label === selectedSeatKey
78
+ ? onSeatSelect === null || onSeatSelect === void 0 ? void 0 : onSeatSelect(null, 0, "", "")
79
+ : onSeatSelect === null || onSeatSelect === void 0 ? void 0 : onSeatSelect(val.label, val.price, val.key, val.apiSeatType)
80
+ : undefined },
81
+ isTrain && (React.createElement("div", { style: {
82
+ border: `1px solid ${val.label === selectedSeatKey ? topLabelColor : "#ccc"}`,
83
+ borderRadius: "50%",
84
+ width: "14px",
85
+ height: "14px",
86
+ minWidth: "14px",
87
+ marginRight: "10px",
88
+ display: "flex",
89
+ alignItems: "center",
90
+ justifyContent: "center",
91
+ } }, val.label === selectedSeatKey && (React.createElement("div", { style: {
92
+ backgroundColor: topLabelColor,
93
+ borderRadius: "50%",
94
+ width: "7px",
95
+ height: "7px",
96
+ } })))),
97
+ React.createElement("span", { key: key, className: `flex items-center justify-between text-[13.33px] ${isSoldOut ? "text-[#c0c0c0]" : ""}` }, typeof val.label === "string" || typeof val.label === "number"
98
+ ? removeDuplicateSeats && isPeru
99
+ ? CommonService.truncateSeatLabel(val.label)
100
+ : val.label
101
+ : null)));
102
+ });
73
103
  };
74
104
  const renderSeatPrices = () => {
75
105
  if (isPeru) {
@@ -16,6 +16,7 @@ interface ExpandedDropdownMobileProps {
16
16
  femaleAnim?: any;
17
17
  flexibleAnim?: any;
18
18
  renderIcon?: any;
19
+ operatorLabel?: string;
19
20
  }
20
- declare function ExpandedDropdownMobile({ serviceItem, isPeru, petSeatInfo, petFriendlyAnim, isSoldOut, isChangeTicket, ladiesBookedSeats, isDpEnabled, femaleAnim, flexibleAnim, renderIcon, }: ExpandedDropdownMobileProps): React.ReactElement;
21
+ declare function ExpandedDropdownMobile({ serviceItem, isPeru, petSeatInfo, petFriendlyAnim, isSoldOut, isChangeTicket, ladiesBookedSeats, isDpEnabled, femaleAnim, flexibleAnim, renderIcon, operatorLabel, }: ExpandedDropdownMobileProps): React.ReactElement;
21
22
  export default ExpandedDropdownMobile;
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- function ExpandedDropdownMobile({ serviceItem, isPeru, petSeatInfo, petFriendlyAnim, isSoldOut, isChangeTicket = false, ladiesBookedSeats, isDpEnabled, femaleAnim, flexibleAnim, renderIcon, }) {
2
+ function ExpandedDropdownMobile({ serviceItem, isPeru, petSeatInfo, petFriendlyAnim, isSoldOut, isChangeTicket = false, ladiesBookedSeats, isDpEnabled, femaleAnim, flexibleAnim, renderIcon, operatorLabel, }) {
3
3
  return (React.createElement("div", { className: "px-[12px] pt-[22px] pb-[12px] relative -z-9", style: {
4
4
  backgroundColor: "#ffefef",
5
5
  borderRadius: "0 0 14px 14px",
@@ -17,7 +17,9 @@ function ExpandedDropdownMobile({ serviceItem, isPeru, petSeatInfo, petFriendlyA
17
17
  (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.change_ticket_hours) || 6,
18
18
  " horas antes"),
19
19
  " ",
20
- "de la salida del bus. El monto ser\u00E1 reembolsado a tu billetera kupospay."))) : (React.createElement("div", { className: "flex gap-[8px] " },
20
+ "de la salida del bus. El monto ser\u00E1 reembolsado a tu billetera",
21
+ operatorLabel || "kupospay",
22
+ "."))) : (React.createElement("div", { className: "flex gap-[8px] " },
21
23
  React.createElement("span", { className: "mt-[3px]" }, renderIcon("changeTicketIcon", "14px")),
22
24
  React.createElement("span", null,
23
25
  React.createElement("span", null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kupos-ui-components-lib",
3
- "version": "9.8.7",
3
+ "version": "9.8.9",
4
4
  "description": "A reusable UI components package",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -116,9 +116,25 @@ function ServiceItemPB({
116
116
  showLoginModal,
117
117
  isLoggedIn,
118
118
  showLoginOption,
119
+ isTrain,
120
+ selectedSeatKey,
121
+ onSeatSelect,
122
+ onTrainButtonClick,
123
+ showSeatSelectionError,
124
+ onShowSeatSelectionError,
125
+ onClearSeatSelectionError,
119
126
  isFlores,
120
127
  operatorLabel,
121
128
  }: ServiceItemProps & { currencySign?: string }): React.ReactElement {
129
+ const handleSeatSelect = (
130
+ key: any,
131
+ price: number,
132
+ seatKey: string,
133
+ apiSeatType?: string,
134
+ ) => {
135
+ onClearSeatSelectionError?.();
136
+ onSeatSelect?.(key, price, seatKey, apiSeatType);
137
+ };
122
138
  const getAnimationIcon = (icon: string) => {
123
139
  const animation = ANIMATION_MAP[icon];
124
140
  if (!animation) return null;
@@ -315,6 +331,17 @@ function ServiceItemPB({
315
331
  return;
316
332
  }
317
333
 
334
+ if (isTrain) {
335
+ if (!selectedSeatKey) {
336
+ onShowSeatSelectionError?.(serviceItem.id);
337
+ return;
338
+ }
339
+ if (onTrainButtonClick) {
340
+ onTrainButtonClick();
341
+ return;
342
+ }
343
+ }
344
+
318
345
  onBookButtonPress();
319
346
  };
320
347
 
@@ -528,6 +555,10 @@ function ServiceItemPB({
528
555
  isPeru={isPeru}
529
556
  renderIcon={renderIcon}
530
557
  discountSeatPriceColor={colors.discountSeatPriceColor}
558
+ isTrain={isTrain}
559
+ selectedSeatKey={selectedSeatKey}
560
+ onSeatSelect={handleSeatSelect}
561
+ topLabelColor={colors.topLabelColor}
531
562
  />
532
563
  </div>
533
564
 
@@ -543,6 +574,18 @@ function ServiceItemPB({
543
574
  soldOutIcon={renderIcon("soldOutIcon", "14px")}
544
575
  onClick={checkMidnight}
545
576
  />
577
+ {showSeatSelectionError === serviceItem.id && isTrain && (
578
+ <div className="flex justify-center mr-[11px] w-[100%] right-[0px] absolute left-[0] top-[40px]">
579
+ <div
580
+ className="text-[9px] text-center whitespace-nowrap"
581
+ style={{
582
+ color: colors.seatPriceColor,
583
+ }}
584
+ >
585
+ Selecciona el tipo de servicio
586
+ </div>
587
+ </div>
588
+ )}
546
589
  {showLastSeats ? (
547
590
  <div className="flex justify-center mr-[11px] w-[100%] right-[0px] absolute left-[0] top-[40px]">
548
591
  {serviceItem?.available_seats < 10 &&
@@ -45,6 +45,7 @@ function ServiceItemMobile({
45
45
  removeDuplicateSeats,
46
46
  isLinatal,
47
47
  viewersConfig,
48
+ operatorLabel,
48
49
  }: MobileServiceItemProps): React.ReactElement {
49
50
  const isItemExpanded = serviceItem.id === isExpanded;
50
51
  const isPetSeat = (Object.keys(serviceItem?.pet_seat_info) || []).length > 0;
@@ -459,6 +460,7 @@ function ServiceItemMobile({
459
460
  femaleAnim={serviceItem.icons.femaleAnim}
460
461
  flexibleAnim={serviceItem.icons.flexibleAnim}
461
462
  renderIcon={renderIcon}
463
+ operatorLabel={operatorLabel}
462
464
  />
463
465
  </div>
464
466
  </div>
@@ -121,16 +121,16 @@ export interface MobileServiceItemProps {
121
121
  bombAnim?: string;
122
122
  whiteBoardingIcon?: string;
123
123
  downArrow?: string;
124
- personIcon?: string
124
+ personIcon?: string;
125
125
  specialDeparture?: string;
126
126
  fireIcon?: string;
127
127
  directoIcon?: string;
128
- whiteFireIcon?: string
129
- femaleAnim?:string
130
- cancelTicketIcon?: string;
128
+ whiteFireIcon?: string;
129
+ femaleAnim?: string;
130
+ cancelTicketIcon?: string;
131
131
  changeTicketIcon?: string;
132
132
  petFriendlyIcon?: string;
133
- womenSeatIcon?: string
133
+ womenSeatIcon?: string;
134
134
  [key: string]: string | Record<string, string | undefined> | undefined;
135
135
  };
136
136
  useLottieFor?: string[];
@@ -179,7 +179,7 @@ export interface MobileServiceItemProps {
179
179
  seatPriceColor?: string;
180
180
  rightGradiantColor?: string;
181
181
  leftGradiantColor?: string;
182
- discountSeatPriceColor?: string
182
+ discountSeatPriceColor?: string;
183
183
  };
184
184
  isCiva?: boolean;
185
185
  currencySign?: string;
@@ -192,11 +192,12 @@ export interface MobileServiceItemProps {
192
192
  showLastSeats?: boolean;
193
193
  removeDuplicateSeats?: boolean;
194
194
  isLinatal?: boolean;
195
- viewersConfig?: {
195
+ viewersConfig?: {
196
196
  min: number;
197
197
  max: number;
198
198
  interval?: number; // ms, default 5000
199
199
  label?: string; // e.g. "personas están viendo este viaje"
200
200
  icon?: string; // optional icon URL
201
201
  };
202
+ operatorLabel?: string;
202
203
  }
@@ -226,6 +226,18 @@ export interface ServiceItemProps {
226
226
  showLoginModal?: any;
227
227
  isLoggedIn?: any;
228
228
  showLoginOption?: boolean;
229
+ isTrain?: boolean;
230
+ selectedSeatKey?: any;
231
+ onSeatSelect?: (
232
+ key: any,
233
+ price: number,
234
+ seatKey: string,
235
+ apiSeatType?: string,
236
+ ) => void;
237
+ onTrainButtonClick?: any;
238
+ showSeatSelectionError?: string | null;
239
+ onShowSeatSelectionError?: (serviceId: string) => void;
240
+ onClearSeatSelectionError?: () => void;
229
241
  isFlores?: boolean;
230
242
  operatorLabel?: string;
231
243
  }
@@ -7,6 +7,8 @@ interface SeatType {
7
7
  label: string;
8
8
  fare: number;
9
9
  key: any;
10
+ apiSeatType?: string;
11
+ api_seat_type?: string;
10
12
  }
11
13
 
12
14
  interface SeatSectionProps {
@@ -21,6 +23,15 @@ interface SeatSectionProps {
21
23
  serviceItem?: any;
22
24
  renderIcon?: (iconKey: string, size?: string) => React.ReactNode;
23
25
  discountSeatPriceColor?: string;
26
+ isTrain?: boolean;
27
+ selectedSeatKey?: any;
28
+ onSeatSelect?: (
29
+ key: any,
30
+ price: number,
31
+ seatKey: string,
32
+ apiSeatType?: string,
33
+ ) => void;
34
+ topLabelColor?: string;
24
35
  }
25
36
 
26
37
  function getAllSeatTypes(seatTypes: SeatType[]) {
@@ -31,6 +42,8 @@ function getAllSeatTypes(seatTypes: SeatType[]) {
31
42
  let seatTypesWithPrices = seatTypes.filter(Boolean).map((val) => ({
32
43
  label: val?.label,
33
44
  price: val?.fare,
45
+ key: val?.key,
46
+ apiSeatType: val?.apiSeatType || val?.api_seat_type,
34
47
  }));
35
48
 
36
49
  seatTypesWithPrices.sort((a, b) => a.price - b.price);
@@ -38,7 +51,7 @@ function getAllSeatTypes(seatTypes: SeatType[]) {
38
51
  return seatTypesWithPrices;
39
52
  }
40
53
 
41
- function getSortedSeatTypes(seatTypes: SeatType[]) {
54
+ function getSortedSeatTypes(seatTypes: SeatType[], isTrain: any) {
42
55
  if (!seatTypes?.length) {
43
56
  return [{ label: "Salon cama", price: 0 }];
44
57
  }
@@ -52,7 +65,11 @@ function getSortedSeatTypes(seatTypes: SeatType[]) {
52
65
  seatTypesWithPrices[2] = seatTypesWithPrices[premiumIndex];
53
66
  }
54
67
 
55
- seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
68
+ if (isTrain) {
69
+ seatTypesWithPrices = seatTypesWithPrices.slice(0, 4);
70
+ } else {
71
+ seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
72
+ }
56
73
 
57
74
  const seenPrices = new Set<number>();
58
75
  seatTypesWithPrices = seatTypesWithPrices.filter((seat) => {
@@ -97,14 +114,18 @@ function SeatSection({
97
114
  priceColor,
98
115
  currencySign,
99
116
  removeDuplicateSeats,
117
+ selectedSeatKey,
118
+ onSeatSelect,
100
119
  isPeru,
101
120
  serviceItem,
102
121
  renderIcon,
103
122
  dpSeatColor,
104
123
  discountSeatPriceColor,
124
+ isTrain,
125
+ topLabelColor,
105
126
  }: SeatSectionProps): React.ReactElement {
106
127
  const uniqueSeats = getUniqueSeats(seatTypes);
107
- const sortedSeatTypes = getSortedSeatTypes(seatTypes);
128
+ const sortedSeatTypes = getSortedSeatTypes(seatTypes, isTrain);
108
129
  const numberOfSeats = getNumberOfSeats(seatTypes);
109
130
  const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
110
131
 
@@ -116,22 +137,66 @@ function SeatSection({
116
137
  const renderSeatNames = () => {
117
138
  const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
118
139
 
119
- return seats.map((val, key: number) =>
120
- SEAT_EXCEPTIONS.includes(val.label) ? null : (
121
- <span
122
- key={key}
123
- className={`flex items-center justify-between text-[13.33px] ${
124
- isSoldOut ? "text-[#c0c0c0]" : ""
125
- }`}
140
+ return seats.map((val, key: number) => {
141
+ return SEAT_EXCEPTIONS.includes(val.label) ? null : (
142
+ <div
143
+ className="flex items-center"
144
+ style={isTrain ? { cursor: "pointer" } : undefined}
145
+ onClick={
146
+ isTrain && !isSoldOut
147
+ ? () =>
148
+ val.label === selectedSeatKey
149
+ ? onSeatSelect?.(null, 0, "", "")
150
+ : onSeatSelect?.(
151
+ val.label,
152
+ val.price,
153
+ val.key,
154
+ (val as any).apiSeatType,
155
+ )
156
+ : undefined
157
+ }
126
158
  >
127
- {typeof val.label === "string" || typeof val.label === "number"
128
- ? removeDuplicateSeats && isPeru
129
- ? CommonService.truncateSeatLabel(val.label)
130
- : val.label
131
- : null}
132
- </span>
133
- ),
134
- );
159
+ {isTrain && (
160
+ <div
161
+ style={{
162
+ border: `1px solid ${val.label === selectedSeatKey ? topLabelColor : "#ccc"}`,
163
+ borderRadius: "50%",
164
+ width: "14px",
165
+ height: "14px",
166
+ minWidth: "14px",
167
+ marginRight: "10px",
168
+ display: "flex",
169
+ alignItems: "center",
170
+ justifyContent: "center",
171
+ }}
172
+ >
173
+ {val.label === selectedSeatKey && (
174
+ <div
175
+ style={{
176
+ backgroundColor: topLabelColor,
177
+ borderRadius: "50%",
178
+ width: "7px",
179
+ height: "7px",
180
+ }}
181
+ />
182
+ )}
183
+ </div>
184
+ )}
185
+ <span
186
+ key={key}
187
+ className={`flex items-center justify-between text-[13.33px] ${
188
+ isSoldOut ? "text-[#c0c0c0]" : ""
189
+ }`}
190
+ >
191
+ {typeof val.label === "string" || typeof val.label === "number"
192
+ ? removeDuplicateSeats && isPeru
193
+ ? CommonService.truncateSeatLabel(val.label)
194
+ : val.label
195
+ : null}
196
+ </span>
197
+ </div>
198
+ );
199
+ });
135
200
  };
136
201
 
137
202
  const renderSeatPrices = () => {
@@ -18,6 +18,7 @@ interface ExpandedDropdownMobileProps {
18
18
  femaleAnim?: any;
19
19
  flexibleAnim?: any;
20
20
  renderIcon?: any;
21
+ operatorLabel?: string;
21
22
  }
22
23
 
23
24
  function ExpandedDropdownMobile({
@@ -32,6 +33,7 @@ function ExpandedDropdownMobile({
32
33
  femaleAnim,
33
34
  flexibleAnim,
34
35
  renderIcon,
36
+ operatorLabel,
35
37
  }: ExpandedDropdownMobileProps): React.ReactElement {
36
38
  return (
37
39
  <div
@@ -59,7 +61,7 @@ function ExpandedDropdownMobile({
59
61
  hasta {serviceItem?.change_ticket_hours || 6} horas antes
60
62
  </span>{" "}
61
63
  de la salida del bus. El monto será reembolsado a tu billetera
62
- kupospay.
64
+ {operatorLabel || "kupospay"}.
63
65
  </span>
64
66
  </div>
65
67
  ) : (