kupos-ui-components-lib 9.0.4 → 9.0.6
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/bomb.json +1 -0
- 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/ExpandedDropdown.d.ts +19 -0
- package/dist/components/ServiceItem/ExpandedDropdown.js +28 -0
- package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemDesktop.js +125 -262
- 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 +67 -12
- package/dist/ui/AmenitiesBlock.js +60 -66
- package/dist/ui/BottomAmenities/BottomAmenities.d.ts +26 -0
- package/dist/ui/BottomAmenities/BottomAmenities.js +22 -0
- package/dist/ui/DurationBlock.js +2 -2
- package/dist/ui/ExpendedDropDown/ExpandedDropdown.d.ts +19 -0
- package/dist/ui/ExpendedDropDown/ExpandedDropdown.js +27 -0
- package/dist/ui/FlexibleBlock.js +2 -4
- package/dist/ui/KuposButton/KuposButton.d.ts +12 -0
- package/dist/ui/KuposButton/KuposButton.js +12 -0
- package/dist/ui/PetBlock.js +1 -3
- package/dist/ui/RatingBlock.js +6 -2
- package/dist/ui/SeatSection/SeatSection.d.ts +17 -0
- package/dist/ui/SeatSection/SeatSection.js +92 -0
- package/dist/ui/TopAmenities/TopAmenities.d.ts +12 -0
- package/dist/ui/TopAmenities/TopAmenities.js +32 -0
- package/dist/ui/mobileweb/BottomAmenitiesMobile.d.ts +23 -0
- package/dist/ui/mobileweb/BottomAmenitiesMobile.js +37 -0
- package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +23 -0
- package/dist/ui/mobileweb/DateTimeSectionMobile.js +57 -0
- package/dist/ui/mobileweb/SeatSectionMobile.d.ts +17 -0
- package/dist/ui/mobileweb/SeatSectionMobile.js +100 -0
- package/dist/ui/mobileweb/TopAmenitieMobile.d.ts +10 -0
- package/dist/ui/mobileweb/TopAmenitieMobile.js +35 -0
- package/package.json +1 -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/ServiceItemDesktop.tsx +222 -465
- 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 +115 -97
- package/src/ui/BottomAmenities/BottomAmenities.tsx +109 -0
- package/src/ui/DurationBlock.tsx +2 -2
- package/src/ui/ExpendedDropDown/ExpandedDropdown.tsx +85 -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 +82 -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
|
}
|
|
@@ -1,6 +1,50 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import LottiePlayer from "../assets/LottiePlayer";
|
|
3
3
|
|
|
4
|
+
const DEFAULT_PRIORITY_IDS = ["2", "3", "13"];
|
|
5
|
+
|
|
6
|
+
const TOOLTIP_CLASS =
|
|
7
|
+
"hidden group-hover:block absolute top-[30px] left-1/2 -translate-x-1/2 text-white rounded-[14px] whitespace-nowrap mt-2.5 text-center shadow-service text-[13.33px]";
|
|
8
|
+
|
|
9
|
+
const getAmenityBaseName = (amenityStr) => amenityStr?.split(".")[0] ?? "";
|
|
10
|
+
|
|
11
|
+
const isWater = (amenityStr) =>
|
|
12
|
+
getAmenityBaseName(amenityStr)?.toUpperCase() === "WATER";
|
|
13
|
+
|
|
14
|
+
const TooltipArrow = ({ color }) => (
|
|
15
|
+
<div
|
|
16
|
+
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"
|
|
17
|
+
style={{ borderBottomColor: color }}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const getAmenitySplit = ({ isPeru, amenities, priorityIds }) => {
|
|
22
|
+
const priority = amenities.filter((id) => priorityIds.includes(id));
|
|
23
|
+
const nonPriority = amenities.filter((id) => !priorityIds.includes(id));
|
|
24
|
+
const hasPriority = priority.length > 0;
|
|
25
|
+
|
|
26
|
+
/* ============================
|
|
27
|
+
🇵🇪 PERU LOGIC
|
|
28
|
+
============================ */
|
|
29
|
+
if (isPeru) {
|
|
30
|
+
return hasPriority
|
|
31
|
+
? { visible: priority, plus: nonPriority }
|
|
32
|
+
: { visible: [], plus: amenities };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* ============================
|
|
36
|
+
🌍 NON-PERU LOGIC
|
|
37
|
+
============================ */
|
|
38
|
+
const sorted = [...amenities].sort(
|
|
39
|
+
(a, b) => Number(priorityIds.includes(b)) - Number(priorityIds.includes(a)),
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
visible: sorted.slice(0, 3),
|
|
44
|
+
plus: sorted.slice(3),
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
4
48
|
const AmenitiesBlock = ({
|
|
5
49
|
serviceItem,
|
|
6
50
|
metaData,
|
|
@@ -19,100 +63,77 @@ const AmenitiesBlock = ({
|
|
|
19
63
|
return null;
|
|
20
64
|
}
|
|
21
65
|
|
|
22
|
-
const
|
|
66
|
+
const operatorPriorityIds = serviceItem?.operator_details?.[5];
|
|
67
|
+
const priorityIds =
|
|
68
|
+
operatorPriorityIds?.length > 0
|
|
69
|
+
? operatorPriorityIds
|
|
70
|
+
: DEFAULT_PRIORITY_IDS;
|
|
23
71
|
|
|
24
72
|
const amenities = [...serviceItem.operator_details[4]];
|
|
25
73
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
const hasPriority = priorityAmenities.length > 0;
|
|
33
|
-
|
|
34
|
-
/* ============================
|
|
35
|
-
🇵🇪 PERU LOGIC
|
|
36
|
-
============================ */
|
|
37
|
-
let visibleAmenities = [];
|
|
38
|
-
let shouldShowPlus = false;
|
|
39
|
-
let plusAmenities = [];
|
|
40
|
-
|
|
41
|
-
if (isPeru) {
|
|
42
|
-
if (hasPriority) {
|
|
43
|
-
visibleAmenities = priorityAmenities;
|
|
44
|
-
shouldShowPlus = nonPriorityAmenities.length > 0;
|
|
45
|
-
plusAmenities = nonPriorityAmenities;
|
|
46
|
-
} else {
|
|
47
|
-
visibleAmenities = [];
|
|
48
|
-
shouldShowPlus = amenities.length > 0;
|
|
49
|
-
plusAmenities = amenities;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
74
|
+
const { visible: visibleAmenities, plus: plusAmenities } = getAmenitySplit({
|
|
75
|
+
isPeru,
|
|
76
|
+
amenities,
|
|
77
|
+
priorityIds,
|
|
78
|
+
});
|
|
52
79
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
============================ */
|
|
56
|
-
if (!isPeru) {
|
|
57
|
-
const sortedAmenities = [...amenities].sort(
|
|
58
|
-
(a, b) =>
|
|
59
|
-
Number(PRIORITY_IDS.includes(b)) - Number(PRIORITY_IDS.includes(a)),
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
visibleAmenities = sortedAmenities.slice(0, 3);
|
|
63
|
-
shouldShowPlus = sortedAmenities.length > 3;
|
|
64
|
-
plusAmenities = sortedAmenities.slice(3);
|
|
65
|
-
}
|
|
80
|
+
const shouldShowPlus = plusAmenities.length > 0;
|
|
81
|
+
const grayscaleClass = isSoldOut ? "grayscale" : "";
|
|
66
82
|
|
|
67
83
|
return (
|
|
68
84
|
<div className="flex items-center gap-[6px]">
|
|
69
|
-
{/* GPS */}
|
|
70
|
-
{serviceItem?.is_tracking_enabled && (
|
|
71
|
-
<div className={isSoldOut ? "grayscale" : ""}>
|
|
72
|
-
<LottiePlayer
|
|
73
|
-
animationData={getAnimationIcon("locationAnim")}
|
|
74
|
-
width="20px"
|
|
75
|
-
height="20px"
|
|
76
|
-
/>
|
|
77
|
-
</div>
|
|
78
|
-
)}
|
|
79
|
-
|
|
80
85
|
{/* AMENITIES */}
|
|
81
|
-
{visibleAmenities.map((val, key) =>
|
|
82
|
-
metaData.amenities[val]
|
|
86
|
+
{visibleAmenities.map((val, key) => {
|
|
87
|
+
const raw = metaData.amenities[val];
|
|
88
|
+
if (isWater(raw)) return null;
|
|
89
|
+
const baseName = getAmenityBaseName(raw);
|
|
90
|
+
|
|
91
|
+
return (
|
|
83
92
|
<div key={key} className="relative group cursor-pointer">
|
|
84
|
-
<div className={
|
|
93
|
+
<div className={grayscaleClass}>
|
|
85
94
|
<SvgAmenities
|
|
86
95
|
moreAnemities={false}
|
|
87
|
-
name={
|
|
96
|
+
name={baseName.toLowerCase()}
|
|
88
97
|
/>
|
|
89
98
|
</div>
|
|
90
99
|
|
|
91
|
-
{/* Tooltip */}
|
|
100
|
+
{/* Tooltip – show ALL amenities */}
|
|
92
101
|
<div
|
|
93
|
-
className=
|
|
102
|
+
className={TOOLTIP_CLASS}
|
|
94
103
|
style={{
|
|
95
104
|
backgroundColor: colors.tooltipColor,
|
|
96
105
|
zIndex: 21,
|
|
97
106
|
padding: "12px",
|
|
98
107
|
}}
|
|
99
108
|
>
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
<TooltipArrow color={colors.tooltipColor} />
|
|
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>
|
|
109
130
|
</div>
|
|
110
131
|
</div>
|
|
111
|
-
)
|
|
112
|
-
)}
|
|
132
|
+
);
|
|
133
|
+
})}
|
|
113
134
|
|
|
114
135
|
{/* PLUS ICON */}
|
|
115
|
-
{shouldShowPlus && (
|
|
136
|
+
{/* {shouldShowPlus && (
|
|
116
137
|
<div className="relative ml-1 cursor-pointer">
|
|
117
138
|
<div className="group">
|
|
118
139
|
<img
|
|
@@ -124,51 +145,48 @@ const AmenitiesBlock = ({
|
|
|
124
145
|
alt="plus"
|
|
125
146
|
/>
|
|
126
147
|
|
|
127
|
-
<div
|
|
128
|
-
|
|
129
|
-
className="hidden group-hover:block absolute top-[30px] left-1/2 -translate-x-1/2 text-white rounded-[14px] whitespace-nowrap mt-2.5 text-center shadow-service text-[13.33px]"
|
|
130
|
-
>
|
|
131
|
-
<div
|
|
132
|
-
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"
|
|
133
|
-
style={{
|
|
134
|
-
borderBottomColor: colors.tooltipColor,
|
|
135
|
-
}}
|
|
136
|
-
></div>
|
|
148
|
+
<div style={{ zIndex: 100 }} className={TOOLTIP_CLASS}>
|
|
149
|
+
<TooltipArrow color={colors.tooltipColor} />
|
|
137
150
|
|
|
138
151
|
<div
|
|
139
152
|
className="flex flex-col gap-[10px] p-3 rounded-[8px] shadow-md"
|
|
140
|
-
style={{
|
|
141
|
-
backgroundColor: colors.tooltipColor,
|
|
142
|
-
}}
|
|
153
|
+
style={{ backgroundColor: colors.tooltipColor }}
|
|
143
154
|
>
|
|
144
|
-
{plusAmenities.map((val, key) =>
|
|
145
|
-
metaData.amenities[val]
|
|
146
|
-
|
|
155
|
+
{plusAmenities.map((val, key) => {
|
|
156
|
+
const raw = metaData.amenities[val];
|
|
157
|
+
if (isWater(raw)) return null;
|
|
158
|
+
const baseName = getAmenityBaseName(raw);
|
|
159
|
+
|
|
160
|
+
return (
|
|
147
161
|
<div
|
|
148
162
|
key={key}
|
|
149
163
|
className="flex items-center gap-[5px] text-xs whitespace-nowrap"
|
|
150
164
|
>
|
|
151
165
|
<SvgAmenities
|
|
152
166
|
moreAnemities={true}
|
|
153
|
-
name={
|
|
154
|
-
?.split(".")[0]
|
|
155
|
-
?.toUpperCase()}
|
|
167
|
+
name={baseName.toUpperCase()}
|
|
156
168
|
color="white"
|
|
157
169
|
/>
|
|
158
|
-
{getAmenityName(
|
|
159
|
-
metaData.amenities[val]
|
|
160
|
-
?.split(".")[0]
|
|
161
|
-
?.split("_")
|
|
162
|
-
?.join(" "),
|
|
163
|
-
)}
|
|
170
|
+
{getAmenityName(baseName.split("_").join(" "))}
|
|
164
171
|
</div>
|
|
165
|
-
)
|
|
166
|
-
)}
|
|
172
|
+
);
|
|
173
|
+
})}
|
|
167
174
|
</div>
|
|
168
175
|
</div>
|
|
169
176
|
</div>
|
|
170
177
|
</div>
|
|
171
|
-
)}
|
|
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
|
+
)} */}
|
|
172
190
|
</div>
|
|
173
191
|
);
|
|
174
192
|
};
|
|
@@ -0,0 +1,109 @@
|
|
|
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: "18% 18% 23% 23%",
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
{otherItems.map((item) => (
|
|
60
|
+
<div key={item.key} className="flex items-center">
|
|
61
|
+
{item.render}
|
|
62
|
+
</div>
|
|
63
|
+
))}
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
{/* PET + FLEXIBLE (always visible) */}
|
|
67
|
+
<div className="flex items-center justify-end shrink-0 ml-[5px] w-[150px]">
|
|
68
|
+
{serviceItem?.is_tracking_enabled && (
|
|
69
|
+
<div className={grayscaleClass + " mr-[10px]"}>
|
|
70
|
+
<LottiePlayer
|
|
71
|
+
animationData={getAnimationIcon("locationAnim")}
|
|
72
|
+
width="20px"
|
|
73
|
+
height="20px"
|
|
74
|
+
/>
|
|
75
|
+
</div>
|
|
76
|
+
)}
|
|
77
|
+
{serviceItem.is_change_ticket && (
|
|
78
|
+
<FlexibleBlock
|
|
79
|
+
translation={translation}
|
|
80
|
+
getAnimationIcon={getAnimationIcon}
|
|
81
|
+
colors={colors}
|
|
82
|
+
serviceItem={serviceItem}
|
|
83
|
+
isSoldOut={isSoldOut}
|
|
84
|
+
/>
|
|
85
|
+
)}
|
|
86
|
+
{hasPetInfo && (
|
|
87
|
+
<PetBlock
|
|
88
|
+
translation={translation}
|
|
89
|
+
getAnimationIcon={getAnimationIcon}
|
|
90
|
+
colors={colors}
|
|
91
|
+
isSoldOut={isSoldOut}
|
|
92
|
+
/>
|
|
93
|
+
)}
|
|
94
|
+
|
|
95
|
+
{/* DOWN ARROW ICON */}
|
|
96
|
+
{showDownArrow ? (
|
|
97
|
+
<div
|
|
98
|
+
className="flex items-center cursor-pointer ml-[4px] transition-transform duration-300 w-[14px] h-[14px]"
|
|
99
|
+
onClick={onToggleExpand}
|
|
100
|
+
>
|
|
101
|
+
{downArrowIcon}
|
|
102
|
+
</div>
|
|
103
|
+
) : null}
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export default BottomAmenities;
|
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,85 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import LottiePlayer from "../../assets/LottiePlayer";
|
|
3
|
+
|
|
4
|
+
interface ExpandedDropdownProps {
|
|
5
|
+
serviceItem: {
|
|
6
|
+
pet_seat_info?: Record<string, any>;
|
|
7
|
+
is_change_ticket?: boolean;
|
|
8
|
+
is_tracking_enabled?: boolean;
|
|
9
|
+
};
|
|
10
|
+
showPromo: boolean;
|
|
11
|
+
colors: {
|
|
12
|
+
priceColor?: string;
|
|
13
|
+
};
|
|
14
|
+
grayscaleClass: string;
|
|
15
|
+
translation?: { [key: string]: string };
|
|
16
|
+
getAnimationIcon: (icon: string) => any;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function ExpandedDropdown({
|
|
20
|
+
serviceItem,
|
|
21
|
+
showPromo,
|
|
22
|
+
colors,
|
|
23
|
+
grayscaleClass,
|
|
24
|
+
translation,
|
|
25
|
+
getAnimationIcon,
|
|
26
|
+
}: ExpandedDropdownProps): React.ReactElement {
|
|
27
|
+
const hasPetInfo =
|
|
28
|
+
serviceItem.pet_seat_info &&
|
|
29
|
+
Object.keys(serviceItem.pet_seat_info).length > 0;
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
className="px-[15px] pt-[26px] pb-[14px] -mt-[16px] pt-[20px] relative -z-9"
|
|
34
|
+
style={{
|
|
35
|
+
backgroundColor: "#f5f5f5",
|
|
36
|
+
borderRadius: "0 0 10px 10px",
|
|
37
|
+
// border: showPromo ? `1px solid ${colors.priceColor}` : "1px solid #ccc",
|
|
38
|
+
border: `1px solid ${colors.priceColor}`,
|
|
39
|
+
|
|
40
|
+
borderTop: "none",
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
<div className="flex flex-col gap-[12px] text-[13px] text-[#464647]">
|
|
44
|
+
{hasPetInfo && (
|
|
45
|
+
<div className="flex items-center gap-[10px]">
|
|
46
|
+
<LottiePlayer
|
|
47
|
+
animationData={getAnimationIcon("petFriendlyAnim")}
|
|
48
|
+
width="20px"
|
|
49
|
+
height="20px"
|
|
50
|
+
/>
|
|
51
|
+
<div className="h-auto mr-[4px] text-[13px] text-[#464647] bold-text">
|
|
52
|
+
<span>{translation?.petFriendly}</span>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
)}
|
|
56
|
+
{serviceItem.is_change_ticket && (
|
|
57
|
+
<div className="flex items-center gap-[10px]">
|
|
58
|
+
<LottiePlayer
|
|
59
|
+
animationData={getAnimationIcon("flexibleIcon")}
|
|
60
|
+
width="20px"
|
|
61
|
+
height="20px"
|
|
62
|
+
/>
|
|
63
|
+
<div className="h-auto mr-[4px] text-[13px] text-[#464647] bold-text">
|
|
64
|
+
<span>{translation?.flexible}</span>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
{serviceItem?.is_tracking_enabled && (
|
|
69
|
+
<div className={`${grayscaleClass} flex items-center gap-[10px]`}>
|
|
70
|
+
<LottiePlayer
|
|
71
|
+
animationData={getAnimationIcon("locationAnim")}
|
|
72
|
+
width="20px"
|
|
73
|
+
height="20px"
|
|
74
|
+
/>
|
|
75
|
+
<div className="h-auto mr-[4px] text-[13px] text-[#464647] bold-text">
|
|
76
|
+
<span>{"GPS Tracker"}</span>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
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"
|
package/src/ui/RatingBlock.tsx
CHANGED
|
@@ -20,15 +20,27 @@ const RatingBlock = ({
|
|
|
20
20
|
/>
|
|
21
21
|
)}
|
|
22
22
|
|
|
23
|
-
<
|
|
24
|
-
className="ml-[10px] text-[13.33px]"
|
|
23
|
+
<div
|
|
24
|
+
className="group relative ml-[10px] text-[13.33px]"
|
|
25
25
|
style={{
|
|
26
26
|
marginLeft: showRating ? "10px" : "0",
|
|
27
27
|
color: isSoldOut ? "#c0c0c0" : "#464647",
|
|
28
28
|
}}
|
|
29
29
|
>
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
<span className="block max-w-[120px] overflow-hidden text-ellipsis whitespace-nowrap cursor-pointer">
|
|
31
|
+
{serviceItem.operator_details[2]}
|
|
32
|
+
</span>
|
|
33
|
+
<div
|
|
34
|
+
className="hidden group-hover:block absolute top-[24px] left-1/2 -translate-x-1/2 text-white p-3 rounded-[14px] whitespace-nowrap z-10 mt-2.5 w-max text-center shadow-service text-[12px]"
|
|
35
|
+
style={{ backgroundColor: colors.tooltipColor }}
|
|
36
|
+
>
|
|
37
|
+
<div
|
|
38
|
+
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 "
|
|
39
|
+
style={{ borderBottomColor: colors.tooltipColor }}
|
|
40
|
+
></div>
|
|
41
|
+
{serviceItem.operator_details[2]}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
32
44
|
</div>
|
|
33
45
|
);
|
|
34
46
|
|