kupos-ui-components-lib 9.6.3 → 9.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/assets/images/anims/service_list/female_anim.json +1 -0
  2. package/dist/components/ServiceItem/PeruServiceItemDesktop.d.ts +1 -1
  3. package/dist/components/ServiceItem/PeruServiceItemDesktop.js +133 -189
  4. package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
  5. package/dist/components/ServiceItem/ServiceItemDesktop.js +7 -3
  6. package/dist/components/ServiceItem/ServiceItemMobile.js +8 -5
  7. package/dist/components/ServiceItem/mobileTypes.d.ts +5 -0
  8. package/dist/components/ServiceItem/types.d.ts +5 -3
  9. package/dist/styles.css +17 -2
  10. package/dist/types.d.ts +1 -0
  11. package/dist/ui/BottomAmenities/BottomAmenities.d.ts +2 -0
  12. package/dist/ui/BottomAmenities/BottomAmenities.js +4 -0
  13. package/dist/ui/FemaleBlock.d.ts +9 -0
  14. package/dist/ui/FemaleBlock.js +19 -0
  15. package/dist/ui/OfferBanner.d.ts +2 -1
  16. package/dist/ui/OfferBanner.js +17 -6
  17. package/dist/ui/SeatSection/SeatSection.js +17 -9
  18. package/dist/ui/mobileweb/BottomAmenitiesMobile.d.ts +4 -1
  19. package/dist/ui/mobileweb/BottomAmenitiesMobile.js +8 -1
  20. package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +2 -1
  21. package/dist/ui/mobileweb/DateTimeSectionMobile.js +2 -2
  22. package/dist/ui/mobileweb/ExpandedDropdownMobile.d.ts +3 -1
  23. package/dist/ui/mobileweb/ExpandedDropdownMobile.js +8 -1
  24. package/dist/ui/mobileweb/SeatSectionMobile.d.ts +2 -1
  25. package/dist/ui/mobileweb/SeatSectionMobile.js +30 -15
  26. package/package.json +1 -1
  27. package/src/assets/images/anims/service_list/female_anim.json +1 -0
  28. package/src/components/ServiceItem/PeruServiceItemDesktop.tsx +255 -322
  29. package/src/components/ServiceItem/ServiceItemDesktop.tsx +6 -6
  30. package/src/components/ServiceItem/ServiceItemMobile.tsx +10 -70
  31. package/src/components/ServiceItem/mobileTypes.ts +5 -0
  32. package/src/components/ServiceItem/types.ts +5 -3
  33. package/src/types.ts +1 -0
  34. package/src/ui/BottomAmenities/BottomAmenities.tsx +14 -0
  35. package/src/ui/FemaleBlock.tsx +45 -0
  36. package/src/ui/OfferBanner.tsx +24 -6
  37. package/src/ui/SeatSection/SeatSection.tsx +17 -8
  38. package/src/ui/mobileweb/BottomAmenitiesMobile.tsx +27 -0
  39. package/src/ui/mobileweb/DateTimeSectionMobile.tsx +3 -0
  40. package/src/ui/mobileweb/ExpandedDropdownMobile.tsx +15 -0
  41. package/src/ui/mobileweb/SeatSectionMobile.tsx +41 -32
@@ -26,6 +26,7 @@ import opsitesPriorityStageAnimation from "../../assets/images/anims/service_lis
26
26
  import bombAnimation from "../../assets/images/anims/service_list/bomb.json";
27
27
  import dotAnimation from "../../assets/images/anims/service_list/dot_animation.json";
28
28
  import starAnimation from "../../assets/images/anims/service_list/star_anim.json";
29
+ import femaleAnimation from "../../assets/images/anims/service_list/female_anim.json";
29
30
 
30
31
  import RatingBlock from "../../ui/RatingBlock";
31
32
  import DurationBlock from "../../ui/DurationBlock";
@@ -76,6 +77,9 @@ const ANIMATION_MAP: Record<string, Record<string, any>> = {
76
77
  starAnimation: {
77
78
  kupos: starAnimation,
78
79
  },
80
+ femaaleAnimation: {
81
+ kupos: femaleAnimation,
82
+ },
79
83
  };
80
84
 
81
85
  function ServiceItemPB({
@@ -111,6 +115,7 @@ function ServiceItemPB({
111
115
  viewersConfig,
112
116
  showLoginModal,
113
117
  isLoggedIn,
118
+ showLoginOption
114
119
  }: ServiceItemProps & { currencySign?: string }): React.ReactElement {
115
120
  const getAnimationIcon = (icon: string) => {
116
121
  const animation = ANIMATION_MAP[icon];
@@ -409,12 +414,6 @@ function ServiceItemPB({
409
414
  isPeru={isPeru}
410
415
  siteType={siteType}
411
416
  isAllinBus={isAllinBus}
412
- viewersConfig={viewersConfig}
413
- isLoggedIn={isLoggedIn}
414
- showLoginModal={showLoginModal}
415
- isExpand={isExpand}
416
- setIsExpand={setIsExpand}
417
- coachKey={coachKey}
418
417
  />
419
418
  ) : (
420
419
  <div
@@ -436,6 +435,7 @@ function ServiceItemPB({
436
435
  showLoginModal={showLoginModal}
437
436
  viewersConfig={viewersConfig}
438
437
  getAnimationIcon={getAnimationIcon}
438
+ showLoginOption={showLoginOption}
439
439
  />
440
440
  )}
441
441
  <div
@@ -247,6 +247,7 @@ function ServiceItemMobile({
247
247
  removeDuplicateSeats={removeDuplicateSeats}
248
248
  serviceItem={serviceItem}
249
249
  showLastSeats={showLastSeats}
250
+ discountSeatPriceColor={colors.discountSeatPriceColor}
250
251
  />
251
252
 
252
253
  {hasDiscount && (
@@ -302,6 +303,9 @@ function ServiceItemMobile({
302
303
  setIsExpanded(isItemExpanded ? null : serviceItem.id);
303
304
  }}
304
305
  isPeru={isPeru}
306
+ femaleAnim={serviceItem.icons.femaleAnim}
307
+ ladiesBookedSeats={serviceItem.ladies_booked_seats}
308
+ isDpEnabled={serviceItem.is_dp_enabled}
305
309
  />
306
310
  </div>
307
311
 
@@ -332,7 +336,10 @@ function ServiceItemMobile({
332
336
  style={{ lineHeight: 1.6 }}
333
337
  >
334
338
  <div className="flex justify-between items-center">
335
- {serviceItem?.is_dp_enabled ? (
339
+ {serviceItem?.is_dp_enabled &&
340
+ Object.keys(serviceItem?.dp_discount_percents ?? {}).length ===
341
+ 0 &&
342
+ (serviceItem?.dp_discounted_seats ?? []).length === 0 ? (
336
343
  <div className="flex items-center gap-[6px]">
337
344
  {/* {renderIcon("whiteFireIcon", "14px")} */}
338
345
  <LottiePlayer
@@ -414,77 +421,8 @@ function ServiceItemMobile({
414
421
  </span>
415
422
  </span>
416
423
  </div>
417
- {/* <div className="flex items-center">
418
- <span className="whitespace-nowrap">
419
- {serviceItem?.is_dp_enabled ? null : "Quedan pocos • "}
420
- <span
421
- className="bold-text"
422
- ref={(node) =>
423
- commonService.startComprandoCount(node, 4, 16)
424
- }
425
- style={{ fontVariantNumeric: "tabular-nums" }}
426
- />{" "}
427
- comprando
428
- </span>
429
- </div> */}
430
424
  </div>
431
425
  </div>
432
- {/* <div className="flex flex-col gap-[4px]">
433
- <div
434
- className={`flex ${isLongOfferText ? "items-start" : "items-center"}`}
435
- >
436
- <div className={isLongOfferText ? "mt-[2px]" : ""}>
437
- <LottiePlayer
438
- animationData={serviceItem.icons.bombAnim}
439
- width="12px"
440
- height="12px"
441
- />
442
- </div>
443
- <div
444
- className={`ml-[6px] flex-1 outline-none ${isLongOfferText ? "mt-[2px]" : ""}`}
445
- style={{
446
- color: "#fff",
447
- lineHeight: 1.4,
448
- }}
449
- >
450
- <span className="min-[380px]:text-[12px] bold-text">
451
- {serviceItem?.offer_text || ""}
452
- </span>{" "}
453
- <span className="min-[380px]:text-[12px]">|</span>{" "}
454
- <span className="whitespace-nowrap min-[380px]:text-[12px]">
455
- Termina en&nbsp;
456
- <span
457
- className="bold-text"
458
- ref={(node) => commonService.startCountdown(node, 599)}
459
- style={{
460
- fontVariantNumeric: "tabular-nums",
461
- display: "inline-block",
462
- }}
463
- />
464
- </span>
465
- </div>
466
- </div>
467
- <div
468
- className="flex items-start"
469
- style={{
470
- color: "#fff",
471
- }}
472
- >
473
- <div>{renderIcon("personIcon", "16px")}</div>
474
- <span className="flex-1" style={{ lineHeight: 1.4 }}>
475
- <span
476
- className="bold-text"
477
- ref={(node) => commonService.startViewerCount(node, viewersConfig)}
478
- style={{ fontVariantNumeric: "tabular-nums" }}
479
- />{" "}
480
- <span className="bold-text">personas</span>{" "}
481
- <span>
482
- {" "}
483
- {viewersConfig?.label || " están viendo este viaje"}
484
- </span>
485
- </span>
486
- </div>
487
- </div> */}
488
426
  </div>
489
427
  </div>
490
428
  )}
@@ -516,6 +454,8 @@ function ServiceItemMobile({
516
454
  petFriendlyAnim={serviceItem.icons.petFriendlyAnim}
517
455
  isSoldOut={isSoldOut}
518
456
  isChangeTicket={serviceItem.is_change_ticket === true}
457
+ ladiesBookedSeats={serviceItem.ladies_booked_seats}
458
+ isDpEnabled={serviceItem.is_dp_enabled}
519
459
  />
520
460
  </div>
521
461
  </div>
@@ -37,11 +37,14 @@ export interface MobileServiceItemProps {
37
37
  change_ticket_hours?: number;
38
38
  duration?: number;
39
39
  train_type_label?: string;
40
+ ladies_booked_seats?: string;
40
41
  is_dp_enabled?: boolean;
41
42
  offer_text?: string;
42
43
  is_direct_trip?: boolean;
43
44
  is_train_type?: boolean;
44
45
  operator_service_name?: string;
46
+ dp_discount_percents?: Record<string, number>;
47
+ dp_discounted_seats?: string[];
45
48
  dep_validation_text?: string;
46
49
  metaData?: {};
47
50
  is_tracking_enabled?: boolean;
@@ -123,6 +126,7 @@ export interface MobileServiceItemProps {
123
126
  fireIcon?: string;
124
127
  directoIcon?: string;
125
128
  whiteFireIcon?: string
129
+ femaleAnim?:string
126
130
  [key: string]: string | Record<string, string | undefined> | undefined;
127
131
  };
128
132
  useLottieFor?: string[];
@@ -171,6 +175,7 @@ export interface MobileServiceItemProps {
171
175
  seatPriceColor?: string;
172
176
  rightGradiantColor?: string;
173
177
  leftGradiantColor?: string;
178
+ discountSeatPriceColor?: string
174
179
  };
175
180
  isCiva?: boolean;
176
181
  currencySign?: string;
@@ -41,15 +41,16 @@ export interface ServiceItemProps {
41
41
  offer_text?: string;
42
42
  is_direct_trip?: boolean;
43
43
  is_dp_enabled?: boolean;
44
- dp_discount_percents?: Record<string, number | string> | Array<number | string>;
45
- dp_discounted_seats?: Array<string | number>;
46
- original_dp_price?: Record<string, number | string> | Array<number | string>;
44
+ dp_discount_percents?: any;
45
+ dp_discounted_seats?: any;
46
+ original_dp_price?: any;
47
47
  discount_type?: string;
48
48
  discount_value?: number;
49
49
  max_discount?: number;
50
50
  is_transpordo?: boolean;
51
51
  is_train_type?: boolean;
52
52
  operator_service_name?: string;
53
+ ladies_booked_seats?: string;
53
54
  dep_validation_text?: string;
54
55
  metaData?: {};
55
56
  is_tracking_enabled?: boolean;
@@ -224,5 +225,6 @@ export interface ServiceItemProps {
224
225
  };
225
226
  showLoginModal?: any
226
227
  isLoggedIn?: any
228
+ showLoginOption?: boolean
227
229
 
228
230
  }
package/src/types.ts CHANGED
@@ -57,6 +57,7 @@ export interface ServiceItemProps {
57
57
  is_direct_trip?: boolean;
58
58
  is_transpordo?: boolean;
59
59
  is_train_type?: boolean;
60
+ ladies_booked_seats?: any
60
61
  operator_service_name?: string;
61
62
  dep_validation_text?: string;
62
63
  metaData?: {};
@@ -2,6 +2,7 @@ import React from "react";
2
2
  import LottiePlayer from "../../assets/LottiePlayer";
3
3
  import FlexibleBlock from "../FlexibleBlock";
4
4
  import PetBlock from "../PetBlock";
5
+ import FemaleBlock from "../FemaleBlock";
5
6
 
6
7
  interface ItemEntry {
7
8
  key: string;
@@ -15,6 +16,8 @@ interface BottomAmenitiesProps {
15
16
  is_tracking_enabled?: boolean;
16
17
  is_change_ticket?: boolean;
17
18
  pet_seat_info?: Record<string, any>;
19
+ ladies_booked_seats?: any;
20
+ is_dp_enabled?: boolean;
18
21
  };
19
22
  grayscaleClass: string;
20
23
  isSoldOut: boolean;
@@ -86,6 +89,17 @@ function BottomAmenities({
86
89
  isSoldOut={isSoldOut}
87
90
  />
88
91
  )}
92
+ {serviceItem.ladies_booked_seats &&
93
+ String(serviceItem.ladies_booked_seats).trim() !== "" &&
94
+ serviceItem?.is_dp_enabled === true && (
95
+ <FemaleBlock
96
+ translation={translation}
97
+ getAnimationIcon={getAnimationIcon}
98
+ colors={colors}
99
+ serviceItem={serviceItem}
100
+ isSoldOut={isSoldOut}
101
+ />
102
+ )}
89
103
  {hasPetInfo && (
90
104
  <PetBlock
91
105
  translation={translation}
@@ -0,0 +1,45 @@
1
+ import React from "react";
2
+ import LottiePlayer from "../assets/LottiePlayer";
3
+
4
+ const FemaleBlock = ({
5
+ translation,
6
+ getAnimationIcon,
7
+ colors,
8
+ serviceItem,
9
+ isSoldOut,
10
+ }) => (
11
+ <div className="flex items-center">
12
+ <div className="relative group cursor-pointer">
13
+ <div className="flex items-center">
14
+ <div className={`mr-[5px] ${isSoldOut ? "grayscale" : ""}`}>
15
+ <LottiePlayer
16
+ // animationData={serviceItem.icons.flexibleAnim}
17
+ animationData={getAnimationIcon("femaaleAnimation")}
18
+ width="20px"
19
+ height="20px"
20
+ />
21
+ </div>
22
+ {/* <div className="h-auto mr-[4px] text-[13px] text-[#464647]">
23
+ <span>{translation?.flexible}</span>
24
+ </div> */}
25
+ </div>
26
+ <div
27
+ className="hidden group-hover:block absolute top-[24px] left-1/2 -translate-x-1/2 text-white p-3 rounded-[14px] whitespace-normal z-10 mt-2.5 w-[230px] text-center break-normal shadow-service text-[12px]"
28
+ style={{
29
+ backgroundColor: colors.bottomStripColor,
30
+ lineHeight: "1.5",
31
+ zIndex: "1000",
32
+ }}
33
+ >
34
+ {/* Tooltip arrow */}
35
+ <div
36
+ className="tooltip-arrow absolute -top-[7px] left-1/2 -translate-x-1/2 w-0 h-0 border-l-8 border-r-8 border-b-8 border-l-transparent border-r-transparent "
37
+ style={{ borderBottomColor: colors.bottomStripColor }}
38
+ ></div>
39
+ Esta empresa cuenta con asientos recomendados para mujeres.
40
+ </div>
41
+ </div>
42
+ </div>
43
+ );
44
+
45
+ export default FemaleBlock;
@@ -8,13 +8,17 @@ interface OfferBannerProps {
8
8
  isSoldOut: boolean;
9
9
  serviceItem: Pick<
10
10
  ServiceItemProps["serviceItem"],
11
- "is_dp_enabled" | "offer_text"
11
+ | "is_dp_enabled"
12
+ | "offer_text"
13
+ | "dp_discount_percents"
14
+ | "dp_discounted_seats"
12
15
  >;
13
16
  renderIcon: (name: string, size: string) => React.ReactNode;
14
17
  isLoggedIn: any;
15
18
  showLoginModal: any;
16
19
  viewersConfig: ServiceItemProps["viewersConfig"];
17
20
  getAnimationIcon: (name: string) => any;
21
+ showLoginOption?: boolean
18
22
  }
19
23
 
20
24
  const OfferBanner: React.FC<OfferBannerProps> = ({
@@ -26,6 +30,7 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
26
30
  showLoginModal,
27
31
  viewersConfig,
28
32
  getAnimationIcon,
33
+ showLoginOption
29
34
  }) => {
30
35
  return (
31
36
  <div
@@ -38,7 +43,9 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
38
43
  >
39
44
  <div className="flex justify-between items-center w-full">
40
45
  <div className="flex items-center ">
41
- {serviceItem?.is_dp_enabled ? (
46
+ {serviceItem?.is_dp_enabled &&
47
+ Object.keys(serviceItem?.dp_discount_percents ?? {}).length === 0 &&
48
+ (serviceItem?.dp_discounted_seats ?? []).length === 0 ? (
42
49
  <div className="flex items-center gap-[5px]">
43
50
  {/* {renderIcon("whiteFireIcon", "14px")} */}
44
51
  <LottiePlayer
@@ -57,18 +64,24 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
57
64
  height="18px"
58
65
  />
59
66
  <div className="flex items-center mt-[2px]">
60
- <span className="bold-text ml-[6px]">
67
+ <span
68
+ className="bold-text"
69
+ style={{
70
+ marginLeft: serviceItem?.offer_text ? "6px" : "3px",
71
+ }}
72
+ >
61
73
  {(serviceItem?.offer_text || "").length > 30
62
74
  ? (serviceItem?.offer_text || "").slice(0, 30) + "..."
63
75
  : serviceItem?.offer_text || ""}{" "}
64
- {isLoggedIn ? null : (
76
+ {isLoggedIn && showLoginOption ? null : (
65
77
  <span onClick={showLoginModal} className="cursor-pointer">
66
78
  - registro
67
79
  </span>
68
80
  )}{" "}
69
81
  &nbsp;
70
82
  </span>{" "}
71
- | Termina en&nbsp;
83
+ {serviceItem?.offer_text ? "|" : ""}
84
+ Termina en&nbsp;
72
85
  <span
73
86
  className="bold-text text-end"
74
87
  ref={(node) => CommonService.startCountdown(node, 599)}
@@ -102,7 +115,12 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
102
115
  {" "}
103
116
  {viewersConfig?.label || " viendo"} |{" "}
104
117
  <span className="">
105
- {serviceItem?.is_dp_enabled ? null : "Quedan pocos • "}
118
+ {serviceItem?.is_dp_enabled &&
119
+ Object.keys(serviceItem?.dp_discount_percents ?? {}).length ===
120
+ 0 &&
121
+ (serviceItem?.dp_discounted_seats ?? []).length === 0
122
+ ? null
123
+ : "Quedan pocos • "}
106
124
  <span
107
125
  className="bold-text"
108
126
  ref={(node) => CommonService.startComprandoCount(node, 4, 16)}
@@ -241,11 +241,15 @@ function SeatSection({
241
241
  // ).find(([, percent]) => Number(percent));
242
242
  const dpDiscountEntry = Object.entries(
243
243
  serviceItem?.dp_discount_percents || {},
244
- )[0];
244
+ ).sort(([, a], [, b]) => Number(a) - Number(b))[0];
245
245
  const dpDiscountPercent = dpDiscountEntry?.[1];
246
- const getFirstDpValue = (source: any) => {
246
+ const getLowestDpValue = (source: any): number | undefined => {
247
247
  if (!source) return undefined;
248
- return Array.isArray(source) ? source[0] : Object.values(source)[0];
248
+ const values: any[] = Array.isArray(source)
249
+ ? source
250
+ : Object.values(source);
251
+ const nums = values.map(Number).filter((n) => !isNaN(n) && n > 0);
252
+ return nums.length > 0 ? Math.min(...nums) : undefined;
249
253
  };
250
254
 
251
255
  const renderDpDiscountUi = (
@@ -315,7 +319,7 @@ function SeatSection({
315
319
  >
316
320
  <div
317
321
  className="absolute"
318
- style={{ left: isPeru ? "-1px" : "-8px" }}
322
+ style={{ left: isPeru ? "-1px" : "-19px", bottom: "1px" }}
319
323
  >
320
324
  {renderIcon("fireIcon", "16px")}
321
325
  </div>
@@ -353,7 +357,7 @@ function SeatSection({
353
357
  </div>
354
358
  <div>
355
359
  <div className="relative">
356
- <div className="absolute -left-[20px] top-1/2 transform -translate-y-1/2">
360
+ <div className="absolute -left-[20px] top-1/3 transform -translate-y-1/2">
357
361
  {renderIcon("fireIcon", "16px")}
358
362
  </div>
359
363
  <div
@@ -389,8 +393,12 @@ function SeatSection({
389
393
  }
390
394
 
391
395
  if (dpDiscountEntry) {
392
- const originalDpPrice = getFirstDpValue(serviceItem.original_dp_price);
393
- const seatTypeFare = serviceItem.seat_types?.[0]?.fare ?? originalDpPrice;
396
+ const originalDpPrice = getLowestDpValue(serviceItem.original_dp_price);
397
+ const allFares = (serviceItem.seat_types ?? [])
398
+ .map((st: any) => st.fare)
399
+ .filter((f: any) => f != null && !isNaN(Number(f)));
400
+ const seatTypeFare =
401
+ allFares.length > 0 ? Math.min(...allFares) : originalDpPrice;
394
402
 
395
403
  if (originalDpPrice && seatTypeFare) {
396
404
  return renderDpDiscountUi(originalDpPrice, seatTypeFare);
@@ -468,7 +476,8 @@ function SeatSection({
468
476
  <div
469
477
  className="absolute"
470
478
  style={{
471
- left: isPeru ? "-1px" : "-8px",
479
+ left: isPeru ? "-1px" : "-18px",
480
+ bottom:"1px"
472
481
  }}
473
482
  >
474
483
  {renderIcon("fireIcon", "16px")}
@@ -22,6 +22,9 @@ interface BottomAmenitiesMobileProps {
22
22
  onDropdownToggle: () => void;
23
23
  isItemExpanded?: boolean;
24
24
  isPeru?: boolean;
25
+ femaleAnim?: any;
26
+ ladiesBookedSeats?: string;
27
+ isDpEnabled?: boolean;
25
28
  }
26
29
 
27
30
  function BottomAmenitiesMobile({
@@ -45,6 +48,9 @@ function BottomAmenitiesMobile({
45
48
  onDropdownToggle,
46
49
  isItemExpanded,
47
50
  isPeru,
51
+ femaleAnim,
52
+ ladiesBookedSeats,
53
+ isDpEnabled,
48
54
  }: BottomAmenitiesMobileProps): React.ReactElement {
49
55
  return (
50
56
  <div className={`${"flex justify-between items-center items-center "}`}>
@@ -132,6 +138,27 @@ function BottomAmenitiesMobile({
132
138
  </div>
133
139
  )}
134
140
 
141
+ {/* Flexible ticket */}
142
+ {ladiesBookedSeats &&
143
+ String(ladiesBookedSeats).trim() !== "" &&
144
+ isDpEnabled === true && (
145
+ <div className="flex items-center">
146
+ <div className="relative group cursor-default">
147
+ <div className="flex items-center">
148
+ <div
149
+ className={`mr-[5px] ${isSoldOut ? "grayscale" : ""}`}
150
+ >
151
+ <LottiePlayer
152
+ animationData={femaleAnim}
153
+ width="16px"
154
+ height="16px"
155
+ />
156
+ </div>
157
+ </div>
158
+ </div>
159
+ </div>
160
+ )}
161
+
135
162
  {isTrackingEnabled && (
136
163
  <div className="flex items-center mr-[10px]">
137
164
  <div
@@ -24,6 +24,7 @@ interface DateTimeSectionMobileProps {
24
24
  serviceItem?: any;
25
25
  tooltipBgColor?: string;
26
26
  showLastSeats?: boolean;
27
+ discountSeatPriceColor?: string;
27
28
  }
28
29
 
29
30
  const pad = (n: number) => (n < 10 ? "0" + n : String(n));
@@ -123,6 +124,7 @@ function DateTimeSectionMobile({
123
124
  serviceItem,
124
125
  tooltipBgColor,
125
126
  showLastSeats,
127
+ discountSeatPriceColor,
126
128
  }: DateTimeSectionMobileProps): React.ReactElement {
127
129
  const { cleaned: cleanedDepTime, hasAM, hasPM } = getCleanedDepTime(depTime);
128
130
 
@@ -193,6 +195,7 @@ function DateTimeSectionMobile({
193
195
  serviceItem={serviceItem}
194
196
  tooltipBgColor={tooltipBgColor}
195
197
  showLastSeats={showLastSeats}
198
+ discountSeatPriceColor={discountSeatPriceColor}
196
199
  />
197
200
  </div>
198
201
  );
@@ -13,6 +13,8 @@ interface ExpandedDropdownMobileProps {
13
13
  petFriendlyAnim?: any;
14
14
  isSoldOut?: boolean;
15
15
  isChangeTicket?: boolean;
16
+ ladiesBookedSeats?: string;
17
+ isDpEnabled?: boolean;
16
18
  }
17
19
 
18
20
  function ExpandedDropdownMobile({
@@ -22,6 +24,8 @@ function ExpandedDropdownMobile({
22
24
  petFriendlyAnim,
23
25
  isSoldOut,
24
26
  isChangeTicket = false,
27
+ ladiesBookedSeats,
28
+ isDpEnabled,
25
29
  }: ExpandedDropdownMobileProps): React.ReactElement {
26
30
  return (
27
31
  <div
@@ -60,6 +64,17 @@ function ExpandedDropdownMobile({
60
64
  </span>
61
65
  </div>
62
66
  )}
67
+ {ladiesBookedSeats &&
68
+ String(ladiesBookedSeats).trim() !== "" &&
69
+ isDpEnabled === true && (
70
+ <div className="flex gap-[6px]">
71
+ <span style={{ marginTop: "2px" }}>•</span>
72
+ <span>
73
+ <span className="bold-text">Asientos para damas:</span> Esta
74
+ empresa cuenta con asientos recomendados para mujeres.
75
+ </span>
76
+ </div>
77
+ )}
63
78
  {petSeatInfo && Object.keys(petSeatInfo).length > 0 ? (
64
79
  <div className="flex items-center">
65
80
  <div className={`relative group cursor-default `}>
@@ -30,6 +30,7 @@ interface SeatSectionMobileProps {
30
30
  serviceItem?: any;
31
31
  tooltipBgColor?: string;
32
32
  showLastSeats?: boolean;
33
+ discountSeatPriceColor?: string;
33
34
  }
34
35
 
35
36
  interface SeatRowProps {
@@ -116,8 +117,8 @@ function SeatSectionMobile({
116
117
  serviceItem,
117
118
  tooltipBgColor,
118
119
  showLastSeats,
120
+ discountSeatPriceColor,
119
121
  }: SeatSectionMobileProps): React.ReactElement {
120
- console.log("🚀 ~ SeatSectionMobile ~ serviceItem:", serviceItem);
121
122
  const hasMultipleTypes = (seatTypesData?.length ?? 0) > 2;
122
123
 
123
124
  const getFare = (fare: number) => {
@@ -244,21 +245,6 @@ function SeatSectionMobile({
244
245
  {commonService.currency(discountedPrice, currencySign)}
245
246
  </span>
246
247
  </div>
247
- {/* {showLastSeats ? (
248
- <div className="flex justify-end">
249
- {serviceItem?.available_seats < 10 &&
250
- serviceItem?.available_seats > 0 && (
251
- <div
252
- className="text-[10px] text-center mt-[3px]"
253
- style={{
254
- color: tooltipBgColor,
255
- }}
256
- >
257
- ¡Últimos Asientos!
258
- </div>
259
- )}
260
- </div>
261
- ) : null} */}
262
248
  {isSoldOut ? (
263
249
  <div className="flex justify-end">
264
250
  <span
@@ -344,21 +330,40 @@ function SeatSectionMobile({
344
330
  ?.filter((seat) => !EXCEPTIONS.includes(seat.label))
345
331
  ?.sort((a, b) => a.discountedPrice - b.discountedPrice)[0];
346
332
 
347
- const discountValue =
348
- serviceItem?.discount_type === "percentage" &&
349
- typeof serviceItem?.discount_value === "number"
350
- ? Math.round(serviceItem.discount_value)
351
- : null;
333
+ const discountValue = (() => {
334
+ if (
335
+ serviceItem?.discount_type === "percentage" &&
336
+ typeof serviceItem?.discount_value === "number"
337
+ ) {
338
+ return Math.round(serviceItem.discount_value);
339
+ }
340
+ if (serviceItem?.discount_type === "fixed" && discountSeat) {
341
+ const { originalPrice, discountedPrice } = discountSeat;
342
+ if (originalPrice > 0 && originalPrice !== discountedPrice) {
343
+ return Math.round(
344
+ ((originalPrice - discountedPrice) / originalPrice) * 100,
345
+ );
346
+ }
347
+ }
348
+ return null;
349
+ })();
352
350
 
353
- const originalDpPrice = Array.isArray(serviceItem?.original_dp_price)
354
- ? serviceItem.original_dp_price[0]
355
- : Object.values(serviceItem?.original_dp_price || {})[0];
356
- const dpDiscountPercent = Array.isArray(serviceItem?.dp_discount_percents)
357
- ? serviceItem.dp_discount_percents[0]
358
- : Object.values(serviceItem?.dp_discount_percents || {})[0];
359
- const firstSeatFare = seatTypesData?.filter(
360
- (item) => getFilteredSeats(item.label) && !EXCEPTIONS.includes(item.label),
361
- )?.[0]?.fare;
351
+ const getMinValue = (data: any): number | undefined => {
352
+ const vals = (Array.isArray(data) ? data : Object.values(data || {})).map(
353
+ Number,
354
+ );
355
+ if (!vals.length) return undefined;
356
+ const min = Math.min(...vals);
357
+ return isFinite(min) ? min : undefined;
358
+ };
359
+ const originalDpPrice = getMinValue(serviceItem?.original_dp_price);
360
+ const dpDiscountPercent = getMinValue(serviceItem?.dp_discount_percents);
361
+ const firstSeatFare = seatTypesData
362
+ ?.filter(
363
+ (item) =>
364
+ getFilteredSeats(item.label) && !EXCEPTIONS.includes(item.label),
365
+ )
366
+ ?.sort((a, b) => a.fare - b.fare)[0]?.fare;
362
367
 
363
368
  const hasDpDiscount =
364
369
  serviceItem?.dp_discounted_seats &&
@@ -433,7 +438,9 @@ function SeatSectionMobile({
433
438
  </span>
434
439
  <span
435
440
  className="flex items-center justify-end gap-[4px] text-[14px] bold-text leading-[24px]"
436
- style={{ color: isSoldOut ? "#bbb" : "#ff5964" }}
441
+ style={{
442
+ color: isSoldOut ? "#bbb" : discountSeatPriceColor || "#ff5964",
443
+ }}
437
444
  >
438
445
  {serviceItem?.icons?.fireIcon ? (
439
446
  <img
@@ -511,7 +518,9 @@ function SeatSectionMobile({
511
518
  </span>
512
519
  <span
513
520
  className="flex items-center justify-end gap-[4px] text-[14px] bold-text leading-[24px]"
514
- style={{ color: isSoldOut ? "#bbb" : "#ff5964" }}
521
+ style={{
522
+ color: isSoldOut ? "#bbb" : discountSeatPriceColor || "#ff5964",
523
+ }}
515
524
  >
516
525
  {serviceItem?.icons?.fireIcon ? (
517
526
  <img