kupos-ui-components-lib 10.4.29 → 10.4.30
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/components/ServiceItem/PeruServiceItemDesktop.js +21 -14
- package/dist/components/ServiceItem/PeruServiceItemMobile.js +39 -44
- package/dist/components/ServiceItem/ServiceItemMobile.js +7 -3
- package/dist/ui/OfferBanner.js +5 -2
- package/dist/ui/PeruOfferBanner.d.ts +1 -0
- package/dist/ui/PeruOfferBanner.js +16 -24
- package/dist/ui/SeatSection/PeruSeatSection.js +42 -15
- package/dist/ui/mobileweb/SeatSectionMobile.js +16 -11
- package/package.json +1 -1
- package/src/components/ServiceItem/PeruServiceItemDesktop.tsx +32 -24
- package/src/components/ServiceItem/PeruServiceItemMobile.tsx +62 -79
- package/src/components/ServiceItem/ServiceItemMobile.tsx +17 -11
- package/src/ui/OfferBanner.tsx +11 -6
- package/src/ui/PeruOfferBanner.tsx +23 -36
- package/src/ui/SeatSection/PeruSeatSection.tsx +64 -17
- package/src/ui/mobileweb/SeatSectionMobile.tsx +53 -46
|
@@ -236,14 +236,19 @@ function PeruSeatSection({
|
|
|
236
236
|
.filter((seat) => !SEAT_EXCEPTIONS.includes(seat.label))
|
|
237
237
|
.sort((a, b) => a.discountedPrice - b.discountedPrice)[0];
|
|
238
238
|
|
|
239
|
+
// discount_type/discount_value/max_discount live on the service item
|
|
240
|
+
// itself; only ui_type and the ready-made badge text come from discounts[0].
|
|
241
|
+
const peruDiscount = serviceItem?.discounts?.[0];
|
|
242
|
+
const uiType = peruDiscount?.ui_type;
|
|
243
|
+
const discountType = serviceItem?.discount_type;
|
|
244
|
+
const discountValueRaw = serviceItem?.discount_value;
|
|
245
|
+
const maxDiscount = serviceItem?.max_discount;
|
|
246
|
+
|
|
239
247
|
const discountValue = (() => {
|
|
240
|
-
if (
|
|
241
|
-
|
|
242
|
-
typeof serviceItem?.discount_value === "number"
|
|
243
|
-
) {
|
|
244
|
-
return Math.round(serviceItem.discount_value);
|
|
248
|
+
if (discountType === "percentage" && typeof discountValueRaw === "number") {
|
|
249
|
+
return Math.round(discountValueRaw);
|
|
245
250
|
}
|
|
246
|
-
if (
|
|
251
|
+
if (discountType === "fixed" && discountSeat) {
|
|
247
252
|
const { originalPrice, discountedPrice } = discountSeat;
|
|
248
253
|
if (originalPrice > 0 && originalPrice !== discountedPrice) {
|
|
249
254
|
return Math.round(
|
|
@@ -255,21 +260,30 @@ function PeruSeatSection({
|
|
|
255
260
|
})();
|
|
256
261
|
|
|
257
262
|
const isMaxDiscountApplied = (() => {
|
|
258
|
-
const { discount_type, discount_value, max_discount } = serviceItem ?? {};
|
|
259
263
|
if (
|
|
260
|
-
|
|
261
|
-
typeof
|
|
262
|
-
|
|
263
|
-
|
|
264
|
+
discountType === "percentage" &&
|
|
265
|
+
typeof discountValueRaw === "number" &&
|
|
266
|
+
maxDiscount != null &&
|
|
267
|
+
maxDiscount > 0 &&
|
|
264
268
|
discountSeat
|
|
265
269
|
) {
|
|
266
270
|
const rawPercentageDiscount =
|
|
267
|
-
(discountSeat.originalPrice *
|
|
268
|
-
return rawPercentageDiscount >
|
|
271
|
+
(discountSeat.originalPrice * discountValueRaw) / 100;
|
|
272
|
+
return rawPercentageDiscount > maxDiscount;
|
|
269
273
|
}
|
|
270
274
|
return false;
|
|
271
275
|
})();
|
|
272
276
|
|
|
277
|
+
// Backend-provided ready-made badge text (e.g. "30% OFF" / "$2.000 OFF")
|
|
278
|
+
// takes precedence over the value computed client-side.
|
|
279
|
+
const discountBadgeText =
|
|
280
|
+
peruDiscount?.discount_display_badge ||
|
|
281
|
+
(isMaxDiscountApplied
|
|
282
|
+
? `${CommonService.currency(maxDiscount)} OFF`
|
|
283
|
+
: discountValue != null
|
|
284
|
+
? `${discountValue}% OFF`
|
|
285
|
+
: null);
|
|
286
|
+
|
|
273
287
|
const renderLabels = () => {
|
|
274
288
|
const isMovilBus =
|
|
275
289
|
serviceItem?.operator_service_name === "MovilBus" ||
|
|
@@ -363,6 +377,41 @@ function PeruSeatSection({
|
|
|
363
377
|
};
|
|
364
378
|
|
|
365
379
|
if (hasDiscount && discountSeat) {
|
|
380
|
+
// Tier B (ui_type 1): offer text is announced elsewhere, but the fare
|
|
381
|
+
// itself must render exactly as it would with no discount — no
|
|
382
|
+
// strike-off, no badge, no fire icon.
|
|
383
|
+
if (uiType === 1) {
|
|
384
|
+
return (
|
|
385
|
+
<div
|
|
386
|
+
className="grid grid-cols-2 items-center text-[13.33px] relative"
|
|
387
|
+
style={{ opacity: isSoldOut ? 0.5 : 1 }}
|
|
388
|
+
>
|
|
389
|
+
<div className="col-start-1 row-start-3 flex h-[20px] items-end">
|
|
390
|
+
<span className="text-[13.33px] font-normal leading-[20px] text-[#464647]">
|
|
391
|
+
{discountSeat.label}
|
|
392
|
+
</span>
|
|
393
|
+
</div>
|
|
394
|
+
|
|
395
|
+
<div className="col-start-2 row-start-3 flex h-[30px] items-end justify-center relative">
|
|
396
|
+
<span
|
|
397
|
+
className="flex items-center gap-[6px] bold-text leading-[30px]"
|
|
398
|
+
style={{
|
|
399
|
+
color: isSoldOut ? "#c0c0c0" : "#464647",
|
|
400
|
+
fontSize: "13.33px",
|
|
401
|
+
}}
|
|
402
|
+
>
|
|
403
|
+
{availableSeats <= 0
|
|
404
|
+
? CommonService.currency(0, currencySign)
|
|
405
|
+
: CommonService.discountedCurrency(
|
|
406
|
+
discountSeat.originalPrice,
|
|
407
|
+
currencySign,
|
|
408
|
+
)}
|
|
409
|
+
</span>
|
|
410
|
+
</div>
|
|
411
|
+
</div>
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
366
415
|
return (
|
|
367
416
|
<div
|
|
368
417
|
className="grid grid-cols-2 items-center text-[13.33px] relative"
|
|
@@ -384,7 +433,7 @@ function PeruSeatSection({
|
|
|
384
433
|
className="col-start-2 row-start-1 flex items-center justify-center absolute"
|
|
385
434
|
style={{ top: "-22px", left: "50%", transform: "translateX(-50%)" }}
|
|
386
435
|
>
|
|
387
|
-
{
|
|
436
|
+
{discountBadgeText ? (
|
|
388
437
|
<span
|
|
389
438
|
className="rounded-[100px] bg-[#ff5964] px-[6px] text-[12px] bold-text leading-[20px] text-white"
|
|
390
439
|
style={{
|
|
@@ -393,9 +442,7 @@ function PeruSeatSection({
|
|
|
393
442
|
backgroundColor: discountSeatPriceColor,
|
|
394
443
|
}}
|
|
395
444
|
>
|
|
396
|
-
{
|
|
397
|
-
? `${CommonService.currency(serviceItem?.max_discount)} OFF`
|
|
398
|
-
: `${discountValue}% OFF`}
|
|
445
|
+
{discountBadgeText}
|
|
399
446
|
</span>
|
|
400
447
|
) : null}
|
|
401
448
|
</div>
|
|
@@ -478,6 +478,16 @@ function SeatSectionMobile({
|
|
|
478
478
|
return false;
|
|
479
479
|
})();
|
|
480
480
|
|
|
481
|
+
// Backend-provided ready-made badge text (e.g. "30% OFF" / "$2.000 OFF")
|
|
482
|
+
// takes precedence over the value computed client-side.
|
|
483
|
+
const discountBadgeText =
|
|
484
|
+
serviceItem?.discounts?.[0]?.discount_display_badge ||
|
|
485
|
+
(isMaxDiscountApplied
|
|
486
|
+
? `${commonService.currency(serviceItem?.max_discount)} OFF`
|
|
487
|
+
: discountValue != null
|
|
488
|
+
? `${discountValue}% OFF`
|
|
489
|
+
: null);
|
|
490
|
+
|
|
481
491
|
const getMinValue = (data: any): number | undefined => {
|
|
482
492
|
const vals = (Array.isArray(data) ? data : Object.values(data || {})).map(
|
|
483
493
|
Number,
|
|
@@ -595,59 +605,56 @@ function SeatSectionMobile({
|
|
|
595
605
|
) : hasDiscount && discountSeat ? (
|
|
596
606
|
<div>
|
|
597
607
|
<div className="relative grid grid-cols-[auto_auto] justify-between gap-x-[8px] ">
|
|
598
|
-
{serviceItem?.ui_type !== 1 &&
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
608
|
+
{serviceItem?.ui_type !== 1 && discountBadgeText && (
|
|
609
|
+
<>
|
|
610
|
+
<div
|
|
611
|
+
className="absolute -top-[18px] right-[0px]"
|
|
612
|
+
style={{
|
|
613
|
+
animation: "pulse-zoom 2s ease-in-out infinite",
|
|
614
|
+
opacity: isSoldOut ? 0.5 : 1,
|
|
615
|
+
}}
|
|
616
|
+
>
|
|
617
|
+
<span
|
|
618
|
+
className="rounded-[100px] px-[8px] text-[12px] bold-text leading-[20px] text-[#fff]"
|
|
603
619
|
style={{
|
|
604
|
-
|
|
605
|
-
opacity: isSoldOut ? 0.5 : 1,
|
|
620
|
+
backgroundColor: tooltipBgColor,
|
|
606
621
|
}}
|
|
607
622
|
>
|
|
608
|
-
|
|
609
|
-
className="rounded-[100px] px-[8px] text-[12px] bold-text leading-[20px] text-[#fff]"
|
|
610
|
-
style={{
|
|
611
|
-
backgroundColor: tooltipBgColor,
|
|
612
|
-
}}
|
|
613
|
-
>
|
|
614
|
-
{isMaxDiscountApplied
|
|
615
|
-
? `${commonService.currency(serviceItem?.max_discount)} OFF`
|
|
616
|
-
: `${discountValue}% OFF`}
|
|
617
|
-
</span>
|
|
618
|
-
</div>
|
|
619
|
-
|
|
620
|
-
<span className="min-[420]:text-[13px] text-[12px] leading-[20px] text-[#c2c2c2]">
|
|
621
|
-
Antes
|
|
623
|
+
{discountBadgeText}
|
|
622
624
|
</span>
|
|
625
|
+
</div>
|
|
626
|
+
|
|
627
|
+
<span className="min-[420]:text-[13px] text-[12px] leading-[20px] text-[#c2c2c2]">
|
|
628
|
+
Antes
|
|
629
|
+
</span>
|
|
630
|
+
<span
|
|
631
|
+
className="min-[420]:text-[13px] text-[12px] leading-[20px] text-right "
|
|
632
|
+
style={{
|
|
633
|
+
position: "relative",
|
|
634
|
+
display: "inline-block",
|
|
635
|
+
overflow: "hidden",
|
|
636
|
+
color: discountSeatPriceColor,
|
|
637
|
+
}}
|
|
638
|
+
>
|
|
639
|
+
{commonService.currency(
|
|
640
|
+
discountSeat.originalPrice,
|
|
641
|
+
currencySign,
|
|
642
|
+
)}
|
|
623
643
|
<span
|
|
624
|
-
className="min-[420]:text-[13px] text-[12px] leading-[20px] text-right"
|
|
625
644
|
style={{
|
|
626
|
-
position: "
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
645
|
+
position: "absolute",
|
|
646
|
+
top: "35%",
|
|
647
|
+
left: "50%",
|
|
648
|
+
width: "80%",
|
|
649
|
+
height: "1px",
|
|
650
|
+
background: discountSeatCrossPriceColor,
|
|
651
|
+
transform: "rotate(-12deg)",
|
|
652
|
+
transformOrigin: "center",
|
|
630
653
|
}}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
)}
|
|
636
|
-
<span
|
|
637
|
-
style={{
|
|
638
|
-
position: "absolute",
|
|
639
|
-
top: "35%",
|
|
640
|
-
left: "50%",
|
|
641
|
-
width: "80%",
|
|
642
|
-
height: "1px",
|
|
643
|
-
background: discountSeatCrossPriceColor,
|
|
644
|
-
transform: "rotate(-12deg)",
|
|
645
|
-
transformOrigin: "center",
|
|
646
|
-
}}
|
|
647
|
-
/>
|
|
648
|
-
</span>
|
|
649
|
-
</>
|
|
650
|
-
)}
|
|
654
|
+
/>
|
|
655
|
+
</span>
|
|
656
|
+
</>
|
|
657
|
+
)}
|
|
651
658
|
|
|
652
659
|
<span
|
|
653
660
|
className="min-[420]:text-[13px] text-[12px] leading-[24px]"
|