kupos-ui-components-lib 9.9.3 → 9.9.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/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemDesktop.js +20 -2
- package/dist/components/ServiceItem/ServiceItemMobile.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemMobile.js +2 -2
- package/dist/components/ServiceItem/mobileTypes.d.ts +1 -0
- package/dist/components/ServiceItem/types.d.ts +7 -0
- package/dist/styles.css +3 -0
- package/dist/ui/SeatSection/SeatSection.d.ts +7 -1
- package/dist/ui/SeatSection/SeatSection.js +38 -9
- package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +2 -1
- package/dist/ui/mobileweb/DateTimeSectionMobile.js +7 -5
- package/dist/ui/mobileweb/SeatSectionMobile.d.ts +2 -1
- package/dist/ui/mobileweb/SeatSectionMobile.js +15 -10
- package/dist/utils/CommonService.d.ts +1 -1
- package/dist/utils/CommonService.js +5 -1
- package/package.json +1 -1
- package/src/components/ServiceItem/ServiceItemDesktop.tsx +43 -0
- package/src/components/ServiceItem/ServiceItemMobile.tsx +2 -0
- package/src/components/ServiceItem/mobileTypes.ts +1 -0
- package/src/components/ServiceItem/types.ts +12 -0
- package/src/ui/SeatSection/SeatSection.tsx +83 -18
- package/src/ui/mobileweb/DateTimeSectionMobile.tsx +38 -33
- package/src/ui/mobileweb/SeatSectionMobile.tsx +12 -7
- package/src/utils/CommonService.ts +7 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { ServiceItemProps } from "./types";
|
|
3
|
-
declare function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, children, busStage, serviceDetailsLoading, cityOrigin, cityDestination, translation, orignLabel, destinationLabel, currencySign, isCiva, showRating, showLastSeats, removeArrivalTime, removeDuplicateSeats, isPeruSites, showAvailableSeats, isSeatIcon, isLinatal, isPeru, t, siteType, isAllinBus, isExpand, setIsExpand, coachKey, viewersConfig, showLoginModal, isLoggedIn, showLoginOption, isFlores, operatorLabel, }: ServiceItemProps & {
|
|
3
|
+
declare function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, children, busStage, serviceDetailsLoading, cityOrigin, cityDestination, translation, orignLabel, destinationLabel, currencySign, isCiva, showRating, showLastSeats, removeArrivalTime, removeDuplicateSeats, isPeruSites, showAvailableSeats, isSeatIcon, isLinatal, isPeru, t, siteType, isAllinBus, isExpand, setIsExpand, coachKey, viewersConfig, showLoginModal, isLoggedIn, showLoginOption, isTrain, selectedSeatKey, onSeatSelect, onTrainButtonClick, showSeatSelectionError, onShowSeatSelectionError, onClearSeatSelectionError, isFlores, operatorLabel, }: ServiceItemProps & {
|
|
4
4
|
currencySign?: string;
|
|
5
5
|
}): React.ReactElement;
|
|
6
6
|
export default ServiceItemPB;
|
|
@@ -74,8 +74,12 @@ const ANIMATION_MAP = {
|
|
|
74
74
|
kupos: femaleAnimation,
|
|
75
75
|
},
|
|
76
76
|
};
|
|
77
|
-
function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, children, busStage, serviceDetailsLoading, cityOrigin, cityDestination, translation, orignLabel, destinationLabel, currencySign, isCiva, showRating, showLastSeats, removeArrivalTime, removeDuplicateSeats, isPeruSites, showAvailableSeats, isSeatIcon, isLinatal, isPeru, t = (key) => key, siteType, isAllinBus, isExpand, setIsExpand, coachKey, viewersConfig, showLoginModal, isLoggedIn, showLoginOption, isFlores, operatorLabel, }) {
|
|
77
|
+
function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, children, busStage, serviceDetailsLoading, cityOrigin, cityDestination, translation, orignLabel, destinationLabel, currencySign, isCiva, showRating, showLastSeats, removeArrivalTime, removeDuplicateSeats, isPeruSites, showAvailableSeats, isSeatIcon, isLinatal, isPeru, t = (key) => key, siteType, isAllinBus, isExpand, setIsExpand, coachKey, viewersConfig, showLoginModal, isLoggedIn, showLoginOption, isTrain, selectedSeatKey, onSeatSelect, onTrainButtonClick, showSeatSelectionError, onShowSeatSelectionError, onClearSeatSelectionError, isFlores, operatorLabel, }) {
|
|
78
78
|
var _a;
|
|
79
|
+
const handleSeatSelect = (key, price, seatKey, apiSeatType) => {
|
|
80
|
+
onClearSeatSelectionError === null || onClearSeatSelectionError === void 0 ? void 0 : onClearSeatSelectionError();
|
|
81
|
+
onSeatSelect === null || onSeatSelect === void 0 ? void 0 : onSeatSelect(key, price, seatKey, apiSeatType);
|
|
82
|
+
};
|
|
79
83
|
const getAnimationIcon = (icon) => {
|
|
80
84
|
var _a;
|
|
81
85
|
const animation = ANIMATION_MAP[icon];
|
|
@@ -213,6 +217,16 @@ function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, child
|
|
|
213
217
|
});
|
|
214
218
|
return;
|
|
215
219
|
}
|
|
220
|
+
if (isTrain) {
|
|
221
|
+
if (!selectedSeatKey) {
|
|
222
|
+
onShowSeatSelectionError === null || onShowSeatSelectionError === void 0 ? void 0 : onShowSeatSelectionError(serviceItem.id);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (onTrainButtonClick) {
|
|
226
|
+
onTrainButtonClick();
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
216
230
|
onBookButtonPress();
|
|
217
231
|
};
|
|
218
232
|
const items = [
|
|
@@ -275,9 +289,13 @@ function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, child
|
|
|
275
289
|
backgroundColor: "#ccc",
|
|
276
290
|
} }),
|
|
277
291
|
React.createElement("div", { className: "content-center" },
|
|
278
|
-
React.createElement(SeatSection, { seatTypes: serviceItem.seat_types, serviceItem: serviceItem, availableSeats: serviceItem.available_seats, isSoldOut: isSoldOut, priceColor: colors.priceColor, dpSeatColor: colors.seatPriceColor, currencySign: currencySign, removeDuplicateSeats: removeDuplicateSeats, isPeru: isPeru, renderIcon: renderIcon, discountSeatPriceColor: colors.discountSeatPriceColor })),
|
|
292
|
+
React.createElement(SeatSection, { seatTypes: serviceItem.seat_types, serviceItem: serviceItem, availableSeats: serviceItem.available_seats, isSoldOut: isSoldOut, priceColor: colors.priceColor, dpSeatColor: colors.seatPriceColor, currencySign: currencySign, removeDuplicateSeats: removeDuplicateSeats, isPeru: isPeru, renderIcon: renderIcon, discountSeatPriceColor: colors.discountSeatPriceColor, isTrain: isTrain, selectedSeatKey: selectedSeatKey, onSeatSelect: handleSeatSelect, topLabelColor: colors.topLabelColor })),
|
|
279
293
|
React.createElement("div", { className: "relative" },
|
|
280
294
|
React.createElement(KuposButton, { isSoldOut: isSoldOut, isLoading: serviceDetailsLoading, buttonColor: colors.kuposButtonColor, buyLabel: translation === null || translation === void 0 ? void 0 : translation.buyButton, soldOutLabel: translation === null || translation === void 0 ? void 0 : translation.soldOutButton, soldOutIcon: renderIcon("soldOutIcon", "14px"), onClick: checkMidnight }),
|
|
295
|
+
showSeatSelectionError === serviceItem.id && isTrain && (React.createElement("div", { className: "flex justify-center mr-[11px] w-[100%] right-[0px] absolute left-[0] top-[40px]" },
|
|
296
|
+
React.createElement("div", { className: "text-[9px] text-center whitespace-nowrap", style: {
|
|
297
|
+
color: colors.seatPriceColor,
|
|
298
|
+
} }, "Selecciona el tipo de servicio"))),
|
|
281
299
|
showLastSeats ? (React.createElement("div", { className: "flex justify-center mr-[11px] w-[100%] right-[0px] absolute left-[0] top-[40px]" }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.available_seats) < 10 &&
|
|
282
300
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.available_seats) > 0 && (React.createElement("div", { className: "text-[12px] mt-1 text-center", style: {
|
|
283
301
|
color: colors.seatPriceColor,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { MobileServiceItemProps } from "./mobileTypes";
|
|
3
|
-
declare function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, orignLabel, destinationLabel, amenitiesData, setShowDropdown, showDropdown, isExpanded, setIsExpanded, setAmenetiesAtomValue, isCiva, currencySign, isPeru, showRating, showLastSeats, removeDuplicateSeats, isLinatal, viewersConfig, operatorLabel, }: MobileServiceItemProps): React.ReactElement;
|
|
3
|
+
declare function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, orignLabel, destinationLabel, amenitiesData, setShowDropdown, showDropdown, isExpanded, setIsExpanded, setAmenetiesAtomValue, isCiva, currencySign, isPeru, showRating, showLastSeats, removeDuplicateSeats, isLinatal, viewersConfig, operatorLabel, isTrain, }: MobileServiceItemProps): React.ReactElement;
|
|
4
4
|
export default ServiceItemMobile;
|
|
@@ -17,7 +17,7 @@ const exceptions = [
|
|
|
17
17
|
"blanco",
|
|
18
18
|
"asiento_mascota",
|
|
19
19
|
];
|
|
20
|
-
function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, orignLabel, destinationLabel, amenitiesData, setShowDropdown, showDropdown, isExpanded, setIsExpanded, setAmenetiesAtomValue, isCiva, currencySign, isPeru, showRating, showLastSeats, removeDuplicateSeats, isLinatal, viewersConfig, operatorLabel, }) {
|
|
20
|
+
function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, orignLabel, destinationLabel, amenitiesData, setShowDropdown, showDropdown, isExpanded, setIsExpanded, setAmenetiesAtomValue, isCiva, currencySign, isPeru, showRating, showLastSeats, removeDuplicateSeats, isLinatal, viewersConfig, operatorLabel, isTrain, }) {
|
|
21
21
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
22
22
|
const isItemExpanded = serviceItem.id === isExpanded;
|
|
23
23
|
const isPetSeat = (Object.keys(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.pet_seat_info) || []).length > 0;
|
|
@@ -110,7 +110,7 @@ function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, o
|
|
|
110
110
|
React.createElement("span", { style: { lineHeight: "normal" } }, getServiceStars(serviceItem))),
|
|
111
111
|
React.createElement("div", { className: "flex items-center cursor-pointer ", style: { color: isSoldOut ? "#bbb" : "text-[#464647]" } },
|
|
112
112
|
React.createElement("span", { className: "ml-[3px] min-[420]:text-[13px] text-[12px] text-ellipsis overflow-hidden whitespace-nowrap max-w-[120px]" }, serviceItem.operator_details[2]))))) : null)),
|
|
113
|
-
React.createElement(DateTimeSectionMobile, { onBookButtonPress: onBookButtonPress, isCiva: isCiva, isSoldOut: isSoldOut, isLinatal: isLinatal, isPeru: isPeru, orignLabel: orignLabel, destinationLabel: destinationLabel, originIcon: (_c = serviceItem.icons) === null || _c === void 0 ? void 0 : _c.origin, destinationIcon: (_d = serviceItem.icons) === null || _d === void 0 ? void 0 : _d.destination, travelDate: serviceItem.travel_date, arrivalDate: serviceItem.arrival_date, depTime: serviceItem.dep_time, arrTime: serviceItem.arr_time, seatTypes: serviceItem.seat_types, seatPriceColor: colors.seatPriceColor, tooltipBgColor: colors.tooltipBgColor, currencySign: currencySign, availableSeats: serviceItem.available_seats, removeDuplicateSeats: removeDuplicateSeats, serviceItem: serviceItem, showLastSeats: showLastSeats, discountSeatPriceColor: colors.discountSeatPriceColor }),
|
|
113
|
+
React.createElement(DateTimeSectionMobile, { onBookButtonPress: onBookButtonPress, isCiva: isCiva, isSoldOut: isSoldOut, isLinatal: isLinatal, isPeru: isPeru, orignLabel: orignLabel, destinationLabel: destinationLabel, originIcon: (_c = serviceItem.icons) === null || _c === void 0 ? void 0 : _c.origin, destinationIcon: (_d = serviceItem.icons) === null || _d === void 0 ? void 0 : _d.destination, travelDate: serviceItem.travel_date, arrivalDate: serviceItem.arrival_date, depTime: serviceItem.dep_time, arrTime: serviceItem.arr_time, seatTypes: serviceItem.seat_types, seatPriceColor: colors.seatPriceColor, tooltipBgColor: colors.tooltipBgColor, currencySign: currencySign, availableSeats: serviceItem.available_seats, removeDuplicateSeats: removeDuplicateSeats, serviceItem: serviceItem, showLastSeats: showLastSeats, discountSeatPriceColor: colors.discountSeatPriceColor, isTrain: isTrain }),
|
|
114
114
|
hasDiscount && (React.createElement("div", { className: "flex justify-end" }, isSoldOut ? (React.createElement("span", { className: "col-span-2 min-[420]:text-[13px] text-right text-[12px] text-[#ccc]" }, "Agotado")) : null)),
|
|
115
115
|
showLastSeats ? (React.createElement("div", { className: "flex justify-end " }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.available_seats) < 10 &&
|
|
116
116
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.available_seats) > 0 && (React.createElement("div", { className: "text-[10px] text-center", style: {
|
|
@@ -224,6 +224,13 @@ export interface ServiceItemProps {
|
|
|
224
224
|
showLoginModal?: any;
|
|
225
225
|
isLoggedIn?: any;
|
|
226
226
|
showLoginOption?: boolean;
|
|
227
|
+
isTrain?: boolean;
|
|
228
|
+
selectedSeatKey?: any;
|
|
229
|
+
onSeatSelect?: (key: any, price: number, seatKey: string, apiSeatType?: string) => void;
|
|
230
|
+
onTrainButtonClick?: any;
|
|
231
|
+
showSeatSelectionError?: string | null;
|
|
232
|
+
onShowSeatSelectionError?: (serviceId: string) => void;
|
|
233
|
+
onClearSeatSelectionError?: () => void;
|
|
227
234
|
isFlores?: boolean;
|
|
228
235
|
operatorLabel?: string;
|
|
229
236
|
}
|
package/dist/styles.css
CHANGED
|
@@ -3,6 +3,8 @@ interface SeatType {
|
|
|
3
3
|
label: string;
|
|
4
4
|
fare: number;
|
|
5
5
|
key: any;
|
|
6
|
+
apiSeatType?: string;
|
|
7
|
+
api_seat_type?: string;
|
|
6
8
|
}
|
|
7
9
|
interface SeatSectionProps {
|
|
8
10
|
seatTypes: SeatType[];
|
|
@@ -16,6 +18,10 @@ interface SeatSectionProps {
|
|
|
16
18
|
serviceItem?: any;
|
|
17
19
|
renderIcon?: (iconKey: string, size?: string) => React.ReactNode;
|
|
18
20
|
discountSeatPriceColor?: string;
|
|
21
|
+
isTrain?: boolean;
|
|
22
|
+
selectedSeatKey?: any;
|
|
23
|
+
onSeatSelect?: (key: any, price: number, seatKey: string, apiSeatType?: string) => void;
|
|
24
|
+
topLabelColor?: string;
|
|
19
25
|
}
|
|
20
|
-
declare function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, }: SeatSectionProps): React.ReactElement;
|
|
26
|
+
declare function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, selectedSeatKey, onSeatSelect, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, isTrain, topLabelColor, }: SeatSectionProps): React.ReactElement;
|
|
21
27
|
export default SeatSection;
|
|
@@ -8,11 +8,13 @@ function getAllSeatTypes(seatTypes) {
|
|
|
8
8
|
let seatTypesWithPrices = seatTypes.filter(Boolean).map((val) => ({
|
|
9
9
|
label: val === null || val === void 0 ? void 0 : val.label,
|
|
10
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),
|
|
11
13
|
}));
|
|
12
14
|
seatTypesWithPrices.sort((a, b) => a.price - b.price);
|
|
13
15
|
return seatTypesWithPrices;
|
|
14
16
|
}
|
|
15
|
-
function getSortedSeatTypes(seatTypes) {
|
|
17
|
+
function getSortedSeatTypes(seatTypes, isTrain) {
|
|
16
18
|
if (!(seatTypes === null || seatTypes === void 0 ? void 0 : seatTypes.length)) {
|
|
17
19
|
return [{ label: "Salon cama", price: 0 }];
|
|
18
20
|
}
|
|
@@ -21,7 +23,9 @@ function getSortedSeatTypes(seatTypes) {
|
|
|
21
23
|
if (premiumIndex >= 3) {
|
|
22
24
|
seatTypesWithPrices[2] = seatTypesWithPrices[premiumIndex];
|
|
23
25
|
}
|
|
24
|
-
|
|
26
|
+
if (!isTrain) {
|
|
27
|
+
seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
|
|
28
|
+
}
|
|
25
29
|
const seenPrices = new Set();
|
|
26
30
|
seatTypesWithPrices = seatTypesWithPrices.filter((seat) => {
|
|
27
31
|
if (seenPrices.has(seat.price))
|
|
@@ -54,10 +58,10 @@ function getUniqueSeats(seatTypes) {
|
|
|
54
58
|
function getNumberOfSeats(seatTypes) {
|
|
55
59
|
return seatTypes.filter((val) => !SEAT_EXCEPTIONS.includes(val.label)).length;
|
|
56
60
|
}
|
|
57
|
-
function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, }) {
|
|
61
|
+
function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, selectedSeatKey, onSeatSelect, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, isTrain, topLabelColor, }) {
|
|
58
62
|
var _a;
|
|
59
63
|
const uniqueSeats = getUniqueSeats(seatTypes);
|
|
60
|
-
const sortedSeatTypes = getSortedSeatTypes(seatTypes);
|
|
64
|
+
const sortedSeatTypes = getSortedSeatTypes(seatTypes, isTrain);
|
|
61
65
|
const numberOfSeats = getNumberOfSeats(seatTypes);
|
|
62
66
|
const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
|
|
63
67
|
const formatPrice = (price) => availableSeats <= 0
|
|
@@ -65,11 +69,36 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
|
|
|
65
69
|
: CommonService.currency(price, currencySign);
|
|
66
70
|
const renderSeatNames = () => {
|
|
67
71
|
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
68
|
-
return seats.map((val, key) =>
|
|
69
|
-
?
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
return seats.map((val, key) => {
|
|
73
|
+
return SEAT_EXCEPTIONS.includes(val.label) ? null : (React.createElement("div", { className: "flex items-center", style: isTrain ? { cursor: "pointer" } : undefined, onClick: isTrain && !isSoldOut
|
|
74
|
+
? () => val.label === selectedSeatKey
|
|
75
|
+
? onSeatSelect === null || onSeatSelect === void 0 ? void 0 : onSeatSelect(null, 0, "", "")
|
|
76
|
+
: onSeatSelect === null || onSeatSelect === void 0 ? void 0 : onSeatSelect(val.label, val.price, val.key, val.apiSeatType)
|
|
77
|
+
: undefined },
|
|
78
|
+
isTrain && (React.createElement("div", { style: {
|
|
79
|
+
border: `1px solid ${val.label === selectedSeatKey ? topLabelColor : "#ccc"}`,
|
|
80
|
+
borderRadius: "50%",
|
|
81
|
+
width: "14px",
|
|
82
|
+
height: "14px",
|
|
83
|
+
minWidth: "14px",
|
|
84
|
+
marginRight: "10px",
|
|
85
|
+
display: "flex",
|
|
86
|
+
alignItems: "center",
|
|
87
|
+
justifyContent: "center",
|
|
88
|
+
} }, val.label === selectedSeatKey && (React.createElement("div", { style: {
|
|
89
|
+
backgroundColor: topLabelColor,
|
|
90
|
+
borderRadius: "50%",
|
|
91
|
+
width: "7px",
|
|
92
|
+
height: "7px",
|
|
93
|
+
} })))),
|
|
94
|
+
React.createElement("span", { key: key, className: `flex items-center justify-between text-[13.33px] ${isSoldOut ? "text-[#c0c0c0]" : ""}` }, typeof val.label === "string" || typeof val.label === "number"
|
|
95
|
+
? removeDuplicateSeats && isPeru
|
|
96
|
+
? CommonService.truncateSeatLabel(val.label)
|
|
97
|
+
: isTrain
|
|
98
|
+
? CommonService.truncateSeatLabel(val.label, 8)
|
|
99
|
+
: val.label
|
|
100
|
+
: null)));
|
|
101
|
+
});
|
|
73
102
|
};
|
|
74
103
|
const renderSeatPrices = () => {
|
|
75
104
|
if (isPeru) {
|
|
@@ -22,6 +22,7 @@ interface DateTimeSectionMobileProps {
|
|
|
22
22
|
tooltipBgColor?: string;
|
|
23
23
|
showLastSeats?: boolean;
|
|
24
24
|
discountSeatPriceColor?: string;
|
|
25
|
+
isTrain?: boolean;
|
|
25
26
|
}
|
|
26
|
-
declare function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal, isPeru, orignLabel, destinationLabel, originIcon, destinationIcon, travelDate, arrivalDate, depTime, arrTime, seatTypes, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, tooltipBgColor, showLastSeats, discountSeatPriceColor, }: DateTimeSectionMobileProps): React.ReactElement;
|
|
27
|
+
declare function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal, isPeru, orignLabel, destinationLabel, originIcon, destinationIcon, travelDate, arrivalDate, depTime, arrTime, seatTypes, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, tooltipBgColor, showLastSeats, discountSeatPriceColor, isTrain, }: DateTimeSectionMobileProps): React.ReactElement;
|
|
27
28
|
export default DateTimeSectionMobile;
|
|
@@ -23,8 +23,10 @@ const getCleanedDepTime = (raw) => {
|
|
|
23
23
|
};
|
|
24
24
|
const TimeRow = ({ label, icon, alt, date, timeContent, isSoldOut, }) => {
|
|
25
25
|
const formattedDate = DateService.getServiceItemDate(date);
|
|
26
|
-
const dotPositionClass = formattedDate.includes("dom")
|
|
27
|
-
|
|
26
|
+
const dotPositionClass = formattedDate.includes("dom")
|
|
27
|
+
? "max-[399px]:left-[53%]"
|
|
28
|
+
: "";
|
|
29
|
+
return (React.createElement("div", { className: `flex items-center min-[420]:text-[13px] text-[12px] justify-between ${isSoldOut ? "text-[#c0c0c0]" : ""}` },
|
|
28
30
|
React.createElement("div", { className: "flex items-center", style: { flex: 1 } },
|
|
29
31
|
React.createElement("div", null,
|
|
30
32
|
" ",
|
|
@@ -33,9 +35,9 @@ const TimeRow = ({ label, icon, alt, date, timeContent, isSoldOut, }) => {
|
|
|
33
35
|
React.createElement("div", { className: "flex items-center relative capitalize justify-between", style: { flex: 1 } },
|
|
34
36
|
React.createElement("span", { className: "cursor-pointer black-text" }, formattedDate),
|
|
35
37
|
React.createElement("div", { className: `absolute left-[50%] ${dotPositionClass}` }, "\u2022"),
|
|
36
|
-
React.createElement("div", { className: "font-[900] relative black-text" }, timeContent))));
|
|
38
|
+
React.createElement("div", { className: "font-[900] relative black-text" }, timeContent)))));
|
|
37
39
|
};
|
|
38
|
-
function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal, isPeru, orignLabel, destinationLabel, originIcon, destinationIcon, travelDate, arrivalDate, depTime, arrTime, seatTypes, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, tooltipBgColor, showLastSeats, discountSeatPriceColor, }) {
|
|
40
|
+
function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal, isPeru, orignLabel, destinationLabel, originIcon, destinationIcon, travelDate, arrivalDate, depTime, arrTime, seatTypes, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, tooltipBgColor, showLastSeats, discountSeatPriceColor, isTrain, }) {
|
|
39
41
|
const { cleaned: cleanedDepTime, hasAM, hasPM } = getCleanedDepTime(depTime);
|
|
40
42
|
const depTimeContent = isLinatal ? (React.createElement("div", null,
|
|
41
43
|
React.createElement("span", null,
|
|
@@ -56,6 +58,6 @@ function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal
|
|
|
56
58
|
backgroundColor: "#ccc",
|
|
57
59
|
margin: "auto",
|
|
58
60
|
} }),
|
|
59
|
-
React.createElement(SeatSectionMobile, { seatTypes: seatTypes, isSoldOut: isSoldOut, isPeru: isPeru, seatPriceColor: seatPriceColor, currencySign: currencySign, availableSeats: availableSeats, removeDuplicateSeats: removeDuplicateSeats, serviceItem: serviceItem, tooltipBgColor: tooltipBgColor, showLastSeats: showLastSeats, discountSeatPriceColor: discountSeatPriceColor })));
|
|
61
|
+
React.createElement(SeatSectionMobile, { seatTypes: seatTypes, isSoldOut: isSoldOut, isPeru: isPeru, seatPriceColor: seatPriceColor, currencySign: currencySign, availableSeats: availableSeats, removeDuplicateSeats: removeDuplicateSeats, serviceItem: serviceItem, tooltipBgColor: tooltipBgColor, showLastSeats: showLastSeats, discountSeatPriceColor: discountSeatPriceColor, isTrain: isTrain })));
|
|
60
62
|
}
|
|
61
63
|
export default DateTimeSectionMobile;
|
|
@@ -16,6 +16,7 @@ interface SeatSectionMobileProps {
|
|
|
16
16
|
tooltipBgColor?: string;
|
|
17
17
|
showLastSeats?: boolean;
|
|
18
18
|
discountSeatPriceColor?: string;
|
|
19
|
+
isTrain?: boolean;
|
|
19
20
|
}
|
|
20
|
-
declare function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, tooltipBgColor, showLastSeats, discountSeatPriceColor, }: SeatSectionMobileProps): React.ReactElement;
|
|
21
|
+
declare function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, tooltipBgColor, showLastSeats, discountSeatPriceColor, isTrain, }: SeatSectionMobileProps): React.ReactElement;
|
|
21
22
|
export default SeatSectionMobile;
|
|
@@ -42,8 +42,8 @@ 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, serviceItem, tooltipBgColor, showLastSeats, discountSeatPriceColor, }) {
|
|
46
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
45
|
+
function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, tooltipBgColor, showLastSeats, discountSeatPriceColor, isTrain, }) {
|
|
46
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
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) {
|
|
@@ -101,7 +101,7 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
101
101
|
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] text-[#464647]", style: { opacity: isSoldOut ? 0.5 : 1 } }, "Agotado"))) : null));
|
|
102
102
|
};
|
|
103
103
|
const renderSeats = () => {
|
|
104
|
-
var _a, _b
|
|
104
|
+
var _a, _b;
|
|
105
105
|
if (isPeru) {
|
|
106
106
|
return renderPeruSeats();
|
|
107
107
|
}
|
|
@@ -109,11 +109,16 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
109
109
|
const uniqueSeats = getUniqueSeats(seatTypesData, 3);
|
|
110
110
|
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]" })));
|
|
111
111
|
}
|
|
112
|
-
|
|
112
|
+
const filteredSeats = (_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);
|
|
113
|
+
return (_b = (isTrain ? filteredSeats : filteredSeats === null || filteredSeats === void 0 ? void 0 : filteredSeats.slice(0, 2))) === null || _b === void 0 ? void 0 : _b.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]" })));
|
|
113
114
|
};
|
|
114
115
|
const seats = removeDuplicateSeats
|
|
115
116
|
? getUniqueSeats(seatTypesData, 3)
|
|
116
|
-
: (
|
|
117
|
+
: (() => {
|
|
118
|
+
var _a;
|
|
119
|
+
const filtered = (_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);
|
|
120
|
+
return isTrain ? filtered : filtered === null || filtered === void 0 ? void 0 : filtered.slice(0, 2);
|
|
121
|
+
})();
|
|
117
122
|
const discountedSeats = seats === null || seats === void 0 ? void 0 : seats.map((seat) => (Object.assign(Object.assign({}, seat), commonService.calculateDiscountedPrice(seat.fare, serviceItem))));
|
|
118
123
|
const peruLowestFare = isPeru ? getLowestFare() : null;
|
|
119
124
|
const peruDiscountCalc = isPeru && peruLowestFare != null
|
|
@@ -124,7 +129,7 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
124
129
|
peruDiscountCalc.originalPrice !== peruDiscountCalc.discountedPrice
|
|
125
130
|
: discountedSeats === null || discountedSeats === void 0 ? void 0 : discountedSeats.some((s) => s.originalPrice !== s.discountedPrice);
|
|
126
131
|
const discountSeat = isPeru && peruDiscountCalc
|
|
127
|
-
? Object.assign({ label: "", fare: peruLowestFare }, peruDiscountCalc) : (
|
|
132
|
+
? Object.assign({ label: "", fare: peruLowestFare }, peruDiscountCalc) : (_b = discountedSeats === null || discountedSeats === void 0 ? void 0 : discountedSeats.filter((seat) => !EXCEPTIONS.includes(seat.label))) === null || _b === void 0 ? void 0 : _b.sort((a, b) => a.discountedPrice - b.discountedPrice)[0];
|
|
128
133
|
const discountValue = (() => {
|
|
129
134
|
if ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_type) === "percentage" &&
|
|
130
135
|
typeof (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_value) === "number") {
|
|
@@ -147,14 +152,14 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
147
152
|
};
|
|
148
153
|
const originalDpPrice = getMinValue(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.original_dp_price);
|
|
149
154
|
const dpDiscountPercent = getMinValue(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents);
|
|
150
|
-
const firstSeatFare = (
|
|
155
|
+
const firstSeatFare = (_d = (_c = seatTypesData === null || seatTypesData === void 0 ? void 0 : seatTypesData.filter((item) => getFilteredSeats(item.label) && !EXCEPTIONS.includes(item.label))) === null || _c === void 0 ? void 0 : _c.sort((a, b) => a.fare - b.fare)[0]) === null || _d === void 0 ? void 0 : _d.fare;
|
|
151
156
|
const hasDpDiscount = (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) &&
|
|
152
157
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents) &&
|
|
153
158
|
originalDpPrice != null &&
|
|
154
159
|
dpDiscountPercent != null &&
|
|
155
160
|
firstSeatFare != null;
|
|
156
161
|
return (React.createElement("div", { className: "content-center relative", style: { width: "40%" } }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) &&
|
|
157
|
-
!((
|
|
162
|
+
!((_e = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) === null || _e === void 0 ? void 0 : _e.length) &&
|
|
158
163
|
!dpDiscountPercent ? (React.createElement("div", { className: "flex flex-col justify-between h-[2.5rem]", style: { gap: isSoldOut ? "0px" : "5px" } }, renderDpSeats())) : hasDpDiscount ? (React.createElement("div", { className: "relative grid grid-cols-[auto_auto] justify-between gap-x-[8px] " },
|
|
159
164
|
!isNaN(Number(dpDiscountPercent)) &&
|
|
160
165
|
Number(dpDiscountPercent) > 0 && (React.createElement("div", { className: "absolute -top-[18px] right-[0px]", style: {
|
|
@@ -186,7 +191,7 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
186
191
|
React.createElement("span", { className: "flex items-center justify-end gap-[4px] text-[14px] bold-text leading-[24px]", style: {
|
|
187
192
|
color: isSoldOut ? "#bbb" : discountSeatPriceColor || "#ff5964",
|
|
188
193
|
} },
|
|
189
|
-
((
|
|
194
|
+
((_f = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _f === void 0 ? void 0 : _f.fireIcon) ? (React.createElement("img", { src: serviceItem.icons.fireIcon, alt: "discount", className: "h-[16px] w-[16px] object-contain", style: { filter: isSoldOut ? "grayscale" : "" } })) : null,
|
|
190
195
|
commonService.discountedCurrency(Number(firstSeatFare), currencySign)),
|
|
191
196
|
isSoldOut ? (React.createElement("span", { className: "col-span-2 min-[420]:text-[13px] text-right text-[12px] text-[#ccc]" }, "Agotado")) : null)) : hasDiscount && discountSeat ? (React.createElement("div", null,
|
|
192
197
|
React.createElement("div", { className: "relative grid grid-cols-[auto_auto] justify-between gap-x-[8px] " },
|
|
@@ -220,7 +225,7 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
220
225
|
React.createElement("span", { className: "flex items-center justify-end gap-[4px] text-[14px] bold-text leading-[24px]", style: {
|
|
221
226
|
color: isSoldOut ? "#bbb" : discountSeatPriceColor || "#ff5964",
|
|
222
227
|
} },
|
|
223
|
-
((
|
|
228
|
+
((_g = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _g === void 0 ? void 0 : _g.fireIcon) ? (React.createElement("img", { src: serviceItem.icons.fireIcon, alt: "discount", className: "h-[16px] w-[16px] object-contain", style: { opacity: isSoldOut ? 0.5 : 1 } })) : null,
|
|
224
229
|
commonService.discountedCurrency(discountSeat.discountedPrice, currencySign))))) : (React.createElement("div", { className: "flex flex-col justify-between h-[2.5rem] ", style: {
|
|
225
230
|
gap: isSoldOut ? "0px" : "5px",
|
|
226
231
|
justifyContent: hasMultipleTypes ? "space-between" : "center",
|
|
@@ -3,7 +3,7 @@ declare const commonService: {
|
|
|
3
3
|
discountedCurrency(amount: number, currencySign?: string): string;
|
|
4
4
|
copyObject: (ob: any) => any;
|
|
5
5
|
getServiceTypeLabelForFilters: (service_type: any) => "Tipo de servicio" | "Punto de embarque" | "Tipo de asiento" | "SERVICIOS" | "";
|
|
6
|
-
truncateSeatLabel: (label: string | number) => string;
|
|
6
|
+
truncateSeatLabel: (label: string | number, maxLength?: number) => string;
|
|
7
7
|
getAmenitiesImage: (name: string, serviceItem: any) => string;
|
|
8
8
|
getAmenityName: (rawAmenity: string) => string;
|
|
9
9
|
getSeatNameForFilters: (rawSeat: any) => any;
|
|
@@ -34,11 +34,15 @@ const commonService = {
|
|
|
34
34
|
return "";
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
|
-
truncateSeatLabel: (label) => {
|
|
37
|
+
truncateSeatLabel: (label, maxLength) => {
|
|
38
38
|
if (typeof label !== "string")
|
|
39
39
|
return String(label);
|
|
40
40
|
if (label.includes("("))
|
|
41
41
|
return label;
|
|
42
|
+
// If maxLength provided, hard-truncate regardless of word count
|
|
43
|
+
if (maxLength != null && label.length > maxLength) {
|
|
44
|
+
return label.slice(0, maxLength) + "...";
|
|
45
|
+
}
|
|
42
46
|
const words = label.trim().split(/\s+/);
|
|
43
47
|
const truncateWord = (word) => word.length > 5 ? word.slice(0, 3) + "..." : word;
|
|
44
48
|
if (words.length === 1)
|
package/package.json
CHANGED
|
@@ -116,9 +116,25 @@ function ServiceItemPB({
|
|
|
116
116
|
showLoginModal,
|
|
117
117
|
isLoggedIn,
|
|
118
118
|
showLoginOption,
|
|
119
|
+
isTrain,
|
|
120
|
+
selectedSeatKey,
|
|
121
|
+
onSeatSelect,
|
|
122
|
+
onTrainButtonClick,
|
|
123
|
+
showSeatSelectionError,
|
|
124
|
+
onShowSeatSelectionError,
|
|
125
|
+
onClearSeatSelectionError,
|
|
119
126
|
isFlores,
|
|
120
127
|
operatorLabel,
|
|
121
128
|
}: ServiceItemProps & { currencySign?: string }): React.ReactElement {
|
|
129
|
+
const handleSeatSelect = (
|
|
130
|
+
key: any,
|
|
131
|
+
price: number,
|
|
132
|
+
seatKey: string,
|
|
133
|
+
apiSeatType?: string,
|
|
134
|
+
) => {
|
|
135
|
+
onClearSeatSelectionError?.();
|
|
136
|
+
onSeatSelect?.(key, price, seatKey, apiSeatType);
|
|
137
|
+
};
|
|
122
138
|
const getAnimationIcon = (icon: string) => {
|
|
123
139
|
const animation = ANIMATION_MAP[icon];
|
|
124
140
|
if (!animation) return null;
|
|
@@ -315,6 +331,17 @@ function ServiceItemPB({
|
|
|
315
331
|
return;
|
|
316
332
|
}
|
|
317
333
|
|
|
334
|
+
if (isTrain) {
|
|
335
|
+
if (!selectedSeatKey) {
|
|
336
|
+
onShowSeatSelectionError?.(serviceItem.id);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (onTrainButtonClick) {
|
|
340
|
+
onTrainButtonClick();
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
318
345
|
onBookButtonPress();
|
|
319
346
|
};
|
|
320
347
|
|
|
@@ -528,6 +555,10 @@ function ServiceItemPB({
|
|
|
528
555
|
isPeru={isPeru}
|
|
529
556
|
renderIcon={renderIcon}
|
|
530
557
|
discountSeatPriceColor={colors.discountSeatPriceColor}
|
|
558
|
+
isTrain={isTrain}
|
|
559
|
+
selectedSeatKey={selectedSeatKey}
|
|
560
|
+
onSeatSelect={handleSeatSelect}
|
|
561
|
+
topLabelColor={colors.topLabelColor}
|
|
531
562
|
/>
|
|
532
563
|
</div>
|
|
533
564
|
|
|
@@ -543,6 +574,18 @@ function ServiceItemPB({
|
|
|
543
574
|
soldOutIcon={renderIcon("soldOutIcon", "14px")}
|
|
544
575
|
onClick={checkMidnight}
|
|
545
576
|
/>
|
|
577
|
+
{showSeatSelectionError === serviceItem.id && isTrain && (
|
|
578
|
+
<div className="flex justify-center mr-[11px] w-[100%] right-[0px] absolute left-[0] top-[40px]">
|
|
579
|
+
<div
|
|
580
|
+
className="text-[9px] text-center whitespace-nowrap"
|
|
581
|
+
style={{
|
|
582
|
+
color: colors.seatPriceColor,
|
|
583
|
+
}}
|
|
584
|
+
>
|
|
585
|
+
Selecciona el tipo de servicio
|
|
586
|
+
</div>
|
|
587
|
+
</div>
|
|
588
|
+
)}
|
|
546
589
|
{showLastSeats ? (
|
|
547
590
|
<div className="flex justify-center mr-[11px] w-[100%] right-[0px] absolute left-[0] top-[40px]">
|
|
548
591
|
{serviceItem?.available_seats < 10 &&
|
|
@@ -46,6 +46,7 @@ function ServiceItemMobile({
|
|
|
46
46
|
isLinatal,
|
|
47
47
|
viewersConfig,
|
|
48
48
|
operatorLabel,
|
|
49
|
+
isTrain,
|
|
49
50
|
}: MobileServiceItemProps): React.ReactElement {
|
|
50
51
|
const isItemExpanded = serviceItem.id === isExpanded;
|
|
51
52
|
const isPetSeat = (Object.keys(serviceItem?.pet_seat_info) || []).length > 0;
|
|
@@ -249,6 +250,7 @@ function ServiceItemMobile({
|
|
|
249
250
|
serviceItem={serviceItem}
|
|
250
251
|
showLastSeats={showLastSeats}
|
|
251
252
|
discountSeatPriceColor={colors.discountSeatPriceColor}
|
|
253
|
+
isTrain={isTrain}
|
|
252
254
|
/>
|
|
253
255
|
|
|
254
256
|
{hasDiscount && (
|
|
@@ -226,6 +226,18 @@ export interface ServiceItemProps {
|
|
|
226
226
|
showLoginModal?: any;
|
|
227
227
|
isLoggedIn?: any;
|
|
228
228
|
showLoginOption?: boolean;
|
|
229
|
+
isTrain?: boolean;
|
|
230
|
+
selectedSeatKey?: any;
|
|
231
|
+
onSeatSelect?: (
|
|
232
|
+
key: any,
|
|
233
|
+
price: number,
|
|
234
|
+
seatKey: string,
|
|
235
|
+
apiSeatType?: string,
|
|
236
|
+
) => void;
|
|
237
|
+
onTrainButtonClick?: any;
|
|
238
|
+
showSeatSelectionError?: string | null;
|
|
239
|
+
onShowSeatSelectionError?: (serviceId: string) => void;
|
|
240
|
+
onClearSeatSelectionError?: () => void;
|
|
229
241
|
isFlores?: boolean;
|
|
230
242
|
operatorLabel?: string;
|
|
231
243
|
}
|
|
@@ -7,6 +7,8 @@ interface SeatType {
|
|
|
7
7
|
label: string;
|
|
8
8
|
fare: number;
|
|
9
9
|
key: any;
|
|
10
|
+
apiSeatType?: string;
|
|
11
|
+
api_seat_type?: string;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
interface SeatSectionProps {
|
|
@@ -21,6 +23,15 @@ interface SeatSectionProps {
|
|
|
21
23
|
serviceItem?: any;
|
|
22
24
|
renderIcon?: (iconKey: string, size?: string) => React.ReactNode;
|
|
23
25
|
discountSeatPriceColor?: string;
|
|
26
|
+
isTrain?: boolean;
|
|
27
|
+
selectedSeatKey?: any;
|
|
28
|
+
onSeatSelect?: (
|
|
29
|
+
key: any,
|
|
30
|
+
price: number,
|
|
31
|
+
seatKey: string,
|
|
32
|
+
apiSeatType?: string,
|
|
33
|
+
) => void;
|
|
34
|
+
topLabelColor?: string;
|
|
24
35
|
}
|
|
25
36
|
|
|
26
37
|
function getAllSeatTypes(seatTypes: SeatType[]) {
|
|
@@ -31,6 +42,8 @@ function getAllSeatTypes(seatTypes: SeatType[]) {
|
|
|
31
42
|
let seatTypesWithPrices = seatTypes.filter(Boolean).map((val) => ({
|
|
32
43
|
label: val?.label,
|
|
33
44
|
price: val?.fare,
|
|
45
|
+
key: val?.key,
|
|
46
|
+
apiSeatType: val?.apiSeatType || val?.api_seat_type,
|
|
34
47
|
}));
|
|
35
48
|
|
|
36
49
|
seatTypesWithPrices.sort((a, b) => a.price - b.price);
|
|
@@ -38,7 +51,7 @@ function getAllSeatTypes(seatTypes: SeatType[]) {
|
|
|
38
51
|
return seatTypesWithPrices;
|
|
39
52
|
}
|
|
40
53
|
|
|
41
|
-
function getSortedSeatTypes(seatTypes: SeatType[]) {
|
|
54
|
+
function getSortedSeatTypes(seatTypes: SeatType[], isTrain: any) {
|
|
42
55
|
if (!seatTypes?.length) {
|
|
43
56
|
return [{ label: "Salon cama", price: 0 }];
|
|
44
57
|
}
|
|
@@ -52,7 +65,9 @@ function getSortedSeatTypes(seatTypes: SeatType[]) {
|
|
|
52
65
|
seatTypesWithPrices[2] = seatTypesWithPrices[premiumIndex];
|
|
53
66
|
}
|
|
54
67
|
|
|
55
|
-
|
|
68
|
+
if (!isTrain) {
|
|
69
|
+
seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
|
|
70
|
+
}
|
|
56
71
|
|
|
57
72
|
const seenPrices = new Set<number>();
|
|
58
73
|
seatTypesWithPrices = seatTypesWithPrices.filter((seat) => {
|
|
@@ -97,14 +112,18 @@ function SeatSection({
|
|
|
97
112
|
priceColor,
|
|
98
113
|
currencySign,
|
|
99
114
|
removeDuplicateSeats,
|
|
115
|
+
selectedSeatKey,
|
|
116
|
+
onSeatSelect,
|
|
100
117
|
isPeru,
|
|
101
118
|
serviceItem,
|
|
102
119
|
renderIcon,
|
|
103
120
|
dpSeatColor,
|
|
104
121
|
discountSeatPriceColor,
|
|
122
|
+
isTrain,
|
|
123
|
+
topLabelColor,
|
|
105
124
|
}: SeatSectionProps): React.ReactElement {
|
|
106
125
|
const uniqueSeats = getUniqueSeats(seatTypes);
|
|
107
|
-
const sortedSeatTypes = getSortedSeatTypes(seatTypes);
|
|
126
|
+
const sortedSeatTypes = getSortedSeatTypes(seatTypes, isTrain);
|
|
108
127
|
const numberOfSeats = getNumberOfSeats(seatTypes);
|
|
109
128
|
const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
|
|
110
129
|
|
|
@@ -116,22 +135,68 @@ function SeatSection({
|
|
|
116
135
|
const renderSeatNames = () => {
|
|
117
136
|
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
118
137
|
|
|
119
|
-
return seats.map((val, key: number) =>
|
|
120
|
-
SEAT_EXCEPTIONS.includes(val.label) ? null : (
|
|
121
|
-
<
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
138
|
+
return seats.map((val, key: number) => {
|
|
139
|
+
return SEAT_EXCEPTIONS.includes(val.label) ? null : (
|
|
140
|
+
<div
|
|
141
|
+
className="flex items-center"
|
|
142
|
+
style={isTrain ? { cursor: "pointer" } : undefined}
|
|
143
|
+
onClick={
|
|
144
|
+
isTrain && !isSoldOut
|
|
145
|
+
? () =>
|
|
146
|
+
val.label === selectedSeatKey
|
|
147
|
+
? onSeatSelect?.(null, 0, "", "")
|
|
148
|
+
: onSeatSelect?.(
|
|
149
|
+
val.label,
|
|
150
|
+
val.price,
|
|
151
|
+
val.key,
|
|
152
|
+
(val as any).apiSeatType,
|
|
153
|
+
)
|
|
154
|
+
: undefined
|
|
155
|
+
}
|
|
126
156
|
>
|
|
127
|
-
{
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
157
|
+
{isTrain && (
|
|
158
|
+
<div
|
|
159
|
+
style={{
|
|
160
|
+
border: `1px solid ${val.label === selectedSeatKey ? topLabelColor : "#ccc"}`,
|
|
161
|
+
borderRadius: "50%",
|
|
162
|
+
width: "14px",
|
|
163
|
+
height: "14px",
|
|
164
|
+
minWidth: "14px",
|
|
165
|
+
marginRight: "10px",
|
|
166
|
+
display: "flex",
|
|
167
|
+
alignItems: "center",
|
|
168
|
+
justifyContent: "center",
|
|
169
|
+
}}
|
|
170
|
+
>
|
|
171
|
+
{val.label === selectedSeatKey && (
|
|
172
|
+
<div
|
|
173
|
+
style={{
|
|
174
|
+
backgroundColor: topLabelColor,
|
|
175
|
+
borderRadius: "50%",
|
|
176
|
+
width: "7px",
|
|
177
|
+
height: "7px",
|
|
178
|
+
}}
|
|
179
|
+
/>
|
|
180
|
+
)}
|
|
181
|
+
</div>
|
|
182
|
+
)}
|
|
183
|
+
<span
|
|
184
|
+
key={key}
|
|
185
|
+
className={`flex items-center justify-between text-[13.33px] ${
|
|
186
|
+
isSoldOut ? "text-[#c0c0c0]" : ""
|
|
187
|
+
}`}
|
|
188
|
+
>
|
|
189
|
+
{typeof val.label === "string" || typeof val.label === "number"
|
|
190
|
+
? removeDuplicateSeats && isPeru
|
|
191
|
+
? CommonService.truncateSeatLabel(val.label)
|
|
192
|
+
: isTrain
|
|
193
|
+
? CommonService.truncateSeatLabel(val.label, 8)
|
|
194
|
+
: val.label
|
|
195
|
+
: null}
|
|
196
|
+
</span>
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
});
|
|
135
200
|
};
|
|
136
201
|
|
|
137
202
|
const renderSeatPrices = () => {
|
|
@@ -25,6 +25,7 @@ interface DateTimeSectionMobileProps {
|
|
|
25
25
|
tooltipBgColor?: string;
|
|
26
26
|
showLastSeats?: boolean;
|
|
27
27
|
discountSeatPriceColor?: string;
|
|
28
|
+
isTrain?: boolean;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
const pad = (n: number) => (n < 10 ? "0" + n : String(n));
|
|
@@ -67,41 +68,43 @@ const TimeRow: React.FC<TimeRowProps> = ({
|
|
|
67
68
|
isSoldOut,
|
|
68
69
|
}) => {
|
|
69
70
|
const formattedDate = DateService.getServiceItemDate(date);
|
|
70
|
-
const dotPositionClass = formattedDate.includes("dom")
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
{
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
71
|
+
const dotPositionClass = formattedDate.includes("dom")
|
|
72
|
+
? "max-[399px]:left-[53%]"
|
|
73
|
+
: "";
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
className={`flex items-center min-[420]:text-[13px] text-[12px] justify-between ${
|
|
77
|
+
isSoldOut ? "text-[#c0c0c0]" : ""
|
|
78
|
+
}`}
|
|
79
|
+
>
|
|
80
|
+
<div className="flex items-center" style={{ flex: 1 }}>
|
|
81
|
+
<div>
|
|
82
|
+
{" "}
|
|
83
|
+
{label ? (
|
|
84
|
+
<div className="w-[60px]">{label}</div>
|
|
85
|
+
) : (
|
|
86
|
+
<div className="w-[12px] h-auto mr-[5px]">
|
|
87
|
+
<img
|
|
88
|
+
src={icon}
|
|
89
|
+
alt={alt}
|
|
90
|
+
className={`w-[12px] h-auto mr-[5px] ${
|
|
91
|
+
isSoldOut ? "grayscale" : ""
|
|
92
|
+
}`}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
</div>
|
|
97
|
+
<div
|
|
98
|
+
className="flex items-center relative capitalize justify-between"
|
|
99
|
+
style={{ flex: 1 }}
|
|
100
|
+
>
|
|
101
|
+
<span className="cursor-pointer black-text">{formattedDate}</span>
|
|
102
|
+
<div className={`absolute left-[50%] ${dotPositionClass}`}>•</div>
|
|
103
|
+
<div className="font-[900] relative black-text">{timeContent}</div>
|
|
104
|
+
</div>
|
|
102
105
|
</div>
|
|
103
106
|
</div>
|
|
104
|
-
|
|
107
|
+
);
|
|
105
108
|
};
|
|
106
109
|
|
|
107
110
|
function DateTimeSectionMobile({
|
|
@@ -127,6 +130,7 @@ function DateTimeSectionMobile({
|
|
|
127
130
|
tooltipBgColor,
|
|
128
131
|
showLastSeats,
|
|
129
132
|
discountSeatPriceColor,
|
|
133
|
+
isTrain,
|
|
130
134
|
}: DateTimeSectionMobileProps): React.ReactElement {
|
|
131
135
|
const { cleaned: cleanedDepTime, hasAM, hasPM } = getCleanedDepTime(depTime);
|
|
132
136
|
|
|
@@ -198,6 +202,7 @@ function DateTimeSectionMobile({
|
|
|
198
202
|
tooltipBgColor={tooltipBgColor}
|
|
199
203
|
showLastSeats={showLastSeats}
|
|
200
204
|
discountSeatPriceColor={discountSeatPriceColor}
|
|
205
|
+
isTrain={isTrain}
|
|
201
206
|
/>
|
|
202
207
|
</div>
|
|
203
208
|
);
|
|
@@ -31,6 +31,7 @@ interface SeatSectionMobileProps {
|
|
|
31
31
|
tooltipBgColor?: string;
|
|
32
32
|
showLastSeats?: boolean;
|
|
33
33
|
discountSeatPriceColor?: string;
|
|
34
|
+
isTrain?: boolean;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
interface SeatRowProps {
|
|
@@ -118,6 +119,7 @@ function SeatSectionMobile({
|
|
|
118
119
|
tooltipBgColor,
|
|
119
120
|
showLastSeats,
|
|
120
121
|
discountSeatPriceColor,
|
|
122
|
+
isTrain,
|
|
121
123
|
}: SeatSectionMobileProps): React.ReactElement {
|
|
122
124
|
const hasMultipleTypes = (seatTypesData?.length ?? 0) > 2;
|
|
123
125
|
|
|
@@ -282,10 +284,11 @@ function SeatSectionMobile({
|
|
|
282
284
|
));
|
|
283
285
|
}
|
|
284
286
|
|
|
285
|
-
|
|
287
|
+
const filteredSeats = seatTypesData
|
|
286
288
|
?.filter((item) => getFilteredSeats(item.label))
|
|
287
|
-
?.sort((a, b) => a.fare - b.fare)
|
|
288
|
-
|
|
289
|
+
?.sort((a, b) => a.fare - b.fare);
|
|
290
|
+
|
|
291
|
+
return (isTrain ? filteredSeats : filteredSeats?.slice(0, 2))
|
|
289
292
|
?.map((type, i) => (
|
|
290
293
|
<SeatRow
|
|
291
294
|
key={i}
|
|
@@ -303,10 +306,12 @@ function SeatSectionMobile({
|
|
|
303
306
|
|
|
304
307
|
const seats = removeDuplicateSeats
|
|
305
308
|
? getUniqueSeats(seatTypesData, 3)
|
|
306
|
-
:
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
309
|
+
: (() => {
|
|
310
|
+
const filtered = seatTypesData
|
|
311
|
+
?.filter((item) => getFilteredSeats(item.label))
|
|
312
|
+
?.sort((a, b) => a.fare - b.fare);
|
|
313
|
+
return isTrain ? filtered : filtered?.slice(0, 2);
|
|
314
|
+
})();
|
|
310
315
|
|
|
311
316
|
const discountedSeats = seats?.map((seat) => ({
|
|
312
317
|
...seat,
|
|
@@ -39,9 +39,15 @@ const commonService = {
|
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
|
|
42
|
-
truncateSeatLabel: (label: string | number): string => {
|
|
42
|
+
truncateSeatLabel: (label: string | number, maxLength?: number): string => {
|
|
43
43
|
if (typeof label !== "string") return String(label);
|
|
44
44
|
if (label.includes("(")) return label;
|
|
45
|
+
|
|
46
|
+
// If maxLength provided, hard-truncate regardless of word count
|
|
47
|
+
if (maxLength != null && label.length > maxLength) {
|
|
48
|
+
return label.slice(0, maxLength) + "...";
|
|
49
|
+
}
|
|
50
|
+
|
|
45
51
|
const words = label.trim().split(/\s+/);
|
|
46
52
|
|
|
47
53
|
const truncateWord = (word: string) =>
|