kupos-ui-components-lib 9.9.6 → 9.9.7
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/KuposUIComponent.d.ts +0 -3
- package/dist/components/ServiceItem/PeruServiceItemDesktop.d.ts +1 -1
- package/dist/components/ServiceItem/PeruServiceItemDesktop.js +176 -156
- package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemDesktop.js +31 -29
- package/dist/components/ServiceItem/ServiceItemMobile.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemMobile.js +17 -43
- package/dist/components/ServiceItem/mobileTypes.d.ts +2 -48
- package/dist/components/ServiceItem/types.d.ts +8 -27
- package/dist/styles.css +16 -219
- package/dist/ui/ExpendedDropDown/ExpandedDropdown.d.ts +2 -1
- package/dist/ui/ExpendedDropDown/ExpandedDropdown.js +4 -2
- package/dist/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.js +10 -3
- package/dist/ui/OfferBanner.d.ts +0 -2
- package/dist/ui/OfferBanner.js +15 -22
- package/dist/ui/SeatSection/SeatSection.d.ts +7 -1
- package/dist/ui/SeatSection/SeatSection.js +41 -12
- package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +2 -1
- package/dist/ui/mobileweb/DateTimeSectionMobile.js +12 -6
- package/dist/ui/mobileweb/SeatSectionMobile.d.ts +2 -1
- package/dist/ui/mobileweb/SeatSectionMobile.js +21 -14
- package/dist/utils/CommonService.d.ts +1 -4
- package/dist/utils/CommonService.js +6 -19
- package/package.json +1 -1
- package/src/KuposUIComponent.tsx +0 -3
- package/src/components/ServiceItem/PeruServiceItemDesktop.tsx +277 -404
- package/src/components/ServiceItem/ServiceItemDesktop.tsx +51 -71
- package/src/components/ServiceItem/ServiceItemMobile.tsx +290 -387
- package/src/components/ServiceItem/mobileTypes.ts +8 -50
- package/src/components/ServiceItem/types.ts +13 -32
- package/src/styles.css +0 -15
- package/src/ui/ExpendedDropDown/ExpandedDropdown.tsx +4 -2
- package/src/ui/OfferBanner.tsx +43 -71
- package/src/ui/SeatSection/SeatSection.tsx +86 -21
- package/src/ui/mobileweb/DateTimeSectionMobile.tsx +44 -35
- package/src/ui/mobileweb/SeatSectionMobile.tsx +23 -11
- package/src/utils/CommonService.ts +8 -27
- package/src/assets/images/anims/service_list/flame_anim.json +0 -1
- package/src/assets/images/anims/service_list/thunder_icon.json +0 -1
- package/src/assets/images/anims/service_list/users_anim.json +0 -1
- package/src/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.tsx +0 -575
- package/src/ui/FeatureServiceUI/FeatureServiceUi.tsx +0 -634
package/dist/ui/OfferBanner.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import LottiePlayer from "../assets/LottiePlayer";
|
|
3
3
|
import CommonService from "../utils/CommonService";
|
|
4
|
-
const OfferBanner = ({ offerGradient, isSoldOut, serviceItem, renderIcon, isLoggedIn, showLoginModal, viewersConfig, getAnimationIcon, showLoginOption,
|
|
5
|
-
var _a, _b, _c, _d;
|
|
6
|
-
return (React.createElement("div", { className: "text-white p-[
|
|
7
|
-
background:
|
|
8
|
-
? colors === null || colors === void 0 ? void 0 : colors.bottomStripColor
|
|
9
|
-
: offerGradient,
|
|
4
|
+
const OfferBanner = ({ offerGradient, isSoldOut, serviceItem, renderIcon, isLoggedIn, showLoginModal, viewersConfig, getAnimationIcon, showLoginOption, }) => {
|
|
5
|
+
var _a, _b, _c, _d, _e, _f;
|
|
6
|
+
return (React.createElement("div", { className: "text-white p-[10px_15px] text-left w-full flex items-center absolute -bottom-[36px] pt-[50px] rounded-b-[14px] text-[14px]", style: {
|
|
7
|
+
background: offerGradient,
|
|
10
8
|
opacity: isSoldOut ? 0.5 : 1,
|
|
11
9
|
// zIndex: 0,
|
|
12
10
|
} },
|
|
@@ -15,7 +13,7 @@ const OfferBanner = ({ offerGradient, isSoldOut, serviceItem, renderIcon, isLogg
|
|
|
15
13
|
Object.keys((_a = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents) !== null && _a !== void 0 ? _a : {}).length === 0 &&
|
|
16
14
|
((_b = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) !== null && _b !== void 0 ? _b : []).length === 0 ? (React.createElement("div", { className: "flex items-center gap-[5px]" },
|
|
17
15
|
React.createElement(LottiePlayer, { animationData: getAnimationIcon("starAnimation"), width: "18px", height: "18px" }),
|
|
18
|
-
React.createElement("span", null, "Servicio popular entre los usuarios"))) :
|
|
16
|
+
React.createElement("span", null, "Servicio popular entre los usuarios"))) : (React.createElement("div", { className: "flex items-center" },
|
|
19
17
|
React.createElement(LottiePlayer, { animationData: getAnimationIcon("bombAnimation"), width: "18px", height: "18px" }),
|
|
20
18
|
React.createElement("div", { className: "flex items-center mt-[2px]" },
|
|
21
19
|
React.createElement("span", { className: "bold-text", style: {
|
|
@@ -25,24 +23,19 @@ const OfferBanner = ({ offerGradient, isSoldOut, serviceItem, renderIcon, isLogg
|
|
|
25
23
|
? ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) || "").slice(0, 30) + "..."
|
|
26
24
|
: (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) || "",
|
|
27
25
|
" ",
|
|
28
|
-
isLoggedIn && showLoginOption ? null :
|
|
26
|
+
isLoggedIn && showLoginOption ? null : Object.keys((_c = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents) !== null && _c !== void 0 ? _c : {}).length > 0 ||
|
|
27
|
+
((_d = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) !== null && _d !== void 0 ? _d : []).length >
|
|
28
|
+
0 ? null : (React.createElement("span", { onClick: showLoginModal, className: "cursor-pointer" }, "- registro")),
|
|
29
29
|
" ",
|
|
30
30
|
"\u00A0"),
|
|
31
31
|
" ",
|
|
32
|
-
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) ? "|" : "",
|
|
32
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) ? "| " : "",
|
|
33
33
|
"Termina en\u00A0",
|
|
34
34
|
React.createElement("span", { className: "bold-text text-end", ref: (node) => CommonService.startCountdown(node, 599), style: {
|
|
35
35
|
fontVariantNumeric: "tabular-nums",
|
|
36
36
|
display: "inline-block",
|
|
37
|
-
} }))))
|
|
38
|
-
|
|
39
|
-
React.createElement(LottiePlayer, { animationData: getAnimationIcon("promoAnim"), width: "18px", height: "18px" }),
|
|
40
|
-
React.createElement("div", { className: "flex items-center mt-[2px]" },
|
|
41
|
-
React.createElement("span", { className: "bold-text", style: {
|
|
42
|
-
marginLeft: (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) ? "6px" : "3px",
|
|
43
|
-
} }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) || ""),
|
|
44
|
-
" "))))),
|
|
45
|
-
(isNewUiEnabled || (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled)) && (React.createElement("div", { className: "flex items-center" },
|
|
37
|
+
} }))))),
|
|
38
|
+
React.createElement("div", { className: "flex items-center" },
|
|
46
39
|
React.createElement(LottiePlayer, { animationData: getAnimationIcon("dotAnimation"), width: "12px", height: "12px" }),
|
|
47
40
|
React.createElement("span", { className: "ml-[6px]" },
|
|
48
41
|
React.createElement("span", { className: "bold-text", ref: (node) => CommonService.startViewerCount(node, viewersConfig), style: { fontVariantNumeric: "tabular-nums" } }),
|
|
@@ -54,13 +47,13 @@ const OfferBanner = ({ offerGradient, isSoldOut, serviceItem, renderIcon, isLogg
|
|
|
54
47
|
" ",
|
|
55
48
|
React.createElement("span", { className: "" },
|
|
56
49
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) &&
|
|
57
|
-
Object.keys((
|
|
58
|
-
|
|
59
|
-
((
|
|
50
|
+
Object.keys((_e = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents) !== null && _e !== void 0 ? _e : {}).length ===
|
|
51
|
+
0 &&
|
|
52
|
+
((_f = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) !== null && _f !== void 0 ? _f : []).length === 0
|
|
60
53
|
? null
|
|
61
54
|
: "Quedan pocos • ",
|
|
62
55
|
React.createElement("span", { className: "bold-text", ref: (node) => CommonService.startComprandoCount(node, 4, 16), style: { fontVariantNumeric: "tabular-nums" } }),
|
|
63
56
|
" ",
|
|
64
|
-
"comprando")))))))
|
|
57
|
+
"comprando")))))));
|
|
65
58
|
};
|
|
66
59
|
export default OfferBanner;
|
|
@@ -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) {
|
|
@@ -147,7 +176,7 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
|
|
|
147
176
|
React.createElement("div", { className: "col-start-1 row-start-3 flex h-[20px] items-end" },
|
|
148
177
|
React.createElement("span", { className: "text-[13.33px] font-normal leading-[20px] text-[#464647]" }, "Desde")),
|
|
149
178
|
React.createElement("div", { className: "col-start-2 row-start-1 flex items-center justify-center absolute", style: { top: "-22px", left: "50%", transform: "translateX(-50%)" } }, !isNaN(Number(dpDiscountPercent)) &&
|
|
150
|
-
Number(dpDiscountPercent) > 0 && (React.createElement("span", { className:
|
|
179
|
+
Number(dpDiscountPercent) > 0 && (React.createElement("span", { className: "rounded-[100px] bg-[#ff5964] px-[6px] text-[12px] bold-text leading-[20px] text-white", style: {
|
|
151
180
|
animation: "pulse-zoom 2s ease-in-out infinite",
|
|
152
181
|
whiteSpace: "nowrap",
|
|
153
182
|
} },
|
|
@@ -168,7 +197,7 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
|
|
|
168
197
|
} }))),
|
|
169
198
|
React.createElement("div", { className: "col-start-2 row-start-3 flex h-[30px] items-end justify-center relative" },
|
|
170
199
|
React.createElement("span", { className: "flex items-center gap-[6px] text-[22px] bold-text leading-[30px]", style: { color: isSoldOut ? "#c0c0c0" : "#ff5964" } },
|
|
171
|
-
React.createElement("div", { className: "absolute", style: { left: isPeru ? "-
|
|
200
|
+
React.createElement("div", { className: "absolute", style: { left: isPeru ? "-19px" : "-19px", bottom: "1px" } }, renderIcon("fireIcon", "16px")),
|
|
172
201
|
availableSeats <= 0
|
|
173
202
|
? CommonService.currency(0, currencySign)
|
|
174
203
|
: CommonService.discountedCurrency(Number(seatTypeFare), currencySign)))));
|
|
@@ -239,7 +268,7 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
|
|
|
239
268
|
React.createElement("div", { className: "col-start-2 row-start-3 flex h-[30px] items-end justify-center relative" },
|
|
240
269
|
React.createElement("span", { className: "flex items-center gap-[6px] text-[22px] bold-text leading-[30px]", style: { color: isSoldOut ? "#c0c0c0" : discountSeatPriceColor } },
|
|
241
270
|
React.createElement("div", { className: "absolute", style: {
|
|
242
|
-
left: isPeru ? "-
|
|
271
|
+
left: isPeru ? "-18px" : "-18px",
|
|
243
272
|
bottom: "1px",
|
|
244
273
|
} }, renderIcon("fireIcon", "16px")),
|
|
245
274
|
availableSeats <= 0
|
|
@@ -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,
|
|
@@ -47,7 +49,11 @@ function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal
|
|
|
47
49
|
? null
|
|
48
50
|
: DateService.ampmOnly(depTime)))) : (DateService.formatTime(depTime));
|
|
49
51
|
return (React.createElement("div", { className: "flex justify-between gap-[5px] w-full", onClick: onBookButtonPress },
|
|
50
|
-
React.createElement("div", { className:
|
|
52
|
+
React.createElement("div", { className: `flex flex-col gap-[4px] w-[50%] ${isTrain ? "justify-center" : "justify-between"}`, style: {
|
|
53
|
+
justifyContent: isCiva && "center",
|
|
54
|
+
minHeight: isTrain ? undefined : "2.5rem",
|
|
55
|
+
alignSelf: isTrain ? "stretch" : undefined,
|
|
56
|
+
} },
|
|
51
57
|
React.createElement(TimeRow, { label: orignLabel, icon: originIcon, alt: "origin", date: travelDate, timeContent: depTimeContent, isSoldOut: isSoldOut }),
|
|
52
58
|
isCiva ? null : (React.createElement(TimeRow, { label: destinationLabel, icon: destinationIcon, alt: "destination", date: arrivalDate, timeContent: DateService.formatTime(arrTime), isSoldOut: isSoldOut }))),
|
|
53
59
|
React.createElement("div", { style: {
|
|
@@ -56,6 +62,6 @@ function DateTimeSectionMobile({ onBookButtonPress, isCiva, isSoldOut, isLinatal
|
|
|
56
62
|
backgroundColor: "#ccc",
|
|
57
63
|
margin: "auto",
|
|
58
64
|
} }),
|
|
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 })));
|
|
65
|
+
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
66
|
}
|
|
61
67
|
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;
|
|
@@ -11,7 +11,7 @@ const EXCEPTIONS = [
|
|
|
11
11
|
"blanco",
|
|
12
12
|
"asiento_mascota",
|
|
13
13
|
];
|
|
14
|
-
const SeatRow = ({ type, index, displayLabel, fare, isSoldOut, seatPriceColor, hasMultipleTypes, textSize, }) => {
|
|
14
|
+
const SeatRow = ({ type, index, displayLabel, fare, isSoldOut, seatPriceColor, hasMultipleTypes, textSize, isTrain, }) => {
|
|
15
15
|
if (EXCEPTIONS.includes(type.label))
|
|
16
16
|
return null;
|
|
17
17
|
const rowClass = hasMultipleTypes
|
|
@@ -20,7 +20,9 @@ const SeatRow = ({ type, index, displayLabel, fare, isSoldOut, seatPriceColor, h
|
|
|
20
20
|
const labelColor = isSoldOut ? "#bbb" : "#464647";
|
|
21
21
|
const priceColor = isSoldOut ? "#bbb" : seatPriceColor;
|
|
22
22
|
return (React.createElement("div", { className: rowClass, key: index },
|
|
23
|
-
React.createElement("span", { className: `min-[420]:text-[13px] ${textSize} `, style: { color: labelColor } },
|
|
23
|
+
React.createElement("span", { className: `min-[420]:text-[13px] ${textSize} `, style: { color: labelColor } }, isTrain
|
|
24
|
+
? commonService.truncateSeatLabel(displayLabel, 8)
|
|
25
|
+
: displayLabel),
|
|
24
26
|
React.createElement("span", { className: `min-[420]:text-[13px] ${textSize} bold-text`, style: { color: priceColor } }, fare)));
|
|
25
27
|
};
|
|
26
28
|
const getFilteredSeats = (item) => {
|
|
@@ -42,8 +44,8 @@ const getUniqueSeats = (data, limit) => {
|
|
|
42
44
|
.sort((a, b) => a.fare - b.fare)
|
|
43
45
|
.slice(0, limit);
|
|
44
46
|
};
|
|
45
|
-
function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, tooltipBgColor, showLastSeats, discountSeatPriceColor, }) {
|
|
46
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
47
|
+
function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, tooltipBgColor, showLastSeats, discountSeatPriceColor, isTrain, }) {
|
|
48
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
47
49
|
const hasMultipleTypes = ((_a = seatTypesData === null || seatTypesData === void 0 ? void 0 : seatTypesData.length) !== null && _a !== void 0 ? _a : 0) > 2;
|
|
48
50
|
const getFare = (fare) => {
|
|
49
51
|
if (removeDuplicateSeats && availableSeats <= 0 && !isPeru) {
|
|
@@ -101,19 +103,24 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
101
103
|
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] text-[#464647]", style: { opacity: isSoldOut ? 0.5 : 1 } }, "Agotado"))) : null));
|
|
102
104
|
};
|
|
103
105
|
const renderSeats = () => {
|
|
104
|
-
var _a, _b
|
|
106
|
+
var _a, _b;
|
|
105
107
|
if (isPeru) {
|
|
106
108
|
return renderPeruSeats();
|
|
107
109
|
}
|
|
108
110
|
if (removeDuplicateSeats) {
|
|
109
111
|
const uniqueSeats = getUniqueSeats(seatTypesData, 3);
|
|
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]" })));
|
|
112
|
+
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]", isTrain: isTrain })));
|
|
111
113
|
}
|
|
112
|
-
|
|
114
|
+
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);
|
|
115
|
+
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]", isTrain: isTrain })));
|
|
113
116
|
};
|
|
114
117
|
const seats = removeDuplicateSeats
|
|
115
118
|
? getUniqueSeats(seatTypesData, 3)
|
|
116
|
-
: (
|
|
119
|
+
: (() => {
|
|
120
|
+
var _a;
|
|
121
|
+
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);
|
|
122
|
+
return isTrain ? filtered : filtered === null || filtered === void 0 ? void 0 : filtered.slice(0, 2);
|
|
123
|
+
})();
|
|
117
124
|
const discountedSeats = seats === null || seats === void 0 ? void 0 : seats.map((seat) => (Object.assign(Object.assign({}, seat), commonService.calculateDiscountedPrice(seat.fare, serviceItem))));
|
|
118
125
|
const peruLowestFare = isPeru ? getLowestFare() : null;
|
|
119
126
|
const peruDiscountCalc = isPeru && peruLowestFare != null
|
|
@@ -124,7 +131,7 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
124
131
|
peruDiscountCalc.originalPrice !== peruDiscountCalc.discountedPrice
|
|
125
132
|
: discountedSeats === null || discountedSeats === void 0 ? void 0 : discountedSeats.some((s) => s.originalPrice !== s.discountedPrice);
|
|
126
133
|
const discountSeat = isPeru && peruDiscountCalc
|
|
127
|
-
? Object.assign({ label: "", fare: peruLowestFare }, peruDiscountCalc) : (
|
|
134
|
+
? 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
135
|
const discountValue = (() => {
|
|
129
136
|
if ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_type) === "percentage" &&
|
|
130
137
|
typeof (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_value) === "number") {
|
|
@@ -147,14 +154,14 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
147
154
|
};
|
|
148
155
|
const originalDpPrice = getMinValue(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.original_dp_price);
|
|
149
156
|
const dpDiscountPercent = getMinValue(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents);
|
|
150
|
-
const firstSeatFare = (
|
|
157
|
+
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
158
|
const hasDpDiscount = (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) &&
|
|
152
159
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents) &&
|
|
153
160
|
originalDpPrice != null &&
|
|
154
161
|
dpDiscountPercent != null &&
|
|
155
162
|
firstSeatFare != null;
|
|
156
163
|
return (React.createElement("div", { className: "content-center relative", style: { width: "40%" } }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) &&
|
|
157
|
-
!((
|
|
164
|
+
!((_e = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) === null || _e === void 0 ? void 0 : _e.length) &&
|
|
158
165
|
!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
166
|
!isNaN(Number(dpDiscountPercent)) &&
|
|
160
167
|
Number(dpDiscountPercent) > 0 && (React.createElement("div", { className: "absolute -top-[18px] right-[0px]", style: {
|
|
@@ -186,7 +193,7 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
186
193
|
React.createElement("span", { className: "flex items-center justify-end gap-[4px] text-[14px] bold-text leading-[24px]", style: {
|
|
187
194
|
color: isSoldOut ? "#bbb" : discountSeatPriceColor || "#ff5964",
|
|
188
195
|
} },
|
|
189
|
-
((
|
|
196
|
+
((_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
197
|
commonService.discountedCurrency(Number(firstSeatFare), currencySign)),
|
|
191
198
|
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
199
|
React.createElement("div", { className: "relative grid grid-cols-[auto_auto] justify-between gap-x-[8px] " },
|
|
@@ -220,8 +227,8 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
220
227
|
React.createElement("span", { className: "flex items-center justify-end gap-[4px] text-[14px] bold-text leading-[24px]", style: {
|
|
221
228
|
color: isSoldOut ? "#bbb" : discountSeatPriceColor || "#ff5964",
|
|
222
229
|
} },
|
|
223
|
-
((
|
|
224
|
-
commonService.discountedCurrency(discountSeat.discountedPrice, currencySign))))) : (React.createElement("div", { className:
|
|
230
|
+
((_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,
|
|
231
|
+
commonService.discountedCurrency(discountSeat.discountedPrice, currencySign))))) : (React.createElement("div", { className: `flex flex-col justify-between ${isTrain ? "" : "h-[2.5rem]"} `, style: {
|
|
225
232
|
gap: isSoldOut ? "0px" : "5px",
|
|
226
233
|
justifyContent: hasMultipleTypes ? "space-between" : "center",
|
|
227
234
|
} },
|
|
@@ -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;
|
|
@@ -14,9 +14,6 @@ declare const commonService: {
|
|
|
14
14
|
discount_type?: string;
|
|
15
15
|
discount_value?: number;
|
|
16
16
|
max_discount?: number;
|
|
17
|
-
discounts?: Array<{
|
|
18
|
-
new_ui_enabled?: boolean;
|
|
19
|
-
}>;
|
|
20
17
|
}) => {
|
|
21
18
|
originalPrice: number;
|
|
22
19
|
discountedPrice: number;
|
|
@@ -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)
|
|
@@ -275,7 +279,6 @@ const commonService = {
|
|
|
275
279
|
return label.toLowerCase();
|
|
276
280
|
},
|
|
277
281
|
calculateDiscountedPrice: (originalPrice, serviceItem) => {
|
|
278
|
-
var _a;
|
|
279
282
|
const price = typeof originalPrice === "string"
|
|
280
283
|
? parseFloat(originalPrice)
|
|
281
284
|
: originalPrice;
|
|
@@ -283,12 +286,6 @@ const commonService = {
|
|
|
283
286
|
return { originalPrice: price, discountedPrice: price };
|
|
284
287
|
}
|
|
285
288
|
const { discount_type, discount_value, max_discount } = serviceItem;
|
|
286
|
-
// Check if there's a discount with new_ui_enabled = true
|
|
287
|
-
const newUiEnabled = (_a = serviceItem.discounts) === null || _a === void 0 ? void 0 : _a.some((d) => d.new_ui_enabled === true);
|
|
288
|
-
// Only apply discount if new_ui_enabled is true OR if regular discount exists
|
|
289
|
-
if (!newUiEnabled && (!discount_type || discount_value == null)) {
|
|
290
|
-
return { originalPrice: price, discountedPrice: price };
|
|
291
|
-
}
|
|
292
289
|
const fixedDiscount = discount_type === "fixed" && discount_value != null ? discount_value : 0;
|
|
293
290
|
const percentageDiscount = discount_type === "percentage" && discount_value != null
|
|
294
291
|
? (price * discount_value) / 100
|
|
@@ -303,14 +300,10 @@ const commonService = {
|
|
|
303
300
|
startViewerCount: (node, viewersConfig) => {
|
|
304
301
|
if (!node || !viewersConfig)
|
|
305
302
|
return;
|
|
306
|
-
const { min, max, interval = 5000 } = viewersConfig;
|
|
307
|
-
const configKey = `${min}-${max}-${interval}`;
|
|
308
|
-
if (node.dataset.viewerId && node.dataset.viewerConfig === configKey) {
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
303
|
const prevId = node.dataset.viewerId;
|
|
312
304
|
if (prevId)
|
|
313
305
|
clearInterval(Number(prevId));
|
|
306
|
+
const { min, max, interval = 5000 } = viewersConfig;
|
|
314
307
|
const clamp = (v) => Math.min(max, Math.max(min, v));
|
|
315
308
|
const initialValue = Math.floor(Math.random() * (max - min + 1)) + min;
|
|
316
309
|
node.textContent = String(initialValue);
|
|
@@ -321,7 +314,6 @@ const commonService = {
|
|
|
321
314
|
node.textContent = String(clamp(Math.round(next)));
|
|
322
315
|
}, interval);
|
|
323
316
|
node.dataset.viewerId = String(id);
|
|
324
|
-
node.dataset.viewerConfig = configKey;
|
|
325
317
|
},
|
|
326
318
|
startCountdown: (node, countdownSeconds = 599) => {
|
|
327
319
|
if (!node)
|
|
@@ -351,10 +343,6 @@ const commonService = {
|
|
|
351
343
|
startComprandoCount: (node, min = 4, max = 16) => {
|
|
352
344
|
if (!node)
|
|
353
345
|
return;
|
|
354
|
-
const configKey = `${min}-${max}`;
|
|
355
|
-
if (node.dataset.comprandoId && node.dataset.comprandoConfig === configKey) {
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
346
|
const prevId = node.dataset.comprandoId;
|
|
359
347
|
if (prevId)
|
|
360
348
|
clearInterval(Number(prevId));
|
|
@@ -371,7 +359,6 @@ const commonService = {
|
|
|
371
359
|
node.textContent = String(next);
|
|
372
360
|
}, 5000); // Update every 5 seconds
|
|
373
361
|
node.dataset.comprandoId = String(id);
|
|
374
|
-
node.dataset.comprandoConfig = configKey;
|
|
375
362
|
},
|
|
376
363
|
};
|
|
377
364
|
export default commonService;
|
package/package.json
CHANGED
package/src/KuposUIComponent.tsx
CHANGED
|
@@ -32,9 +32,6 @@ interface KuposUIComponentProps {
|
|
|
32
32
|
orignLabel?: string;
|
|
33
33
|
destinationLabel?: string;
|
|
34
34
|
t?: (key: string) => string;
|
|
35
|
-
ticketQuantity?: number;
|
|
36
|
-
onIncreaseTicketQuantity?: (serviceItem: any) => void;
|
|
37
|
-
onDecreaseTicketQuantity?: (serviceItem: any) => void;
|
|
38
35
|
|
|
39
36
|
// New ServiceItem props
|
|
40
37
|
id?: string;
|