kupos-ui-components-lib 9.0.6 → 9.0.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/README copy.md +67 -223
- package/dist/assets/images/anims/service_list/directo.json +1 -1
- package/dist/assets/images/anims/service_list/priority_stage.json +1 -1
- package/dist/components/ServiceItem/RatingHover.js +31 -31
- package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemDesktop.js +263 -125
- package/dist/components/ServiceItem/ServiceItemMobile.js +291 -44
- package/dist/components/ServiceItem/mobileTypes.d.ts +0 -3
- package/dist/components/ServiceItem/types.d.ts +0 -7
- package/dist/styles.css +17 -66
- package/dist/ui/AmenitiesBlock.js +36 -25
- package/dist/ui/DurationBlock.js +2 -2
- package/dist/ui/FlexibleBlock.js +4 -2
- package/dist/ui/PetBlock.js +3 -1
- package/dist/ui/RatingBlock.js +2 -6
- package/package.json +1 -1
- package/src/assets/images/anims/service_list/directo.json +1 -1
- package/src/assets/images/anims/service_list/priority_stage.json +1 -1
- package/src/components/ServiceItem/RatingHover.tsx +51 -51
- package/src/components/ServiceItem/ServiceItemDesktop.tsx +466 -222
- package/src/components/ServiceItem/ServiceItemMobile.tsx +501 -120
- package/src/components/ServiceItem/mobileTypes.ts +0 -3
- package/src/components/ServiceItem/types.ts +0 -7
- package/src/ui/AmenitiesBlock.tsx +15 -34
- package/src/ui/DurationBlock.tsx +2 -2
- package/src/ui/FlexibleBlock.tsx +3 -3
- package/src/ui/PetBlock.tsx +2 -2
- package/src/ui/RatingBlock.tsx +4 -16
- package/src/assets/images/anims/service_list/bomb.json +0 -1
- package/src/ui/BottomAmenities/BottomAmenities.tsx +0 -109
- package/src/ui/ExpendedDropDown/ExpandedDropdown.tsx +0 -85
- package/src/ui/KuposButton/KuposButton.tsx +0 -48
- package/src/ui/SeatSection/SeatSection.tsx +0 -187
- package/src/ui/TopAmenities/TopAmenities.tsx +0 -82
- package/src/ui/mobileweb/BottomAmenitiesMobile.tsx +0 -168
- package/src/ui/mobileweb/DateTimeSectionMobile.tsx +0 -192
- package/src/ui/mobileweb/SeatSectionMobile.tsx +0 -256
- package/src/ui/mobileweb/TopAmenitieMobile.tsx +0 -82
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import CommonService from "../../utils/CommonService";
|
|
3
|
-
|
|
4
|
-
const SEAT_EXCEPTIONS = ["Asiento mascota"];
|
|
5
|
-
|
|
6
|
-
interface SeatType {
|
|
7
|
-
label: string;
|
|
8
|
-
fare: number;
|
|
9
|
-
key: any;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface SeatSectionProps {
|
|
13
|
-
seatTypes: SeatType[];
|
|
14
|
-
availableSeats: number;
|
|
15
|
-
isSoldOut: boolean;
|
|
16
|
-
priceColor?: string;
|
|
17
|
-
currencySign?: string;
|
|
18
|
-
removeDuplicateSeats?: boolean;
|
|
19
|
-
isPeru?: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function getAllSeatTypes(seatTypes: SeatType[]) {
|
|
23
|
-
if (!seatTypes?.length) {
|
|
24
|
-
return [{ label: "Salon cama", price: 0 }];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let seatTypesWithPrices = seatTypes.filter(Boolean).map((val) => ({
|
|
28
|
-
label: val?.label,
|
|
29
|
-
price: val?.fare,
|
|
30
|
-
}));
|
|
31
|
-
|
|
32
|
-
seatTypesWithPrices.sort((a, b) => a.price - b.price);
|
|
33
|
-
|
|
34
|
-
return seatTypesWithPrices;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function getSortedSeatTypes(seatTypes: SeatType[]) {
|
|
38
|
-
if (!seatTypes?.length) {
|
|
39
|
-
return [{ label: "Salon cama", price: 0 }];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
let seatTypesWithPrices = getAllSeatTypes(seatTypes);
|
|
43
|
-
const premiumIndex = seatTypesWithPrices.findIndex(
|
|
44
|
-
(item) => item.label === "Premium",
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
if (premiumIndex >= 3) {
|
|
48
|
-
seatTypesWithPrices[2] = seatTypesWithPrices[premiumIndex];
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
|
|
52
|
-
|
|
53
|
-
return seatTypesWithPrices;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function getUniqueSeats(seatTypes: SeatType[]) {
|
|
57
|
-
const allSeatTypes = getAllSeatTypes(seatTypes);
|
|
58
|
-
const seatMap = new Map();
|
|
59
|
-
|
|
60
|
-
allSeatTypes.forEach((seat) => {
|
|
61
|
-
if (SEAT_EXCEPTIONS.includes(seat.label)) return;
|
|
62
|
-
|
|
63
|
-
// Only check if the label already exists in the map, don't compare prices
|
|
64
|
-
if (!seatMap.has(seat.label)) {
|
|
65
|
-
seatMap.set(seat.label, seat);
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
return Array.from(seatMap.values());
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function getNumberOfSeats(seatTypes: SeatType[]) {
|
|
73
|
-
return seatTypes.filter((val) => !SEAT_EXCEPTIONS.includes(val.label)).length;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function SeatSection({
|
|
77
|
-
seatTypes,
|
|
78
|
-
availableSeats,
|
|
79
|
-
isSoldOut,
|
|
80
|
-
priceColor,
|
|
81
|
-
currencySign,
|
|
82
|
-
removeDuplicateSeats,
|
|
83
|
-
isPeru,
|
|
84
|
-
}: SeatSectionProps): React.ReactElement {
|
|
85
|
-
const uniqueSeats = getUniqueSeats(seatTypes);
|
|
86
|
-
const sortedSeatTypes = getSortedSeatTypes(seatTypes);
|
|
87
|
-
const numberOfSeats = getNumberOfSeats(seatTypes);
|
|
88
|
-
const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
|
|
89
|
-
|
|
90
|
-
const formatPrice = (price: number) =>
|
|
91
|
-
availableSeats <= 0
|
|
92
|
-
? CommonService.currency(0, currencySign)
|
|
93
|
-
: CommonService.currency(price, currencySign);
|
|
94
|
-
|
|
95
|
-
const renderSeatNames = () => {
|
|
96
|
-
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
97
|
-
|
|
98
|
-
return seats.map((val, key: number) =>
|
|
99
|
-
SEAT_EXCEPTIONS.includes(val.label) ? null : (
|
|
100
|
-
<span
|
|
101
|
-
key={key}
|
|
102
|
-
className={`flex items-center justify-between text-[13.33px] ${
|
|
103
|
-
isSoldOut ? "text-[#c0c0c0]" : ""
|
|
104
|
-
}`}
|
|
105
|
-
>
|
|
106
|
-
{typeof val.label === "string" || typeof val.label === "number"
|
|
107
|
-
? removeDuplicateSeats && isPeru
|
|
108
|
-
? CommonService.truncateSeatLabel(val.label)
|
|
109
|
-
: val.label
|
|
110
|
-
: null}
|
|
111
|
-
</span>
|
|
112
|
-
),
|
|
113
|
-
);
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const renderSeatPrices = () => {
|
|
117
|
-
if (removeDuplicateSeats) {
|
|
118
|
-
return uniqueSeats.map((val, key) => (
|
|
119
|
-
<span key={key}>{formatPrice(val.price)}</span>
|
|
120
|
-
));
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return sortedSeatTypes.map((val, key: number) =>
|
|
124
|
-
SEAT_EXCEPTIONS.includes(val.label) ? null : (
|
|
125
|
-
<span key={key} className="flex items-center text-[13.33px] bold-text">
|
|
126
|
-
{typeof val.price === "string" || typeof val.price === "number"
|
|
127
|
-
? formatPrice(val.price)
|
|
128
|
-
: null}
|
|
129
|
-
</span>
|
|
130
|
-
),
|
|
131
|
-
);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const renderLabels = () => {
|
|
135
|
-
if (isPeru) {
|
|
136
|
-
return (
|
|
137
|
-
<>
|
|
138
|
-
<span className="text-[13.33px]" style={{ color: "#999" }}>
|
|
139
|
-
Antes
|
|
140
|
-
</span>
|
|
141
|
-
<span className="text-[13.33px]">Desde</span>
|
|
142
|
-
</>
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
return renderSeatNames();
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const strikethroughStyle: React.CSSProperties = {
|
|
149
|
-
color: "#ccc",
|
|
150
|
-
display: "flex",
|
|
151
|
-
textAlign: "end",
|
|
152
|
-
textDecoration: "line-through",
|
|
153
|
-
...(isPeru
|
|
154
|
-
? { position: "relative", top: 0 }
|
|
155
|
-
: { position: "absolute", top: isCentered ? "-10px" : "-18px" }),
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
return (
|
|
159
|
-
<div
|
|
160
|
-
className="relative flex gap-[10px] text-[13.33px] justify-between min-h-[2.5rem]"
|
|
161
|
-
style={isCentered ? { alignItems: "center" } : {}}
|
|
162
|
-
>
|
|
163
|
-
<div className="flex flex-col justify-between" style={{ gap: "10px" }}>
|
|
164
|
-
{renderLabels()}
|
|
165
|
-
</div>
|
|
166
|
-
<div
|
|
167
|
-
className="flex flex-col justify-between absolute inset-y-0 right-0 left-1/2 h-full"
|
|
168
|
-
style={{
|
|
169
|
-
color: isSoldOut ? "#c0c0c0" : priceColor,
|
|
170
|
-
top: 0,
|
|
171
|
-
bottom: 0,
|
|
172
|
-
left: "clamp(60%, 65% + (100vw - 1300px) * 0.1, 65%)",
|
|
173
|
-
right: 0,
|
|
174
|
-
justifyContent: isCentered ? "center" : "",
|
|
175
|
-
gap: "10px",
|
|
176
|
-
}}
|
|
177
|
-
>
|
|
178
|
-
<span className="text-[13.33px]" style={strikethroughStyle}>
|
|
179
|
-
$1.000
|
|
180
|
-
</span>
|
|
181
|
-
{renderSeatPrices()}
|
|
182
|
-
</div>
|
|
183
|
-
</div>
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export default SeatSection;
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import LottiePlayer from "../../assets/LottiePlayer";
|
|
3
|
-
|
|
4
|
-
interface TopAmenitiesProps {
|
|
5
|
-
showPromo: boolean;
|
|
6
|
-
showTopLabel: string | boolean;
|
|
7
|
-
isSoldOut: boolean;
|
|
8
|
-
priceColor?: string;
|
|
9
|
-
buttonColor?: string;
|
|
10
|
-
boardingIcon?: React.ReactNode;
|
|
11
|
-
getAnimationIcon: (icon: string) => any;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function TopAmenities({
|
|
15
|
-
showPromo,
|
|
16
|
-
showTopLabel,
|
|
17
|
-
isSoldOut,
|
|
18
|
-
priceColor,
|
|
19
|
-
buttonColor,
|
|
20
|
-
boardingIcon,
|
|
21
|
-
getAnimationIcon,
|
|
22
|
-
}: TopAmenitiesProps): React.ReactElement {
|
|
23
|
-
return (
|
|
24
|
-
<div
|
|
25
|
-
style={{
|
|
26
|
-
display: "flex",
|
|
27
|
-
justifyContent: "flex-end",
|
|
28
|
-
position: "relative",
|
|
29
|
-
zIndex: "-1",
|
|
30
|
-
}}
|
|
31
|
-
>
|
|
32
|
-
{/* {showPromo && ( */}
|
|
33
|
-
<div
|
|
34
|
-
style={{
|
|
35
|
-
backgroundColor: priceColor,
|
|
36
|
-
position: "relative",
|
|
37
|
-
right: showTopLabel ? "-21px" : "",
|
|
38
|
-
padding: "0 14px",
|
|
39
|
-
borderTopRightRadius: "10px",
|
|
40
|
-
borderTopLeftRadius: "10px",
|
|
41
|
-
}}
|
|
42
|
-
>
|
|
43
|
-
<div style={{ display: "flex", alignItems: "center" }}>
|
|
44
|
-
<LottiePlayer
|
|
45
|
-
animationData={getAnimationIcon("bombAnimation")}
|
|
46
|
-
width="14px"
|
|
47
|
-
height="14px"
|
|
48
|
-
/>
|
|
49
|
-
<span
|
|
50
|
-
className="flex items-center py-[10px] pl-[6px] text-white text-[13.33px] z-20"
|
|
51
|
-
style={{ paddingRight: showTopLabel ? "18px" : "" }}
|
|
52
|
-
>
|
|
53
|
-
<span className="bold-text">kuponazo 20% </span> | Termina
|
|
54
|
-
en
|
|
55
|
-
<span className="bold-text">02:10:30</span>
|
|
56
|
-
</span>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
{/* )} */}
|
|
60
|
-
{showTopLabel && (
|
|
61
|
-
<div
|
|
62
|
-
className="flex items-center py-[10px] px-[14px] text-[13.33px] z-20"
|
|
63
|
-
style={{
|
|
64
|
-
backgroundColor: isSoldOut ? "#ddd" : buttonColor,
|
|
65
|
-
borderTopRightRadius: "10px",
|
|
66
|
-
borderTopLeftRadius: "10px",
|
|
67
|
-
}}
|
|
68
|
-
>
|
|
69
|
-
<LottiePlayer
|
|
70
|
-
animationData={getAnimationIcon("priorityStageAnim")}
|
|
71
|
-
width="14px"
|
|
72
|
-
height="14px"
|
|
73
|
-
/>
|
|
74
|
-
{/* {boardingIcon} */}
|
|
75
|
-
<div className="text-white pl-[6px]">{showTopLabel}</div>
|
|
76
|
-
</div>
|
|
77
|
-
)}
|
|
78
|
-
</div>
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export default TopAmenities;
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import LottiePlayer from "../../assets/LottiePlayer";
|
|
3
|
-
|
|
4
|
-
interface BottomAmenitiesMobileProps {
|
|
5
|
-
isSoldOut: boolean;
|
|
6
|
-
amenitiesNodes: React.ReactNode;
|
|
7
|
-
hoursIcon: React.ReactNode;
|
|
8
|
-
duration: string;
|
|
9
|
-
isDirectTrip?: boolean;
|
|
10
|
-
directoColor?: string;
|
|
11
|
-
directoAnim?: any;
|
|
12
|
-
isChangeTicket?: boolean;
|
|
13
|
-
isPetSeat: boolean;
|
|
14
|
-
petSeatInfo?: Record<string, any>;
|
|
15
|
-
petFriendlyAnim?: any;
|
|
16
|
-
flexibleAnim?: any;
|
|
17
|
-
isTrackingEnabled?: boolean;
|
|
18
|
-
locationAnim?: any;
|
|
19
|
-
downArrowIcon?: string;
|
|
20
|
-
showDropdown: boolean;
|
|
21
|
-
setShowDropdown: (val: boolean) => void;
|
|
22
|
-
onDropdownToggle: () => void;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function BottomAmenitiesMobile({
|
|
26
|
-
isSoldOut,
|
|
27
|
-
amenitiesNodes,
|
|
28
|
-
hoursIcon,
|
|
29
|
-
duration,
|
|
30
|
-
isDirectTrip,
|
|
31
|
-
directoColor,
|
|
32
|
-
directoAnim,
|
|
33
|
-
isChangeTicket,
|
|
34
|
-
isPetSeat,
|
|
35
|
-
petSeatInfo,
|
|
36
|
-
petFriendlyAnim,
|
|
37
|
-
flexibleAnim,
|
|
38
|
-
isTrackingEnabled,
|
|
39
|
-
locationAnim,
|
|
40
|
-
downArrowIcon,
|
|
41
|
-
showDropdown,
|
|
42
|
-
setShowDropdown,
|
|
43
|
-
onDropdownToggle,
|
|
44
|
-
}: BottomAmenitiesMobileProps): React.ReactElement {
|
|
45
|
-
return (
|
|
46
|
-
<div className={`${"flex justify-between items-center items-center "}`}>
|
|
47
|
-
<div className="w-[55%] flex justify-between items-center">
|
|
48
|
-
<div style={{ opacity: isSoldOut ? 0.5 : 1 }}>{amenitiesNodes}</div>
|
|
49
|
-
|
|
50
|
-
<div
|
|
51
|
-
className="flex relative "
|
|
52
|
-
style={{ color: isSoldOut ? "#bbb" : "text-[#464647]" }}
|
|
53
|
-
>
|
|
54
|
-
<div
|
|
55
|
-
className={`w-[12px] h-auto mr-[2px] ${
|
|
56
|
-
isSoldOut ? "grayscale" : ""
|
|
57
|
-
}`}
|
|
58
|
-
>
|
|
59
|
-
{hoursIcon}
|
|
60
|
-
</div>
|
|
61
|
-
|
|
62
|
-
<div
|
|
63
|
-
className={`cursor-default group min-[420]:text-[13px] text-[12px] ${
|
|
64
|
-
isSoldOut ? "text-[#c0c0c0]" : ""
|
|
65
|
-
}`}
|
|
66
|
-
style={{ lineHeight: "normal" }}
|
|
67
|
-
>
|
|
68
|
-
{duration}hrs
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
|
|
72
|
-
{isDirectTrip && (
|
|
73
|
-
<div
|
|
74
|
-
className={`flex items-center gap-[2px] text-white min-[420]:text-[12px] text-[10px] z-20 `}
|
|
75
|
-
style={{
|
|
76
|
-
// backgroundColor: isSoldOut ? "#ddd" : colors.tooltipBgColor,
|
|
77
|
-
color: isSoldOut ? "#bbb" : directoColor,
|
|
78
|
-
}}
|
|
79
|
-
>
|
|
80
|
-
<LottiePlayer
|
|
81
|
-
animationData={directoAnim}
|
|
82
|
-
width="14px"
|
|
83
|
-
height="14px"
|
|
84
|
-
/>
|
|
85
|
-
<div className="ml-[5px]">Directo</div>
|
|
86
|
-
</div>
|
|
87
|
-
)}
|
|
88
|
-
</div>
|
|
89
|
-
{/* Rating */}
|
|
90
|
-
{/* <div>
|
|
91
|
-
<div className="flex items-center ">
|
|
92
|
-
<div
|
|
93
|
-
className="flex items-center cursor-pointer "
|
|
94
|
-
style={{ color: isSoldOut ? "#bbb" : "text-[#464647]" }}
|
|
95
|
-
>
|
|
96
|
-
<span className="ml-[3px] min-[420]:text-[13px] text-[12px] bold-text">
|
|
97
|
-
{serviceItem.operator_details[2]}
|
|
98
|
-
</span>
|
|
99
|
-
</div>
|
|
100
|
-
</div>
|
|
101
|
-
</div> */}
|
|
102
|
-
|
|
103
|
-
{/* <div style={{ opacity: isSoldOut ? 0.5 : 1 }}>{amenitiesNodes}</div> */}
|
|
104
|
-
|
|
105
|
-
<div>
|
|
106
|
-
{(isChangeTicket || isPetSeat) && (
|
|
107
|
-
<div onClick={onDropdownToggle} className="flex items-center">
|
|
108
|
-
{petSeatInfo && Object.keys(petSeatInfo).length > 0 ? (
|
|
109
|
-
<div className="flex items-center">
|
|
110
|
-
<div className={`relative group cursor-default `}>
|
|
111
|
-
<div className="flex items-center">
|
|
112
|
-
<div className={`mr-[5px] ${isSoldOut ? "grayscale" : ""}`}>
|
|
113
|
-
<LottiePlayer
|
|
114
|
-
animationData={petFriendlyAnim}
|
|
115
|
-
width="16px"
|
|
116
|
-
height="16px"
|
|
117
|
-
/>
|
|
118
|
-
</div>
|
|
119
|
-
</div>
|
|
120
|
-
</div>
|
|
121
|
-
</div>
|
|
122
|
-
) : null}
|
|
123
|
-
|
|
124
|
-
{/* Flexible ticket */}
|
|
125
|
-
{isChangeTicket && (
|
|
126
|
-
<div className="flex items-center">
|
|
127
|
-
<div className="relative group cursor-default">
|
|
128
|
-
<div className="flex items-center">
|
|
129
|
-
<div className={`mr-[5px] ${isSoldOut ? "grayscale" : ""}`}>
|
|
130
|
-
<LottiePlayer
|
|
131
|
-
animationData={flexibleAnim}
|
|
132
|
-
width="16px"
|
|
133
|
-
height="16px"
|
|
134
|
-
/>
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
</div>
|
|
138
|
-
</div>
|
|
139
|
-
)}
|
|
140
|
-
|
|
141
|
-
{isTrackingEnabled && (
|
|
142
|
-
<div className="flex items-center mr-[10px]">
|
|
143
|
-
<div
|
|
144
|
-
className={`h-auto mr-[4px] min-[420]:text-[13px] text-[11px] text-[#464647] ${
|
|
145
|
-
isSoldOut ? "grayscale" : ""
|
|
146
|
-
}`}
|
|
147
|
-
>
|
|
148
|
-
<LottiePlayer
|
|
149
|
-
animationData={locationAnim}
|
|
150
|
-
width="16px"
|
|
151
|
-
height="16px"
|
|
152
|
-
/>
|
|
153
|
-
</div>
|
|
154
|
-
</div>
|
|
155
|
-
)}
|
|
156
|
-
|
|
157
|
-
{(isChangeTicket || isPetSeat) && (
|
|
158
|
-
// <img src={serviceItem.icons.plus} alt="icon" width={11} />
|
|
159
|
-
<img src={downArrowIcon} alt="icon" width={14} height={14} />
|
|
160
|
-
)}
|
|
161
|
-
</div>
|
|
162
|
-
)}
|
|
163
|
-
</div>
|
|
164
|
-
</div>
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export default BottomAmenitiesMobile;
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import DateService from "../../utils/DateService";
|
|
3
|
-
import SeatSectionMobile from "./SeatSectionMobile";
|
|
4
|
-
|
|
5
|
-
interface DateTimeSectionMobileProps {
|
|
6
|
-
onBookButtonPress: () => void;
|
|
7
|
-
isCiva: boolean;
|
|
8
|
-
isSoldOut: boolean;
|
|
9
|
-
isLinatal: boolean;
|
|
10
|
-
isPeru: boolean;
|
|
11
|
-
orignLabel?: React.ReactNode;
|
|
12
|
-
destinationLabel?: React.ReactNode;
|
|
13
|
-
originIcon?: string;
|
|
14
|
-
destinationIcon?: string;
|
|
15
|
-
travelDate: string;
|
|
16
|
-
arrivalDate: string;
|
|
17
|
-
depTime: string;
|
|
18
|
-
arrTime: string;
|
|
19
|
-
seatTypes: any[];
|
|
20
|
-
seatPriceColor: string;
|
|
21
|
-
currencySign: string;
|
|
22
|
-
availableSeats: number;
|
|
23
|
-
removeDuplicateSeats?: boolean;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const pad = (n: number) => (n < 10 ? "0" + n : String(n));
|
|
27
|
-
|
|
28
|
-
const getCleanedDepTime = (raw: string) => {
|
|
29
|
-
const depTimeStr = raw || "";
|
|
30
|
-
const hasAM = depTimeStr.includes("AM");
|
|
31
|
-
const hasPM = depTimeStr.includes("PM");
|
|
32
|
-
const [timePart] = depTimeStr.split(/AM|PM/).map((s) => s.trim());
|
|
33
|
-
const [hour, minute] = timePart.split(":").map(Number);
|
|
34
|
-
|
|
35
|
-
let cleaned: string;
|
|
36
|
-
if (hasAM) {
|
|
37
|
-
cleaned = hour === 12 ? `00:${pad(minute)}` : `${pad(hour)}:${pad(minute)}`;
|
|
38
|
-
} else if (hasPM) {
|
|
39
|
-
cleaned =
|
|
40
|
-
hour === 12 ? `${hour}:${pad(minute)}` : `${hour + 12}:${pad(minute)}`;
|
|
41
|
-
} else {
|
|
42
|
-
cleaned = timePart;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return { cleaned, hasAM, hasPM };
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
interface TimeRowProps {
|
|
49
|
-
label?: React.ReactNode;
|
|
50
|
-
icon?: string;
|
|
51
|
-
alt: string;
|
|
52
|
-
date: string;
|
|
53
|
-
timeContent: React.ReactNode;
|
|
54
|
-
isSoldOut: boolean;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const TimeRow: React.FC<TimeRowProps> = ({
|
|
58
|
-
label,
|
|
59
|
-
icon,
|
|
60
|
-
alt,
|
|
61
|
-
date,
|
|
62
|
-
timeContent,
|
|
63
|
-
isSoldOut,
|
|
64
|
-
}) => (
|
|
65
|
-
<div
|
|
66
|
-
className={`flex items-center min-[420]:text-[13px] text-[12px] justify-between ${
|
|
67
|
-
isSoldOut ? "text-[#c0c0c0]" : ""
|
|
68
|
-
}`}
|
|
69
|
-
>
|
|
70
|
-
<div className="flex items-center" style={{ flex: 1 }}>
|
|
71
|
-
<div>
|
|
72
|
-
{" "}
|
|
73
|
-
{label ? (
|
|
74
|
-
<div className="w-[60px]">{label}</div>
|
|
75
|
-
) : (
|
|
76
|
-
<div className="w-[12px] h-auto mr-[5px]">
|
|
77
|
-
<img
|
|
78
|
-
src={icon}
|
|
79
|
-
alt={alt}
|
|
80
|
-
className={`w-[12px] h-auto mr-[5px] ${
|
|
81
|
-
isSoldOut ? "grayscale" : ""
|
|
82
|
-
}`}
|
|
83
|
-
/>
|
|
84
|
-
</div>
|
|
85
|
-
)}
|
|
86
|
-
</div>
|
|
87
|
-
<div
|
|
88
|
-
className="flex items-center relative capitalize justify-between"
|
|
89
|
-
style={{ flex: 1 }}
|
|
90
|
-
>
|
|
91
|
-
<span className="cursor-pointer black-text">
|
|
92
|
-
{DateService.getServiceItemDate(date)}
|
|
93
|
-
</span>
|
|
94
|
-
<div className="absolute left-[50%]">•</div>
|
|
95
|
-
<div className="font-[900] relative black-text">{timeContent}</div>
|
|
96
|
-
</div>
|
|
97
|
-
</div>
|
|
98
|
-
</div>
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
function DateTimeSectionMobile({
|
|
102
|
-
onBookButtonPress,
|
|
103
|
-
isCiva,
|
|
104
|
-
isSoldOut,
|
|
105
|
-
isLinatal,
|
|
106
|
-
isPeru,
|
|
107
|
-
orignLabel,
|
|
108
|
-
destinationLabel,
|
|
109
|
-
originIcon,
|
|
110
|
-
destinationIcon,
|
|
111
|
-
travelDate,
|
|
112
|
-
arrivalDate,
|
|
113
|
-
depTime,
|
|
114
|
-
arrTime,
|
|
115
|
-
seatTypes,
|
|
116
|
-
seatPriceColor,
|
|
117
|
-
currencySign,
|
|
118
|
-
availableSeats,
|
|
119
|
-
removeDuplicateSeats,
|
|
120
|
-
}: DateTimeSectionMobileProps): React.ReactElement {
|
|
121
|
-
const { cleaned: cleanedDepTime, hasAM, hasPM } = getCleanedDepTime(depTime);
|
|
122
|
-
|
|
123
|
-
const depTimeContent = isLinatal ? (
|
|
124
|
-
<div>
|
|
125
|
-
<span>
|
|
126
|
-
{" "}
|
|
127
|
-
{cleanedDepTime} <span>{hasPM ? "PM" : hasAM ? "AM" : ""}</span>
|
|
128
|
-
</span>
|
|
129
|
-
<span>
|
|
130
|
-
{depTime.includes("AM") || depTime.includes("PM")
|
|
131
|
-
? null
|
|
132
|
-
: DateService.ampmOnly(depTime)}
|
|
133
|
-
</span>
|
|
134
|
-
</div>
|
|
135
|
-
) : (
|
|
136
|
-
DateService.formatTime(depTime)
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
|
-
<div
|
|
141
|
-
className="flex justify-between gap-[5px] w-full"
|
|
142
|
-
onClick={onBookButtonPress}
|
|
143
|
-
>
|
|
144
|
-
{/* DATE AND TIME */}
|
|
145
|
-
<div
|
|
146
|
-
className="min-h-[2.5rem] flex flex-col justify-between gap-[4px] w-[50%] "
|
|
147
|
-
style={{ justifyContent: isCiva && "center" }}
|
|
148
|
-
>
|
|
149
|
-
<TimeRow
|
|
150
|
-
label={orignLabel}
|
|
151
|
-
icon={originIcon}
|
|
152
|
-
alt="origin"
|
|
153
|
-
date={travelDate}
|
|
154
|
-
timeContent={depTimeContent}
|
|
155
|
-
isSoldOut={isSoldOut}
|
|
156
|
-
/>
|
|
157
|
-
{isCiva ? null : (
|
|
158
|
-
<TimeRow
|
|
159
|
-
label={destinationLabel}
|
|
160
|
-
icon={destinationIcon}
|
|
161
|
-
alt="destination"
|
|
162
|
-
date={arrivalDate}
|
|
163
|
-
timeContent={DateService.formatTime(arrTime)}
|
|
164
|
-
isSoldOut={isSoldOut}
|
|
165
|
-
/>
|
|
166
|
-
)}
|
|
167
|
-
</div>
|
|
168
|
-
{isPeru ? null : (
|
|
169
|
-
<div
|
|
170
|
-
style={{
|
|
171
|
-
width: "1px",
|
|
172
|
-
height: "2.5rem",
|
|
173
|
-
backgroundColor: "#ccc",
|
|
174
|
-
margin: "auto",
|
|
175
|
-
}}
|
|
176
|
-
></div>
|
|
177
|
-
)}
|
|
178
|
-
{/* SEATS */}
|
|
179
|
-
<SeatSectionMobile
|
|
180
|
-
seatTypes={seatTypes}
|
|
181
|
-
isSoldOut={isSoldOut}
|
|
182
|
-
isPeru={isPeru}
|
|
183
|
-
seatPriceColor={seatPriceColor}
|
|
184
|
-
currencySign={currencySign}
|
|
185
|
-
availableSeats={availableSeats}
|
|
186
|
-
removeDuplicateSeats={removeDuplicateSeats}
|
|
187
|
-
/>
|
|
188
|
-
</div>
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export default DateTimeSectionMobile;
|