kupos-ui-components-lib 10.4.39 → 10.4.41
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/assets/images/discount/green_new.png +0 -0
- package/dist/assets/images/discount/green_rt.png +0 -0
- package/dist/assets/images/discount/last_minute.png +0 -0
- package/dist/assets/images/discount/purple.png +0 -0
- package/dist/assets/images/discount/yellow_instant.png +0 -0
- package/dist/components/DiscountBanners/DiscountBannerMobile.js +3 -0
- package/dist/ui/DiscountBanners/defaultBackgrounds.js +11 -10
- package/dist/ui/SeatSection/PeruSeatSection.js +14 -22
- package/dist/ui/mobileweb/SeatSectionMobile.js +55 -53
- package/package.json +1 -1
- package/src/assets/images/discount/green_new.png +0 -0
- package/src/assets/images/discount/green_rt.png +0 -0
- package/src/assets/images/discount/last_minute.png +0 -0
- package/src/assets/images/discount/purple.png +0 -0
- package/src/assets/images/discount/yellow_instant.png +0 -0
- package/src/components/DiscountBanners/DiscountBannerMobile.tsx +2 -2
- package/src/ui/DiscountBanners/defaultBackgrounds.ts +11 -11
- package/src/ui/SeatSection/PeruSeatSection.tsx +27 -48
- package/src/ui/mobileweb/SeatSectionMobile.tsx +20 -7
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -120,6 +120,9 @@ class DiscountBannersMobile extends React.Component {
|
|
|
120
120
|
React.createElement("span", { className: `bold-text flex-shrink-0 rounded-full text-center text-[#464647] overflow-hidden whitespace-nowrap ${sizeClasses.chip}`, style: chipPillInArt
|
|
121
121
|
? undefined
|
|
122
122
|
: { backgroundColor: "rgba(255,255,255,0.55)" } }, label),
|
|
123
|
+
showFlamePercent && (React.createElement("span", { className: `bold-text absolute text-[#ffffff] text-center pointer-events-none ${sizeClasses.flameBadge}`, style: Object.assign(Object.assign({}, FLAME_CENTER), { transform: "translate(-50%, -50%)", textShadow: "0 1px 2px rgba(0,0,0,0.28)", fontWeight: 900, whiteSpace: "nowrap" }) },
|
|
124
|
+
card.amount,
|
|
125
|
+
React.createElement("span", { className: sizeClasses.flamePercent, style: { fontWeight: 700 } }, "%"))),
|
|
123
126
|
React.createElement("span", { className: `flex flex-col ${sizeClasses.column}` },
|
|
124
127
|
React.createElement("span", { className: `bold-text text-[#464647] ${sizeClasses.discount}` }, card.discountLabel),
|
|
125
128
|
React.createElement("span", { className: `bold-text ${sizeClasses.subtitle}`, style: { color: accentColor } }, card.subtitle))));
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import greenArt from "../../assets/images/discount/
|
|
1
|
+
import greenArt from "../../assets/images/discount/green_new.png";
|
|
2
2
|
import yellowArt from "../../assets/images/discount/yellow.png";
|
|
3
3
|
import blueArt from "../../assets/images/discount/blue.png";
|
|
4
|
-
import lastMinuteArt from "../../assets/images/discount/
|
|
5
|
-
import firstTimeArt from "../../assets/images/discount/
|
|
4
|
+
import lastMinuteArt from "../../assets/images/discount/last_minute.png";
|
|
5
|
+
import firstTimeArt from "../../assets/images/discount/purple.png";
|
|
6
6
|
import cashbackArt from "../../assets/images/discount/cash.png";
|
|
7
|
-
import roundTripArt from "../../assets/images/discount/
|
|
8
|
-
import promoCodeArt from "../../assets/images/discount/
|
|
7
|
+
import roundTripArt from "../../assets/images/discount/green_rt.png";
|
|
8
|
+
import promoCodeArt from "../../assets/images/discount/yellow.png";
|
|
9
9
|
import seatLevelArt from "../../assets/images/discount/seat.png";
|
|
10
|
+
import instantArt from "../../assets/images/discount/yellow_instant.png";
|
|
10
11
|
export function toImageUrl(art) {
|
|
11
12
|
if (typeof art === "string")
|
|
12
13
|
return art;
|
|
@@ -27,11 +28,11 @@ export const DEFAULT_BACKGROUND_IMAGES = [
|
|
|
27
28
|
blueArt,
|
|
28
29
|
].map(toImageUrl);
|
|
29
30
|
export const CAMPAIGN_ART = {
|
|
30
|
-
last_minute: { image: toImageUrl(lastMinuteArt), accent: "#
|
|
31
|
-
first_time: { image: toImageUrl(firstTimeArt), accent: "#
|
|
31
|
+
last_minute: { image: toImageUrl(lastMinuteArt), accent: "#1633DB" },
|
|
32
|
+
first_time: { image: toImageUrl(firstTimeArt), accent: "#FB488E" },
|
|
32
33
|
cashback: { image: toImageUrl(cashbackArt), accent: "#0069D1" },
|
|
33
|
-
round_trip: { image: toImageUrl(roundTripArt), accent: "#
|
|
34
|
-
instant_discount: { image: toImageUrl(
|
|
34
|
+
round_trip: { image: toImageUrl(roundTripArt), accent: "#107E23" },
|
|
35
|
+
instant_discount: { image: toImageUrl(instantArt), accent: "#FDA105" },
|
|
35
36
|
seat_level: { image: toImageUrl(seatLevelArt), accent: "#B87500" },
|
|
36
|
-
promo_code: { image: toImageUrl(
|
|
37
|
+
promo_code: { image: toImageUrl(promoCodeArt), accent: "#FFC000" },
|
|
37
38
|
};
|
|
@@ -117,9 +117,15 @@ function PeruSeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, cur
|
|
|
117
117
|
// Single seat type → original behaviour (one lowest-fare price)
|
|
118
118
|
const allSeats = getAllSeatTypes(seatTypes);
|
|
119
119
|
const lowestFare = allSeats.length > 0 ? allSeats[0].price : 0;
|
|
120
|
-
const { discountedPrice } = CommonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
const { originalPrice, discountedPrice } = CommonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
121
|
+
const price = (React.createElement("span", { className: "flex items-center text-[13.33px] bold-text" }, formatPrice(showOriginalFare ? originalPrice : discountedPrice)));
|
|
122
|
+
// Inclination fares sit under "Desde", same as the stacked rows above.
|
|
123
|
+
if (hasInclination) {
|
|
124
|
+
return (React.createElement("div", { className: "relative" },
|
|
125
|
+
React.createElement("span", { className: "text-[12px] font-normal text-[#6a6a6a] absolute", style: { top: "-15px" } }, "Desde"),
|
|
126
|
+
price));
|
|
127
|
+
}
|
|
128
|
+
return price;
|
|
123
129
|
};
|
|
124
130
|
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
125
131
|
const discountedSeats = seats.map((seat) => (Object.assign(Object.assign({}, seat), CommonService.calculateDiscountedPrice(seat.price, serviceItem))));
|
|
@@ -134,6 +140,7 @@ function PeruSeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, cur
|
|
|
134
140
|
// Tier B (ui_type 1) announces the offer elsewhere, so the fare itself must
|
|
135
141
|
// render exactly as it would with no discount.
|
|
136
142
|
const showOriginalFare = hasDiscount && uiType === 1;
|
|
143
|
+
const hasStrikeOff = hasDiscount && !showOriginalFare;
|
|
137
144
|
const discountType = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_type;
|
|
138
145
|
const discountValueRaw = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_value;
|
|
139
146
|
const maxDiscount = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.max_discount;
|
|
@@ -189,35 +196,20 @@ function PeruSeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, cur
|
|
|
189
196
|
: filteredSeats[0].label
|
|
190
197
|
: null;
|
|
191
198
|
return (React.createElement(React.Fragment, null,
|
|
192
|
-
|
|
199
|
+
hasStrikeOff && (React.createElement("span", { className: "text-[13.33px]", style: {
|
|
193
200
|
color: "#999",
|
|
194
201
|
} }, "Antes")),
|
|
195
|
-
React.createElement("span", { className: "text-[13.33px] flex flex-col" }, !
|
|
202
|
+
React.createElement("span", { className: "text-[13.33px] flex flex-col" }, !hasStrikeOff ? (React.createElement("span", { className: "text-[13.33px] whitespace-nowrap flex items-center", style: {
|
|
196
203
|
opacity: isSoldOut ? 0.5 : 1,
|
|
197
204
|
} },
|
|
198
|
-
isSeatIcon &&
|
|
205
|
+
isSeatIcon && (React.createElement("img", { src: getSeatTypeIcon(seatLabel, serviceItem), alt: "seattype", style: {
|
|
199
206
|
width: "20px",
|
|
200
207
|
height: "20px",
|
|
201
208
|
marginRight: "5px",
|
|
202
209
|
} })),
|
|
203
210
|
CommonService.capitalize(seatLabel))) : (React.createElement("span", { className: "text-[13.33px]" }, "Desde")))));
|
|
204
211
|
};
|
|
205
|
-
if (hasDiscount && discountSeat &&
|
|
206
|
-
// Tier B (ui_type 1): offer text is announced elsewhere, but the fare
|
|
207
|
-
// itself must render exactly as it would with no discount — no
|
|
208
|
-
// strike-off, no badge, no fire icon.
|
|
209
|
-
if (uiType === 1) {
|
|
210
|
-
return (React.createElement("div", { className: "grid grid-cols-2 items-center text-[13.33px] relative", style: { opacity: isSoldOut ? 0.5 : 1 } },
|
|
211
|
-
React.createElement("div", { className: "col-start-1 row-start-3 flex h-[20px] items-end" },
|
|
212
|
-
React.createElement("span", { className: "text-[13.33px] font-normal leading-[20px] text-[#464647]" }, discountSeat.label)),
|
|
213
|
-
React.createElement("div", { className: "col-start-2 row-start-3 flex h-[30px] items-end justify-center relative" },
|
|
214
|
-
React.createElement("span", { className: "flex items-center gap-[6px] bold-text leading-[30px]", style: {
|
|
215
|
-
color: isSoldOut ? "#c0c0c0" : "#464647",
|
|
216
|
-
fontSize: "13.33px",
|
|
217
|
-
} }, availableSeats <= 0
|
|
218
|
-
? CommonService.currency(0, currencySign)
|
|
219
|
-
: CommonService.discountedCurrency(discountSeat.originalPrice, currencySign)))));
|
|
220
|
-
}
|
|
212
|
+
if (hasDiscount && discountSeat && uiType !== 1) {
|
|
221
213
|
return (React.createElement("div", { className: "grid grid-cols-2 items-center text-[13.33px] relative", style: { opacity: isSoldOut ? 0.5 : 1 } },
|
|
222
214
|
React.createElement("div", { className: "col-start-1 row-start-2 flex items-center" },
|
|
223
215
|
React.createElement("span", { className: "text-[13.33px] font-normal leading-[22px] text-[#ccc]" }, "Antes")),
|
|
@@ -94,18 +94,20 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
94
94
|
})));
|
|
95
95
|
}
|
|
96
96
|
const { originalPrice, discountedPrice } = commonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
97
|
+
const hasStrikeOff = originalPrice !== discountedPrice && !showOriginalFare;
|
|
97
98
|
const seatLabel = uniqueSeats.length > 0
|
|
98
99
|
? commonService.truncateSeatLabel(uniqueSeats[0].label)
|
|
99
100
|
: null;
|
|
100
101
|
return (React.createElement(React.Fragment, null,
|
|
101
|
-
|
|
102
|
+
hasStrikeOff && (React.createElement("div", { className: "w-[100%] flex flex-row justify-between items-center" },
|
|
102
103
|
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px]", style: { color: "#bbb" } }, "Antes"),
|
|
103
104
|
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] line-through", style: { color: "#bbb" } }, commonService.currency(originalPrice, currencySign)))),
|
|
104
|
-
React.createElement("div", { className: "w-[100%] flex flex-row justify-between items-center" },
|
|
105
|
-
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px]
|
|
105
|
+
React.createElement("div", { className: "relative w-[100%] flex flex-row justify-between items-center" },
|
|
106
|
+
hasInclination && !hasStrikeOff && (React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] absolute", style: { color: "#6a6a6a", top: -20, right: 0 } }, "Desde")),
|
|
107
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: isSoldOut ? "#bbb" : "#464647" } }, hasStrikeOff
|
|
106
108
|
? "Desde"
|
|
107
109
|
: commonService.capitalize(seatLabel) || "Desde"),
|
|
108
|
-
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: priceColor } }, commonService.currency(discountedPrice, currencySign)))));
|
|
110
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: priceColor } }, commonService.currency(showOriginalFare ? originalPrice : discountedPrice, currencySign)))));
|
|
109
111
|
};
|
|
110
112
|
const renderDpSeats = () => {
|
|
111
113
|
var _a;
|
|
@@ -254,55 +256,55 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
254
256
|
} },
|
|
255
257
|
((_k = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _k === void 0 ? void 0 : _k.fireIcon) ? (React.createElement("img", { src: serviceItem.icons.fireIcon, alt: "discount", className: "h-[16px] w-[16px] object-contain", style: { filter: isSoldOut ? "grayscale" : "" } })) : null,
|
|
256
258
|
commonService.discountedCurrency(Number(firstSeatFare), currencySign)),
|
|
257
|
-
isSoldOut ? (React.createElement("span", { className: "col-span-2 min-[420]:text-[13px] text-right text-[12px] text-[#ccc]" }, "Agotado")) : null)) :
|
|
258
|
-
|
|
259
|
-
!(isPeru &&
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
259
|
+
isSoldOut ? (React.createElement("span", { className: "col-span-2 min-[420]:text-[13px] text-right text-[12px] text-[#ccc]" }, "Agotado")) : null)) : // Peru Tier B (ui_type 1) falls through to the regular layout — same
|
|
260
|
+
// colours and "Desde" as a service with no discount, original fare.
|
|
261
|
+
hasDiscount && discountSeat && !(isPeru && isOfferTextOnlyTier) ? (React.createElement("div", null,
|
|
262
|
+
React.createElement("div", { className: "relative grid grid-cols-[auto_auto] justify-between gap-x-[8px] " },
|
|
263
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) !== 1 && discountBadgeText && (React.createElement(React.Fragment, null,
|
|
264
|
+
React.createElement("div", { className: "absolute -top-[18px] right-[0px]", style: {
|
|
265
|
+
animation: "pulse-zoom 2s ease-in-out infinite",
|
|
266
|
+
opacity: isSoldOut ? 0.5 : 1,
|
|
267
|
+
} },
|
|
268
|
+
React.createElement("span", { className: "rounded-[100px] px-[8px] text-[12px] bold-text leading-[20px] text-[#fff]", style: {
|
|
269
|
+
backgroundColor: tooltipBgColor,
|
|
270
|
+
} }, discountBadgeText)),
|
|
271
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] leading-[20px] text-[#c2c2c2]" }, "Antes"),
|
|
272
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] leading-[20px] text-right ", style: {
|
|
273
|
+
position: "relative",
|
|
274
|
+
display: "inline-block",
|
|
275
|
+
overflow: "hidden",
|
|
276
|
+
color: discountSeatPriceColor,
|
|
277
|
+
} },
|
|
278
|
+
commonService.currency(discountSeat.originalPrice, currencySign),
|
|
279
|
+
React.createElement("span", { style: {
|
|
280
|
+
position: "absolute",
|
|
281
|
+
top: "35%",
|
|
282
|
+
left: "50%",
|
|
283
|
+
width: "80%",
|
|
284
|
+
height: "1px",
|
|
285
|
+
background: discountSeatCrossPriceColor,
|
|
286
|
+
transform: "rotate(-12deg)",
|
|
287
|
+
transformOrigin: "center",
|
|
288
|
+
} })))),
|
|
289
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] leading-[24px]", style: { color: isSoldOut ? "#bbb" : "#464647" } }, isOfferTextOnlyTier
|
|
290
|
+
? commonService.capitalize(commonService.truncateSeatLabel(discountSeat.label))
|
|
291
|
+
: "Desde"),
|
|
292
|
+
React.createElement("span", { className: "flex items-center justify-end gap-[4px] text-[14px] bold-text leading-[24px]", style: {
|
|
293
|
+
color: isSoldOut
|
|
294
|
+
? "#bbb"
|
|
295
|
+
: (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) === 1
|
|
296
|
+
? "#464647"
|
|
297
|
+
: discountSeatPriceColor || "#ff5964",
|
|
275
298
|
} },
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
} })))),
|
|
287
|
-
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] leading-[24px]", style: { color: isSoldOut ? "#bbb" : "#464647" } }, isOfferTextOnlyTier
|
|
288
|
-
? commonService.capitalize(commonService.truncateSeatLabel(discountSeat.label))
|
|
289
|
-
: "Desde"),
|
|
290
|
-
React.createElement("span", { className: "flex items-center justify-end gap-[4px] text-[14px] bold-text leading-[24px]", style: {
|
|
291
|
-
color: isSoldOut
|
|
292
|
-
? "#bbb"
|
|
293
|
-
: (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) === 1
|
|
294
|
-
? "#464647"
|
|
295
|
-
: discountSeatPriceColor || "#ff5964",
|
|
296
|
-
} },
|
|
297
|
-
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) !== 1 && ((_l = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _l === void 0 ? void 0 : _l.fireIcon) ? (React.createElement("img", { src: serviceItem.icons.fireIcon, alt: "discount", className: "h-[16px] w-[16px] object-contain", style: { opacity: isSoldOut ? 0.5 : 1 } })) : null,
|
|
298
|
-
commonService.discountedCurrency((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) === 1
|
|
299
|
-
? discountSeat.originalPrice
|
|
300
|
-
: discountSeat.discountedPrice, currencySign))))) : (React.createElement("div", { className: `flex flex-col justify-between ${isTrain ? "" : "h-[2.5rem]"} `, style: {
|
|
301
|
-
gap: isSoldOut ? "0px" : "5px",
|
|
302
|
-
justifyContent: hasMultipleTypes ? "space-between" : "center",
|
|
303
|
-
} },
|
|
304
|
-
renderSeats(),
|
|
305
|
-
isSoldOut ? (React.createElement("div", { className: "flex justify-end" },
|
|
306
|
-
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] text-[#ccc]" }, "Agotado"))) : null))));
|
|
299
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) !== 1 && ((_l = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _l === void 0 ? void 0 : _l.fireIcon) ? (React.createElement("img", { src: serviceItem.icons.fireIcon, alt: "discount", className: "h-[16px] w-[16px] object-contain", style: { opacity: isSoldOut ? 0.5 : 1 } })) : null,
|
|
300
|
+
commonService.discountedCurrency((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) === 1
|
|
301
|
+
? discountSeat.originalPrice
|
|
302
|
+
: discountSeat.discountedPrice, currencySign))))) : (React.createElement("div", { className: `flex flex-col justify-between ${isTrain ? "" : "h-[2.5rem]"} `, style: {
|
|
303
|
+
gap: isSoldOut ? "0px" : "5px",
|
|
304
|
+
justifyContent: hasMultipleTypes ? "space-between" : "center",
|
|
305
|
+
} },
|
|
306
|
+
renderSeats(),
|
|
307
|
+
isSoldOut ? (React.createElement("div", { className: "flex justify-end" },
|
|
308
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] text-[#ccc]" }, "Agotado"))) : null))));
|
|
307
309
|
}
|
|
308
310
|
export default SeatSectionMobile;
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -190,7 +190,7 @@ class DiscountBannersMobile extends React.Component<
|
|
|
190
190
|
>
|
|
191
191
|
{label}
|
|
192
192
|
</span>
|
|
193
|
-
{
|
|
193
|
+
{showFlamePercent && (
|
|
194
194
|
<span
|
|
195
195
|
className={`bold-text absolute text-[#ffffff] text-center pointer-events-none ${sizeClasses.flameBadge}`}
|
|
196
196
|
style={{
|
|
@@ -209,7 +209,7 @@ class DiscountBannersMobile extends React.Component<
|
|
|
209
209
|
%
|
|
210
210
|
</span>
|
|
211
211
|
</span>
|
|
212
|
-
)}
|
|
212
|
+
)}
|
|
213
213
|
<span className={`flex flex-col ${sizeClasses.column}`}>
|
|
214
214
|
<span
|
|
215
215
|
className={`bold-text text-[#464647] ${sizeClasses.discount}`}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import greenArt from "../../assets/images/discount/
|
|
1
|
+
import greenArt from "../../assets/images/discount/green_new.png";
|
|
2
2
|
import yellowArt from "../../assets/images/discount/yellow.png";
|
|
3
3
|
import blueArt from "../../assets/images/discount/blue.png";
|
|
4
|
-
import lastMinuteArt from "../../assets/images/discount/
|
|
5
|
-
import firstTimeArt from "../../assets/images/discount/
|
|
4
|
+
import lastMinuteArt from "../../assets/images/discount/last_minute.png";
|
|
5
|
+
import firstTimeArt from "../../assets/images/discount/purple.png";
|
|
6
6
|
import cashbackArt from "../../assets/images/discount/cash.png";
|
|
7
|
-
import roundTripArt from "../../assets/images/discount/
|
|
8
|
-
import promoCodeArt from "../../assets/images/discount/
|
|
7
|
+
import roundTripArt from "../../assets/images/discount/green_rt.png";
|
|
8
|
+
import promoCodeArt from "../../assets/images/discount/yellow.png";
|
|
9
9
|
import seatLevelArt from "../../assets/images/discount/seat.png";
|
|
10
|
-
import instantArt from "../../assets/images/discount/
|
|
10
|
+
import instantArt from "../../assets/images/discount/yellow_instant.png";
|
|
11
11
|
|
|
12
12
|
export type ImageRef =
|
|
13
13
|
| string
|
|
@@ -32,11 +32,11 @@ export const DEFAULT_BACKGROUND_IMAGES: string[] = [
|
|
|
32
32
|
].map(toImageUrl);
|
|
33
33
|
|
|
34
34
|
export const CAMPAIGN_ART: Record<string, { image: string; accent: string }> = {
|
|
35
|
-
last_minute: { image: toImageUrl(lastMinuteArt), accent: "#
|
|
36
|
-
first_time: { image: toImageUrl(firstTimeArt), accent: "#
|
|
35
|
+
last_minute: { image: toImageUrl(lastMinuteArt), accent: "#1633DB" },
|
|
36
|
+
first_time: { image: toImageUrl(firstTimeArt), accent: "#FB488E" },
|
|
37
37
|
cashback: { image: toImageUrl(cashbackArt), accent: "#0069D1" },
|
|
38
|
-
round_trip: { image: toImageUrl(roundTripArt), accent: "#
|
|
39
|
-
instant_discount: { image: toImageUrl(
|
|
38
|
+
round_trip: { image: toImageUrl(roundTripArt), accent: "#107E23" },
|
|
39
|
+
instant_discount: { image: toImageUrl(instantArt), accent: "#FDA105" },
|
|
40
40
|
seat_level: { image: toImageUrl(seatLevelArt), accent: "#B87500" },
|
|
41
|
-
promo_code: { image: toImageUrl(
|
|
41
|
+
promo_code: { image: toImageUrl(promoCodeArt), accent: "#FFC000" },
|
|
42
42
|
};
|
|
@@ -211,18 +211,30 @@ function PeruSeatSection({
|
|
|
211
211
|
// Single seat type → original behaviour (one lowest-fare price)
|
|
212
212
|
const allSeats = getAllSeatTypes(seatTypes);
|
|
213
213
|
const lowestFare = allSeats.length > 0 ? allSeats[0].price : 0;
|
|
214
|
-
const { discountedPrice } =
|
|
215
|
-
lowestFare,
|
|
216
|
-
|
|
214
|
+
const { originalPrice, discountedPrice } =
|
|
215
|
+
CommonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
216
|
+
const price = (
|
|
217
|
+
<span className="flex items-center text-[13.33px] bold-text">
|
|
218
|
+
{formatPrice(showOriginalFare ? originalPrice : discountedPrice)}
|
|
219
|
+
</span>
|
|
217
220
|
);
|
|
218
221
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
222
|
+
// Inclination fares sit under "Desde", same as the stacked rows above.
|
|
223
|
+
if (hasInclination) {
|
|
224
|
+
return (
|
|
225
|
+
<div className="relative">
|
|
226
|
+
<span
|
|
227
|
+
className="text-[12px] font-normal text-[#6a6a6a] absolute"
|
|
228
|
+
style={{ top: "-15px" }}
|
|
229
|
+
>
|
|
230
|
+
Desde
|
|
231
|
+
</span>
|
|
232
|
+
{price}
|
|
233
|
+
</div>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return price;
|
|
226
238
|
};
|
|
227
239
|
|
|
228
240
|
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
@@ -246,6 +258,7 @@ function PeruSeatSection({
|
|
|
246
258
|
// Tier B (ui_type 1) announces the offer elsewhere, so the fare itself must
|
|
247
259
|
// render exactly as it would with no discount.
|
|
248
260
|
const showOriginalFare = hasDiscount && uiType === 1;
|
|
261
|
+
const hasStrikeOff = hasDiscount && !showOriginalFare;
|
|
249
262
|
const discountType = serviceItem?.discount_type;
|
|
250
263
|
const discountValueRaw = serviceItem?.discount_value;
|
|
251
264
|
const maxDiscount = serviceItem?.max_discount;
|
|
@@ -331,7 +344,7 @@ function PeruSeatSection({
|
|
|
331
344
|
|
|
332
345
|
return (
|
|
333
346
|
<>
|
|
334
|
-
{
|
|
347
|
+
{hasStrikeOff && (
|
|
335
348
|
<span
|
|
336
349
|
className="text-[13.33px]"
|
|
337
350
|
style={{
|
|
@@ -343,14 +356,14 @@ function PeruSeatSection({
|
|
|
343
356
|
)}
|
|
344
357
|
|
|
345
358
|
<span className="text-[13.33px] flex flex-col">
|
|
346
|
-
{!
|
|
359
|
+
{!hasStrikeOff ? (
|
|
347
360
|
<span
|
|
348
361
|
className="text-[13.33px] whitespace-nowrap flex items-center"
|
|
349
362
|
style={{
|
|
350
363
|
opacity: isSoldOut ? 0.5 : 1,
|
|
351
364
|
}}
|
|
352
365
|
>
|
|
353
|
-
{isSeatIcon &&
|
|
366
|
+
{isSeatIcon && (
|
|
354
367
|
<img
|
|
355
368
|
src={
|
|
356
369
|
getSeatTypeIcon(
|
|
@@ -376,42 +389,8 @@ function PeruSeatSection({
|
|
|
376
389
|
);
|
|
377
390
|
};
|
|
378
391
|
|
|
379
|
-
if (hasDiscount && discountSeat && !(uiType === 1 && showSeatTypeRows)) {
|
|
380
|
-
// Tier B (ui_type 1): offer text is announced elsewhere, but the fare
|
|
381
|
-
// itself must render exactly as it would with no discount — no
|
|
382
|
-
// strike-off, no badge, no fire icon.
|
|
383
|
-
if (uiType === 1) {
|
|
384
|
-
return (
|
|
385
|
-
<div
|
|
386
|
-
className="grid grid-cols-2 items-center text-[13.33px] relative"
|
|
387
|
-
style={{ opacity: isSoldOut ? 0.5 : 1 }}
|
|
388
|
-
>
|
|
389
|
-
<div className="col-start-1 row-start-3 flex h-[20px] items-end">
|
|
390
|
-
<span className="text-[13.33px] font-normal leading-[20px] text-[#464647]">
|
|
391
|
-
{discountSeat.label}
|
|
392
|
-
</span>
|
|
393
|
-
</div>
|
|
394
|
-
|
|
395
|
-
<div className="col-start-2 row-start-3 flex h-[30px] items-end justify-center relative">
|
|
396
|
-
<span
|
|
397
|
-
className="flex items-center gap-[6px] bold-text leading-[30px]"
|
|
398
|
-
style={{
|
|
399
|
-
color: isSoldOut ? "#c0c0c0" : "#464647",
|
|
400
|
-
fontSize: "13.33px",
|
|
401
|
-
}}
|
|
402
|
-
>
|
|
403
|
-
{availableSeats <= 0
|
|
404
|
-
? CommonService.currency(0, currencySign)
|
|
405
|
-
: CommonService.discountedCurrency(
|
|
406
|
-
discountSeat.originalPrice,
|
|
407
|
-
currencySign,
|
|
408
|
-
)}
|
|
409
|
-
</span>
|
|
410
|
-
</div>
|
|
411
|
-
</div>
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
392
|
|
|
393
|
+
if (hasDiscount && discountSeat && uiType !== 1) {
|
|
415
394
|
return (
|
|
416
395
|
<div
|
|
417
396
|
className="grid grid-cols-2 items-center text-[13.33px] relative"
|
|
@@ -230,6 +230,7 @@ function SeatSectionMobile({
|
|
|
230
230
|
|
|
231
231
|
const { originalPrice, discountedPrice } =
|
|
232
232
|
commonService.calculateDiscountedPrice(lowestFare, serviceItem);
|
|
233
|
+
const hasStrikeOff = originalPrice !== discountedPrice && !showOriginalFare;
|
|
233
234
|
|
|
234
235
|
const seatLabel =
|
|
235
236
|
uniqueSeats.length > 0
|
|
@@ -238,7 +239,7 @@ function SeatSectionMobile({
|
|
|
238
239
|
|
|
239
240
|
return (
|
|
240
241
|
<>
|
|
241
|
-
{
|
|
242
|
+
{hasStrikeOff && (
|
|
242
243
|
<div className="w-[100%] flex flex-row justify-between items-center">
|
|
243
244
|
<span
|
|
244
245
|
className="min-[420]:text-[13px] text-[12px]"
|
|
@@ -254,12 +255,21 @@ function SeatSectionMobile({
|
|
|
254
255
|
</span>
|
|
255
256
|
</div>
|
|
256
257
|
)}
|
|
257
|
-
<div className="w-[100%] flex flex-row justify-between items-center">
|
|
258
|
+
<div className="relative w-[100%] flex flex-row justify-between items-center">
|
|
259
|
+
{/* Inclination fares sit under "Desde", same as the stacked rows above. */}
|
|
260
|
+
{hasInclination && !hasStrikeOff && (
|
|
261
|
+
<span
|
|
262
|
+
className="min-[420]:text-[13px] text-[12px] absolute"
|
|
263
|
+
style={{ color: "#6a6a6a", top: -20, right: 0 }}
|
|
264
|
+
>
|
|
265
|
+
Desde
|
|
266
|
+
</span>
|
|
267
|
+
)}
|
|
258
268
|
<span
|
|
259
269
|
className="min-[420]:text-[13px] text-[12px] bold-text"
|
|
260
270
|
style={{ color: isSoldOut ? "#bbb" : "#464647" }}
|
|
261
271
|
>
|
|
262
|
-
{
|
|
272
|
+
{hasStrikeOff
|
|
263
273
|
? "Desde"
|
|
264
274
|
: commonService.capitalize(seatLabel) || "Desde"}
|
|
265
275
|
</span>
|
|
@@ -267,7 +277,10 @@ function SeatSectionMobile({
|
|
|
267
277
|
className="min-[420]:text-[13px] text-[12px] bold-text"
|
|
268
278
|
style={{ color: priceColor }}
|
|
269
279
|
>
|
|
270
|
-
{commonService.currency(
|
|
280
|
+
{commonService.currency(
|
|
281
|
+
showOriginalFare ? originalPrice : discountedPrice,
|
|
282
|
+
currencySign,
|
|
283
|
+
)}
|
|
271
284
|
</span>
|
|
272
285
|
</div>
|
|
273
286
|
</>
|
|
@@ -594,9 +607,9 @@ function SeatSectionMobile({
|
|
|
594
607
|
</span>
|
|
595
608
|
) : null}
|
|
596
609
|
</div>
|
|
597
|
-
) :
|
|
598
|
-
|
|
599
|
-
|
|
610
|
+
) : // Peru Tier B (ui_type 1) falls through to the regular layout — same
|
|
611
|
+
// colours and "Desde" as a service with no discount, original fare.
|
|
612
|
+
hasDiscount && discountSeat && !(isPeru && isOfferTextOnlyTier) ? (
|
|
600
613
|
<div>
|
|
601
614
|
<div className="relative grid grid-cols-[auto_auto] justify-between gap-x-[8px] ">
|
|
602
615
|
{serviceItem?.ui_type !== 1 && discountBadgeText && (
|