kupos-ui-components-lib 9.1.8 → 9.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ServiceItem/ServiceItemDesktop.js +1 -1
- package/dist/components/ServiceItem/ServiceItemMobile.js +2 -2
- package/dist/styles.css +3 -0
- package/dist/ui/SeatSection/SeatSection.d.ts +2 -1
- package/dist/ui/SeatSection/SeatSection.js +24 -7
- package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +2 -1
- package/dist/ui/mobileweb/DateTimeSectionMobile.js +2 -2
- package/dist/ui/mobileweb/SeatSectionMobile.d.ts +2 -1
- package/dist/ui/mobileweb/SeatSectionMobile.js +18 -8
- package/dist/utils/CommonService.d.ts +8 -0
- package/dist/utils/CommonService.js +17 -0
- package/package.json +1 -1
- package/src/components/ServiceItem/ServiceItemDesktop.tsx +1 -0
- package/src/components/ServiceItem/ServiceItemMobile.tsx +2 -1
- package/src/ui/SeatSection/SeatSection.tsx +61 -15
- package/src/ui/mobileweb/DateTimeSectionMobile.tsx +3 -0
- package/src/ui/mobileweb/SeatSectionMobile.tsx +35 -6
- package/src/utils/CommonService.ts +34 -0
|
@@ -303,7 +303,7 @@ function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, child
|
|
|
303
303
|
backgroundColor: "#ccc",
|
|
304
304
|
} }),
|
|
305
305
|
React.createElement("div", { className: "content-center" },
|
|
306
|
-
React.createElement(SeatSection, { seatTypes: serviceItem.seat_types, availableSeats: serviceItem.available_seats, isSoldOut: isSoldOut, priceColor: colors.priceColor, currencySign: currencySign, removeDuplicateSeats: removeDuplicateSeats, isPeru: isPeru })),
|
|
306
|
+
React.createElement(SeatSection, { seatTypes: serviceItem.seat_types, serviceItem: serviceItem, availableSeats: serviceItem.available_seats, isSoldOut: isSoldOut, priceColor: colors.priceColor, currencySign: currencySign, removeDuplicateSeats: removeDuplicateSeats, isPeru: isPeru })),
|
|
307
307
|
React.createElement("div", null,
|
|
308
308
|
showLastSeats ? (React.createElement("div", { className: "flex justify-end mr-[11px] ", style: {
|
|
309
309
|
position: "absolute",
|
|
@@ -114,7 +114,7 @@ function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, o
|
|
|
114
114
|
// className={`relative ${
|
|
115
115
|
// serviceItem.offer_text ? "mb-[55px]" : "mb-[14px]"
|
|
116
116
|
// }
|
|
117
|
-
className: `relative ${serviceItem.offer_text ? "mb-[
|
|
117
|
+
className: `relative ${!serviceItem.offer_text ? "mb-[14px]" : showTopLabel || (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_direct_trip) ? "mb-[20px]" : "mb-[12px]"} ${(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_direct_trip) ||
|
|
118
118
|
isConexion ||
|
|
119
119
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.train_type_label) === "Tren Express (Nuevo)" ||
|
|
120
120
|
showTopLabel
|
|
@@ -141,7 +141,7 @@ function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, o
|
|
|
141
141
|
React.createElement("span", { className: "ml-[3px] min-[420]:text-[13px] text-[12px] text-ellipsis" }, serviceItem.operator_details[2]))))) : null),
|
|
142
142
|
showLastSeats ? (React.createElement("div", { className: "flex justify-end " }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.available_seats) < 10 &&
|
|
143
143
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.available_seats) > 0 && (React.createElement("div", { className: "text-[10px] text-[#464647] text-center" }, "\u00A1 \u00DAltimos Asientos!")))) : null),
|
|
144
|
-
React.createElement(DateTimeSectionMobile, { onBookButtonPress: onBookButtonPress, isCiva: isCiva, isSoldOut: isSoldOut, isLinatal: isLinatal, isPeru: isPeru, orignLabel: orignLabel, destinationLabel: destinationLabel, originIcon: (_a = serviceItem.icons) === null || _a === void 0 ? void 0 : _a.origin, destinationIcon: (_b = serviceItem.icons) === null || _b === void 0 ? void 0 : _b.destination, travelDate: serviceItem.travel_date, arrivalDate: serviceItem.arrival_date, depTime: serviceItem.dep_time, arrTime: serviceItem.arr_time, seatTypes: serviceItem.seat_types, seatPriceColor: colors.seatPriceColor, currencySign: currencySign, availableSeats: serviceItem.available_seats, removeDuplicateSeats: removeDuplicateSeats }),
|
|
144
|
+
React.createElement(DateTimeSectionMobile, { onBookButtonPress: onBookButtonPress, isCiva: isCiva, isSoldOut: isSoldOut, isLinatal: isLinatal, isPeru: isPeru, orignLabel: orignLabel, destinationLabel: destinationLabel, originIcon: (_a = serviceItem.icons) === null || _a === void 0 ? void 0 : _a.origin, destinationIcon: (_b = serviceItem.icons) === null || _b === void 0 ? void 0 : _b.destination, travelDate: serviceItem.travel_date, arrivalDate: serviceItem.arrival_date, depTime: serviceItem.dep_time, arrTime: serviceItem.arr_time, seatTypes: serviceItem.seat_types, seatPriceColor: colors.seatPriceColor, currencySign: currencySign, availableSeats: serviceItem.available_seats, removeDuplicateSeats: removeDuplicateSeats, serviceItem: serviceItem }),
|
|
145
145
|
React.createElement("div", { className: "bg-[#E6E6E6] mt-[10px] mb-[10px] h-[1px]" }),
|
|
146
146
|
React.createElement(BottomAmenitiesMobile, { isSoldOut: isSoldOut, amenitiesNodes: amenities(), hoursIcon: renderIcon("hours", "14px"), duration: (_c = serviceItem.duration) === null || _c === void 0 ? void 0 : _c.toString(), isDirectTrip: serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_direct_trip, directoColor: colors.directoColor, directoAnim: serviceItem.icons.directoAnim, isChangeTicket: serviceItem.is_change_ticket, isPetSeat: isPetSeat, petSeatInfo: serviceItem.pet_seat_info, petFriendlyAnim: serviceItem.icons.petFriendlyAnim, flexibleAnim: serviceItem.icons.flexibleAnim, isTrackingEnabled: serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_tracking_enabled, locationAnim: serviceItem.icons.locationAnim, downArrowIcon: serviceItem.icons.downArrow, showDropdown: isItemExpanded, setShowDropdown: () => setIsExpanded(isItemExpanded ? null : serviceItem.id),
|
|
147
147
|
// onDropdownToggle={() => {
|
package/dist/styles.css
CHANGED
|
@@ -12,6 +12,7 @@ interface SeatSectionProps {
|
|
|
12
12
|
currencySign?: string;
|
|
13
13
|
removeDuplicateSeats?: boolean;
|
|
14
14
|
isPeru?: boolean;
|
|
15
|
+
serviceItem?: any;
|
|
15
16
|
}
|
|
16
|
-
declare function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, isPeru, }: SeatSectionProps): React.ReactElement;
|
|
17
|
+
declare function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, isPeru, serviceItem, }: SeatSectionProps): React.ReactElement;
|
|
17
18
|
export default SeatSection;
|
|
@@ -54,7 +54,7 @@ function getUniqueSeats(seatTypes) {
|
|
|
54
54
|
function getNumberOfSeats(seatTypes) {
|
|
55
55
|
return seatTypes.filter((val) => !SEAT_EXCEPTIONS.includes(val.label)).length;
|
|
56
56
|
}
|
|
57
|
-
function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, isPeru, }) {
|
|
57
|
+
function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, isPeru, serviceItem, }) {
|
|
58
58
|
const uniqueSeats = getUniqueSeats(seatTypes);
|
|
59
59
|
const sortedSeatTypes = getSortedSeatTypes(seatTypes);
|
|
60
60
|
const numberOfSeats = getNumberOfSeats(seatTypes);
|
|
@@ -74,14 +74,26 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
|
|
|
74
74
|
if (isPeru) {
|
|
75
75
|
const allSeats = getAllSeatTypes(seatTypes);
|
|
76
76
|
const lowestFare = allSeats.length > 0 ? allSeats[0].price : 0;
|
|
77
|
-
|
|
77
|
+
const { originalPrice, discountedPrice } = CommonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
78
|
+
return (React.createElement(React.Fragment, null,
|
|
79
|
+
originalPrice !== discountedPrice && (React.createElement("span", { className: "text-[13.33px]", style: strikethroughStyle }, formatPrice(originalPrice))),
|
|
80
|
+
React.createElement("span", { className: "flex items-center text-[13.33px] bold-text" }, formatPrice(discountedPrice))));
|
|
78
81
|
}
|
|
79
82
|
if (removeDuplicateSeats) {
|
|
80
|
-
return uniqueSeats.map((val, key) =>
|
|
83
|
+
return uniqueSeats.map((val, key) => {
|
|
84
|
+
const { discountedPrice } = CommonService.calculateDiscountedPrice(val.price, serviceItem);
|
|
85
|
+
return React.createElement("span", { key: key }, formatPrice(discountedPrice));
|
|
86
|
+
});
|
|
81
87
|
}
|
|
82
|
-
return sortedSeatTypes.map((val, key) =>
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
return sortedSeatTypes.map((val, key) => {
|
|
89
|
+
if (SEAT_EXCEPTIONS.includes(val.label))
|
|
90
|
+
return null;
|
|
91
|
+
const { discountedPrice } = CommonService.calculateDiscountedPrice(val.price, serviceItem);
|
|
92
|
+
return (React.createElement("span", { key: key, className: "flex items-center text-[13.33px] bold-text" }, typeof discountedPrice === "string" ||
|
|
93
|
+
typeof discountedPrice === "number"
|
|
94
|
+
? formatPrice(discountedPrice)
|
|
95
|
+
: null));
|
|
96
|
+
});
|
|
85
97
|
};
|
|
86
98
|
const renderLabels = () => {
|
|
87
99
|
if (isPeru) {
|
|
@@ -98,6 +110,10 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
|
|
|
98
110
|
const strikethroughStyle = Object.assign({ color: "#ccc", display: "flex", textAlign: "end", textDecoration: "line-through" }, (isPeru
|
|
99
111
|
? { position: "relative", top: 0 }
|
|
100
112
|
: { position: "absolute", top: isCentered ? "-10px" : "-18px" }));
|
|
113
|
+
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
114
|
+
const discountedSeats = seats.map((seat) => (Object.assign(Object.assign({}, seat), CommonService.calculateDiscountedPrice(seat.price, serviceItem))));
|
|
115
|
+
const highestOriginalPrice = Math.max(...discountedSeats.map((seat) => seat.originalPrice));
|
|
116
|
+
const hasDiscount = discountedSeats.some((seat) => seat.originalPrice !== seat.discountedPrice);
|
|
101
117
|
return (React.createElement("div", { className: "relative flex gap-[10px] text-[13.33px] justify-between min-h-[2.2rem]", style: isCentered ? { alignItems: "center" } : {} },
|
|
102
118
|
React.createElement("div", { className: "flex flex-col justify-between", style: { gap: "10px" } }, renderLabels()),
|
|
103
119
|
React.createElement("div", { className: "flex flex-col justify-between absolute inset-y-0 right-0 left-1/2 h-full", style: {
|
|
@@ -109,7 +125,8 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
|
|
|
109
125
|
justifyContent: isCentered ? "center" : "",
|
|
110
126
|
gap: "10px",
|
|
111
127
|
} },
|
|
112
|
-
React.createElement("span", { className: "text-[13.33px]", style: strikethroughStyle },
|
|
128
|
+
isPeru && (React.createElement("span", { className: "text-[13.33px]", style: strikethroughStyle }, formatPrice(1000))),
|
|
129
|
+
hasDiscount && (React.createElement("span", { className: "text-[13.33px]", style: strikethroughStyle }, formatPrice(highestOriginalPrice))),
|
|
113
130
|
renderSeatPrices())));
|
|
114
131
|
}
|
|
115
132
|
export default SeatSection;
|
|
@@ -18,6 +18,7 @@ interface DateTimeSectionMobileProps {
|
|
|
18
18
|
currencySign: string;
|
|
19
19
|
availableSeats: number;
|
|
20
20
|
removeDuplicateSeats?: boolean;
|
|
21
|
+
serviceItem?: any;
|
|
21
22
|
}
|
|
22
|
-
declare function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal, isPeru, orignLabel, destinationLabel, originIcon, destinationIcon, travelDate, arrivalDate, depTime, arrTime, seatTypes, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, }: DateTimeSectionMobileProps): React.ReactElement;
|
|
23
|
+
declare function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal, isPeru, orignLabel, destinationLabel, originIcon, destinationIcon, travelDate, arrivalDate, depTime, arrTime, seatTypes, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, }: DateTimeSectionMobileProps): React.ReactElement;
|
|
23
24
|
export default DateTimeSectionMobile;
|
|
@@ -31,7 +31,7 @@ const TimeRow = ({ label, icon, alt, date, timeContent, isSoldOut, }) => (React.
|
|
|
31
31
|
React.createElement("span", { className: "cursor-pointer black-text" }, DateService.getServiceItemDate(date)),
|
|
32
32
|
React.createElement("div", { className: "absolute left-[50%]" }, "\u2022"),
|
|
33
33
|
React.createElement("div", { className: "font-[900] relative black-text" }, timeContent)))));
|
|
34
|
-
function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal, isPeru, orignLabel, destinationLabel, originIcon, destinationIcon, travelDate, arrivalDate, depTime, arrTime, seatTypes, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, }) {
|
|
34
|
+
function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal, isPeru, orignLabel, destinationLabel, originIcon, destinationIcon, travelDate, arrivalDate, depTime, arrTime, seatTypes, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, }) {
|
|
35
35
|
const { cleaned: cleanedDepTime, hasAM, hasPM } = getCleanedDepTime(depTime);
|
|
36
36
|
const depTimeContent = isLinatal ? (React.createElement("div", null,
|
|
37
37
|
React.createElement("span", null,
|
|
@@ -52,6 +52,6 @@ function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal
|
|
|
52
52
|
backgroundColor: "#ccc",
|
|
53
53
|
margin: "auto",
|
|
54
54
|
} })),
|
|
55
|
-
React.createElement(SeatSectionMobile, { seatTypes: seatTypes, isSoldOut: isSoldOut, isPeru: isPeru, seatPriceColor: seatPriceColor, currencySign: currencySign, availableSeats: availableSeats, removeDuplicateSeats: removeDuplicateSeats })));
|
|
55
|
+
React.createElement(SeatSectionMobile, { seatTypes: seatTypes, isSoldOut: isSoldOut, isPeru: isPeru, seatPriceColor: seatPriceColor, currencySign: currencySign, availableSeats: availableSeats, removeDuplicateSeats: removeDuplicateSeats, serviceItem: serviceItem })));
|
|
56
56
|
}
|
|
57
57
|
export default DateTimeSectionMobile;
|
|
@@ -12,6 +12,7 @@ interface SeatSectionMobileProps {
|
|
|
12
12
|
currencySign: string;
|
|
13
13
|
availableSeats: number;
|
|
14
14
|
removeDuplicateSeats?: boolean;
|
|
15
|
+
serviceItem?: any;
|
|
15
16
|
}
|
|
16
|
-
declare function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, }: SeatSectionMobileProps): React.ReactElement;
|
|
17
|
+
declare function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, }: SeatSectionMobileProps): React.ReactElement;
|
|
17
18
|
export default SeatSectionMobile;
|
|
@@ -42,14 +42,15 @@ const getUniqueSeats = (data, limit) => {
|
|
|
42
42
|
.sort((a, b) => a.fare - b.fare)
|
|
43
43
|
.slice(0, limit);
|
|
44
44
|
};
|
|
45
|
-
function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, }) {
|
|
46
|
-
var _a;
|
|
45
|
+
function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, }) {
|
|
46
|
+
var _a, _b, _c;
|
|
47
47
|
const hasMultipleTypes = ((_a = seatTypesData === null || seatTypesData === void 0 ? void 0 : seatTypesData.length) !== null && _a !== void 0 ? _a : 0) > 2;
|
|
48
48
|
const getFare = (fare) => {
|
|
49
49
|
if (removeDuplicateSeats && availableSeats <= 0 && !isPeru) {
|
|
50
50
|
return commonService.currency(0, currencySign);
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
const { discountedPrice } = commonService.calculateDiscountedPrice(fare, serviceItem);
|
|
53
|
+
return commonService.currency(discountedPrice, currencySign);
|
|
53
54
|
};
|
|
54
55
|
const getLowestFare = () => {
|
|
55
56
|
var _a;
|
|
@@ -67,13 +68,16 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
67
68
|
if (lowestFare === null)
|
|
68
69
|
return null;
|
|
69
70
|
const priceColor = isSoldOut ? "#bbb" : seatPriceColor;
|
|
71
|
+
const { originalPrice, discountedPrice } = commonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
70
72
|
return (React.createElement(React.Fragment, null,
|
|
71
73
|
React.createElement("div", { className: "w-[100%] flex flex-row justify-between items-center" },
|
|
72
74
|
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px]", style: { color: "#bbb" } }, "Antes"),
|
|
73
|
-
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] line-through", style: { color: "#bbb" } },
|
|
75
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] line-through", style: { color: "#bbb" } }, originalPrice !== discountedPrice
|
|
76
|
+
? commonService.currency(originalPrice, currencySign)
|
|
77
|
+
: commonService.currency(getHighestFare(), currencySign))),
|
|
74
78
|
React.createElement("div", { className: "w-[100%] flex flex-row justify-between items-center" },
|
|
75
79
|
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: isSoldOut ? "#bbb" : "#464647" } }, "Desde"),
|
|
76
|
-
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: priceColor } }, commonService.currency(
|
|
80
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: priceColor } }, commonService.currency(discountedPrice, currencySign)))));
|
|
77
81
|
};
|
|
78
82
|
const renderSeats = () => {
|
|
79
83
|
var _a, _b, _c;
|
|
@@ -84,11 +88,17 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
84
88
|
const uniqueSeats = getUniqueSeats(seatTypesData, 3);
|
|
85
89
|
return uniqueSeats.map((type, i) => (React.createElement(SeatRow, { key: i, type: type, index: i, displayLabel: commonService.truncateSeatLabel(type.label), fare: getFare(type.fare), isSoldOut: isSoldOut, seatPriceColor: seatPriceColor, hasMultipleTypes: hasMultipleTypes, textSize: "text-[11px]" })));
|
|
86
90
|
}
|
|
87
|
-
return (_c = (_b = (_a = seatTypesData === null || seatTypesData === void 0 ? void 0 : seatTypesData.filter((item) => getFilteredSeats(item.label))) === null || _a === void 0 ? void 0 : _a.sort((a, b) => a.fare - b.fare)) === null || _b === void 0 ? void 0 : _b.slice(0, 2)) === null || _c === void 0 ? void 0 : _c.map((type, i) => (React.createElement(SeatRow, { key: i, type: type, index: i, displayLabel: type.label, fare:
|
|
91
|
+
return (_c = (_b = (_a = seatTypesData === null || seatTypesData === void 0 ? void 0 : seatTypesData.filter((item) => getFilteredSeats(item.label))) === null || _a === void 0 ? void 0 : _a.sort((a, b) => a.fare - b.fare)) === null || _b === void 0 ? void 0 : _b.slice(0, 2)) === null || _c === void 0 ? void 0 : _c.map((type, i) => (React.createElement(SeatRow, { key: i, type: type, index: i, displayLabel: type.label, fare: getFare(type.fare), isSoldOut: isSoldOut, seatPriceColor: seatPriceColor, hasMultipleTypes: hasMultipleTypes, textSize: "text-[12px]" })));
|
|
88
92
|
};
|
|
93
|
+
const seats = removeDuplicateSeats
|
|
94
|
+
? getUniqueSeats(seatTypesData, 3)
|
|
95
|
+
: (_c = (_b = seatTypesData === null || seatTypesData === void 0 ? void 0 : seatTypesData.filter((item) => getFilteredSeats(item.label))) === null || _b === void 0 ? void 0 : _b.sort((a, b) => a.fare - b.fare)) === null || _c === void 0 ? void 0 : _c.slice(0, 2);
|
|
96
|
+
const discountedSeats = seats === null || seats === void 0 ? void 0 : seats.map((seat) => (Object.assign(Object.assign({}, seat), commonService.calculateDiscountedPrice(seat.fare, serviceItem))));
|
|
97
|
+
const highestOriginalPrice = Math.max(...((discountedSeats === null || discountedSeats === void 0 ? void 0 : discountedSeats.map((s) => s.originalPrice)) || [0]));
|
|
98
|
+
const hasDiscount = discountedSeats === null || discountedSeats === void 0 ? void 0 : discountedSeats.some((s) => s.originalPrice !== s.discountedPrice);
|
|
89
99
|
return (React.createElement("div", { className: "content-center relative", style: { width: "40%" } },
|
|
90
|
-
!isPeru && (React.createElement("div", { className: "absolute -top-[16px] right-[0] flex justify-end" },
|
|
91
|
-
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] line-through", style: { color: "#bbb" } },
|
|
100
|
+
!isPeru && hasDiscount && (React.createElement("div", { className: "absolute -top-[16px] right-[0] flex justify-end" },
|
|
101
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] line-through", style: { color: "#bbb" } }, commonService.currency(highestOriginalPrice, currencySign)))),
|
|
92
102
|
React.createElement("div", { className: "flex flex-col justify-between h-[2.5rem] ", style: {
|
|
93
103
|
gap: isSoldOut ? "0px" : "5px",
|
|
94
104
|
justifyContent: hasMultipleTypes ? "space-between" : "center",
|
|
@@ -9,5 +9,13 @@ declare const commonService: {
|
|
|
9
9
|
capitalize: (str: any) => any;
|
|
10
10
|
formatTimeLabel: (label: string) => string;
|
|
11
11
|
formatDefaultLabel: (label: string) => string;
|
|
12
|
+
calculateDiscountedPrice: (originalPrice: number | string, serviceItem?: {
|
|
13
|
+
discount_type?: string;
|
|
14
|
+
discount_value?: number;
|
|
15
|
+
max_discount?: number;
|
|
16
|
+
}) => {
|
|
17
|
+
originalPrice: number;
|
|
18
|
+
discountedPrice: number;
|
|
19
|
+
};
|
|
12
20
|
};
|
|
13
21
|
export default commonService;
|
|
@@ -267,5 +267,22 @@ const commonService = {
|
|
|
267
267
|
return "";
|
|
268
268
|
return label.toLowerCase();
|
|
269
269
|
},
|
|
270
|
+
calculateDiscountedPrice: (originalPrice, serviceItem) => {
|
|
271
|
+
const price = typeof originalPrice === "string"
|
|
272
|
+
? parseFloat(originalPrice)
|
|
273
|
+
: originalPrice;
|
|
274
|
+
if (!serviceItem || !price) {
|
|
275
|
+
return { originalPrice: price, discountedPrice: price };
|
|
276
|
+
}
|
|
277
|
+
const { discount_type, discount_value, max_discount } = serviceItem;
|
|
278
|
+
const percentageDiscount = discount_type === "percentage" && discount_value != null
|
|
279
|
+
? (price * discount_value) / 100
|
|
280
|
+
: 0;
|
|
281
|
+
const finalDiscount = max_discount != null && max_discount > 0
|
|
282
|
+
? Math.min(percentageDiscount, max_discount)
|
|
283
|
+
: percentageDiscount;
|
|
284
|
+
const discountedPrice = Math.max(0, price - finalDiscount);
|
|
285
|
+
return { originalPrice: price, discountedPrice };
|
|
286
|
+
},
|
|
270
287
|
};
|
|
271
288
|
export default commonService;
|
package/package.json
CHANGED
|
@@ -558,6 +558,7 @@ function ServiceItemPB({
|
|
|
558
558
|
<div className="content-center">
|
|
559
559
|
<SeatSection
|
|
560
560
|
seatTypes={serviceItem.seat_types}
|
|
561
|
+
serviceItem={serviceItem}
|
|
561
562
|
availableSeats={serviceItem.available_seats}
|
|
562
563
|
isSoldOut={isSoldOut}
|
|
563
564
|
priceColor={colors.priceColor}
|
|
@@ -176,7 +176,7 @@ function ServiceItemMobile({
|
|
|
176
176
|
// className={`relative ${
|
|
177
177
|
// serviceItem.offer_text ? "mb-[55px]" : "mb-[14px]"
|
|
178
178
|
// }
|
|
179
|
-
className={`relative ${serviceItem.offer_text ? "mb-[
|
|
179
|
+
className={`relative ${!serviceItem.offer_text ? "mb-[14px]" : showTopLabel || serviceItem?.is_direct_trip ? "mb-[20px]" : "mb-[12px]"} ${
|
|
180
180
|
serviceItem?.is_direct_trip ||
|
|
181
181
|
isConexion ||
|
|
182
182
|
serviceItem?.train_type_label === "Tren Express (Nuevo)" ||
|
|
@@ -291,6 +291,7 @@ function ServiceItemMobile({
|
|
|
291
291
|
currencySign={currencySign}
|
|
292
292
|
availableSeats={serviceItem.available_seats}
|
|
293
293
|
removeDuplicateSeats={removeDuplicateSeats}
|
|
294
|
+
serviceItem={serviceItem}
|
|
294
295
|
/>
|
|
295
296
|
{/* <div className="bg-[#E6E6E6] -ml-[12px] -mr-[12px] mt-[10px] mb-[10px] h-[1px]"></div> */}
|
|
296
297
|
<div className="bg-[#E6E6E6] mt-[10px] mb-[10px] h-[1px]"></div>
|
|
@@ -17,6 +17,7 @@ interface SeatSectionProps {
|
|
|
17
17
|
currencySign?: string;
|
|
18
18
|
removeDuplicateSeats?: boolean;
|
|
19
19
|
isPeru?: boolean;
|
|
20
|
+
serviceItem?: any;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
function getAllSeatTypes(seatTypes: SeatType[]) {
|
|
@@ -94,6 +95,7 @@ function SeatSection({
|
|
|
94
95
|
currencySign,
|
|
95
96
|
removeDuplicateSeats,
|
|
96
97
|
isPeru,
|
|
98
|
+
serviceItem,
|
|
97
99
|
}: SeatSectionProps): React.ReactElement {
|
|
98
100
|
const uniqueSeats = getUniqueSeats(seatTypes);
|
|
99
101
|
const sortedSeatTypes = getSortedSeatTypes(seatTypes);
|
|
@@ -130,28 +132,50 @@ function SeatSection({
|
|
|
130
132
|
if (isPeru) {
|
|
131
133
|
const allSeats = getAllSeatTypes(seatTypes);
|
|
132
134
|
const lowestFare = allSeats.length > 0 ? allSeats[0].price : 0;
|
|
135
|
+
const { originalPrice, discountedPrice } =
|
|
136
|
+
CommonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
137
|
+
|
|
133
138
|
return (
|
|
134
|
-
|
|
135
|
-
{
|
|
136
|
-
|
|
139
|
+
<>
|
|
140
|
+
{originalPrice !== discountedPrice && (
|
|
141
|
+
<span className="text-[13.33px]" style={strikethroughStyle}>
|
|
142
|
+
{formatPrice(originalPrice)}
|
|
143
|
+
</span>
|
|
144
|
+
)}
|
|
145
|
+
<span className="flex items-center text-[13.33px] bold-text">
|
|
146
|
+
{formatPrice(discountedPrice)}
|
|
147
|
+
</span>
|
|
148
|
+
</>
|
|
137
149
|
);
|
|
138
150
|
}
|
|
139
151
|
|
|
140
152
|
if (removeDuplicateSeats) {
|
|
141
|
-
return uniqueSeats.map((val, key) =>
|
|
142
|
-
|
|
143
|
-
|
|
153
|
+
return uniqueSeats.map((val, key) => {
|
|
154
|
+
const { discountedPrice } = CommonService.calculateDiscountedPrice(
|
|
155
|
+
val.price,
|
|
156
|
+
serviceItem,
|
|
157
|
+
);
|
|
158
|
+
return <span key={key}>{formatPrice(discountedPrice)}</span>;
|
|
159
|
+
});
|
|
144
160
|
}
|
|
145
161
|
|
|
146
|
-
return sortedSeatTypes.map((val, key: number) =>
|
|
147
|
-
SEAT_EXCEPTIONS.includes(val.label)
|
|
162
|
+
return sortedSeatTypes.map((val, key: number) => {
|
|
163
|
+
if (SEAT_EXCEPTIONS.includes(val.label)) return null;
|
|
164
|
+
|
|
165
|
+
const { discountedPrice } = CommonService.calculateDiscountedPrice(
|
|
166
|
+
val.price,
|
|
167
|
+
serviceItem,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
return (
|
|
148
171
|
<span key={key} className="flex items-center text-[13.33px] bold-text">
|
|
149
|
-
{typeof
|
|
150
|
-
|
|
172
|
+
{typeof discountedPrice === "string" ||
|
|
173
|
+
typeof discountedPrice === "number"
|
|
174
|
+
? formatPrice(discountedPrice)
|
|
151
175
|
: null}
|
|
152
176
|
</span>
|
|
153
|
-
)
|
|
154
|
-
);
|
|
177
|
+
);
|
|
178
|
+
});
|
|
155
179
|
};
|
|
156
180
|
|
|
157
181
|
const renderLabels = () => {
|
|
@@ -185,6 +209,20 @@ function SeatSection({
|
|
|
185
209
|
: { position: "absolute", top: isCentered ? "-10px" : "-18px" }),
|
|
186
210
|
};
|
|
187
211
|
|
|
212
|
+
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
213
|
+
const discountedSeats = seats.map((seat) => ({
|
|
214
|
+
...seat,
|
|
215
|
+
...CommonService.calculateDiscountedPrice(seat.price, serviceItem),
|
|
216
|
+
}));
|
|
217
|
+
|
|
218
|
+
const highestOriginalPrice = Math.max(
|
|
219
|
+
...discountedSeats.map((seat) => seat.originalPrice),
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
const hasDiscount = discountedSeats.some(
|
|
223
|
+
(seat) => seat.originalPrice !== seat.discountedPrice,
|
|
224
|
+
);
|
|
225
|
+
|
|
188
226
|
return (
|
|
189
227
|
<div
|
|
190
228
|
className="relative flex gap-[10px] text-[13.33px] justify-between min-h-[2.2rem]"
|
|
@@ -205,9 +243,17 @@ function SeatSection({
|
|
|
205
243
|
gap: "10px",
|
|
206
244
|
}}
|
|
207
245
|
>
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
246
|
+
{isPeru && (
|
|
247
|
+
<span className="text-[13.33px]" style={strikethroughStyle}>
|
|
248
|
+
{formatPrice(1000)}
|
|
249
|
+
</span>
|
|
250
|
+
)}
|
|
251
|
+
|
|
252
|
+
{hasDiscount && (
|
|
253
|
+
<span className="text-[13.33px]" style={strikethroughStyle}>
|
|
254
|
+
{formatPrice(highestOriginalPrice)}
|
|
255
|
+
</span>
|
|
256
|
+
)}
|
|
211
257
|
{renderSeatPrices()}
|
|
212
258
|
</div>
|
|
213
259
|
</div>
|
|
@@ -21,6 +21,7 @@ interface DateTimeSectionMobileProps {
|
|
|
21
21
|
currencySign: string;
|
|
22
22
|
availableSeats: number;
|
|
23
23
|
removeDuplicateSeats?: boolean;
|
|
24
|
+
serviceItem?: any;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
const pad = (n: number) => (n < 10 ? "0" + n : String(n));
|
|
@@ -117,6 +118,7 @@ function DateTimeSectionMobile({
|
|
|
117
118
|
currencySign,
|
|
118
119
|
availableSeats,
|
|
119
120
|
removeDuplicateSeats,
|
|
121
|
+
serviceItem,
|
|
120
122
|
}: DateTimeSectionMobileProps): React.ReactElement {
|
|
121
123
|
const { cleaned: cleanedDepTime, hasAM, hasPM } = getCleanedDepTime(depTime);
|
|
122
124
|
|
|
@@ -184,6 +186,7 @@ function DateTimeSectionMobile({
|
|
|
184
186
|
currencySign={currencySign}
|
|
185
187
|
availableSeats={availableSeats}
|
|
186
188
|
removeDuplicateSeats={removeDuplicateSeats}
|
|
189
|
+
serviceItem={serviceItem}
|
|
187
190
|
/>
|
|
188
191
|
</div>
|
|
189
192
|
);
|
|
@@ -27,6 +27,7 @@ interface SeatSectionMobileProps {
|
|
|
27
27
|
currencySign: string;
|
|
28
28
|
availableSeats: number;
|
|
29
29
|
removeDuplicateSeats?: boolean;
|
|
30
|
+
serviceItem?: any;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
interface SeatRowProps {
|
|
@@ -110,6 +111,7 @@ function SeatSectionMobile({
|
|
|
110
111
|
currencySign,
|
|
111
112
|
availableSeats,
|
|
112
113
|
removeDuplicateSeats,
|
|
114
|
+
serviceItem,
|
|
113
115
|
}: SeatSectionMobileProps): React.ReactElement {
|
|
114
116
|
const hasMultipleTypes = (seatTypesData?.length ?? 0) > 2;
|
|
115
117
|
|
|
@@ -117,7 +119,11 @@ function SeatSectionMobile({
|
|
|
117
119
|
if (removeDuplicateSeats && availableSeats <= 0 && !isPeru) {
|
|
118
120
|
return commonService.currency(0, currencySign);
|
|
119
121
|
}
|
|
120
|
-
|
|
122
|
+
const { discountedPrice } = commonService.calculateDiscountedPrice(
|
|
123
|
+
fare,
|
|
124
|
+
serviceItem,
|
|
125
|
+
);
|
|
126
|
+
return commonService.currency(discountedPrice, currencySign);
|
|
121
127
|
};
|
|
122
128
|
|
|
123
129
|
const getLowestFare = (): number | null => {
|
|
@@ -144,6 +150,8 @@ function SeatSectionMobile({
|
|
|
144
150
|
if (lowestFare === null) return null;
|
|
145
151
|
|
|
146
152
|
const priceColor = isSoldOut ? "#bbb" : seatPriceColor;
|
|
153
|
+
const { originalPrice, discountedPrice } =
|
|
154
|
+
commonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
147
155
|
|
|
148
156
|
return (
|
|
149
157
|
<>
|
|
@@ -158,7 +166,9 @@ function SeatSectionMobile({
|
|
|
158
166
|
className="min-[420]:text-[13px] text-[12px] line-through"
|
|
159
167
|
style={{ color: "#bbb" }}
|
|
160
168
|
>
|
|
161
|
-
{
|
|
169
|
+
{originalPrice !== discountedPrice
|
|
170
|
+
? commonService.currency(originalPrice, currencySign)
|
|
171
|
+
: commonService.currency(getHighestFare(), currencySign)}
|
|
162
172
|
</span>
|
|
163
173
|
</div>
|
|
164
174
|
<div className="w-[100%] flex flex-row justify-between items-center">
|
|
@@ -172,7 +182,7 @@ function SeatSectionMobile({
|
|
|
172
182
|
className="min-[420]:text-[13px] text-[12px] bold-text"
|
|
173
183
|
style={{ color: priceColor }}
|
|
174
184
|
>
|
|
175
|
-
{commonService.currency(
|
|
185
|
+
{commonService.currency(discountedPrice, currencySign)}
|
|
176
186
|
</span>
|
|
177
187
|
</div>
|
|
178
188
|
</>
|
|
@@ -211,7 +221,7 @@ function SeatSectionMobile({
|
|
|
211
221
|
type={type}
|
|
212
222
|
index={i}
|
|
213
223
|
displayLabel={type.label}
|
|
214
|
-
fare={
|
|
224
|
+
fare={getFare(type.fare)}
|
|
215
225
|
isSoldOut={isSoldOut}
|
|
216
226
|
seatPriceColor={seatPriceColor}
|
|
217
227
|
hasMultipleTypes={hasMultipleTypes}
|
|
@@ -220,15 +230,34 @@ function SeatSectionMobile({
|
|
|
220
230
|
));
|
|
221
231
|
};
|
|
222
232
|
|
|
233
|
+
const seats = removeDuplicateSeats
|
|
234
|
+
? getUniqueSeats(seatTypesData, 3)
|
|
235
|
+
: seatTypesData
|
|
236
|
+
?.filter((item) => getFilteredSeats(item.label))
|
|
237
|
+
?.sort((a, b) => a.fare - b.fare)
|
|
238
|
+
?.slice(0, 2);
|
|
239
|
+
|
|
240
|
+
const discountedSeats = seats?.map((seat) => ({
|
|
241
|
+
...seat,
|
|
242
|
+
...commonService.calculateDiscountedPrice(seat.fare, serviceItem),
|
|
243
|
+
}));
|
|
244
|
+
|
|
245
|
+
const highestOriginalPrice = Math.max(
|
|
246
|
+
...(discountedSeats?.map((s) => s.originalPrice) || [0]),
|
|
247
|
+
);
|
|
248
|
+
const hasDiscount = discountedSeats?.some(
|
|
249
|
+
(s) => s.originalPrice !== s.discountedPrice,
|
|
250
|
+
);
|
|
251
|
+
|
|
223
252
|
return (
|
|
224
253
|
<div className="content-center relative" style={{ width: "40%" }}>
|
|
225
|
-
{!isPeru && (
|
|
254
|
+
{!isPeru && hasDiscount && (
|
|
226
255
|
<div className="absolute -top-[16px] right-[0] flex justify-end">
|
|
227
256
|
<span
|
|
228
257
|
className="min-[420]:text-[13px] text-[12px] line-through"
|
|
229
258
|
style={{ color: "#bbb" }}
|
|
230
259
|
>
|
|
231
|
-
|
|
260
|
+
{commonService.currency(highestOriginalPrice, currencySign)}
|
|
232
261
|
</span>
|
|
233
262
|
</div>
|
|
234
263
|
)}
|
|
@@ -274,6 +274,40 @@ const commonService = {
|
|
|
274
274
|
if (!label) return "";
|
|
275
275
|
return label.toLowerCase();
|
|
276
276
|
},
|
|
277
|
+
|
|
278
|
+
calculateDiscountedPrice: (
|
|
279
|
+
originalPrice: number | string,
|
|
280
|
+
serviceItem?: {
|
|
281
|
+
discount_type?: string;
|
|
282
|
+
discount_value?: number;
|
|
283
|
+
max_discount?: number;
|
|
284
|
+
},
|
|
285
|
+
): { originalPrice: number; discountedPrice: number } => {
|
|
286
|
+
const price =
|
|
287
|
+
typeof originalPrice === "string"
|
|
288
|
+
? parseFloat(originalPrice)
|
|
289
|
+
: originalPrice;
|
|
290
|
+
|
|
291
|
+
if (!serviceItem || !price) {
|
|
292
|
+
return { originalPrice: price, discountedPrice: price };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const { discount_type, discount_value, max_discount } = serviceItem;
|
|
296
|
+
|
|
297
|
+
const percentageDiscount =
|
|
298
|
+
discount_type === "percentage" && discount_value != null
|
|
299
|
+
? (price * discount_value) / 100
|
|
300
|
+
: 0;
|
|
301
|
+
|
|
302
|
+
const finalDiscount =
|
|
303
|
+
max_discount != null && max_discount > 0
|
|
304
|
+
? Math.min(percentageDiscount, max_discount)
|
|
305
|
+
: percentageDiscount;
|
|
306
|
+
|
|
307
|
+
const discountedPrice = Math.max(0, price - finalDiscount);
|
|
308
|
+
|
|
309
|
+
return { originalPrice: price, discountedPrice };
|
|
310
|
+
},
|
|
277
311
|
};
|
|
278
312
|
|
|
279
313
|
export default commonService;
|