kupos-ui-components-lib 9.6.2 → 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.
- package/dist/assets/images/anims/service_list/female_anim.json +1 -0
- package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemDesktop.js +7 -3
- package/dist/components/ServiceItem/ServiceItemMobile.js +9 -6
- package/dist/components/ServiceItem/mobileTypes.d.ts +5 -0
- package/dist/components/ServiceItem/types.d.ts +7 -3
- package/dist/styles.css +2 -2
- package/dist/types.d.ts +1 -0
- package/dist/ui/BottomAmenities/BottomAmenities.d.ts +2 -0
- package/dist/ui/BottomAmenities/BottomAmenities.js +4 -0
- package/dist/ui/FemaleBlock.d.ts +9 -0
- package/dist/ui/FemaleBlock.js +19 -0
- package/dist/ui/OfferBanner.d.ts +2 -1
- package/dist/ui/OfferBanner.js +17 -6
- package/dist/ui/SeatSection/SeatSection.d.ts +2 -1
- package/dist/ui/SeatSection/SeatSection.js +33 -15
- package/dist/ui/mobileweb/BottomAmenitiesMobile.d.ts +4 -1
- package/dist/ui/mobileweb/BottomAmenitiesMobile.js +8 -1
- package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +2 -1
- package/dist/ui/mobileweb/DateTimeSectionMobile.js +2 -2
- package/dist/ui/mobileweb/ExpandedDropdownMobile.d.ts +3 -1
- package/dist/ui/mobileweb/ExpandedDropdownMobile.js +8 -1
- package/dist/ui/mobileweb/SeatSectionMobile.d.ts +2 -1
- package/dist/ui/mobileweb/SeatSectionMobile.js +30 -18
- package/dist/utils/CommonService.js +4 -2
- package/package.json +1 -1
- package/src/assets/images/anims/service_list/female_anim.json +1 -0
- package/src/components/ServiceItem/ServiceItemDesktop.tsx +7 -0
- package/src/components/ServiceItem/ServiceItemMobile.tsx +11 -71
- package/src/components/ServiceItem/mobileTypes.ts +5 -0
- package/src/components/ServiceItem/types.ts +7 -3
- package/src/types.ts +1 -0
- package/src/ui/BottomAmenities/BottomAmenities.tsx +14 -0
- package/src/ui/FemaleBlock.tsx +45 -0
- package/src/ui/OfferBanner.tsx +24 -6
- package/src/ui/SeatSection/SeatSection.tsx +38 -14
- package/src/ui/mobileweb/BottomAmenitiesMobile.tsx +27 -0
- package/src/ui/mobileweb/DateTimeSectionMobile.tsx +3 -0
- package/src/ui/mobileweb/ExpandedDropdownMobile.tsx +15 -0
- package/src/ui/mobileweb/SeatSectionMobile.tsx +41 -31
- package/src/utils/CommonService.ts +7 -2
|
@@ -20,6 +20,7 @@ interface SeatSectionProps {
|
|
|
20
20
|
isPeru?: boolean;
|
|
21
21
|
serviceItem?: any;
|
|
22
22
|
renderIcon?: (iconKey: string, size?: string) => React.ReactNode;
|
|
23
|
+
discountSeatPriceColor?: string;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
function getAllSeatTypes(seatTypes: SeatType[]) {
|
|
@@ -100,6 +101,7 @@ function SeatSection({
|
|
|
100
101
|
serviceItem,
|
|
101
102
|
renderIcon,
|
|
102
103
|
dpSeatColor,
|
|
104
|
+
discountSeatPriceColor,
|
|
103
105
|
}: SeatSectionProps): React.ReactElement {
|
|
104
106
|
const uniqueSeats = getUniqueSeats(seatTypes);
|
|
105
107
|
const sortedSeatTypes = getSortedSeatTypes(seatTypes);
|
|
@@ -193,11 +195,23 @@ function SeatSection({
|
|
|
193
195
|
.filter((seat) => !SEAT_EXCEPTIONS.includes(seat.label))
|
|
194
196
|
.sort((a, b) => a.discountedPrice - b.discountedPrice)[0];
|
|
195
197
|
|
|
196
|
-
const discountValue =
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
const discountValue = (() => {
|
|
199
|
+
if (
|
|
200
|
+
serviceItem?.discount_type === "percentage" &&
|
|
201
|
+
typeof serviceItem?.discount_value === "number"
|
|
202
|
+
) {
|
|
203
|
+
return Math.round(serviceItem.discount_value);
|
|
204
|
+
}
|
|
205
|
+
if (serviceItem?.discount_type === "fixed" && discountSeat) {
|
|
206
|
+
const { originalPrice, discountedPrice } = discountSeat;
|
|
207
|
+
if (originalPrice > 0 && originalPrice !== discountedPrice) {
|
|
208
|
+
return Math.round(
|
|
209
|
+
((originalPrice - discountedPrice) / originalPrice) * 100,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
})();
|
|
201
215
|
|
|
202
216
|
const renderLabels = () => {
|
|
203
217
|
if (isPeru) {
|
|
@@ -227,11 +241,15 @@ function SeatSection({
|
|
|
227
241
|
// ).find(([, percent]) => Number(percent));
|
|
228
242
|
const dpDiscountEntry = Object.entries(
|
|
229
243
|
serviceItem?.dp_discount_percents || {},
|
|
230
|
-
)[0];
|
|
244
|
+
).sort(([, a], [, b]) => Number(a) - Number(b))[0];
|
|
231
245
|
const dpDiscountPercent = dpDiscountEntry?.[1];
|
|
232
|
-
const
|
|
246
|
+
const getLowestDpValue = (source: any): number | undefined => {
|
|
233
247
|
if (!source) return undefined;
|
|
234
|
-
|
|
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;
|
|
235
253
|
};
|
|
236
254
|
|
|
237
255
|
const renderDpDiscountUi = (
|
|
@@ -301,7 +319,7 @@ function SeatSection({
|
|
|
301
319
|
>
|
|
302
320
|
<div
|
|
303
321
|
className="absolute"
|
|
304
|
-
style={{ left: isPeru ? "-1px" : "-
|
|
322
|
+
style={{ left: isPeru ? "-1px" : "-19px", bottom: "1px" }}
|
|
305
323
|
>
|
|
306
324
|
{renderIcon("fireIcon", "16px")}
|
|
307
325
|
</div>
|
|
@@ -339,7 +357,7 @@ function SeatSection({
|
|
|
339
357
|
</div>
|
|
340
358
|
<div>
|
|
341
359
|
<div className="relative">
|
|
342
|
-
<div className="absolute -left-[20px] top-1/
|
|
360
|
+
<div className="absolute -left-[20px] top-1/3 transform -translate-y-1/2">
|
|
343
361
|
{renderIcon("fireIcon", "16px")}
|
|
344
362
|
</div>
|
|
345
363
|
<div
|
|
@@ -375,8 +393,12 @@ function SeatSection({
|
|
|
375
393
|
}
|
|
376
394
|
|
|
377
395
|
if (dpDiscountEntry) {
|
|
378
|
-
const originalDpPrice =
|
|
379
|
-
const
|
|
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;
|
|
380
402
|
|
|
381
403
|
if (originalDpPrice && seatTypeFare) {
|
|
382
404
|
return renderDpDiscountUi(originalDpPrice, seatTypeFare);
|
|
@@ -411,6 +433,7 @@ function SeatSection({
|
|
|
411
433
|
style={{
|
|
412
434
|
animation: "pulse-zoom 2s ease-in-out infinite",
|
|
413
435
|
whiteSpace: "nowrap",
|
|
436
|
+
backgroundColor: discountSeatPriceColor,
|
|
414
437
|
}}
|
|
415
438
|
>
|
|
416
439
|
{discountValue}% OFF
|
|
@@ -447,13 +470,14 @@ function SeatSection({
|
|
|
447
470
|
<div className="col-start-2 row-start-3 flex h-[30px] items-end justify-center relative">
|
|
448
471
|
<span
|
|
449
472
|
className="flex items-center gap-[6px] text-[22px] bold-text leading-[30px]"
|
|
450
|
-
style={{ color: isSoldOut ? "#c0c0c0" :
|
|
473
|
+
style={{ color: isSoldOut ? "#c0c0c0" : discountSeatPriceColor }}
|
|
451
474
|
>
|
|
452
475
|
{/* <span className="text-[18px] leading-[24px]">🔥</span> */}
|
|
453
476
|
<div
|
|
454
477
|
className="absolute"
|
|
455
478
|
style={{
|
|
456
|
-
left: isPeru ? "-1px" : "-
|
|
479
|
+
left: isPeru ? "-1px" : "-18px",
|
|
480
|
+
bottom:"1px"
|
|
457
481
|
}}
|
|
458
482
|
>
|
|
459
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,6 +117,7 @@ function SeatSectionMobile({
|
|
|
116
117
|
serviceItem,
|
|
117
118
|
tooltipBgColor,
|
|
118
119
|
showLastSeats,
|
|
120
|
+
discountSeatPriceColor,
|
|
119
121
|
}: SeatSectionMobileProps): React.ReactElement {
|
|
120
122
|
const hasMultipleTypes = (seatTypesData?.length ?? 0) > 2;
|
|
121
123
|
|
|
@@ -243,21 +245,6 @@ function SeatSectionMobile({
|
|
|
243
245
|
{commonService.currency(discountedPrice, currencySign)}
|
|
244
246
|
</span>
|
|
245
247
|
</div>
|
|
246
|
-
{showLastSeats ? (
|
|
247
|
-
<div className="flex justify-end">
|
|
248
|
-
{serviceItem?.available_seats < 10 &&
|
|
249
|
-
serviceItem?.available_seats > 0 && (
|
|
250
|
-
<div
|
|
251
|
-
className="text-[10px] text-center mt-[3px]"
|
|
252
|
-
style={{
|
|
253
|
-
color: tooltipBgColor,
|
|
254
|
-
}}
|
|
255
|
-
>
|
|
256
|
-
¡Últimos Asientos!
|
|
257
|
-
</div>
|
|
258
|
-
)}
|
|
259
|
-
</div>
|
|
260
|
-
) : null}
|
|
261
248
|
{isSoldOut ? (
|
|
262
249
|
<div className="flex justify-end">
|
|
263
250
|
<span
|
|
@@ -343,21 +330,40 @@ function SeatSectionMobile({
|
|
|
343
330
|
?.filter((seat) => !EXCEPTIONS.includes(seat.label))
|
|
344
331
|
?.sort((a, b) => a.discountedPrice - b.discountedPrice)[0];
|
|
345
332
|
|
|
346
|
-
const discountValue =
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
+
})();
|
|
351
350
|
|
|
352
|
-
const
|
|
353
|
-
?
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
)
|
|
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;
|
|
361
367
|
|
|
362
368
|
const hasDpDiscount =
|
|
363
369
|
serviceItem?.dp_discounted_seats &&
|
|
@@ -432,7 +438,9 @@ function SeatSectionMobile({
|
|
|
432
438
|
</span>
|
|
433
439
|
<span
|
|
434
440
|
className="flex items-center justify-end gap-[4px] text-[14px] bold-text leading-[24px]"
|
|
435
|
-
style={{
|
|
441
|
+
style={{
|
|
442
|
+
color: isSoldOut ? "#bbb" : discountSeatPriceColor || "#ff5964",
|
|
443
|
+
}}
|
|
436
444
|
>
|
|
437
445
|
{serviceItem?.icons?.fireIcon ? (
|
|
438
446
|
<img
|
|
@@ -510,7 +518,9 @@ function SeatSectionMobile({
|
|
|
510
518
|
</span>
|
|
511
519
|
<span
|
|
512
520
|
className="flex items-center justify-end gap-[4px] text-[14px] bold-text leading-[24px]"
|
|
513
|
-
style={{
|
|
521
|
+
style={{
|
|
522
|
+
color: isSoldOut ? "#bbb" : discountSeatPriceColor || "#ff5964",
|
|
523
|
+
}}
|
|
514
524
|
>
|
|
515
525
|
{serviceItem?.icons?.fireIcon ? (
|
|
516
526
|
<img
|
|
@@ -303,15 +303,20 @@ const commonService = {
|
|
|
303
303
|
|
|
304
304
|
const { discount_type, discount_value, max_discount } = serviceItem;
|
|
305
305
|
|
|
306
|
+
const fixedDiscount =
|
|
307
|
+
discount_type === "fixed" && discount_value != null ? discount_value : 0;
|
|
308
|
+
|
|
306
309
|
const percentageDiscount =
|
|
307
310
|
discount_type === "percentage" && discount_value != null
|
|
308
311
|
? (price * discount_value) / 100
|
|
309
312
|
: 0;
|
|
310
313
|
|
|
314
|
+
const rawDiscount = fixedDiscount || percentageDiscount;
|
|
315
|
+
|
|
311
316
|
const finalDiscount =
|
|
312
317
|
max_discount != null && max_discount > 0
|
|
313
|
-
? Math.min(
|
|
314
|
-
:
|
|
318
|
+
? Math.min(rawDiscount, max_discount)
|
|
319
|
+
: rawDiscount;
|
|
315
320
|
|
|
316
321
|
const discountedPrice = Math.max(0, price - finalDiscount);
|
|
317
322
|
|