kupos-ui-components-lib 9.0.7 → 9.0.8
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 +223 -67
- 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 +124 -299
- package/dist/components/ServiceItem/ServiceItemMobile.js +44 -291
- package/dist/components/ServiceItem/mobileTypes.d.ts +3 -0
- package/dist/components/ServiceItem/types.d.ts +7 -0
- package/dist/styles.css +76 -17
- package/dist/ui/AmenitiesBlock.js +25 -36
- package/dist/ui/BottomAmenities/BottomAmenities.js +3 -2
- package/dist/ui/DateTimeSection/DateTimeSection.d.ts +28 -0
- package/dist/ui/DateTimeSection/DateTimeSection.js +58 -0
- package/dist/ui/DirectoBlock.d.ts +8 -0
- package/dist/ui/DirectoBlock.js +11 -0
- package/dist/ui/DurationBlock.js +2 -2
- package/dist/ui/ExpendedDropDown/ExpandedDropdown.d.ts +1 -0
- package/dist/ui/ExpendedDropDown/ExpandedDropdown.js +28 -18
- package/dist/ui/FlexibleBlock.js +2 -4
- package/dist/ui/PetBlock.js +1 -3
- package/dist/ui/RatingBlock.js +6 -2
- package/dist/ui/SeatSection/SeatSection.js +1 -1
- package/dist/ui/TopAmenities/PromoCountdown.d.ts +18 -0
- package/dist/ui/TopAmenities/PromoCountdown.js +55 -0
- package/dist/ui/TopAmenities/TopAmenities.d.ts +4 -1
- package/dist/ui/TopAmenities/TopAmenities.js +31 -4
- package/dist/utils/CommonService.d.ts +1 -1
- package/package.json +2 -1
- package/src/assets/images/anims/service_list/bomb.json +1 -0
- 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 +241 -616
- package/src/components/ServiceItem/ServiceItemMobile.tsx +120 -501
- package/src/components/ServiceItem/mobileTypes.ts +3 -0
- package/src/components/ServiceItem/types.ts +7 -0
- package/src/ui/AmenitiesBlock.tsx +34 -15
- package/src/ui/BottomAmenities/BottomAmenities.tsx +110 -0
- package/src/ui/DateTimeSection/DateTimeSection.tsx +207 -0
- package/src/ui/DirectoBlock.tsx +31 -0
- package/src/ui/DurationBlock.tsx +2 -2
- package/src/ui/ExpendedDropDown/ExpandedDropdown.tsx +115 -0
- package/src/ui/FlexibleBlock.tsx +3 -3
- package/src/ui/KuposButton/KuposButton.tsx +48 -0
- package/src/ui/PetBlock.tsx +2 -2
- package/src/ui/RatingBlock.tsx +16 -4
- package/src/ui/SeatSection/SeatSection.tsx +187 -0
- package/src/ui/TopAmenities/TopAmenities.tsx +116 -0
- package/src/ui/mobileweb/BottomAmenitiesMobile.tsx +168 -0
- package/src/ui/mobileweb/DateTimeSectionMobile.tsx +192 -0
- package/src/ui/mobileweb/SeatSectionMobile.tsx +256 -0
- package/src/ui/mobileweb/TopAmenitieMobile.tsx +82 -0
|
@@ -113,6 +113,9 @@ export interface MobileServiceItemProps {
|
|
|
113
113
|
seatFallBackIcon: string;
|
|
114
114
|
headPhoneIcon?: string;
|
|
115
115
|
allowCancellationIcon?: string;
|
|
116
|
+
bombAnim?: string;
|
|
117
|
+
whiteBoardingIcon?: string;
|
|
118
|
+
downArrow?: string;
|
|
116
119
|
[key: string]: string | Record<string, string | undefined> | undefined;
|
|
117
120
|
};
|
|
118
121
|
useLottieFor?: string[];
|
|
@@ -117,6 +117,9 @@ export interface ServiceItemProps {
|
|
|
117
117
|
seatFallBackIcon: string;
|
|
118
118
|
headPhoneIcon?: string;
|
|
119
119
|
allowCancellationIcon?: string;
|
|
120
|
+
whiteBoardingIcon?: string
|
|
121
|
+
bombJson?:string
|
|
122
|
+
downArrow?:string
|
|
120
123
|
|
|
121
124
|
[key: string]: string | Record<string, string | undefined> | undefined;
|
|
122
125
|
};
|
|
@@ -192,7 +195,11 @@ export interface ServiceItemProps {
|
|
|
192
195
|
petFriendlyAnim?: string;
|
|
193
196
|
priorityStageAnim?: string;
|
|
194
197
|
promoAnim?: string;
|
|
198
|
+
bombAnimation?: string;
|
|
195
199
|
isPeru?: boolean;
|
|
196
200
|
siteType?: "kupos" | "pullman" | "opsites" | "linatal";
|
|
197
201
|
isAllinBus?: boolean;
|
|
202
|
+
isExpand?: any;
|
|
203
|
+
setIsExpand?: (value: any) => void;
|
|
204
|
+
coachKey?: number
|
|
198
205
|
}
|
|
@@ -82,17 +82,6 @@ const AmenitiesBlock = ({
|
|
|
82
82
|
|
|
83
83
|
return (
|
|
84
84
|
<div className="flex items-center gap-[6px]">
|
|
85
|
-
{/* GPS */}
|
|
86
|
-
{serviceItem?.is_tracking_enabled && (
|
|
87
|
-
<div className={grayscaleClass}>
|
|
88
|
-
<LottiePlayer
|
|
89
|
-
animationData={getAnimationIcon("locationAnim")}
|
|
90
|
-
width="20px"
|
|
91
|
-
height="20px"
|
|
92
|
-
/>
|
|
93
|
-
</div>
|
|
94
|
-
)}
|
|
95
|
-
|
|
96
85
|
{/* AMENITIES */}
|
|
97
86
|
{visibleAmenities.map((val, key) => {
|
|
98
87
|
const raw = metaData.amenities[val];
|
|
@@ -108,7 +97,7 @@ const AmenitiesBlock = ({
|
|
|
108
97
|
/>
|
|
109
98
|
</div>
|
|
110
99
|
|
|
111
|
-
{/* Tooltip */}
|
|
100
|
+
{/* Tooltip – show ALL amenities */}
|
|
112
101
|
<div
|
|
113
102
|
className={TOOLTIP_CLASS}
|
|
114
103
|
style={{
|
|
@@ -118,14 +107,33 @@ const AmenitiesBlock = ({
|
|
|
118
107
|
}}
|
|
119
108
|
>
|
|
120
109
|
<TooltipArrow color={colors.tooltipColor} />
|
|
121
|
-
|
|
110
|
+
<div className="flex flex-col gap-[10px]">
|
|
111
|
+
{amenities.map((id, i) => {
|
|
112
|
+
const rawItem = metaData.amenities[id];
|
|
113
|
+
if (isWater(rawItem)) return null;
|
|
114
|
+
const name = getAmenityBaseName(rawItem);
|
|
115
|
+
return (
|
|
116
|
+
<div
|
|
117
|
+
key={i}
|
|
118
|
+
className="flex items-center gap-[5px] text-xs whitespace-nowrap"
|
|
119
|
+
>
|
|
120
|
+
<SvgAmenities
|
|
121
|
+
moreAnemities={true}
|
|
122
|
+
name={name.toUpperCase()}
|
|
123
|
+
color="white"
|
|
124
|
+
/>
|
|
125
|
+
{getAmenityName(name.split("_").join(" "))}
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
})}
|
|
129
|
+
</div>
|
|
122
130
|
</div>
|
|
123
131
|
</div>
|
|
124
132
|
);
|
|
125
133
|
})}
|
|
126
134
|
|
|
127
135
|
{/* PLUS ICON */}
|
|
128
|
-
{shouldShowPlus && (
|
|
136
|
+
{/* {shouldShowPlus && (
|
|
129
137
|
<div className="relative ml-1 cursor-pointer">
|
|
130
138
|
<div className="group">
|
|
131
139
|
<img
|
|
@@ -167,7 +175,18 @@ const AmenitiesBlock = ({
|
|
|
167
175
|
</div>
|
|
168
176
|
</div>
|
|
169
177
|
</div>
|
|
170
|
-
)}
|
|
178
|
+
)} */}
|
|
179
|
+
|
|
180
|
+
{/* GPS */}
|
|
181
|
+
{/* {serviceItem?.is_tracking_enabled && (
|
|
182
|
+
<div className={grayscaleClass}>
|
|
183
|
+
<LottiePlayer
|
|
184
|
+
animationData={getAnimationIcon("locationAnim")}
|
|
185
|
+
width="20px"
|
|
186
|
+
height="20px"
|
|
187
|
+
/>
|
|
188
|
+
</div>
|
|
189
|
+
)} */}
|
|
171
190
|
</div>
|
|
172
191
|
);
|
|
173
192
|
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import LottiePlayer from "../../assets/LottiePlayer";
|
|
3
|
+
import FlexibleBlock from "../FlexibleBlock";
|
|
4
|
+
import PetBlock from "../PetBlock";
|
|
5
|
+
|
|
6
|
+
interface ItemEntry {
|
|
7
|
+
key: string;
|
|
8
|
+
render: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface BottomAmenitiesProps {
|
|
12
|
+
otherItems: ItemEntry[];
|
|
13
|
+
serviceItem: {
|
|
14
|
+
id: string;
|
|
15
|
+
is_tracking_enabled?: boolean;
|
|
16
|
+
is_change_ticket?: boolean;
|
|
17
|
+
pet_seat_info?: Record<string, any>;
|
|
18
|
+
};
|
|
19
|
+
grayscaleClass: string;
|
|
20
|
+
isSoldOut: boolean;
|
|
21
|
+
isItemExpanded: boolean;
|
|
22
|
+
colors: Record<string, any>;
|
|
23
|
+
translation?: { [key: string]: string };
|
|
24
|
+
getAnimationIcon: (icon: string) => any;
|
|
25
|
+
downArrowIcon?: React.ReactNode;
|
|
26
|
+
onToggleExpand: () => void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function BottomAmenities({
|
|
30
|
+
otherItems,
|
|
31
|
+
serviceItem,
|
|
32
|
+
grayscaleClass,
|
|
33
|
+
isSoldOut,
|
|
34
|
+
isItemExpanded,
|
|
35
|
+
colors,
|
|
36
|
+
translation,
|
|
37
|
+
getAnimationIcon,
|
|
38
|
+
downArrowIcon,
|
|
39
|
+
onToggleExpand,
|
|
40
|
+
}: BottomAmenitiesProps): React.ReactElement {
|
|
41
|
+
const hasPetInfo =
|
|
42
|
+
serviceItem.pet_seat_info &&
|
|
43
|
+
Object.keys(serviceItem.pet_seat_info).length > 0;
|
|
44
|
+
|
|
45
|
+
const showDownArrow =
|
|
46
|
+
(serviceItem?.is_change_ticket && serviceItem.pet_seat_info) ||
|
|
47
|
+
(serviceItem.pet_seat_info &&
|
|
48
|
+
Object.keys(serviceItem.pet_seat_info).length > 0);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className="flex items-center mt-[15px] border-t border-[#eee] pt-[6px]">
|
|
52
|
+
{/* OTHER ITEMS (GRID) */}
|
|
53
|
+
<div
|
|
54
|
+
className="grid items-center gap-[2%] flex-1 "
|
|
55
|
+
style={{
|
|
56
|
+
// gridTemplateColumns: " 28% 21% 23% 23%",
|
|
57
|
+
gridTemplateColumns: "28% 17% 23% 23%",
|
|
58
|
+
}}
|
|
59
|
+
>
|
|
60
|
+
{otherItems.map((item) => (
|
|
61
|
+
<div key={item.key} className="flex items-center">
|
|
62
|
+
{item.render}
|
|
63
|
+
</div>
|
|
64
|
+
))}
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
{/* PET + FLEXIBLE (always visible) */}
|
|
68
|
+
<div className="flex items-center justify-end shrink-0 ml-[5px] w-[150px]">
|
|
69
|
+
{serviceItem?.is_tracking_enabled && (
|
|
70
|
+
<div className={grayscaleClass + " mr-[10px]"}>
|
|
71
|
+
<LottiePlayer
|
|
72
|
+
animationData={getAnimationIcon("locationAnim")}
|
|
73
|
+
width="20px"
|
|
74
|
+
height="20px"
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
)}
|
|
78
|
+
{serviceItem.is_change_ticket && (
|
|
79
|
+
<FlexibleBlock
|
|
80
|
+
translation={translation}
|
|
81
|
+
getAnimationIcon={getAnimationIcon}
|
|
82
|
+
colors={colors}
|
|
83
|
+
serviceItem={serviceItem}
|
|
84
|
+
isSoldOut={isSoldOut}
|
|
85
|
+
/>
|
|
86
|
+
)}
|
|
87
|
+
{hasPetInfo && (
|
|
88
|
+
<PetBlock
|
|
89
|
+
translation={translation}
|
|
90
|
+
getAnimationIcon={getAnimationIcon}
|
|
91
|
+
colors={colors}
|
|
92
|
+
isSoldOut={isSoldOut}
|
|
93
|
+
/>
|
|
94
|
+
)}
|
|
95
|
+
|
|
96
|
+
{/* DOWN ARROW ICON */}
|
|
97
|
+
{showDownArrow ? (
|
|
98
|
+
<div
|
|
99
|
+
className={`flex items-center cursor-pointer ml-[4px] transition-transform duration-300 w-[14px] h-[14px] ${isItemExpanded ? "rotate-180" : ""}`}
|
|
100
|
+
onClick={onToggleExpand}
|
|
101
|
+
>
|
|
102
|
+
{downArrowIcon}
|
|
103
|
+
</div>
|
|
104
|
+
) : null}
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default BottomAmenities;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import DateService from "../../utils/DateService";
|
|
3
|
+
import StageTooltip from "../StagesTooltip";
|
|
4
|
+
|
|
5
|
+
interface DateTimeSectionProps {
|
|
6
|
+
serviceItem: {
|
|
7
|
+
icons?: { origin?: string; destination?: string; [key: string]: any };
|
|
8
|
+
boarding_stages?: string;
|
|
9
|
+
dropoff_stages?: string;
|
|
10
|
+
travel_date: string;
|
|
11
|
+
arrival_date: string;
|
|
12
|
+
dep_time: string;
|
|
13
|
+
arr_time: string;
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
};
|
|
16
|
+
isSoldOut: boolean;
|
|
17
|
+
isCiva?: boolean;
|
|
18
|
+
isLinatal?: boolean;
|
|
19
|
+
removeArrivalTime?: boolean;
|
|
20
|
+
orignLabel?: string;
|
|
21
|
+
destinationLabel?: string;
|
|
22
|
+
busStage?: Record<string, string>;
|
|
23
|
+
metaData?: any;
|
|
24
|
+
colors: Record<string, any>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function DateTimeSection({
|
|
28
|
+
serviceItem,
|
|
29
|
+
isSoldOut,
|
|
30
|
+
isCiva,
|
|
31
|
+
isLinatal,
|
|
32
|
+
removeArrivalTime,
|
|
33
|
+
orignLabel,
|
|
34
|
+
destinationLabel,
|
|
35
|
+
busStage,
|
|
36
|
+
metaData,
|
|
37
|
+
colors,
|
|
38
|
+
}: DateTimeSectionProps): React.ReactElement {
|
|
39
|
+
const depTime = serviceItem.dep_time || "";
|
|
40
|
+
const hasAM = depTime.includes("AM");
|
|
41
|
+
const hasPM = depTime.includes("PM");
|
|
42
|
+
|
|
43
|
+
const convertTo24Hour = (depTime: string): string => {
|
|
44
|
+
const hasAM = depTime.includes("AM");
|
|
45
|
+
const hasPM = depTime.includes("PM");
|
|
46
|
+
const [timePart] = depTime.split(/AM|PM/).map((part) => part.trim());
|
|
47
|
+
const [hour, minute] = timePart.split(":").map(Number);
|
|
48
|
+
const pad = (n: number) => (n < 10 ? "0" + n : String(n));
|
|
49
|
+
|
|
50
|
+
if (hasAM) {
|
|
51
|
+
return `${pad(hour === 12 ? 0 : hour)}:${pad(minute)}`;
|
|
52
|
+
}
|
|
53
|
+
if (hasPM) {
|
|
54
|
+
return `${hour === 12 ? hour : hour + 12}:${pad(minute)}`;
|
|
55
|
+
}
|
|
56
|
+
return timePart;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const cleanedDepTime = convertTo24Hour(depTime);
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div
|
|
63
|
+
className={`min-h-[2.2rem] grid grid-cols-[26px_auto_26%_1fr] gap-x-4 items-center text-[13.33px] ${
|
|
64
|
+
isSoldOut ? "text-[#c0c0c0]" : ""
|
|
65
|
+
}`}
|
|
66
|
+
style={{
|
|
67
|
+
gridTemplateRows: "1fr",
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
{/* ICONS COLUMN */}
|
|
71
|
+
<div className="flex flex-col gap-[6px]">
|
|
72
|
+
{/* Origin Icon */}
|
|
73
|
+
{orignLabel ? (
|
|
74
|
+
<div className="w-[60px] h-[20px] flex items-center">
|
|
75
|
+
{orignLabel}
|
|
76
|
+
</div>
|
|
77
|
+
) : (
|
|
78
|
+
<div className="h-[20px] flex items-center">
|
|
79
|
+
<img
|
|
80
|
+
src={serviceItem.icons?.origin}
|
|
81
|
+
alt="origin"
|
|
82
|
+
className={`w-[16px] h-auto mr-[8px] ${
|
|
83
|
+
isSoldOut ? "grayscale" : ""
|
|
84
|
+
}`}
|
|
85
|
+
/>
|
|
86
|
+
</div>
|
|
87
|
+
)}
|
|
88
|
+
|
|
89
|
+
{/* Destination Icon */}
|
|
90
|
+
{!isCiva &&
|
|
91
|
+
(destinationLabel ? (
|
|
92
|
+
<div className="w-[60px] h-[20px] flex items-center">
|
|
93
|
+
{destinationLabel}
|
|
94
|
+
</div>
|
|
95
|
+
) : (
|
|
96
|
+
<div className="h-[20px] flex items-center">
|
|
97
|
+
<img
|
|
98
|
+
src={serviceItem.icons?.destination}
|
|
99
|
+
className={`w-[16px] h-auto mr-[8px] ${
|
|
100
|
+
isSoldOut ? "grayscale" : ""
|
|
101
|
+
}`}
|
|
102
|
+
style={{ opacity: isSoldOut ? 0.5 : 1 }}
|
|
103
|
+
/>
|
|
104
|
+
</div>
|
|
105
|
+
))}
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
{/* DATES COLUMN */}
|
|
109
|
+
<div className="flex flex-col gap-[6px]">
|
|
110
|
+
{/* Departure Date */}
|
|
111
|
+
<StageTooltip
|
|
112
|
+
stageData={serviceItem.boarding_stages}
|
|
113
|
+
direction={1}
|
|
114
|
+
terminals={busStage}
|
|
115
|
+
serviceItem={serviceItem}
|
|
116
|
+
metaData={metaData}
|
|
117
|
+
colors={colors}
|
|
118
|
+
>
|
|
119
|
+
<span className="cursor-pointer bold-text capitalize">
|
|
120
|
+
{DateService.getServiceItemDate(serviceItem.travel_date)}
|
|
121
|
+
</span>
|
|
122
|
+
</StageTooltip>
|
|
123
|
+
|
|
124
|
+
{/* Arrival Date */}
|
|
125
|
+
{!isCiva && (
|
|
126
|
+
<StageTooltip
|
|
127
|
+
stageData={serviceItem.boarding_stages}
|
|
128
|
+
direction={1}
|
|
129
|
+
terminals={busStage}
|
|
130
|
+
serviceItem={serviceItem}
|
|
131
|
+
metaData={metaData}
|
|
132
|
+
colors={colors}
|
|
133
|
+
>
|
|
134
|
+
<span className="cursor-pointer bold-text capitalize">
|
|
135
|
+
{DateService.getServiceItemDate(serviceItem.arrival_date)}
|
|
136
|
+
</span>
|
|
137
|
+
</StageTooltip>
|
|
138
|
+
)}
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
{/* DOTS COLUMN */}
|
|
142
|
+
<div className="flex flex-col gap-[6px] items-center">
|
|
143
|
+
{/* Departure Dot */}
|
|
144
|
+
<div className="h-[20px] flex items-center justify-center">
|
|
145
|
+
<div>•</div>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
{/* Arrival Dot */}
|
|
149
|
+
{!isCiva && (
|
|
150
|
+
<div className="h-[20px] flex items-center justify-center">
|
|
151
|
+
{removeArrivalTime ? null : serviceItem.arr_time ? (
|
|
152
|
+
<div>•</div>
|
|
153
|
+
) : null}
|
|
154
|
+
</div>
|
|
155
|
+
)}
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
{/* TIMES COLUMN */}
|
|
159
|
+
<div className="flex flex-col gap-[6px]">
|
|
160
|
+
{/* Departure Time */}
|
|
161
|
+
<StageTooltip
|
|
162
|
+
stageData={serviceItem.dropoff_stages}
|
|
163
|
+
direction={2}
|
|
164
|
+
terminals={busStage}
|
|
165
|
+
serviceItem={serviceItem}
|
|
166
|
+
metaData={metaData}
|
|
167
|
+
colors={colors}
|
|
168
|
+
>
|
|
169
|
+
<div className="font-[900] bold-text">
|
|
170
|
+
{isLinatal ? (
|
|
171
|
+
<>
|
|
172
|
+
{cleanedDepTime} <span>{hasPM ? "PM" : hasAM ? "AM" : ""}</span>
|
|
173
|
+
{!serviceItem?.dep_time.includes("AM") &&
|
|
174
|
+
!serviceItem?.dep_time.includes("PM") &&
|
|
175
|
+
DateService.ampmOnly(serviceItem.dep_time)}
|
|
176
|
+
</>
|
|
177
|
+
) : (
|
|
178
|
+
DateService.formatTime(serviceItem.dep_time)
|
|
179
|
+
)}
|
|
180
|
+
</div>
|
|
181
|
+
</StageTooltip>
|
|
182
|
+
|
|
183
|
+
{/* Arrival Time */}
|
|
184
|
+
{!isCiva && (
|
|
185
|
+
<StageTooltip
|
|
186
|
+
stageData={serviceItem.dropoff_stages}
|
|
187
|
+
direction={2}
|
|
188
|
+
terminals={busStage}
|
|
189
|
+
serviceItem={serviceItem}
|
|
190
|
+
metaData={metaData}
|
|
191
|
+
colors={colors}
|
|
192
|
+
>
|
|
193
|
+
<div className="font-[900] bold-text">
|
|
194
|
+
{removeArrivalTime
|
|
195
|
+
? null
|
|
196
|
+
: serviceItem.arr_time
|
|
197
|
+
? DateService.formatTime(serviceItem.arr_time)
|
|
198
|
+
: null}
|
|
199
|
+
</div>
|
|
200
|
+
</StageTooltip>
|
|
201
|
+
)}
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export default DateTimeSection;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import LottiePlayer from "../assets/LottiePlayer";
|
|
3
|
+
|
|
4
|
+
const DirectoBlock = ({ translation, isSoldOut, colors, getAnimationIcon }) => (
|
|
5
|
+
<div className="flex items-center relative whitespace-nowrap mt-[3px]">
|
|
6
|
+
<div className={`w-[18px] mr-[4px] ${isSoldOut ? "grayscale" : ""}`}>
|
|
7
|
+
<LottiePlayer
|
|
8
|
+
animationData={getAnimationIcon("directoAnim")}
|
|
9
|
+
width="14px"
|
|
10
|
+
height="14px"
|
|
11
|
+
/>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<div className="group text-[13.33px] cursor-pointer">
|
|
15
|
+
{translation?.directService}
|
|
16
|
+
<div
|
|
17
|
+
className="hidden group-hover:block absolute top-[24px] left-1/2 -translate-x-1/2 text-white p-3 rounded-[14px] whitespace-nowrap w-fit z-10 mt-2.5 text-center shadow-service text-[12px]"
|
|
18
|
+
style={{ backgroundColor: colors.tooltipColor }}
|
|
19
|
+
>
|
|
20
|
+
{/* Tooltip arrow */}
|
|
21
|
+
<div
|
|
22
|
+
className="tooltip-arrow absolute -top-[7px] left-1/2 -translate-x-1/2 w-0 h-0 border-l-8 border-r-8 border-b-8 border-l-transparent border-r-transparent"
|
|
23
|
+
style={{ borderBottomColor: colors.tooltipColor }}
|
|
24
|
+
></div>
|
|
25
|
+
{translation?.directServiceText}
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
export default DirectoBlock;
|
package/src/ui/DurationBlock.tsx
CHANGED
|
@@ -7,12 +7,12 @@ const DurationBlock = ({
|
|
|
7
7
|
isSoldOut,
|
|
8
8
|
colors,
|
|
9
9
|
}) => (
|
|
10
|
-
<div className="flex items-baseline relative whitespace-nowrap">
|
|
10
|
+
<div className="flex items-baseline relative whitespace-nowrap ">
|
|
11
11
|
<div className={`w-[18px] mr-[4px] ${isSoldOut ? "grayscale" : ""}`}>
|
|
12
12
|
{renderIcon("hours", "14px")}
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
|
-
<div className="group text-[13.33px]">
|
|
15
|
+
<div className="group text-[13.33px] cursor-pointer">
|
|
16
16
|
{serviceItem.duration} {translation.hours}
|
|
17
17
|
<div
|
|
18
18
|
className="hidden group-hover:block absolute top-[24px] left-1/2 -translate-x-1/2 text-white p-3 rounded-[14px] whitespace-normal z-10 mt-2.5 w-[188px] text-center break-normal shadow-service text-[12px]"
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import LottiePlayer from "../../assets/LottiePlayer";
|
|
3
|
+
|
|
4
|
+
interface ExpandedDropdownProps {
|
|
5
|
+
serviceItem: {
|
|
6
|
+
change_ticket_hours?: number;
|
|
7
|
+
pet_seat_info?: Record<string, any>;
|
|
8
|
+
is_change_ticket?: boolean;
|
|
9
|
+
is_tracking_enabled?: boolean;
|
|
10
|
+
};
|
|
11
|
+
showPromo: boolean;
|
|
12
|
+
colors: {
|
|
13
|
+
priceColor?: string;
|
|
14
|
+
};
|
|
15
|
+
grayscaleClass: string;
|
|
16
|
+
translation?: { [key: string]: string };
|
|
17
|
+
getAnimationIcon: (icon: string) => any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function ExpandedDropdown({
|
|
21
|
+
serviceItem,
|
|
22
|
+
showPromo,
|
|
23
|
+
colors,
|
|
24
|
+
grayscaleClass,
|
|
25
|
+
translation,
|
|
26
|
+
getAnimationIcon,
|
|
27
|
+
}: ExpandedDropdownProps): React.ReactElement {
|
|
28
|
+
const hasPetInfo =
|
|
29
|
+
serviceItem.pet_seat_info &&
|
|
30
|
+
Object.keys(serviceItem.pet_seat_info).length > 0;
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
className="px-[15px] pt-[26px] pb-[14px] -mt-[16px] pt-[35px] relative -z-9"
|
|
35
|
+
style={{
|
|
36
|
+
backgroundColor: "#ffefef",
|
|
37
|
+
borderRadius: "0 0 10px 10px",
|
|
38
|
+
// border: showPromo ? `1px solid ${colors.priceColor}` : "1px solid #ccc",
|
|
39
|
+
// border: `1px solid ${colors.priceColor}`,
|
|
40
|
+
|
|
41
|
+
// borderTop: "none",
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
{/* <div className="flex flex-col gap-[12px] text-[13px] text-[#464647]">
|
|
45
|
+
{hasPetInfo && (
|
|
46
|
+
<div className="flex items-center gap-[10px]">
|
|
47
|
+
<LottiePlayer
|
|
48
|
+
animationData={getAnimationIcon("petFriendlyAnim")}
|
|
49
|
+
width="20px"
|
|
50
|
+
height="20px"
|
|
51
|
+
/>
|
|
52
|
+
<div className="h-auto mr-[4px] text-[13px] text-[#464647] bold-text">
|
|
53
|
+
<span>{translation?.petFriendly}</span>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
)}
|
|
57
|
+
{serviceItem.is_change_ticket && (
|
|
58
|
+
<div className="flex items-center gap-[10px]">
|
|
59
|
+
<LottiePlayer
|
|
60
|
+
animationData={getAnimationIcon("flexibleIcon")}
|
|
61
|
+
width="20px"
|
|
62
|
+
height="20px"
|
|
63
|
+
/>
|
|
64
|
+
<div className="h-auto mr-[4px] text-[13px] text-[#464647] bold-text">
|
|
65
|
+
<span>{translation?.flexible}</span>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
)}
|
|
69
|
+
{serviceItem?.is_tracking_enabled && (
|
|
70
|
+
<div className={`${grayscaleClass} flex items-center gap-[10px]`}>
|
|
71
|
+
<LottiePlayer
|
|
72
|
+
animationData={getAnimationIcon("locationAnim")}
|
|
73
|
+
width="20px"
|
|
74
|
+
height="20px"
|
|
75
|
+
/>
|
|
76
|
+
<div className="h-auto mr-[4px] text-[13px] text-[#464647] bold-text">
|
|
77
|
+
<span>{"GPS Tracker"}</span>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
)}
|
|
81
|
+
</div> */}
|
|
82
|
+
<div
|
|
83
|
+
className="flex flex-col gap-[10px] text-[13px] text-[#464647]"
|
|
84
|
+
style={{ lineHeight: 1.6 }}
|
|
85
|
+
>
|
|
86
|
+
<div className="flex gap-[8px] text-[13.33px]">
|
|
87
|
+
<span style={{ marginTop: "2px" }}>•</span>
|
|
88
|
+
<span>
|
|
89
|
+
<span className="bold-text">Políticas de anulación:</span> Tu pasaje
|
|
90
|
+
puede ser anulado de forma online{" "}
|
|
91
|
+
<span className="bold-text">
|
|
92
|
+
hasta {serviceItem?.change_ticket_hours ?? 6} horas antes
|
|
93
|
+
</span>{" "}
|
|
94
|
+
de la salida del bus. Al anular tu pasaje recibirás una devolución
|
|
95
|
+
del 85% del monto de tu compra.
|
|
96
|
+
</span>
|
|
97
|
+
</div>
|
|
98
|
+
<div className="flex gap-[8px]">
|
|
99
|
+
<span style={{ marginTop: "2px" }}>•</span>
|
|
100
|
+
<span>
|
|
101
|
+
<span className="bold-text">Políticas de cambios:</span> Tu pasaje
|
|
102
|
+
puede ser cambiado de manera online{" "}
|
|
103
|
+
<span className="bold-text">
|
|
104
|
+
hasta {serviceItem?.change_ticket_hours ?? 6} horas antes
|
|
105
|
+
</span>{" "}
|
|
106
|
+
de la salida del bus. El monto será reembolsado a tu billetera
|
|
107
|
+
kupospay.
|
|
108
|
+
</span>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export default ExpandedDropdown;
|
package/src/ui/FlexibleBlock.tsx
CHANGED
|
@@ -9,7 +9,7 @@ const FlexibleBlock = ({
|
|
|
9
9
|
isSoldOut,
|
|
10
10
|
}) => (
|
|
11
11
|
<div className="flex items-center">
|
|
12
|
-
<div className="relative group cursor-
|
|
12
|
+
<div className="relative group cursor-pointer">
|
|
13
13
|
<div className="flex items-center">
|
|
14
14
|
<div className={`mr-[5px] ${isSoldOut ? "grayscale" : ""}`}>
|
|
15
15
|
<LottiePlayer
|
|
@@ -19,9 +19,9 @@ const FlexibleBlock = ({
|
|
|
19
19
|
height="20px"
|
|
20
20
|
/>
|
|
21
21
|
</div>
|
|
22
|
-
<div className="h-auto mr-[4px] text-[13px] text-[#464647]">
|
|
22
|
+
{/* <div className="h-auto mr-[4px] text-[13px] text-[#464647]">
|
|
23
23
|
<span>{translation?.flexible}</span>
|
|
24
|
-
</div>
|
|
24
|
+
</div> */}
|
|
25
25
|
</div>
|
|
26
26
|
<div
|
|
27
27
|
className="hidden group-hover:block absolute top-[24px] left-1/2 -translate-x-1/2 text-white p-3 rounded-[14px] whitespace-normal z-10 mt-2.5 w-[230px] text-center break-normal shadow-service text-[12px]"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
interface KuposButtonProps {
|
|
4
|
+
isSoldOut: boolean;
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
buttonColor?: string;
|
|
7
|
+
buyLabel?: string;
|
|
8
|
+
soldOutLabel?: string;
|
|
9
|
+
soldOutIcon?: React.ReactNode;
|
|
10
|
+
onClick: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function KuposButton({
|
|
14
|
+
isSoldOut,
|
|
15
|
+
isLoading,
|
|
16
|
+
buttonColor,
|
|
17
|
+
buyLabel,
|
|
18
|
+
soldOutLabel,
|
|
19
|
+
soldOutIcon,
|
|
20
|
+
onClick,
|
|
21
|
+
}: KuposButtonProps): React.ReactElement {
|
|
22
|
+
const isDisabled = isLoading || isSoldOut;
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<button
|
|
26
|
+
onClick={() => (!isSoldOut ? onClick() : null)}
|
|
27
|
+
disabled={isLoading}
|
|
28
|
+
className="w-full py-[12px] text-[12px] font-bold text-white rounded-[14px] border-none px-[20px] flex items-center justify-center"
|
|
29
|
+
style={{
|
|
30
|
+
backgroundColor: isDisabled ? "lightgray" : buttonColor,
|
|
31
|
+
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
<span className="min-w-[75px] flex justify-center items-center bold-text uppercase">
|
|
35
|
+
{isSoldOut ? soldOutIcon : null}
|
|
36
|
+
{isLoading ? (
|
|
37
|
+
<span className="loader-circle"></span>
|
|
38
|
+
) : !isSoldOut ? (
|
|
39
|
+
buyLabel
|
|
40
|
+
) : (
|
|
41
|
+
soldOutLabel
|
|
42
|
+
)}
|
|
43
|
+
</span>
|
|
44
|
+
</button>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default KuposButton;
|
package/src/ui/PetBlock.tsx
CHANGED
|
@@ -13,9 +13,9 @@ const PetBlock = ({ translation, getAnimationIcon, colors, isSoldOut }) => (
|
|
|
13
13
|
height="20px"
|
|
14
14
|
/>
|
|
15
15
|
</div>
|
|
16
|
-
<div className="h-auto mr-[4px] text-[13px] text-[#464647]">
|
|
16
|
+
{/* <div className="h-auto mr-[4px] text-[13px] text-[#464647]">
|
|
17
17
|
<span>{translation?.petFriendly}</span>
|
|
18
|
-
</div>
|
|
18
|
+
</div> */}
|
|
19
19
|
</div>
|
|
20
20
|
<div
|
|
21
21
|
className=" hidden group-hover:block absolute top-[24px] left-1/2 -translate-x-1/2 text-white p-3 rounded-[14px] whitespace-normal z-10 mt-2.5 w-[230px] text-center break-normal shadow-service"
|