kupos-ui-components-lib 10.4.62 → 10.4.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/FilterBar/FilterBarDesktop.js +10 -0
- package/dist/components/FilterBar/ServiceFilter.d.ts +1 -0
- package/dist/components/FilterBar/ServiceFilter.js +10 -4
- package/dist/components/ServiceItem/PeruServiceItemDesktop.js +3 -1
- package/dist/components/ServiceItem/PeruServiceItemMobile.js +5 -3
- package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemDesktop.js +7 -5
- package/dist/components/ServiceItem/ServiceItemMobile.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemMobile.js +14 -16
- package/dist/components/ServiceItem/mobileTypes.d.ts +3 -0
- package/dist/components/ServiceItem/types.d.ts +3 -0
- package/dist/styles.css +3 -0
- package/dist/ui/OfferBanner.d.ts +1 -1
- package/dist/ui/OfferBanner.js +9 -5
- package/dist/ui/PeruOfferBanner.d.ts +1 -1
- package/dist/ui/PeruOfferBanner.js +5 -1
- package/dist/ui/RatingBlock.d.ts +1 -1
- package/dist/ui/RatingBlock.js +7 -3
- package/dist/ui/SeatSection/SeatSection.js +28 -13
- package/dist/ui/ServiceBadges/ServiceBadges.js +1 -1
- package/dist/ui/mobileweb/SeatSectionMobile.js +10 -5
- package/dist/utils/CommonService.d.ts +7 -0
- package/dist/utils/CommonService.js +6 -0
- package/package.json +1 -1
- package/src/components/FilterBar/FilterBarDesktop.tsx +16 -0
- package/src/components/FilterBar/ServiceFilter.tsx +12 -2
- package/src/components/ServiceItem/PeruServiceItemDesktop.tsx +4 -1
- package/src/components/ServiceItem/PeruServiceItemMobile.tsx +6 -3
- package/src/components/ServiceItem/ServiceItemDesktop.tsx +9 -3
- package/src/components/ServiceItem/ServiceItemMobile.tsx +25 -14
- package/src/components/ServiceItem/mobileTypes.ts +3 -0
- package/src/components/ServiceItem/types.ts +3 -0
- package/src/ui/OfferBanner.tsx +10 -5
- package/src/ui/PeruOfferBanner.tsx +7 -1
- package/src/ui/RatingBlock.tsx +7 -2
- package/src/ui/SeatSection/SeatSection.tsx +53 -29
- package/src/ui/ServiceBadges/ServiceBadges.tsx +1 -1
- package/src/ui/mobileweb/SeatSectionMobile.tsx +30 -20
- package/src/utils/CommonService.ts +13 -0
|
@@ -45,7 +45,8 @@ function addSeatDegree(label) {
|
|
|
45
45
|
return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
|
|
46
46
|
}
|
|
47
47
|
function hasInclinationSeatTypes(seatTypes) {
|
|
48
|
-
|
|
48
|
+
// Matches "160°" as well as a bare "160" label
|
|
49
|
+
return (seatTypes !== null && seatTypes !== void 0 ? seatTypes : []).some((seat) => { var _a; return /\b(120|140|160|180)\b/.test(String((_a = seat === null || seat === void 0 ? void 0 : seat.label) !== null && _a !== void 0 ? _a : "")); });
|
|
49
50
|
}
|
|
50
51
|
const getUniqueSeats = (data, limit) => {
|
|
51
52
|
var _a;
|
|
@@ -116,7 +117,7 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
116
117
|
marginRight: "4px",
|
|
117
118
|
filter: isSoldOut ? "grayscale(1)" : "",
|
|
118
119
|
} })),
|
|
119
|
-
commonService.truncateSeatLabel(seat.label)),
|
|
120
|
+
commonService.truncateSeatLabel(commonService.addSeatDegree(seat.label))),
|
|
120
121
|
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: priceColor } }, commonService.currency(showOriginalFare ? originalPrice : discountedPrice, currencySign))));
|
|
121
122
|
})));
|
|
122
123
|
}
|
|
@@ -155,7 +156,7 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
155
156
|
const { discountedPrice } = commonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
156
157
|
const priceColor = isSoldOut ? "#bbb" : tooltipBgColor;
|
|
157
158
|
return (React.createElement("div", { className: "relative flex flex-col justify-center h-full", style: { opacity: isSoldOut ? 0.5 : 1 } },
|
|
158
|
-
React.createElement("div", { className: "absolute right-[0px]", style: {
|
|
159
|
+
commonService.showDpBestPrice(serviceItem) && (React.createElement("div", { className: "absolute right-[0px]", style: {
|
|
159
160
|
animation: "pulse-zoom 2s ease-in-out infinite",
|
|
160
161
|
top: ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.available_seats) < 10 &&
|
|
161
162
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.available_seats) > 0) ||
|
|
@@ -165,7 +166,7 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
165
166
|
} },
|
|
166
167
|
React.createElement("span", { className: "rounded-[100px] px-[8px] text-[11px] bold-text leading-[20px] text-[#fff]", style: {
|
|
167
168
|
backgroundColor: tooltipBgColor,
|
|
168
|
-
} }, "Mejor precio")),
|
|
169
|
+
} }, "Mejor precio"))),
|
|
169
170
|
React.createElement("div", { className: "w-[100%] flex flex-row justify-between items-center" },
|
|
170
171
|
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px]" }, "Desde"),
|
|
171
172
|
React.createElement("span", { className: "flex items-center gap-[4px] min-[420]:text-[13px] text-[14px] bold-text", style: { color: priceColor } },
|
|
@@ -254,12 +255,16 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
254
255
|
const originalDpPrice = getMinValue(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.original_dp_price);
|
|
255
256
|
const dpDiscountPercent = getMinValue(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents);
|
|
256
257
|
const firstSeatFare = (_h = (_g = seatTypesData === null || seatTypesData === void 0 ? void 0 : seatTypesData.filter((item) => getFilteredSeats(item.label) && !EXCEPTIONS.includes(item.label))) === null || _g === void 0 ? void 0 : _g.sort((a, b) => a.fare - b.fare)[0]) === null || _h === void 0 ? void 0 : _h.fare;
|
|
257
|
-
|
|
258
|
+
// show_dp_ui: false falls through to the regular fare layout
|
|
259
|
+
const isDpUiHidden = commonService.isDpUiHidden(serviceItem);
|
|
260
|
+
const hasDpDiscount = !isDpUiHidden &&
|
|
261
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) &&
|
|
258
262
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents) &&
|
|
259
263
|
originalDpPrice != null &&
|
|
260
264
|
dpDiscountPercent != null &&
|
|
261
265
|
firstSeatFare != null;
|
|
262
266
|
return (React.createElement("div", { className: "content-center relative", style: { width: "40%", flexShrink: 0 } }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) &&
|
|
267
|
+
!isDpUiHidden &&
|
|
263
268
|
!((_j = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) === null || _j === void 0 ? void 0 : _j.length) &&
|
|
264
269
|
!dpDiscountPercent ? (React.createElement("div", { className: "flex flex-col justify-between h-[2.5rem]", style: { gap: isSoldOut ? "0px" : "5px" } }, renderDpSeats())) : hasDpDiscount ? (
|
|
265
270
|
// Antes/Desde rows spread top/bottom so they line up with the
|
|
@@ -16,6 +16,13 @@ declare const commonService: {
|
|
|
16
16
|
formatDefaultLabel: (label: string) => string;
|
|
17
17
|
addSeatDegree: (label: string) => string;
|
|
18
18
|
getSeatDegreeIcon: (label: string, icons: any) => string | null;
|
|
19
|
+
isDpUiHidden: (serviceItem?: {
|
|
20
|
+
is_dp_enabled?: boolean;
|
|
21
|
+
show_dp_ui?: boolean;
|
|
22
|
+
}) => boolean;
|
|
23
|
+
showDpBestPrice: (serviceItem?: {
|
|
24
|
+
show_best_price?: boolean;
|
|
25
|
+
}) => boolean;
|
|
19
26
|
calculateDiscountedPrice: (originalPrice: number | string, serviceItem?: {
|
|
20
27
|
discount_type?: string;
|
|
21
28
|
discount_value?: number;
|
|
@@ -332,6 +332,12 @@ const commonService = {
|
|
|
332
332
|
const match = String(label !== null && label !== void 0 ? label : "").match(/\b(120|140|160|180)\b/);
|
|
333
333
|
return match ? (icons === null || icons === void 0 ? void 0 : icons[`seat${match[1]}`]) || null : null;
|
|
334
334
|
},
|
|
335
|
+
// The backend can switch off the DP look (gradient card, ribbon, DP fare
|
|
336
|
+
// block) per DP service with show_dp_ui: false. DP fare rules (no changes /
|
|
337
|
+
// cancellations) still apply. A missing flag keeps the current UI.
|
|
338
|
+
isDpUiHidden: (serviceItem) => Boolean(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) && (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.show_dp_ui) === false,
|
|
339
|
+
// "Mejor precio" pill on DP fares; a missing flag keeps the current UI.
|
|
340
|
+
showDpBestPrice: (serviceItem) => (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.show_best_price) !== false,
|
|
335
341
|
calculateDiscountedPrice: (originalPrice, serviceItem) => {
|
|
336
342
|
var _a;
|
|
337
343
|
const price = typeof originalPrice === "string"
|
package/package.json
CHANGED
|
@@ -221,6 +221,22 @@ const FilterBarDesktop = ({
|
|
|
221
221
|
});
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
if (fil.type == "service_type") {
|
|
225
|
+
const activeOptions = fil.options.filter((it) => it.active);
|
|
226
|
+
if (activeOptions.length) {
|
|
227
|
+
filteredRoutes = filteredRoutes.filter((it) =>
|
|
228
|
+
activeOptions.some(
|
|
229
|
+
(f) =>
|
|
230
|
+
f.value ===
|
|
231
|
+
String(it.service_type || "")
|
|
232
|
+
.trim()
|
|
233
|
+
.replace(/\s+/g, " ")
|
|
234
|
+
.toLowerCase(),
|
|
235
|
+
),
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
224
240
|
if (fil.type == "operator") {
|
|
225
241
|
let activeOptions = fil.options.filter((it) => it.active);
|
|
226
242
|
filteredRoutes = filteredRoutes.filter((it) => {
|
|
@@ -23,6 +23,7 @@ interface ServiceFilterBarDesktopState {
|
|
|
23
23
|
showTrainType: boolean;
|
|
24
24
|
addMargin: boolean;
|
|
25
25
|
showAmenities: boolean;
|
|
26
|
+
showServiceType: boolean;
|
|
26
27
|
sortedFilters: any[];
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -43,6 +44,7 @@ class ServiceFilter extends React.Component<
|
|
|
43
44
|
showTrainType: props.initialOpenFilters?.includes("train_type") || true,
|
|
44
45
|
addMargin: false,
|
|
45
46
|
showAmenities: props.initialOpenFilters?.includes("amenities") || true,
|
|
47
|
+
showServiceType: true,
|
|
46
48
|
sortedFilters: this.sortFilters(props.filtersArray),
|
|
47
49
|
};
|
|
48
50
|
|
|
@@ -80,6 +82,7 @@ class ServiceFilter extends React.Component<
|
|
|
80
82
|
const FILTER_ORDER = [
|
|
81
83
|
"time",
|
|
82
84
|
"operator",
|
|
85
|
+
"service_type",
|
|
83
86
|
"special_departure",
|
|
84
87
|
"tipo",
|
|
85
88
|
"seat_types",
|
|
@@ -173,6 +176,10 @@ class ServiceFilter extends React.Component<
|
|
|
173
176
|
type === "amenities"
|
|
174
177
|
? !prevState.showAmenities
|
|
175
178
|
: prevState.showAmenities,
|
|
179
|
+
showServiceType:
|
|
180
|
+
type === "service_type"
|
|
181
|
+
? !prevState.showServiceType
|
|
182
|
+
: prevState.showServiceType,
|
|
176
183
|
};
|
|
177
184
|
});
|
|
178
185
|
}
|
|
@@ -186,6 +193,7 @@ class ServiceFilter extends React.Component<
|
|
|
186
193
|
showSpecialDeparture,
|
|
187
194
|
showTrainType,
|
|
188
195
|
showAmenities,
|
|
196
|
+
showServiceType,
|
|
189
197
|
} = this.state;
|
|
190
198
|
|
|
191
199
|
const isOpen =
|
|
@@ -195,7 +203,8 @@ class ServiceFilter extends React.Component<
|
|
|
195
203
|
(option.type === "tipo" && showTypeOptions) ||
|
|
196
204
|
(option.type === "special_departure" && showSpecialDeparture) ||
|
|
197
205
|
(option.type === "train_type" && showTrainType) ||
|
|
198
|
-
(option.type === "amenities" && showAmenities)
|
|
206
|
+
(option.type === "amenities" && showAmenities) ||
|
|
207
|
+
(option.type === "service_type" && showServiceType);
|
|
199
208
|
|
|
200
209
|
if (option?.type === "train_type" && !this.props.isTrain) {
|
|
201
210
|
return null;
|
|
@@ -249,7 +258,8 @@ class ServiceFilter extends React.Component<
|
|
|
249
258
|
option.type !== "seat_types" &&
|
|
250
259
|
option.type !== "tipo" &&
|
|
251
260
|
option.type !== "special_departure" &&
|
|
252
|
-
option.type !== "train_type"
|
|
261
|
+
option.type !== "train_type" &&
|
|
262
|
+
option.type !== "service_type")) &&
|
|
253
263
|
option.options.map((val: any, i: number) => {
|
|
254
264
|
let iconKey = "";
|
|
255
265
|
if (val.icon === "sunrise") {
|
|
@@ -180,7 +180,10 @@ function PeruServiceItemDesktop({
|
|
|
180
180
|
})();
|
|
181
181
|
|
|
182
182
|
let isSoldOut = serviceItem.available_seats <= 0;
|
|
183
|
-
|
|
183
|
+
// show_dp_ui: false renders a DP service with the regular card UI
|
|
184
|
+
const hasDpEnabled =
|
|
185
|
+
serviceItem?.is_dp_enabled === true &&
|
|
186
|
+
!CommonService.isDpUiHidden(serviceItem);
|
|
184
187
|
const peruDiscount = (serviceItem as any)?.discounts?.[0];
|
|
185
188
|
const uiType = peruDiscount?.ui_type;
|
|
186
189
|
|
|
@@ -100,7 +100,10 @@ function PeruServiceItemMobile({
|
|
|
100
100
|
offerText.length > OFFER_TEXT_MAX_CHARS
|
|
101
101
|
? `${offerText.slice(0, OFFER_TEXT_MAX_CHARS).trimEnd()}...`
|
|
102
102
|
: offerText;
|
|
103
|
-
|
|
103
|
+
// show_dp_ui: false renders a DP service with the regular card UI
|
|
104
|
+
const hasDpEnabled =
|
|
105
|
+
serviceItem?.is_dp_enabled === true &&
|
|
106
|
+
!commonService.isDpUiHidden(serviceItem);
|
|
104
107
|
const hasDpRibbon = hasDpEnabled && Boolean(serviceItem?.dp_discount_percents);
|
|
105
108
|
|
|
106
109
|
// ui_type comes from the active discount entry: 1 = offer-text-only tier,
|
|
@@ -224,7 +227,7 @@ function PeruServiceItemMobile({
|
|
|
224
227
|
|
|
225
228
|
return (
|
|
226
229
|
<div
|
|
227
|
-
className={`relative ${!hasOfferText || !
|
|
230
|
+
className={`relative ${!hasOfferText || !hasDpEnabled ? "mb-[14px]" : showTopLabel || serviceItem?.is_direct_trip ? "mb-[20px]" : "mb-[12px]"} ${
|
|
228
231
|
serviceItem?.is_direct_trip ||
|
|
229
232
|
isConexion ||
|
|
230
233
|
serviceItem?.train_type_label === "Tren Express (Nuevo)" ||
|
|
@@ -470,7 +473,7 @@ function PeruServiceItemMobile({
|
|
|
470
473
|
style={{ lineHeight: 1.6 }}
|
|
471
474
|
>
|
|
472
475
|
<div className="flex justify-between items-center">
|
|
473
|
-
{
|
|
476
|
+
{hasDpEnabled &&
|
|
474
477
|
Object.keys(serviceItem?.dp_discount_percents ?? {}).length ===
|
|
475
478
|
0 &&
|
|
476
479
|
(serviceItem?.dp_discounted_seats ?? []).length === 0 ? (
|
|
@@ -154,6 +154,7 @@ function ServiceItemPB({
|
|
|
154
154
|
priority_stage_ids,
|
|
155
155
|
isShowSeatIcon = false,
|
|
156
156
|
showDesdeLabel = false,
|
|
157
|
+
showServiceTypeUnderLogo = false,
|
|
157
158
|
}: ServiceItemProps & { currencySign?: string }): React.ReactElement {
|
|
158
159
|
const handleSeatSelect = (
|
|
159
160
|
key: any,
|
|
@@ -277,11 +278,13 @@ function ServiceItemPB({
|
|
|
277
278
|
return false;
|
|
278
279
|
})();
|
|
279
280
|
|
|
281
|
+
// show_dp_ui: false renders a DP service with the regular card UI
|
|
282
|
+
const isDpUiHidden = CommonService.isDpUiHidden(serviceItem);
|
|
280
283
|
const dpDiscountEntry = Object.entries(
|
|
281
284
|
serviceItem?.dp_discount_percents || {},
|
|
282
285
|
)[0];
|
|
283
|
-
const dpDiscountPercent = dpDiscountEntry?.[1];
|
|
284
|
-
const hasDpEnabled = serviceItem?.is_dp_enabled === true;
|
|
286
|
+
const dpDiscountPercent = isDpUiHidden ? undefined : dpDiscountEntry?.[1];
|
|
287
|
+
const hasDpEnabled = serviceItem?.is_dp_enabled === true && !isDpUiHidden;
|
|
285
288
|
|
|
286
289
|
const offerGradient = `linear-gradient(90deg, ${colors.rightGradiantColor || "#ff5964"} 0%, ${colors.leftGradiantColor || "#ff8842"} 100%)`;
|
|
287
290
|
const offerGradientWithOpacity = `linear-gradient(90deg, ${colors.rightGradiantColor || "#ff5964"}80 0%, ${colors.leftGradiantColor || "#ff8842"}80 100%)`;
|
|
@@ -669,6 +672,7 @@ function ServiceItemPB({
|
|
|
669
672
|
translation={translation}
|
|
670
673
|
isPeru={isPeru}
|
|
671
674
|
isTrain={isTrain}
|
|
675
|
+
showServiceTypeUnderLogo={showServiceTypeUnderLogo}
|
|
672
676
|
/>
|
|
673
677
|
</div>
|
|
674
678
|
|
|
@@ -778,7 +782,9 @@ function ServiceItemPB({
|
|
|
778
782
|
isPeru={isPeru}
|
|
779
783
|
isTrain={isTrain}
|
|
780
784
|
isDpEnabled={serviceItem.is_dp_enabled}
|
|
781
|
-
serviceType={
|
|
785
|
+
serviceType={
|
|
786
|
+
showServiceTypeUnderLogo ? undefined : serviceItem.service_type
|
|
787
|
+
}
|
|
782
788
|
renderIcon={renderIcon}
|
|
783
789
|
/>
|
|
784
790
|
</div>
|
|
@@ -69,6 +69,7 @@ function ServiceItemMobile({
|
|
|
69
69
|
priority_stage_ids,
|
|
70
70
|
isShowSeatIcon = false,
|
|
71
71
|
showDesdeLabel = false,
|
|
72
|
+
showServiceTypeUnderLogo = false,
|
|
72
73
|
}: MobileServiceItemProps): React.ReactElement {
|
|
73
74
|
const isItemExpanded = serviceItem.id === isExpanded;
|
|
74
75
|
const isPetSeat = (Object.keys(serviceItem?.pet_seat_info) || []).length > 0;
|
|
@@ -93,6 +94,9 @@ function ServiceItemMobile({
|
|
|
93
94
|
|
|
94
95
|
const isLongOfferText = (serviceItem?.offer_text?.length || 0) > 35;
|
|
95
96
|
const hasDpEnabled = serviceItem?.is_dp_enabled === true;
|
|
97
|
+
// show_dp_ui: false renders a DP service with the regular card UI
|
|
98
|
+
const showDpUi =
|
|
99
|
+
serviceItem?.is_dp_enabled && !commonService.isDpUiHidden(serviceItem);
|
|
96
100
|
|
|
97
101
|
const isDiscountBelow20 =
|
|
98
102
|
(serviceItem as any)?.discount_value > 0 &&
|
|
@@ -102,7 +106,7 @@ function ServiceItemMobile({
|
|
|
102
106
|
const offerGradientWithOpacity = `linear-gradient(90deg, ${colors.rightGradiantColor || "#ff5964"}80 0%, ${colors.leftGradiantColor || "#ff8842"}80 100%)`;
|
|
103
107
|
const serviceCardStyle: React.CSSProperties =
|
|
104
108
|
(isNewUiEnabled && serviceItem?.ui_type === 2) ||
|
|
105
|
-
(
|
|
109
|
+
(showDpUi && serviceItem?.dp_discount_percents)
|
|
106
110
|
? {
|
|
107
111
|
borderColor: isSoldOut ? "#ccc" : "transparent",
|
|
108
112
|
borderStyle: "solid",
|
|
@@ -285,7 +289,7 @@ function ServiceItemMobile({
|
|
|
285
289
|
/>
|
|
286
290
|
) : (
|
|
287
291
|
<div
|
|
288
|
-
className={`relative ${!hasOfferText || !
|
|
292
|
+
className={`relative ${!hasOfferText || !showDpUi ? "mb-[14px]" : showTopLabel || serviceItem?.is_direct_trip ? "mb-[20px]" : "mb-[12px]"} ${
|
|
289
293
|
serviceItem?.is_direct_trip ||
|
|
290
294
|
isConexion ||
|
|
291
295
|
serviceItem?.train_type_label === "Tren Express (Nuevo)" ||
|
|
@@ -299,8 +303,7 @@ function ServiceItemMobile({
|
|
|
299
303
|
<div
|
|
300
304
|
className={`z-1 ${
|
|
301
305
|
((isNewUiEnabled && serviceItem?.ui_type === 2) ||
|
|
302
|
-
(serviceItem?.
|
|
303
|
-
serviceItem?.dp_discount_percents)) &&
|
|
306
|
+
(showDpUi && serviceItem?.dp_discount_percents)) &&
|
|
304
307
|
!isSoldOut
|
|
305
308
|
? "rounded-[18px]"
|
|
306
309
|
: "rounded-[10px] border border-[#ccc]"
|
|
@@ -340,6 +343,15 @@ function ServiceItemMobile({
|
|
|
340
343
|
<div className="black-text min-[420]:text-[12px] text-[12px]">
|
|
341
344
|
{serviceItem?.operator_details[2]}
|
|
342
345
|
</div>
|
|
346
|
+
) : showServiceTypeUnderLogo && serviceItem?.service_type ? (
|
|
347
|
+
<div
|
|
348
|
+
className="min-[420]:text-[13px] text-[12px] text-ellipsis overflow-hidden whitespace-nowrap max-w-[150px]"
|
|
349
|
+
style={{ color: isSoldOut ? "#bbb" : "#464647" }}
|
|
350
|
+
>
|
|
351
|
+
{commonService.capitalizeFirstLetter(
|
|
352
|
+
serviceItem.service_type,
|
|
353
|
+
)}
|
|
354
|
+
</div>
|
|
343
355
|
) : showRating ? (
|
|
344
356
|
<div className="flex min-[420]:text-[13px] text-[12px] h-[22px] items-center">
|
|
345
357
|
<div className="flex items-center">
|
|
@@ -436,7 +448,9 @@ function ServiceItemMobile({
|
|
|
436
448
|
hoursIcon={renderIcon("hours", "14px")}
|
|
437
449
|
duration={serviceItem.duration?.toString()}
|
|
438
450
|
isDirectTrip={serviceItem?.is_direct_trip}
|
|
439
|
-
serviceType={
|
|
451
|
+
serviceType={
|
|
452
|
+
showServiceTypeUnderLogo ? undefined : serviceItem?.service_type
|
|
453
|
+
}
|
|
440
454
|
directoColor={colors.directoColor}
|
|
441
455
|
directoAnim={serviceItem.icons.directoAnim}
|
|
442
456
|
isChangeTicket={serviceItem.is_change_ticket}
|
|
@@ -480,7 +494,7 @@ function ServiceItemMobile({
|
|
|
480
494
|
isNewUiEnabled &&
|
|
481
495
|
serviceItem?.ui_type === 1 &&
|
|
482
496
|
!isSoldOut &&
|
|
483
|
-
!
|
|
497
|
+
!showDpUi && (
|
|
484
498
|
<div
|
|
485
499
|
className="px-[12px] pt-[22px] pb-[8px] relative -z-9 -mt-[15px]"
|
|
486
500
|
style={{
|
|
@@ -523,8 +537,7 @@ function ServiceItemMobile({
|
|
|
523
537
|
|
|
524
538
|
{/* 🔹 EXPANDABLE DROPDOWN (below the card) */}
|
|
525
539
|
{((isNewUiEnabled && serviceItem?.ui_type === 2) ||
|
|
526
|
-
(serviceItem?.
|
|
527
|
-
serviceItem?.dp_discount_percents)) &&
|
|
540
|
+
(showDpUi && serviceItem?.dp_discount_percents)) &&
|
|
528
541
|
!isSoldOut && (
|
|
529
542
|
<div
|
|
530
543
|
className="px-[12px] pt-[22px] pb-[8px] relative -z-9 -mt-[15px]"
|
|
@@ -542,7 +555,7 @@ function ServiceItemMobile({
|
|
|
542
555
|
style={{ lineHeight: 1.6 }}
|
|
543
556
|
>
|
|
544
557
|
<div className="flex justify-between items-center">
|
|
545
|
-
{
|
|
558
|
+
{showDpUi &&
|
|
546
559
|
Object.keys(serviceItem?.dp_discount_percents ?? {})
|
|
547
560
|
.length === 0 &&
|
|
548
561
|
(serviceItem?.dp_discounted_seats ?? []).length === 0 ? (
|
|
@@ -650,8 +663,7 @@ function ServiceItemMobile({
|
|
|
650
663
|
position: "relative",
|
|
651
664
|
zIndex:
|
|
652
665
|
hasOfferText ||
|
|
653
|
-
(serviceItem?.
|
|
654
|
-
serviceItem?.dp_discount_percents) ||
|
|
666
|
+
(showDpUi && serviceItem?.dp_discount_percents) ||
|
|
655
667
|
(isNewUiEnabled && serviceItem?.ui_type === 2)
|
|
656
668
|
? -2
|
|
657
669
|
: -1,
|
|
@@ -662,14 +674,13 @@ function ServiceItemMobile({
|
|
|
662
674
|
overflow: "hidden",
|
|
663
675
|
minHeight: 0,
|
|
664
676
|
position:
|
|
665
|
-
hasOfferText || isNewUiEnabled ||
|
|
677
|
+
hasOfferText || isNewUiEnabled || showDpUi
|
|
666
678
|
? "relative"
|
|
667
679
|
: undefined,
|
|
668
680
|
zIndex:
|
|
669
681
|
serviceItem?.offer_text ||
|
|
670
682
|
(isNewUiEnabled && serviceItem?.ui_type === 2) ||
|
|
671
|
-
(serviceItem?.
|
|
672
|
-
serviceItem?.dp_discount_percents)
|
|
683
|
+
(showDpUi && serviceItem?.dp_discount_percents)
|
|
673
684
|
? -3
|
|
674
685
|
: undefined,
|
|
675
686
|
marginTop: hasOfferText ? "-15px" : "-10px",
|
|
@@ -40,6 +40,8 @@ export interface MobileServiceItemProps {
|
|
|
40
40
|
train_type_label?: string;
|
|
41
41
|
ladies_booked_seats?: string;
|
|
42
42
|
is_dp_enabled?: boolean;
|
|
43
|
+
show_dp_ui?: boolean;
|
|
44
|
+
show_best_price?: boolean;
|
|
43
45
|
offer_text?: string;
|
|
44
46
|
is_direct_trip?: boolean;
|
|
45
47
|
is_train_type?: boolean;
|
|
@@ -267,4 +269,5 @@ export interface MobileServiceItemProps {
|
|
|
267
269
|
isShowSeatIcon?: boolean;
|
|
268
270
|
// shows a small "Desde" label above the price in the seat section
|
|
269
271
|
showDesdeLabel?: boolean;
|
|
272
|
+
showServiceTypeUnderLogo?: boolean;
|
|
270
273
|
}
|
|
@@ -43,6 +43,8 @@ export interface ServiceItemProps {
|
|
|
43
43
|
offer_text?: string;
|
|
44
44
|
is_direct_trip?: boolean;
|
|
45
45
|
is_dp_enabled?: boolean;
|
|
46
|
+
show_dp_ui?: boolean;
|
|
47
|
+
show_best_price?: boolean;
|
|
46
48
|
dp_discount_percents?: any;
|
|
47
49
|
dp_discounted_seats?: any;
|
|
48
50
|
original_dp_price?: any;
|
|
@@ -288,4 +290,5 @@ export interface ServiceItemProps {
|
|
|
288
290
|
isShowSeatIcon?: boolean;
|
|
289
291
|
// shows a small "Desde" label above the price in the seat section
|
|
290
292
|
showDesdeLabel?: boolean;
|
|
293
|
+
showServiceTypeUnderLogo?: boolean;
|
|
291
294
|
}
|
package/src/ui/OfferBanner.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import { ServiceItemProps } from "../components/ServiceItem/types";
|
|
|
8
8
|
type ServiceItemSlice = Pick<
|
|
9
9
|
ServiceItemProps["serviceItem"],
|
|
10
10
|
| "is_dp_enabled"
|
|
11
|
+
| "show_dp_ui"
|
|
11
12
|
| "offer_text"
|
|
12
13
|
| "dp_discount_percents"
|
|
13
14
|
| "dp_discounted_seats"
|
|
@@ -49,6 +50,7 @@ function truncateOfferText(text: string): string {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
function hasDpDiscounts(serviceItem: ServiceItemSlice): boolean {
|
|
53
|
+
if (CommonService.isDpUiHidden(serviceItem)) return false;
|
|
52
54
|
return (
|
|
53
55
|
Object.keys(serviceItem?.dp_discount_percents ?? {}).length > 0 ||
|
|
54
56
|
(serviceItem?.dp_discounted_seats ?? []).length > 0
|
|
@@ -238,23 +240,26 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
238
240
|
(serviceItem as any)?.discount_value > 0 &&
|
|
239
241
|
(serviceItem as any)?.discount_value < 20;
|
|
240
242
|
const offerText = serviceItem?.offer_text || "";
|
|
243
|
+
// With show_dp_ui: false the banner renders as for a non-DP service
|
|
244
|
+
const showDpUi =
|
|
245
|
+
serviceItem?.is_dp_enabled && !CommonService.isDpUiHidden(serviceItem);
|
|
241
246
|
|
|
242
247
|
const isLegacyOffer =
|
|
243
248
|
!!offerText &&
|
|
244
249
|
isNewUiEnabled &&
|
|
245
250
|
serviceItem?.ui_type === 1 &&
|
|
246
|
-
!
|
|
251
|
+
!showDpUi;
|
|
247
252
|
|
|
248
253
|
const showViewers =
|
|
249
254
|
(isNewUiEnabled && serviceItem?.ui_type !== 1) ||
|
|
250
|
-
|
|
255
|
+
showDpUi;
|
|
251
256
|
|
|
252
257
|
const background = isLegacyOffer ? colors?.bottomStripColor : offerGradient;
|
|
253
258
|
|
|
254
259
|
const renderLeftContent = () => {
|
|
255
260
|
const hasDp = hasDpDiscounts(serviceItem);
|
|
256
261
|
|
|
257
|
-
if (
|
|
262
|
+
if (showDpUi && !hasDp) {
|
|
258
263
|
return <PopularServiceBanner getAnimationIcon={getAnimationIcon} />;
|
|
259
264
|
}
|
|
260
265
|
|
|
@@ -292,14 +297,14 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
292
297
|
style={{
|
|
293
298
|
background:
|
|
294
299
|
(isNewUiEnabled && serviceItem?.ui_type === 2) ||
|
|
295
|
-
(
|
|
300
|
+
(showDpUi && serviceItem?.dp_discount_percents)
|
|
296
301
|
? offerGradient
|
|
297
302
|
: background,
|
|
298
303
|
opacity: isSoldOut ? 0.5 : 1,
|
|
299
304
|
zIndex: isLinatal ? "-1" : "0",
|
|
300
305
|
paddingBottom:
|
|
301
306
|
serviceItem?.offer_text && serviceItem?.ui_type !== 2
|
|
302
|
-
? "
|
|
307
|
+
? "7px"
|
|
303
308
|
: "9px",
|
|
304
309
|
}}
|
|
305
310
|
>
|
|
@@ -8,6 +8,7 @@ import { ServiceItemProps } from "../components/ServiceItem/types";
|
|
|
8
8
|
type ServiceItemSlice = Pick<
|
|
9
9
|
ServiceItemProps["serviceItem"],
|
|
10
10
|
| "is_dp_enabled"
|
|
11
|
+
| "show_dp_ui"
|
|
11
12
|
| "offer_text"
|
|
12
13
|
| "dp_discount_percents"
|
|
13
14
|
| "dp_discounted_seats"
|
|
@@ -49,6 +50,7 @@ function truncateOfferText(text: string): string {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
function hasDpDiscounts(serviceItem: ServiceItemSlice): boolean {
|
|
53
|
+
if (CommonService.isDpUiHidden(serviceItem)) return false;
|
|
52
54
|
return (
|
|
53
55
|
Object.keys(serviceItem?.dp_discount_percents ?? {}).length > 0 ||
|
|
54
56
|
(serviceItem?.dp_discounted_seats ?? []).length > 0
|
|
@@ -232,7 +234,11 @@ const PeruOfferBanner: React.FC<PeruOfferBannerProps> = ({
|
|
|
232
234
|
: offerGradient;
|
|
233
235
|
|
|
234
236
|
const renderLeftContent = () => {
|
|
235
|
-
if (
|
|
237
|
+
if (
|
|
238
|
+
serviceItem?.is_dp_enabled &&
|
|
239
|
+
!CommonService.isDpUiHidden(serviceItem) &&
|
|
240
|
+
!hasDp
|
|
241
|
+
) {
|
|
236
242
|
return <PopularServiceBanner getAnimationIcon={getAnimationIcon} />;
|
|
237
243
|
}
|
|
238
244
|
|
package/src/ui/RatingBlock.tsx
CHANGED
|
@@ -11,7 +11,12 @@ const RatingBlock = ({
|
|
|
11
11
|
translation,
|
|
12
12
|
isPeru = false,
|
|
13
13
|
isTrain = false,
|
|
14
|
+
showServiceTypeUnderLogo = false,
|
|
14
15
|
}: any) => {
|
|
16
|
+
const operatorLabel = showServiceTypeUnderLogo
|
|
17
|
+
? commonService.capitalizeFirstLetter(serviceItem?.service_type)
|
|
18
|
+
: serviceItem.operator_details[2];
|
|
19
|
+
|
|
15
20
|
return (
|
|
16
21
|
<div
|
|
17
22
|
className="flex items-center whitespace-nowrap"
|
|
@@ -38,7 +43,7 @@ const RatingBlock = ({
|
|
|
38
43
|
<span
|
|
39
44
|
className={`block max-w-[120px] cursor-pointer text-[12px] ${isPeru || isTrain ? "overflow-hidden text-ellipsis whitespace-nowrap" : ""}`}
|
|
40
45
|
>
|
|
41
|
-
{
|
|
46
|
+
{operatorLabel}
|
|
42
47
|
</span>
|
|
43
48
|
<div
|
|
44
49
|
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]"
|
|
@@ -48,7 +53,7 @@ const RatingBlock = ({
|
|
|
48
53
|
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 "
|
|
49
54
|
style={{ borderBottomColor: colors.bottomStripColor }}
|
|
50
55
|
></div>
|
|
51
|
-
{
|
|
56
|
+
{operatorLabel}
|
|
52
57
|
</div>
|
|
53
58
|
</div>
|
|
54
59
|
</div>
|