kupos-ui-components-lib 10.4.9 → 10.4.11
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 +10 -4
- package/dist/components/ServiceItem/PeruServiceItemMobile.d.ts +7 -0
- package/dist/components/ServiceItem/PeruServiceItemMobile.js +235 -0
- package/dist/components/ServiceItem/ServiceItemDesktop.js +4 -4
- package/dist/components/ServiceItem/ServiceItemMobile.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemMobile.js +3 -2
- package/dist/components/ServiceItem/mobileTypes.d.ts +3 -0
- package/dist/components/ServiceItem/types.d.ts +1 -0
- package/dist/styles.css +13 -0
- package/dist/ui/PaymentCardMobile/PaymentCardMobile.d.ts +4 -0
- package/dist/ui/PaymentCardMobile/PaymentCardMobile.js +531 -0
- package/dist/ui/PaymentCardMobile/index.d.ts +1 -0
- package/dist/ui/PaymentCardMobile/index.js +1 -0
- package/dist/ui/PeruOfferBanner.d.ts +24 -0
- package/dist/ui/PeruOfferBanner.js +94 -0
- package/dist/ui/SeatSection/PeruSeatSection.d.ts +22 -0
- package/dist/ui/SeatSection/PeruSeatSection.js +247 -0
- package/dist/ui/SlidingModal/SlidingModal.d.ts +9 -0
- package/dist/ui/SlidingModal/SlidingModal.js +100 -0
- package/dist/ui/SlidingModal/index.d.ts +2 -0
- package/dist/ui/SlidingModal/index.js +1 -0
- package/dist/ui/mobileweb/BottomAmenitiesMobile.d.ts +2 -1
- package/dist/ui/mobileweb/BottomAmenitiesMobile.js +2 -1
- package/dist/ui/mobileweb/SeatSectionMobile.js +15 -1
- package/package.json +1 -1
- package/src/components/ServiceItem/PeruServiceItemDesktop.tsx +20 -6
- package/src/components/ServiceItem/PeruServiceItemMobile.tsx +601 -0
- package/src/components/ServiceItem/ServiceItemDesktop.tsx +2 -2
- package/src/components/ServiceItem/ServiceItemMobile.tsx +44 -1
- package/src/components/ServiceItem/mobileTypes.ts +3 -0
- package/src/components/ServiceItem/types.ts +1 -0
- package/src/ui/PeruOfferBanner.tsx +298 -0
- package/src/ui/SeatSection/PeruSeatSection.tsx +487 -0
- package/src/ui/mobileweb/BottomAmenitiesMobile.tsx +11 -0
- package/src/ui/mobileweb/SeatSectionMobile.tsx +46 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import LottiePlayer from "../assets/LottiePlayer";
|
|
3
|
+
import CommonService from "../utils/CommonService";
|
|
4
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
5
|
+
const OFFER_TEXT_MAX_LENGTH = 30;
|
|
6
|
+
function truncateOfferText(text) {
|
|
7
|
+
return text.length > OFFER_TEXT_MAX_LENGTH
|
|
8
|
+
? `${text.slice(0, OFFER_TEXT_MAX_LENGTH)}...`
|
|
9
|
+
: text;
|
|
10
|
+
}
|
|
11
|
+
function hasDpDiscounts(serviceItem) {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
return (Object.keys((_a = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents) !== null && _a !== void 0 ? _a : {}).length > 0 ||
|
|
14
|
+
((_b = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) !== null && _b !== void 0 ? _b : []).length > 0);
|
|
15
|
+
}
|
|
16
|
+
const AnimationIcon = ({ getAnimationIcon, name, width = "18px", height = "18px", }) => (React.createElement(LottiePlayer, { animationData: getAnimationIcon(name), width: width, height: height }));
|
|
17
|
+
// Shown when DP is enabled but no discounts / discounted seats are present
|
|
18
|
+
const PopularServiceBanner = ({ getAnimationIcon }) => (React.createElement("div", { className: "flex items-center gap-[5px]" },
|
|
19
|
+
React.createElement(AnimationIcon, { getAnimationIcon: getAnimationIcon, name: "starAnimation" }),
|
|
20
|
+
React.createElement("span", null, "Servicio popular entre los usuarios")));
|
|
21
|
+
const OfferBannerContent = ({ offerText, isLoggedIn, showLoginModal, showLoginOption, getAnimationIcon, hideRegister, showLoginButton, }) => (React.createElement("div", { className: "flex items-center" },
|
|
22
|
+
React.createElement(AnimationIcon, { getAnimationIcon: getAnimationIcon, name: "bombAnimation" }),
|
|
23
|
+
React.createElement("div", { className: "flex items-center mt-[0px]" },
|
|
24
|
+
React.createElement("span", { className: "bold-text", style: { marginLeft: offerText ? "6px" : "3px" } },
|
|
25
|
+
offerText,
|
|
26
|
+
" ",
|
|
27
|
+
isLoggedIn && showLoginOption
|
|
28
|
+
? null
|
|
29
|
+
: showLoginOption &&
|
|
30
|
+
showLoginButton && (React.createElement("span", { onClick: showLoginModal, className: "cursor-pointer" }, "- registro")),
|
|
31
|
+
" ",
|
|
32
|
+
"\u00A0"),
|
|
33
|
+
" ",
|
|
34
|
+
offerText ? "| " : "",
|
|
35
|
+
"Termina en\u00A0",
|
|
36
|
+
React.createElement("span", { className: "bold-text text-end", ref: (node) => CommonService.startCountdown(node, 599), style: { fontVariantNumeric: "tabular-nums", display: "inline-block" } }))));
|
|
37
|
+
const LegacyOfferBanner = ({ offerText, getAnimationIcon, }) => (React.createElement("div", { className: "flex items-center" },
|
|
38
|
+
React.createElement(AnimationIcon, { getAnimationIcon: getAnimationIcon, name: "promoAnim" }),
|
|
39
|
+
React.createElement("div", { className: "flex items-center mb-[2px]" },
|
|
40
|
+
React.createElement("span", { className: "bold-text", style: { marginLeft: offerText ? "6px" : "3px" } }, offerText))));
|
|
41
|
+
const ViewersCount = ({ serviceItem, viewersConfig, getAnimationIcon, }) => {
|
|
42
|
+
const showScarcity = hasDpDiscounts(serviceItem);
|
|
43
|
+
return (React.createElement("div", { className: "flex items-center" },
|
|
44
|
+
React.createElement(AnimationIcon, { getAnimationIcon: getAnimationIcon, name: "dotAnimation", width: "12px", height: "12px" }),
|
|
45
|
+
React.createElement("span", { className: "ml-[6px]" },
|
|
46
|
+
React.createElement("span", { className: "bold-text", ref: (node) => CommonService.startViewerCount(node, viewersConfig), style: { fontVariantNumeric: "tabular-nums" } }),
|
|
47
|
+
" ",
|
|
48
|
+
React.createElement("span", null,
|
|
49
|
+
(viewersConfig === null || viewersConfig === void 0 ? void 0 : viewersConfig.label) || " viendo",
|
|
50
|
+
" |",
|
|
51
|
+
" ",
|
|
52
|
+
React.createElement("span", null,
|
|
53
|
+
showScarcity && "Quedan pocos • ",
|
|
54
|
+
React.createElement("span", { className: "bold-text", ref: (node) => CommonService.startComprandoCount(node, 4, 16), style: { fontVariantNumeric: "tabular-nums" } }),
|
|
55
|
+
" ",
|
|
56
|
+
"comprando")))));
|
|
57
|
+
};
|
|
58
|
+
// ─── Main Component ───────────────────────────────────────────────────────────
|
|
59
|
+
const PeruOfferBanner = ({ offerGradient, isSoldOut, serviceItem, isLoggedIn, showLoginModal, viewersConfig, getAnimationIcon, showLoginOption, colors, isLinatal, coachKey, isExpand, isNewUiEnabled, }) => {
|
|
60
|
+
const isDiscountBelow20 = (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_value) > 0 &&
|
|
61
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_value) < 20;
|
|
62
|
+
const offerText = isDiscountBelow20 ? "" : (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) || "";
|
|
63
|
+
const isLegacyOffer = !!offerText &&
|
|
64
|
+
!isNewUiEnabled;
|
|
65
|
+
// const showViewers = serviceItem?.is_dp_enabled;
|
|
66
|
+
const showViewers = isNewUiEnabled;
|
|
67
|
+
const background = isLegacyOffer ? colors === null || colors === void 0 ? void 0 : colors.bottomStripColor : offerGradient;
|
|
68
|
+
const renderLeftContent = () => {
|
|
69
|
+
const hasDp = hasDpDiscounts(serviceItem);
|
|
70
|
+
if ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) && !hasDp) {
|
|
71
|
+
return React.createElement(PopularServiceBanner, { getAnimationIcon: getAnimationIcon });
|
|
72
|
+
}
|
|
73
|
+
// If new UI is enabled, show offer with registro and countdown
|
|
74
|
+
if (isNewUiEnabled && offerText) {
|
|
75
|
+
return (React.createElement(OfferBannerContent, { offerText: offerText, isLoggedIn: isLoggedIn, showLoginModal: showLoginModal, showLoginOption: showLoginOption, getAnimationIcon: getAnimationIcon, hideRegister: hasDp, showLoginButton: serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.show_register_button }));
|
|
76
|
+
}
|
|
77
|
+
// If new UI is disabled, show offer text only
|
|
78
|
+
if (offerText) {
|
|
79
|
+
return (React.createElement(LegacyOfferBanner, { offerText: offerText, getAnimationIcon: getAnimationIcon }));
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
};
|
|
83
|
+
return (React.createElement("div", { className: `text-white w-full absolute ${coachKey ? "-bottom-[32px]" : isExpand ? "-bottom-[32px]" : "-bottom-[40px]"} rounded-b-[14px] text-[14px] h-[58px] flex items-end pb-[7px]`, style: {
|
|
84
|
+
background: ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) && (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents))
|
|
85
|
+
? offerGradient
|
|
86
|
+
: background,
|
|
87
|
+
opacity: isSoldOut ? 0.5 : 1,
|
|
88
|
+
zIndex: isLinatal ? "-1" : "0",
|
|
89
|
+
} },
|
|
90
|
+
React.createElement("div", { className: "flex items-center w-full gap-[20px] px-[15px] justify-between" },
|
|
91
|
+
React.createElement("div", { className: "flex items-center justify-start" }, renderLeftContent()),
|
|
92
|
+
showViewers && (React.createElement(ViewersCount, { serviceItem: serviceItem, viewersConfig: viewersConfig, getAnimationIcon: getAnimationIcon })))));
|
|
93
|
+
};
|
|
94
|
+
export default PeruOfferBanner;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface SeatType {
|
|
3
|
+
label: string;
|
|
4
|
+
fare: number;
|
|
5
|
+
key: any;
|
|
6
|
+
apiSeatType?: string;
|
|
7
|
+
api_seat_type?: string;
|
|
8
|
+
}
|
|
9
|
+
interface PeruSeatSectionProps {
|
|
10
|
+
seatTypes: SeatType[];
|
|
11
|
+
availableSeats: number;
|
|
12
|
+
isSoldOut: boolean;
|
|
13
|
+
priceColor?: string;
|
|
14
|
+
currencySign?: string;
|
|
15
|
+
removeDuplicateSeats?: boolean;
|
|
16
|
+
serviceItem?: any;
|
|
17
|
+
renderIcon?: (iconKey: string, size?: string) => React.ReactNode;
|
|
18
|
+
discountSeatPriceColor?: string;
|
|
19
|
+
isSeatIcon?: boolean;
|
|
20
|
+
}
|
|
21
|
+
declare function PeruSeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, serviceItem, renderIcon, discountSeatPriceColor, isSeatIcon, }: PeruSeatSectionProps): React.ReactElement;
|
|
22
|
+
export default PeruSeatSection;
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import CommonService from "../../utils/CommonService";
|
|
3
|
+
const SEAT_EXCEPTIONS = ["Asiento mascota"];
|
|
4
|
+
function getAllSeatTypes(seatTypes) {
|
|
5
|
+
if (!(seatTypes === null || seatTypes === void 0 ? void 0 : seatTypes.length)) {
|
|
6
|
+
return [{ label: "Salon cama", price: 0 }];
|
|
7
|
+
}
|
|
8
|
+
let seatTypesWithPrices = seatTypes.filter(Boolean).map((val) => ({
|
|
9
|
+
label: val === null || val === void 0 ? void 0 : val.label,
|
|
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),
|
|
13
|
+
}));
|
|
14
|
+
seatTypesWithPrices.sort((a, b) => a.price - b.price);
|
|
15
|
+
return seatTypesWithPrices;
|
|
16
|
+
}
|
|
17
|
+
function getSortedSeatTypes(seatTypes) {
|
|
18
|
+
if (!(seatTypes === null || seatTypes === void 0 ? void 0 : seatTypes.length)) {
|
|
19
|
+
return [{ label: "Salon cama", price: 0 }];
|
|
20
|
+
}
|
|
21
|
+
let seatTypesWithPrices = getAllSeatTypes(seatTypes);
|
|
22
|
+
const premiumIndex = seatTypesWithPrices.findIndex((item) => item.label === "Premium");
|
|
23
|
+
if (premiumIndex >= 3) {
|
|
24
|
+
seatTypesWithPrices[2] = seatTypesWithPrices[premiumIndex];
|
|
25
|
+
}
|
|
26
|
+
seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
|
|
27
|
+
const seenPrices = new Set();
|
|
28
|
+
seatTypesWithPrices = seatTypesWithPrices.filter((seat) => {
|
|
29
|
+
if (seenPrices.has(seat.price))
|
|
30
|
+
return false;
|
|
31
|
+
seenPrices.add(seat.price);
|
|
32
|
+
return true;
|
|
33
|
+
});
|
|
34
|
+
return seatTypesWithPrices;
|
|
35
|
+
}
|
|
36
|
+
function getUniqueSeats(seatTypes) {
|
|
37
|
+
const allSeatTypes = getAllSeatTypes(seatTypes);
|
|
38
|
+
const seatMap = new Map();
|
|
39
|
+
allSeatTypes.forEach((seat) => {
|
|
40
|
+
if (SEAT_EXCEPTIONS.includes(seat.label))
|
|
41
|
+
return;
|
|
42
|
+
// Only check if the label already exists in the map, don't compare prices
|
|
43
|
+
if (!seatMap.has(seat.label)) {
|
|
44
|
+
seatMap.set(seat.label, seat);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
const uniqueByLabel = Array.from(seatMap.values());
|
|
48
|
+
const seenPrices = new Set();
|
|
49
|
+
return uniqueByLabel.filter((seat) => {
|
|
50
|
+
if (seenPrices.has(seat.price))
|
|
51
|
+
return false;
|
|
52
|
+
seenPrices.add(seat.price);
|
|
53
|
+
return true;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function getNumberOfSeats(seatTypes) {
|
|
57
|
+
return seatTypes.filter((val) => !SEAT_EXCEPTIONS.includes(val.label)).length;
|
|
58
|
+
}
|
|
59
|
+
function hasInclinationSeatTypes(seatTypes) {
|
|
60
|
+
return seatTypes.some((seat) => seat.label.includes("°"));
|
|
61
|
+
}
|
|
62
|
+
function getSeatTypeIcon(label, serviceItem) {
|
|
63
|
+
var _a, _b, _c, _d;
|
|
64
|
+
const seatLabel = String(label !== null && label !== void 0 ? label : "");
|
|
65
|
+
if (seatLabel.includes("180°"))
|
|
66
|
+
return (_a = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _a === void 0 ? void 0 : _a.seat180Icon;
|
|
67
|
+
if (seatLabel.includes("160°"))
|
|
68
|
+
return (_b = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _b === void 0 ? void 0 : _b.seat160Icon;
|
|
69
|
+
if (seatLabel.includes("140°"))
|
|
70
|
+
return (_c = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _c === void 0 ? void 0 : _c.seat140Icon;
|
|
71
|
+
return (_d = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _d === void 0 ? void 0 : _d.seatFallBackIcon;
|
|
72
|
+
}
|
|
73
|
+
function PeruSeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, serviceItem, renderIcon, discountSeatPriceColor, isSeatIcon, }) {
|
|
74
|
+
const uniqueSeats = getUniqueSeats(seatTypes);
|
|
75
|
+
const sortedSeatTypes = getSortedSeatTypes(seatTypes);
|
|
76
|
+
const numberOfSeats = getNumberOfSeats(seatTypes);
|
|
77
|
+
const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
|
|
78
|
+
const formatPrice = (price) => availableSeats <= 0
|
|
79
|
+
? CommonService.currency(0, currencySign)
|
|
80
|
+
: CommonService.currency(price, currencySign);
|
|
81
|
+
const renderSeatNames = () => {
|
|
82
|
+
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
83
|
+
return seats.map((val, key) => {
|
|
84
|
+
return SEAT_EXCEPTIONS.includes(val.label) ? null : (React.createElement("div", { className: "flex items-center" },
|
|
85
|
+
React.createElement("span", { key: key, className: `flex items-center justify-between text-[13.33px] whitespace-nowrap ${isSoldOut ? "text-[#c0c0c0]" : ""}` },
|
|
86
|
+
isSeatIcon && (React.createElement("img", { src: getSeatTypeIcon(val.label, serviceItem), alt: "seattype", style: {
|
|
87
|
+
width: "20px",
|
|
88
|
+
height: "20px",
|
|
89
|
+
marginRight: "5px",
|
|
90
|
+
} })),
|
|
91
|
+
typeof val.label === "string" || typeof val.label === "number"
|
|
92
|
+
? CommonService.truncateSeatLabel(val.label)
|
|
93
|
+
: null)));
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
const renderSeatPrices = () => {
|
|
97
|
+
const isMovilBus = (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_service_name) === "MovilBus" ||
|
|
98
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_service_name) === "Movil Bus";
|
|
99
|
+
const hasInclination = hasInclinationSeatTypes(seatTypes);
|
|
100
|
+
// Multiple unique seat types → show a price row for each (MovilBus or inclination types)
|
|
101
|
+
if ((isMovilBus || hasInclination) && uniqueSeats.length > 1) {
|
|
102
|
+
const filteredSeats = uniqueSeats.filter((s) => !SEAT_EXCEPTIONS.includes(s.label));
|
|
103
|
+
const prices = filteredSeats.map((val, key) => {
|
|
104
|
+
const { discountedPrice } = CommonService.calculateDiscountedPrice(val.price, serviceItem);
|
|
105
|
+
return (React.createElement("span", { key: key, className: "flex items-center text-[13.33px] bold-text" }, formatPrice(discountedPrice)));
|
|
106
|
+
});
|
|
107
|
+
// Only add "Desde" for inclination types, not for MovilBus
|
|
108
|
+
if (hasInclination && !isMovilBus) {
|
|
109
|
+
return (React.createElement("div", { className: "relative" },
|
|
110
|
+
React.createElement("span", { key: "desde", className: "text-[12px] font-normal text-[#6a6a6a] absolute", style: { top: "-15px" } }, "Desde"),
|
|
111
|
+
React.createElement("div", { className: "flex flex-col", style: { gap: "12px" } }, prices)));
|
|
112
|
+
}
|
|
113
|
+
return prices;
|
|
114
|
+
}
|
|
115
|
+
// Single seat type → original behaviour (one lowest-fare price)
|
|
116
|
+
const allSeats = getAllSeatTypes(seatTypes);
|
|
117
|
+
const lowestFare = allSeats.length > 0 ? allSeats[0].price : 0;
|
|
118
|
+
const { discountedPrice } = CommonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
119
|
+
return (React.createElement(React.Fragment, null,
|
|
120
|
+
React.createElement("span", { className: "flex items-center text-[13.33px] bold-text" }, formatPrice(discountedPrice))));
|
|
121
|
+
};
|
|
122
|
+
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
123
|
+
const discountedSeats = seats.map((seat) => (Object.assign(Object.assign({}, seat), CommonService.calculateDiscountedPrice(seat.price, serviceItem))));
|
|
124
|
+
const hasDiscount = discountedSeats.some((seat) => seat.originalPrice !== seat.discountedPrice);
|
|
125
|
+
const discountSeat = discountedSeats
|
|
126
|
+
.filter((seat) => !SEAT_EXCEPTIONS.includes(seat.label))
|
|
127
|
+
.sort((a, b) => a.discountedPrice - b.discountedPrice)[0];
|
|
128
|
+
const discountValue = (() => {
|
|
129
|
+
if ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_type) === "percentage" &&
|
|
130
|
+
typeof (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_value) === "number") {
|
|
131
|
+
return Math.round(serviceItem.discount_value);
|
|
132
|
+
}
|
|
133
|
+
if ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_type) === "fixed" && discountSeat) {
|
|
134
|
+
const { originalPrice, discountedPrice } = discountSeat;
|
|
135
|
+
if (originalPrice > 0 && originalPrice !== discountedPrice) {
|
|
136
|
+
return Math.round(((originalPrice - discountedPrice) / originalPrice) * 100);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
})();
|
|
141
|
+
const isMaxDiscountApplied = (() => {
|
|
142
|
+
const { discount_type, discount_value, max_discount } = serviceItem !== null && serviceItem !== void 0 ? serviceItem : {};
|
|
143
|
+
if (discount_type === "percentage" &&
|
|
144
|
+
typeof discount_value === "number" &&
|
|
145
|
+
max_discount != null &&
|
|
146
|
+
max_discount > 0 &&
|
|
147
|
+
discountSeat) {
|
|
148
|
+
const rawPercentageDiscount = (discountSeat.originalPrice * discount_value) / 100;
|
|
149
|
+
return rawPercentageDiscount > max_discount;
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
})();
|
|
153
|
+
const renderLabels = () => {
|
|
154
|
+
const isMovilBus = (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_service_name) === "MovilBus" ||
|
|
155
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_service_name) === "Movil Bus";
|
|
156
|
+
const hasInclination = hasInclinationSeatTypes(seatTypes);
|
|
157
|
+
// Multiple unique seat types → show a label row for each (MovilBus or inclination types)
|
|
158
|
+
if ((isMovilBus || hasInclination) && uniqueSeats.length > 1) {
|
|
159
|
+
return uniqueSeats
|
|
160
|
+
.filter((s) => !SEAT_EXCEPTIONS.includes(s.label))
|
|
161
|
+
.map((val, key) => (React.createElement("span", { key: key, className: `flex items-center justify-between text-[13.33px] ${isSoldOut ? "text-[#c0c0c0]" : ""}` },
|
|
162
|
+
isSeatIcon && !hasDiscount && (React.createElement("img", { src: getSeatTypeIcon(val.label, serviceItem), alt: "seattype", style: {
|
|
163
|
+
width: "20px",
|
|
164
|
+
height: "20px",
|
|
165
|
+
marginRight: "5px",
|
|
166
|
+
} })),
|
|
167
|
+
CommonService.truncateSeatLabel(val.label))));
|
|
168
|
+
}
|
|
169
|
+
// Single seat type → original behaviour
|
|
170
|
+
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
171
|
+
const filteredSeats = seats.filter((s) => !SEAT_EXCEPTIONS.includes(s.label));
|
|
172
|
+
const seatLabel = filteredSeats.length > 0
|
|
173
|
+
? removeDuplicateSeats
|
|
174
|
+
? filteredSeats[0].label
|
|
175
|
+
: filteredSeats[0].label
|
|
176
|
+
: null;
|
|
177
|
+
return (React.createElement(React.Fragment, null,
|
|
178
|
+
hasDiscount && (React.createElement("span", { className: "text-[13.33px]", style: {
|
|
179
|
+
color: "#999",
|
|
180
|
+
} }, "Antes")),
|
|
181
|
+
React.createElement("span", { className: "text-[13.33px] flex flex-col" }, !hasDiscount ? (React.createElement("span", { className: "text-[13.33px] whitespace-nowrap flex items-center", style: {
|
|
182
|
+
opacity: isSoldOut ? 0.5 : 1,
|
|
183
|
+
} },
|
|
184
|
+
isSeatIcon && !hasDiscount && (React.createElement("img", { src: getSeatTypeIcon(seatLabel, serviceItem), alt: "seattype", style: {
|
|
185
|
+
width: "20px",
|
|
186
|
+
height: "20px",
|
|
187
|
+
marginRight: "5px",
|
|
188
|
+
} })),
|
|
189
|
+
CommonService.capitalize(seatLabel))) : (React.createElement("span", { className: "text-[13.33px]" }, "Desde")))));
|
|
190
|
+
};
|
|
191
|
+
if (hasDiscount && discountSeat) {
|
|
192
|
+
return (React.createElement("div", { className: "grid grid-cols-2 items-center text-[13.33px] relative", style: { opacity: isSoldOut ? 0.5 : 1 } },
|
|
193
|
+
React.createElement("div", { className: "col-start-1 row-start-2 flex items-center" },
|
|
194
|
+
React.createElement("span", { className: "text-[13.33px] font-normal leading-[22px] text-[#ccc]" }, "Antes")),
|
|
195
|
+
React.createElement("div", { className: "col-start-1 row-start-3 flex h-[20px] items-end" },
|
|
196
|
+
React.createElement("span", { className: "text-[13.33px] font-normal leading-[20px] text-[#464647]" }, "Desde")),
|
|
197
|
+
React.createElement("div", { className: "col-start-2 row-start-1 flex items-center justify-center absolute", style: { top: "-22px", left: "50%", transform: "translateX(-50%)" } }, discountValue != null || isMaxDiscountApplied ? (React.createElement("span", { className: "rounded-[100px] bg-[#ff5964] px-[6px] text-[12px] bold-text leading-[20px] text-white", style: {
|
|
198
|
+
animation: "pulse-zoom 2s ease-in-out infinite",
|
|
199
|
+
whiteSpace: "nowrap",
|
|
200
|
+
backgroundColor: discountSeatPriceColor,
|
|
201
|
+
} }, isMaxDiscountApplied
|
|
202
|
+
? `${CommonService.currency(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.max_discount)} OFF`
|
|
203
|
+
: `${discountValue}% OFF`)) : null),
|
|
204
|
+
React.createElement("div", { className: "col-start-2 row-start-2 flex items-center justify-center ", style: { textAlign: "center" } },
|
|
205
|
+
React.createElement("span", { className: "text-[13.33px] font-normal leading-[20px] relative whitespace-nowrap", style: {
|
|
206
|
+
position: "relative",
|
|
207
|
+
color: discountSeatPriceColor,
|
|
208
|
+
} },
|
|
209
|
+
formatPrice(discountSeat.originalPrice),
|
|
210
|
+
React.createElement("span", { style: {
|
|
211
|
+
position: "absolute",
|
|
212
|
+
left: "-2px",
|
|
213
|
+
top: "50%",
|
|
214
|
+
width: "calc(100% + 4px)",
|
|
215
|
+
height: "1px",
|
|
216
|
+
backgroundColor: discountSeatPriceColor,
|
|
217
|
+
transform: "rotate(-10deg)",
|
|
218
|
+
transformOrigin: "center",
|
|
219
|
+
} }))),
|
|
220
|
+
React.createElement("div", { className: "col-start-2 row-start-3 flex h-[30px] items-end justify-center relative" },
|
|
221
|
+
React.createElement("span", { className: "flex items-center gap-[6px] bold-text leading-[30px]", style: {
|
|
222
|
+
color: isSoldOut
|
|
223
|
+
? "#c0c0c0"
|
|
224
|
+
: discountSeatPriceColor,
|
|
225
|
+
fontSize: "22px",
|
|
226
|
+
} },
|
|
227
|
+
React.createElement("div", { className: "absolute", style: {
|
|
228
|
+
left: "-16px",
|
|
229
|
+
bottom: "1px",
|
|
230
|
+
} }, renderIcon === null || renderIcon === void 0 ? void 0 : renderIcon("fireIcon", "16px")),
|
|
231
|
+
availableSeats <= 0
|
|
232
|
+
? CommonService.currency(0, currencySign)
|
|
233
|
+
: CommonService.discountedCurrency(discountSeat.discountedPrice, currencySign)))));
|
|
234
|
+
}
|
|
235
|
+
return (React.createElement("div", { className: "relative flex gap-[10px] text-[13.33px] justify-between min-h-[2.2rem]", style: isCentered ? { alignItems: "center" } : {} },
|
|
236
|
+
React.createElement("div", { className: "flex flex-col justify-between", style: { gap: "10px" } }, renderLabels()),
|
|
237
|
+
React.createElement("div", { className: "flex flex-col justify-between absolute inset-y-0 right-0 left-1/2 h-full", style: {
|
|
238
|
+
color: isSoldOut ? "#c0c0c0" : priceColor,
|
|
239
|
+
top: 0,
|
|
240
|
+
bottom: 0,
|
|
241
|
+
left: "73%",
|
|
242
|
+
right: 0,
|
|
243
|
+
justifyContent: isCentered ? "center" : "",
|
|
244
|
+
gap: "10px",
|
|
245
|
+
} }, renderSeatPrices())));
|
|
246
|
+
}
|
|
247
|
+
export default PeruSeatSection;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
const SlidingModal = ({ isOpen, onClose, title = "Detalles del viaje", children, }) => {
|
|
3
|
+
// Close on backdrop click
|
|
4
|
+
const handleBackdropClick = (e) => {
|
|
5
|
+
if (e.target === e.currentTarget) {
|
|
6
|
+
onClose();
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
return (React.createElement(React.Fragment, null,
|
|
10
|
+
React.createElement("style", null, `
|
|
11
|
+
@keyframes slidingModalFadeIn {
|
|
12
|
+
from { opacity: 0; }
|
|
13
|
+
to { opacity: 1; }
|
|
14
|
+
}
|
|
15
|
+
@keyframes slidingModalSlideUp {
|
|
16
|
+
from { transform: translateY(100%); }
|
|
17
|
+
to { transform: translateY(0); }
|
|
18
|
+
}
|
|
19
|
+
@keyframes slidingModalSlideDown {
|
|
20
|
+
from { transform: translateY(0); }
|
|
21
|
+
to { transform: translateY(100%); }
|
|
22
|
+
}
|
|
23
|
+
.sliding-modal-backdrop {
|
|
24
|
+
position: fixed;
|
|
25
|
+
inset: 0;
|
|
26
|
+
background: rgba(0, 0, 0, 0.4);
|
|
27
|
+
z-index: 1000;
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: flex-end;
|
|
30
|
+
backdrop-filter: blur(2px);
|
|
31
|
+
-webkit-backdrop-filter: blur(2px);
|
|
32
|
+
animation: slidingModalFadeIn 0.25s ease forwards;
|
|
33
|
+
}
|
|
34
|
+
.sliding-modal-sheet {
|
|
35
|
+
width: 100%;
|
|
36
|
+
max-height: 85vh;
|
|
37
|
+
background: #fff;
|
|
38
|
+
border-radius: 24px 24px 0 0;
|
|
39
|
+
overflow: hidden;
|
|
40
|
+
display: flex;
|
|
41
|
+
flex-direction: column;
|
|
42
|
+
animation: slidingModalSlideUp 0.35s cubic-bezier(0.32, 0.72, 0, 1) forwards;
|
|
43
|
+
box-shadow: 0 -4px 32px rgba(0,0,0,0.15);
|
|
44
|
+
}
|
|
45
|
+
.sliding-modal-header {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: space-between;
|
|
49
|
+
padding: 20px 20px 14px;
|
|
50
|
+
border-bottom: 1px solid #f0f0f0;
|
|
51
|
+
flex-shrink: 0;
|
|
52
|
+
}
|
|
53
|
+
.sliding-modal-handle {
|
|
54
|
+
width: 36px;
|
|
55
|
+
height: 4px;
|
|
56
|
+
background: #ddd;
|
|
57
|
+
border-radius: 99px;
|
|
58
|
+
margin: 12px auto 0;
|
|
59
|
+
flex-shrink: 0;
|
|
60
|
+
}
|
|
61
|
+
.sliding-modal-title {
|
|
62
|
+
font-size: 18px;
|
|
63
|
+
font-weight: 700;
|
|
64
|
+
color: #1a1a1a;
|
|
65
|
+
margin: 0;
|
|
66
|
+
}
|
|
67
|
+
.sliding-modal-close-btn {
|
|
68
|
+
width: 32px;
|
|
69
|
+
height: 32px;
|
|
70
|
+
border-radius: 50%;
|
|
71
|
+
background: #f5f5f5;
|
|
72
|
+
border: none;
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
transition: background 0.15s ease;
|
|
78
|
+
flex-shrink: 0;
|
|
79
|
+
}
|
|
80
|
+
.sliding-modal-close-btn:hover {
|
|
81
|
+
background: #e8e8e8;
|
|
82
|
+
}
|
|
83
|
+
.sliding-modal-body {
|
|
84
|
+
overflow-y: auto;
|
|
85
|
+
padding: 16px 20px 32px;
|
|
86
|
+
flex: 1;
|
|
87
|
+
-webkit-overflow-scrolling: touch;
|
|
88
|
+
}
|
|
89
|
+
`),
|
|
90
|
+
isOpen ? (React.createElement("div", { className: "sliding-modal-backdrop", onClick: handleBackdropClick },
|
|
91
|
+
React.createElement("div", { className: "sliding-modal-sheet" },
|
|
92
|
+
React.createElement("div", { className: "sliding-modal-handle" }),
|
|
93
|
+
React.createElement("div", { className: "sliding-modal-header" },
|
|
94
|
+
React.createElement("h2", { className: "sliding-modal-title" }, title),
|
|
95
|
+
React.createElement("button", { className: "sliding-modal-close-btn", onClick: onClose, "aria-label": "Close" },
|
|
96
|
+
React.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#555", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
97
|
+
React.createElement("path", { d: "M18 6L6 18M6 6l12 12" })))),
|
|
98
|
+
React.createElement("div", { className: "sliding-modal-body" }, children)))) : null));
|
|
99
|
+
};
|
|
100
|
+
export default SlidingModal;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as SlidingModal } from "./SlidingModal";
|
|
@@ -24,6 +24,7 @@ interface BottomAmenitiesMobileProps {
|
|
|
24
24
|
ladiesBookedSeats?: string;
|
|
25
25
|
isDpEnabled?: boolean;
|
|
26
26
|
isTrain?: boolean;
|
|
27
|
+
seatCategoryText?: string;
|
|
27
28
|
}
|
|
28
|
-
declare function BottomAmenitiesMobile({ isSoldOut, amenitiesNodes, hoursIcon, duration, isDirectTrip, directoColor, directoAnim, isChangeTicket, isPetSeat, petSeatInfo, petFriendlyAnim, flexibleAnim, isTrackingEnabled, locationAnim, downArrowIcon, showDropdown, setShowDropdown, onDropdownToggle, isItemExpanded, isPeru, femaleAnim, ladiesBookedSeats, isDpEnabled, isTrain, }: BottomAmenitiesMobileProps): React.ReactElement;
|
|
29
|
+
declare function BottomAmenitiesMobile({ isSoldOut, amenitiesNodes, hoursIcon, duration, isDirectTrip, directoColor, directoAnim, isChangeTicket, isPetSeat, petSeatInfo, petFriendlyAnim, flexibleAnim, isTrackingEnabled, locationAnim, downArrowIcon, showDropdown, setShowDropdown, onDropdownToggle, isItemExpanded, isPeru, femaleAnim, ladiesBookedSeats, isDpEnabled, isTrain, seatCategoryText, }: BottomAmenitiesMobileProps): React.ReactElement;
|
|
29
30
|
export default BottomAmenitiesMobile;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import LottiePlayer from "../../assets/LottiePlayer";
|
|
3
3
|
import DateService from "../../utils/DateService";
|
|
4
|
-
function BottomAmenitiesMobile({ isSoldOut, amenitiesNodes, hoursIcon, duration, isDirectTrip, directoColor, directoAnim, isChangeTicket, isPetSeat, petSeatInfo, petFriendlyAnim, flexibleAnim, isTrackingEnabled, locationAnim, downArrowIcon, showDropdown, setShowDropdown, onDropdownToggle, isItemExpanded, isPeru, femaleAnim, ladiesBookedSeats, isDpEnabled, isTrain, }) {
|
|
4
|
+
function BottomAmenitiesMobile({ isSoldOut, amenitiesNodes, hoursIcon, duration, isDirectTrip, directoColor, directoAnim, isChangeTicket, isPetSeat, petSeatInfo, petFriendlyAnim, flexibleAnim, isTrackingEnabled, locationAnim, downArrowIcon, showDropdown, setShowDropdown, onDropdownToggle, isItemExpanded, isPeru, femaleAnim, ladiesBookedSeats, isDpEnabled, isTrain, seatCategoryText, }) {
|
|
5
5
|
return (React.createElement("div", { className: `${"flex justify-between items-center items-center "}` },
|
|
6
6
|
React.createElement("div", { className: "w-[55%] flex justify-between items-center" },
|
|
7
7
|
React.createElement("div", { style: { opacity: isSoldOut ? 0.5 : 1 } }, amenitiesNodes),
|
|
@@ -11,6 +11,7 @@ function BottomAmenitiesMobile({ isSoldOut, amenitiesNodes, hoursIcon, duration,
|
|
|
11
11
|
React.createElement("div", { className: `cursor-default group min-[420]:text-[13px] text-[12px] ${isSoldOut ? "text-[#c0c0c0]" : ""}`, style: { lineHeight: "normal" } },
|
|
12
12
|
DateService.formatDuration(duration),
|
|
13
13
|
"hrs"))),
|
|
14
|
+
seatCategoryText && (React.createElement("div", { className: "flex-1 text-right whitespace-nowrap min-[420]:text-[13px] text-[12px]", style: { opacity: isSoldOut ? 0.5 : 1 } }, seatCategoryText)),
|
|
14
15
|
React.createElement("div", { className: "flex items-center" },
|
|
15
16
|
React.createElement("div", null, (isChangeTicket || isPetSeat) && (React.createElement("div", { className: "flex items-center" },
|
|
16
17
|
petSeatInfo && Object.keys(petSeatInfo).length > 0 ? (React.createElement("div", { className: "flex items-center" },
|
|
@@ -28,6 +28,9 @@ const SeatRow = ({ type, index, displayLabel, fare, isSoldOut, seatPriceColor, h
|
|
|
28
28
|
const getFilteredSeats = (item) => {
|
|
29
29
|
return item;
|
|
30
30
|
};
|
|
31
|
+
function hasInclinationSeatTypes(seatTypes) {
|
|
32
|
+
return seatTypes.some((seat) => seat.label.includes("°"));
|
|
33
|
+
}
|
|
31
34
|
const getUniqueSeats = (data, limit) => {
|
|
32
35
|
var _a;
|
|
33
36
|
const seatMap = new Map();
|
|
@@ -68,6 +71,7 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
68
71
|
const priceColor = isSoldOut ? "#bbb" : seatPriceColor;
|
|
69
72
|
const isMovilBus = (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_service_name) === "MovilBus" ||
|
|
70
73
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_service_name) === "Movil Bus";
|
|
74
|
+
const hasInclination = hasInclinationSeatTypes(seatTypesData !== null && seatTypesData !== void 0 ? seatTypesData : []);
|
|
71
75
|
// Fetch ALL unique seats (no slice limit) for the multi-row MovilBus case
|
|
72
76
|
const uniqueSeats = getUniqueSeats(seatTypesData !== null && seatTypesData !== void 0 ? seatTypesData : [], Infinity);
|
|
73
77
|
// MovilBus + multiple unique seat types → render a row per seat
|
|
@@ -79,7 +83,17 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
79
83
|
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: priceColor } }, commonService.currency(discountedPrice, currencySign))));
|
|
80
84
|
})));
|
|
81
85
|
}
|
|
82
|
-
//
|
|
86
|
+
// Inclination seat types + multiple unique seat types → render a row per seat with "Desde" above prices
|
|
87
|
+
if (hasInclination && uniqueSeats.length > 1) {
|
|
88
|
+
return (React.createElement("div", { className: "relative" },
|
|
89
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] absolute", style: { color: "#6a6a6a", top: -20, right: 0 } }, "Desde"),
|
|
90
|
+
uniqueSeats.map((seat, key) => {
|
|
91
|
+
const { discountedPrice } = commonService.calculateDiscountedPrice(Number(seat.fare), serviceItem);
|
|
92
|
+
return (React.createElement("div", { key: key, className: "w-[100%] flex flex-row justify-between items-center", style: { marginTop: key > 0 ? "8px" : "0" } },
|
|
93
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text whitespace-nowrap", style: { color: isSoldOut ? "#bbb" : "#464647" } }, commonService.truncateSeatLabel(seat.label)),
|
|
94
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: priceColor } }, commonService.currency(discountedPrice, currencySign))));
|
|
95
|
+
})));
|
|
96
|
+
}
|
|
83
97
|
const { originalPrice, discountedPrice } = commonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
84
98
|
const seatLabel = uniqueSeats.length > 0
|
|
85
99
|
? commonService.truncateSeatLabel(uniqueSeats[0].label)
|
package/package.json
CHANGED
|
@@ -33,10 +33,10 @@ import DurationBlock from "../../ui/DurationBlock";
|
|
|
33
33
|
import PetBlock from "../../ui/PetBlock";
|
|
34
34
|
import FlexibleBlock from "../../ui/FlexibleBlock";
|
|
35
35
|
import AmenitiesBlock from "../../ui/AmenitiesBlock";
|
|
36
|
-
import
|
|
36
|
+
import PeruSeatSection from "../../ui/SeatSection/PeruSeatSection";
|
|
37
37
|
import KuposButton from "../../ui/KuposButton/KuposButton";
|
|
38
38
|
import BottomAmenities from "../../ui/BottomAmenities/BottomAmenities";
|
|
39
|
-
import
|
|
39
|
+
import PeruOfferBanner from "../../ui/PeruOfferBanner";
|
|
40
40
|
import ServiceBadges from "../../ui/ServiceBadges/ServiceBadges";
|
|
41
41
|
|
|
42
42
|
const SEAT_EXCEPTIONS = ["Asiento mascota"];
|
|
@@ -547,6 +547,19 @@ function PeruServiceItemDesktop({
|
|
|
547
547
|
/>
|
|
548
548
|
),
|
|
549
549
|
},
|
|
550
|
+
{
|
|
551
|
+
key: "seatCategory",
|
|
552
|
+
width: "40%",
|
|
553
|
+
condition: serviceItem.api_type === 78 && !!serviceItem.number,
|
|
554
|
+
render: (
|
|
555
|
+
<span
|
|
556
|
+
className="text-[13.33px] whitespace-nowrap ml-auto mt-[3px] translate-x-[100px]"
|
|
557
|
+
style={{ opacity: isSoldOut ? 0.5 : 1 }}
|
|
558
|
+
>
|
|
559
|
+
{serviceItem.number}
|
|
560
|
+
</span>
|
|
561
|
+
),
|
|
562
|
+
},
|
|
550
563
|
|
|
551
564
|
{
|
|
552
565
|
key: "flexible",
|
|
@@ -614,7 +627,7 @@ function PeruServiceItemDesktop({
|
|
|
614
627
|
} `}
|
|
615
628
|
>
|
|
616
629
|
{(serviceItem?.offer_text || hasDpEnabled) && !isSoldOut && (
|
|
617
|
-
<
|
|
630
|
+
<PeruOfferBanner
|
|
618
631
|
offerGradient={offerGradient}
|
|
619
632
|
isSoldOut={isSoldOut}
|
|
620
633
|
serviceItem={serviceItem}
|
|
@@ -624,8 +637,10 @@ function PeruServiceItemDesktop({
|
|
|
624
637
|
viewersConfig={viewersConfig}
|
|
625
638
|
getAnimationIcon={getAnimationIcon}
|
|
626
639
|
showLoginOption={showLoginOption}
|
|
627
|
-
isNewUiEnabled={isNewUiEnabled}
|
|
628
640
|
colors={colors}
|
|
641
|
+
coachKey={coachKey}
|
|
642
|
+
isExpand={isExpand}
|
|
643
|
+
isNewUiEnabled={isNewUiEnabled}
|
|
629
644
|
/>
|
|
630
645
|
)}
|
|
631
646
|
<div
|
|
@@ -854,7 +869,7 @@ function PeruServiceItemDesktop({
|
|
|
854
869
|
></div>
|
|
855
870
|
{/* SEATS */}
|
|
856
871
|
<div className="content-center">
|
|
857
|
-
<
|
|
872
|
+
<PeruSeatSection
|
|
858
873
|
seatTypes={serviceItem.seat_types}
|
|
859
874
|
serviceItem={serviceItem}
|
|
860
875
|
availableSeats={serviceItem.available_seats}
|
|
@@ -862,7 +877,6 @@ function PeruServiceItemDesktop({
|
|
|
862
877
|
priceColor={colors.priceColor}
|
|
863
878
|
currencySign={currencySign}
|
|
864
879
|
removeDuplicateSeats={removeDuplicateSeats}
|
|
865
|
-
isPeru={isPeru}
|
|
866
880
|
renderIcon={renderIcon}
|
|
867
881
|
discountSeatPriceColor={colors.discountSeatPriceColor}
|
|
868
882
|
isSeatIcon={isSeatIcon}
|