kupos-ui-components-lib 10.4.28 → 10.4.30
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/ServiceItem/PeruServiceItemDesktop.js +21 -14
- package/dist/components/ServiceItem/PeruServiceItemMobile.js +39 -44
- package/dist/components/ServiceItem/ServiceItemDesktop.js +1 -1
- package/dist/components/ServiceItem/ServiceItemMobile.js +7 -3
- package/dist/ui/OfferBanner.d.ts +1 -0
- package/dist/ui/OfferBanner.js +10 -6
- package/dist/ui/PeruOfferBanner.d.ts +1 -0
- package/dist/ui/PeruOfferBanner.js +16 -24
- package/dist/ui/SeatSection/PeruSeatSection.js +42 -15
- package/dist/ui/SeatSection/SeatSection.js +18 -9
- package/dist/ui/mobileweb/SeatSectionMobile.js +16 -11
- package/package.json +1 -1
- package/src/components/ServiceItem/PeruServiceItemDesktop.tsx +32 -24
- package/src/components/ServiceItem/PeruServiceItemMobile.tsx +62 -79
- package/src/components/ServiceItem/ServiceItemDesktop.tsx +1 -0
- package/src/components/ServiceItem/ServiceItemMobile.tsx +17 -11
- package/src/ui/OfferBanner.tsx +17 -7
- package/src/ui/PeruOfferBanner.tsx +23 -36
- package/src/ui/SeatSection/PeruSeatSection.tsx +64 -17
- package/src/ui/SeatSection/SeatSection.tsx +17 -1
- package/src/ui/mobileweb/SeatSectionMobile.tsx +53 -46
|
@@ -329,18 +329,27 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
|
|
|
329
329
|
React.createElement("span", { className: "text-[13.33px] font-normal leading-[22px] text-[#ccc]" }, "Antes"))),
|
|
330
330
|
React.createElement("div", { className: "col-start-1 row-start-3 flex h-[20px] items-end" },
|
|
331
331
|
React.createElement("span", { className: "text-[13.33px] font-normal leading-[20px] text-[#464647]" }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) === 1 ? discountSeat.label : "Desde")),
|
|
332
|
-
React.createElement("div", { className: "col-start-2 row-start-1 flex items-center justify-center absolute", style: { top: "-22px", left: "50%", transform: "translateX(-50%)" } },
|
|
333
|
-
(
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
332
|
+
React.createElement("div", { className: "col-start-2 row-start-1 flex items-center justify-center absolute", style: { top: "-22px", left: "50%", transform: "translateX(-50%)" } },
|
|
333
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) !== 1 &&
|
|
334
|
+
!isPeru &&
|
|
335
|
+
(discountValue != null || isMaxDiscountApplied) && (React.createElement("span", { className: "rounded-[100px] bg-[#ff5964] px-[6px] text-[12px] bold-text leading-[20px] text-white", style: {
|
|
336
|
+
animation: "pulse-zoom 2s ease-in-out infinite",
|
|
337
|
+
whiteSpace: "nowrap",
|
|
338
|
+
backgroundColor: discountSeatPriceColor,
|
|
339
|
+
} }, isMaxDiscountApplied
|
|
340
|
+
? `${CommonService.currency(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.max_discount)} OFF`
|
|
341
|
+
: `${discountValue}% OFF`)),
|
|
342
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) !== 1 &&
|
|
343
|
+
isPeru &&
|
|
344
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_display_badge) && (React.createElement("span", { className: "rounded-[100px] bg-[#ff5964] px-[6px] text-[12px] bold-text leading-[20px] text-white", style: {
|
|
345
|
+
animation: "pulse-zoom 2s ease-in-out infinite",
|
|
346
|
+
whiteSpace: "nowrap",
|
|
347
|
+
backgroundColor: discountSeatCrossPriceColor,
|
|
348
|
+
} }, serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discount_display_badge))),
|
|
340
349
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) === 1 ? null : (React.createElement("div", { className: "col-start-2 row-start-2 flex items-center justify-center ", style: { textAlign: "center" } },
|
|
341
350
|
React.createElement("span", { className: "text-[13.33px] font-normal leading-[20px] relative whitespace-nowrap", style: {
|
|
342
351
|
position: "relative",
|
|
343
|
-
color:
|
|
352
|
+
color: discountSeatCrossPriceColor,
|
|
344
353
|
} },
|
|
345
354
|
formatPrice(discountSeat.originalPrice),
|
|
346
355
|
React.createElement("span", { style: {
|
|
@@ -48,7 +48,7 @@ const getUniqueSeats = (data, limit) => {
|
|
|
48
48
|
.slice(0, limit);
|
|
49
49
|
};
|
|
50
50
|
function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPriceColor, currencySign, availableSeats, removeDuplicateSeats, serviceItem, tooltipBgColor, showLastSeats, discountSeatPriceColor, isTrain, discountSeatCrossPriceColor, }) {
|
|
51
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
51
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
52
52
|
const hasMultipleTypes = ((_a = seatTypesData === null || seatTypesData === void 0 ? void 0 : seatTypesData.length) !== null && _a !== void 0 ? _a : 0) > 2;
|
|
53
53
|
const getFare = (fare) => {
|
|
54
54
|
if (removeDuplicateSeats && availableSeats <= 0 && !isPeru) {
|
|
@@ -193,6 +193,14 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
193
193
|
}
|
|
194
194
|
return false;
|
|
195
195
|
})();
|
|
196
|
+
// Backend-provided ready-made badge text (e.g. "30% OFF" / "$2.000 OFF")
|
|
197
|
+
// takes precedence over the value computed client-side.
|
|
198
|
+
const discountBadgeText = ((_d = (_c = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.discounts) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.discount_display_badge) ||
|
|
199
|
+
(isMaxDiscountApplied
|
|
200
|
+
? `${commonService.currency(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.max_discount)} OFF`
|
|
201
|
+
: discountValue != null
|
|
202
|
+
? `${discountValue}% OFF`
|
|
203
|
+
: null);
|
|
196
204
|
const getMinValue = (data) => {
|
|
197
205
|
const vals = (Array.isArray(data) ? data : Object.values(data || {})).map(Number);
|
|
198
206
|
if (!vals.length)
|
|
@@ -202,14 +210,14 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
202
210
|
};
|
|
203
211
|
const originalDpPrice = getMinValue(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.original_dp_price);
|
|
204
212
|
const dpDiscountPercent = getMinValue(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents);
|
|
205
|
-
const firstSeatFare = (
|
|
213
|
+
const firstSeatFare = (_f = (_e = seatTypesData === null || seatTypesData === void 0 ? void 0 : seatTypesData.filter((item) => getFilteredSeats(item.label) && !EXCEPTIONS.includes(item.label))) === null || _e === void 0 ? void 0 : _e.sort((a, b) => a.fare - b.fare)[0]) === null || _f === void 0 ? void 0 : _f.fare;
|
|
206
214
|
const hasDpDiscount = (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) &&
|
|
207
215
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents) &&
|
|
208
216
|
originalDpPrice != null &&
|
|
209
217
|
dpDiscountPercent != null &&
|
|
210
218
|
firstSeatFare != null;
|
|
211
219
|
return (React.createElement("div", { className: "content-center relative", style: { width: "40%" } }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) &&
|
|
212
|
-
!((
|
|
220
|
+
!((_g = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) === null || _g === void 0 ? void 0 : _g.length) &&
|
|
213
221
|
!dpDiscountPercent ? (React.createElement("div", { className: "flex flex-col justify-between h-[2.5rem]", style: { gap: isSoldOut ? "0px" : "5px" } }, renderDpSeats())) : hasDpDiscount ? (React.createElement("div", { className: "relative grid grid-cols-[auto_auto] justify-between gap-x-[8px] " },
|
|
214
222
|
!isNaN(Number(dpDiscountPercent)) &&
|
|
215
223
|
Number(dpDiscountPercent) > 0 && (React.createElement("div", { className: "absolute -top-[18px] right-[0px]", style: {
|
|
@@ -241,23 +249,20 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
241
249
|
React.createElement("span", { className: "flex items-center justify-end gap-[4px] text-[14px] bold-text leading-[24px]", style: {
|
|
242
250
|
color: isSoldOut ? "#bbb" : discountSeatPriceColor || "#ff5964",
|
|
243
251
|
} },
|
|
244
|
-
((
|
|
252
|
+
((_h = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _h === void 0 ? void 0 : _h.fireIcon) ? (React.createElement("img", { src: serviceItem.icons.fireIcon, alt: "discount", className: "h-[16px] w-[16px] object-contain", style: { filter: isSoldOut ? "grayscale" : "" } })) : null,
|
|
245
253
|
commonService.discountedCurrency(Number(firstSeatFare), currencySign)),
|
|
246
254
|
isSoldOut ? (React.createElement("span", { className: "col-span-2 min-[420]:text-[13px] text-right text-[12px] text-[#ccc]" }, "Agotado")) : null)) : hasDiscount && discountSeat ? (React.createElement("div", null,
|
|
247
255
|
React.createElement("div", { className: "relative grid grid-cols-[auto_auto] justify-between gap-x-[8px] " },
|
|
248
|
-
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) !== 1 &&
|
|
249
|
-
(discountValue != null || isMaxDiscountApplied) && (React.createElement(React.Fragment, null,
|
|
256
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) !== 1 && discountBadgeText && (React.createElement(React.Fragment, null,
|
|
250
257
|
React.createElement("div", { className: "absolute -top-[18px] right-[0px]", style: {
|
|
251
258
|
animation: "pulse-zoom 2s ease-in-out infinite",
|
|
252
259
|
opacity: isSoldOut ? 0.5 : 1,
|
|
253
260
|
} },
|
|
254
261
|
React.createElement("span", { className: "rounded-[100px] px-[8px] text-[12px] bold-text leading-[20px] text-[#fff]", style: {
|
|
255
262
|
backgroundColor: tooltipBgColor,
|
|
256
|
-
} },
|
|
257
|
-
? `${commonService.currency(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.max_discount)} OFF`
|
|
258
|
-
: `${discountValue}% OFF`)),
|
|
263
|
+
} }, discountBadgeText)),
|
|
259
264
|
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] leading-[20px] text-[#c2c2c2]" }, "Antes"),
|
|
260
|
-
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] leading-[20px] text-right", style: {
|
|
265
|
+
React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] leading-[20px] text-right ", style: {
|
|
261
266
|
position: "relative",
|
|
262
267
|
display: "inline-block",
|
|
263
268
|
overflow: "hidden",
|
|
@@ -282,7 +287,7 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
|
|
|
282
287
|
? "#464647"
|
|
283
288
|
: discountSeatPriceColor || "#ff5964",
|
|
284
289
|
} },
|
|
285
|
-
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) !== 1 && ((
|
|
290
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) !== 1 && ((_j = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _j === void 0 ? void 0 : _j.fireIcon) ? (React.createElement("img", { src: serviceItem.icons.fireIcon, alt: "discount", className: "h-[16px] w-[16px] object-contain", style: { opacity: isSoldOut ? 0.5 : 1 } })) : null,
|
|
286
291
|
commonService.discountedCurrency((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) === 1
|
|
287
292
|
? discountSeat.originalPrice
|
|
288
293
|
: discountSeat.discountedPrice, currencySign))))) : (React.createElement("div", { className: `flex flex-col justify-between ${isTrain ? "" : "h-[2.5rem]"} `, style: {
|
package/package.json
CHANGED
|
@@ -180,6 +180,8 @@ function PeruServiceItemDesktop({
|
|
|
180
180
|
|
|
181
181
|
let isSoldOut = serviceItem.available_seats <= 0;
|
|
182
182
|
const hasDpEnabled = serviceItem?.is_dp_enabled === true;
|
|
183
|
+
const peruDiscount = (serviceItem as any)?.discounts?.[0];
|
|
184
|
+
const uiType = peruDiscount?.ui_type;
|
|
183
185
|
|
|
184
186
|
const renderIcon = (iconKey: string, size: string = "14px") => {
|
|
185
187
|
const iconValue = serviceItem.icons?.[iconKey];
|
|
@@ -609,12 +611,18 @@ function PeruServiceItemDesktop({
|
|
|
609
611
|
const isItemExpanded = serviceItem.id === isExpand || isExpand === true;
|
|
610
612
|
const grayscaleClass = isSoldOut ? "grayscale" : "";
|
|
611
613
|
|
|
612
|
-
|
|
614
|
+
// Offer text is only ever shown when the discount's new UI is enabled
|
|
615
|
+
// (tiers B/C). Tier A must stay unchanged even if the backend still sends
|
|
616
|
+
// an offer_text.
|
|
617
|
+
const hasOfferText = isNewUiEnabled && Boolean(serviceItem?.offer_text);
|
|
618
|
+
// Tier C (ui_type 2) always shows the bottom ribbon — timer, bomb
|
|
619
|
+
// animation and viewers count don't depend on offer_text being present.
|
|
620
|
+
const isFullNewUi = isNewUiEnabled && uiType === 2;
|
|
613
621
|
|
|
614
622
|
const offerGradient = `linear-gradient(90deg, ${colors.rightGradiantColor || "#ff5964"} 0%, ${colors.leftGradiantColor || "#ff8842"} 100%)`;
|
|
615
623
|
const offerGradientWithOpacity = `linear-gradient(90deg, ${colors.rightGradiantColor || "#ff5964"}80 0%, ${colors.leftGradiantColor || "#ff8842"}80 100%)`;
|
|
616
624
|
const serviceCardStyle: React.CSSProperties =
|
|
617
|
-
(
|
|
625
|
+
(isFullNewUi || hasDpEnabled) &&
|
|
618
626
|
!isSoldOut
|
|
619
627
|
? {
|
|
620
628
|
borderColor: "transparent",
|
|
@@ -628,7 +636,7 @@ function PeruServiceItemDesktop({
|
|
|
628
636
|
|
|
629
637
|
return (
|
|
630
638
|
<div
|
|
631
|
-
className={`relative hover:z-[150] ${(hasOfferText || hasDpEnabled ||
|
|
639
|
+
className={`relative hover:z-[150] ${(hasOfferText || hasDpEnabled || isFullNewUi) && !isSoldOut ? "mb-[65px]" : "mb-[20px]"} ${
|
|
632
640
|
serviceItem?.is_direct_trip ||
|
|
633
641
|
serviceItem?.train_type_label === "Tren Express (Nuevo)" ||
|
|
634
642
|
showTopLabel
|
|
@@ -636,28 +644,28 @@ function PeruServiceItemDesktop({
|
|
|
636
644
|
: "mt-[20px]"
|
|
637
645
|
} `}
|
|
638
646
|
>
|
|
639
|
-
{(
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
647
|
+
{(hasOfferText || hasDpEnabled || isFullNewUi) && !isSoldOut && (
|
|
648
|
+
<PeruOfferBanner
|
|
649
|
+
offerGradient={offerGradient}
|
|
650
|
+
isSoldOut={isSoldOut}
|
|
651
|
+
serviceItem={serviceItem}
|
|
652
|
+
renderIcon={renderIcon}
|
|
653
|
+
isLoggedIn={isLoggedIn}
|
|
654
|
+
showLoginModal={showLoginModal}
|
|
655
|
+
viewersConfig={viewersConfig}
|
|
656
|
+
getAnimationIcon={getAnimationIcon}
|
|
657
|
+
showLoginOption={showLoginOption}
|
|
658
|
+
colors={colors}
|
|
659
|
+
coachKey={coachKey}
|
|
660
|
+
isExpand={isExpand}
|
|
661
|
+
isNewUiEnabled={isNewUiEnabled}
|
|
662
|
+
uiType={uiType}
|
|
663
|
+
/>
|
|
664
|
+
)}
|
|
657
665
|
<div
|
|
658
666
|
id={`service-card-${serviceItem.id}`}
|
|
659
667
|
className={`bg-white mx-auto relative ${
|
|
660
|
-
(
|
|
668
|
+
(isFullNewUi || hasDpEnabled) &&
|
|
661
669
|
!isSoldOut
|
|
662
670
|
? "z-[3] rounded-[18px]"
|
|
663
671
|
: "rounded-[10px] border border-[#ccc]"
|
|
@@ -667,13 +675,13 @@ function PeruServiceItemDesktop({
|
|
|
667
675
|
<div
|
|
668
676
|
className=" pt-[20px]"
|
|
669
677
|
style={{
|
|
670
|
-
padding: hasOfferText
|
|
678
|
+
padding: hasOfferText || isFullNewUi
|
|
671
679
|
? "20px 15px 10px 15px"
|
|
672
680
|
: coachKey
|
|
673
681
|
? "20px 15px 20px 15px"
|
|
674
682
|
: "20px 15px 10px 15px",
|
|
675
683
|
|
|
676
|
-
marginTop: hasDiscount || hasOfferText ? "14px" : "",
|
|
684
|
+
marginTop: hasDiscount || hasOfferText || isFullNewUi ? "14px" : "",
|
|
677
685
|
}}
|
|
678
686
|
>
|
|
679
687
|
{/* <div className="grid grid-cols-[1.5fr_1fr_auto] gap-[3rem] sm:gap-[4rem] md:gap-[5rem] lg:gap-[6rem] xl:gap-[5rem] 2xl:gap-[7rem] text-[#464647]"> */}
|
|
@@ -12,6 +12,7 @@ import ServiceBadgesMobile from "../../ui/mobileweb/ServiceBadgesMobile";
|
|
|
12
12
|
import FeatureServiceUiMobile from "../../ui/FeaturServiceUiMobile/FeatureServiceUiMobile";
|
|
13
13
|
|
|
14
14
|
const SEAT_EXCEPTIONS = ["Asiento mascota"];
|
|
15
|
+
const OFFER_TEXT_MAX_CHARS = 20;
|
|
15
16
|
|
|
16
17
|
const exceptions = [
|
|
17
18
|
"gy",
|
|
@@ -94,17 +95,33 @@ function PeruServiceItemMobile({
|
|
|
94
95
|
);
|
|
95
96
|
|
|
96
97
|
const isLongOfferText = (serviceItem?.offer_text?.length || 0) > 35;
|
|
98
|
+
const offerText = serviceItem?.offer_text || "";
|
|
99
|
+
const displayOfferText =
|
|
100
|
+
offerText.length > OFFER_TEXT_MAX_CHARS
|
|
101
|
+
? `${offerText.slice(0, OFFER_TEXT_MAX_CHARS).trimEnd()}...`
|
|
102
|
+
: offerText;
|
|
97
103
|
const hasDpEnabled = serviceItem?.is_dp_enabled === true;
|
|
104
|
+
const hasDpRibbon = hasDpEnabled && Boolean(serviceItem?.dp_discount_percents);
|
|
105
|
+
|
|
106
|
+
// ui_type comes from the active discount entry: 1 = offer-text-only tier,
|
|
107
|
+
// 2 = full new-UI tier (timer, bomb animation, viewers).
|
|
108
|
+
const peruDiscount = (serviceItem as any)?.discounts?.[0];
|
|
109
|
+
const uiType = peruDiscount?.ui_type;
|
|
98
110
|
|
|
99
111
|
const isDiscountBelow20 =
|
|
100
112
|
(serviceItem as any)?.discount_value > 0 &&
|
|
101
113
|
(serviceItem as any)?.discount_value < 20;
|
|
102
|
-
|
|
114
|
+
// Offer text is only ever shown when the discount's new UI is enabled
|
|
115
|
+
// (tiers B/C). Tier A must stay unchanged even if the backend still sends
|
|
116
|
+
// an offer_text.
|
|
117
|
+
const hasOfferText = isNewUiEnabled && Boolean(serviceItem?.offer_text);
|
|
118
|
+
// Tier B: offer text only, no timer/viewers. Tier C: full ribbon.
|
|
119
|
+
const isOfferTextOnly = isNewUiEnabled && uiType === 1 && hasOfferText;
|
|
120
|
+
const isFullNewUi = isNewUiEnabled && uiType === 2;
|
|
103
121
|
const offerGradient = `linear-gradient(90deg, ${colors.rightGradiantColor || "#ff5964"} 0%, ${colors.leftGradiantColor || "#ff8842"} 100%)`;
|
|
104
122
|
const offerGradientWithOpacity = `linear-gradient(90deg, ${colors.rightGradiantColor || "#ff5964"}80 0%, ${colors.leftGradiantColor || "#ff8842"}80 100%)`;
|
|
105
123
|
const serviceCardStyle: React.CSSProperties =
|
|
106
|
-
|
|
107
|
-
(serviceItem?.is_dp_enabled && serviceItem?.dp_discount_percents)
|
|
124
|
+
isFullNewUi || hasDpRibbon
|
|
108
125
|
? {
|
|
109
126
|
borderColor: isSoldOut ? "#ccc" : "transparent",
|
|
110
127
|
borderStyle: "solid",
|
|
@@ -220,10 +237,7 @@ function PeruServiceItemMobile({
|
|
|
220
237
|
>
|
|
221
238
|
<div
|
|
222
239
|
className={`z-1 ${
|
|
223
|
-
(
|
|
224
|
-
(serviceItem?.is_dp_enabled &&
|
|
225
|
-
serviceItem?.dp_discount_percents)) &&
|
|
226
|
-
!isSoldOut
|
|
240
|
+
(isFullNewUi || hasDpRibbon) && !isSoldOut
|
|
227
241
|
? "rounded-[18px]"
|
|
228
242
|
: "rounded-[10px] border border-[#ccc]"
|
|
229
243
|
}`}
|
|
@@ -398,55 +412,50 @@ function PeruServiceItemMobile({
|
|
|
398
412
|
/>
|
|
399
413
|
</div>
|
|
400
414
|
|
|
401
|
-
{/* 🔹 EXPANDABLE DROPDOWN (below the card) -
|
|
402
|
-
{
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
415
|
+
{/* 🔹 EXPANDABLE DROPDOWN (below the card) - Tier B: offer text only, no timer/viewers */}
|
|
416
|
+
{isOfferTextOnly && !isSoldOut && !hasDpRibbon && (
|
|
417
|
+
<div
|
|
418
|
+
className="px-[12px] pt-[22px] pb-[8px] relative -z-9 -mt-[15px]"
|
|
419
|
+
style={{
|
|
420
|
+
background: colors?.bottomStripColor,
|
|
421
|
+
borderRadius: "0 0 14px 14px",
|
|
422
|
+
zIndex: -1,
|
|
423
|
+
}}
|
|
424
|
+
>
|
|
406
425
|
<div
|
|
407
|
-
className="
|
|
408
|
-
style={{
|
|
409
|
-
background: colors?.bottomStripColor,
|
|
410
|
-
borderRadius: "0 0 14px 14px",
|
|
411
|
-
zIndex: -1,
|
|
412
|
-
}}
|
|
426
|
+
className="flex flex-col gap-[8px] text-[12px] min-[420px]:text-[12px] text-[#464647]"
|
|
427
|
+
style={{ lineHeight: 1.6 }}
|
|
413
428
|
>
|
|
414
|
-
<div
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
429
|
+
<div className="flex justify-between items-center">
|
|
430
|
+
<div
|
|
431
|
+
className={`flex ${(serviceItem?.offer_text || "").length > 10 ? "items-start" : "items-center"}`}
|
|
432
|
+
>
|
|
433
|
+
<div className={isLongOfferText ? "mt-[2px]" : ""}>
|
|
434
|
+
<LottiePlayer
|
|
435
|
+
animationData={serviceItem?.icons?.promoAnim}
|
|
436
|
+
width="14px"
|
|
437
|
+
height="14px"
|
|
438
|
+
/>
|
|
439
|
+
</div>
|
|
419
440
|
<div
|
|
420
|
-
className={`flex ${
|
|
441
|
+
className={`ml-[4px] flex-1 outline-none ${isLongOfferText ? "mt-[2px]" : ""}`}
|
|
442
|
+
style={{
|
|
443
|
+
color: "#fff",
|
|
444
|
+
lineHeight: 1.4,
|
|
445
|
+
}}
|
|
421
446
|
>
|
|
422
|
-
<
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
width="14px"
|
|
426
|
-
height="14px"
|
|
427
|
-
/>
|
|
428
|
-
</div>
|
|
429
|
-
<div
|
|
430
|
-
className={`ml-[4px] flex-1 outline-none ${isLongOfferText ? "mt-[2px]" : ""}`}
|
|
431
|
-
style={{
|
|
432
|
-
color: "#fff",
|
|
433
|
-
lineHeight: 1.4,
|
|
434
|
-
}}
|
|
435
|
-
>
|
|
436
|
-
<span className="whitespace-nowrap min-[380px]:text-[12px]">
|
|
437
|
-
{serviceItem?.offer_text}
|
|
438
|
-
</span>
|
|
439
|
-
</div>
|
|
447
|
+
<span className="whitespace-nowrap min-[380px]:text-[12px]">
|
|
448
|
+
{serviceItem?.offer_text}
|
|
449
|
+
</span>
|
|
440
450
|
</div>
|
|
441
451
|
</div>
|
|
442
452
|
</div>
|
|
443
453
|
</div>
|
|
444
|
-
|
|
454
|
+
</div>
|
|
455
|
+
)}
|
|
445
456
|
|
|
446
|
-
{/* 🔹 EXPANDABLE DROPDOWN (below the card) -
|
|
447
|
-
{(
|
|
448
|
-
(serviceItem?.is_dp_enabled && serviceItem?.dp_discount_percents)) &&
|
|
449
|
-
!isSoldOut && (
|
|
457
|
+
{/* 🔹 EXPANDABLE DROPDOWN (below the card) - Tier C / DP: full ribbon with timer, bomb animation, viewers */}
|
|
458
|
+
{(isFullNewUi || hasDpRibbon) && !isSoldOut && (
|
|
450
459
|
<div
|
|
451
460
|
className="px-[12px] pt-[22px] pb-[8px] relative -z-9 -mt-[15px]"
|
|
452
461
|
style={{
|
|
@@ -493,25 +502,9 @@ function PeruServiceItemMobile({
|
|
|
493
502
|
lineHeight: 1.4,
|
|
494
503
|
}}
|
|
495
504
|
>
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
</span>
|
|
500
|
-
) : (
|
|
501
|
-
<span className="whitespace-nowrap min-[380px]:text-[12px]">
|
|
502
|
-
Termina en
|
|
503
|
-
<span
|
|
504
|
-
className="bold-text"
|
|
505
|
-
ref={(node) =>
|
|
506
|
-
commonService.startCountdown(node, 599)
|
|
507
|
-
}
|
|
508
|
-
style={{
|
|
509
|
-
fontVariantNumeric: "tabular-nums",
|
|
510
|
-
display: "inline-block",
|
|
511
|
-
}}
|
|
512
|
-
/>
|
|
513
|
-
</span>
|
|
514
|
-
)}
|
|
505
|
+
<span className="whitespace-nowrap min-[380px]:text-[12px]">
|
|
506
|
+
{displayOfferText}
|
|
507
|
+
</span>
|
|
515
508
|
</div>
|
|
516
509
|
</div>
|
|
517
510
|
)}
|
|
@@ -563,12 +556,7 @@ function PeruServiceItemMobile({
|
|
|
563
556
|
transition:
|
|
564
557
|
"grid-template-rows 0.3s ease-in-out, opacity 0.25s ease-in-out",
|
|
565
558
|
position: "relative",
|
|
566
|
-
zIndex:
|
|
567
|
-
hasOfferText ||
|
|
568
|
-
(serviceItem?.is_dp_enabled && serviceItem?.dp_discount_percents) ||
|
|
569
|
-
isNewUiEnabled
|
|
570
|
-
? -2
|
|
571
|
-
: -1,
|
|
559
|
+
zIndex: isOfferTextOnly || isFullNewUi || hasDpRibbon ? -2 : -1,
|
|
572
560
|
}}
|
|
573
561
|
>
|
|
574
562
|
<div
|
|
@@ -576,15 +564,10 @@ function PeruServiceItemMobile({
|
|
|
576
564
|
overflow: "hidden",
|
|
577
565
|
minHeight: 0,
|
|
578
566
|
position:
|
|
579
|
-
|
|
567
|
+
isOfferTextOnly || isFullNewUi || hasDpEnabled
|
|
580
568
|
? "relative"
|
|
581
569
|
: undefined,
|
|
582
|
-
zIndex:
|
|
583
|
-
serviceItem?.offer_text ||
|
|
584
|
-
isNewUiEnabled ||
|
|
585
|
-
(serviceItem?.is_dp_enabled && serviceItem?.dp_discount_percents)
|
|
586
|
-
? -3
|
|
587
|
-
: undefined,
|
|
570
|
+
zIndex: isOfferTextOnly || isFullNewUi || hasDpRibbon ? -3 : undefined,
|
|
588
571
|
marginTop: hasOfferText ? "-15px" : "-10px",
|
|
589
572
|
}}
|
|
590
573
|
>
|
|
@@ -68,6 +68,7 @@ function ServiceItemMobile({
|
|
|
68
68
|
isPeruSite,
|
|
69
69
|
priority_stage_ids,
|
|
70
70
|
}: MobileServiceItemProps): React.ReactElement {
|
|
71
|
+
console.log("🚀 ~ ServiceItemMobile ~ serviceItem:", serviceItem);
|
|
71
72
|
const isItemExpanded = serviceItem.id === isExpanded;
|
|
72
73
|
const isPetSeat = (Object.keys(serviceItem?.pet_seat_info) || []).length > 0;
|
|
73
74
|
const isNewUiEnabled = serviceItem?.discounts?.[0]?.new_ui_enabled === true;
|
|
@@ -569,17 +570,22 @@ function ServiceItemMobile({
|
|
|
569
570
|
}}
|
|
570
571
|
>
|
|
571
572
|
<span className="whitespace-nowrap min-[380px]:text-[12px]">
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
573
|
+
{serviceItem?.ui_type === 2 && isPeru
|
|
574
|
+
? serviceItem?.offer_text
|
|
575
|
+
: "Termina en"}
|
|
576
|
+
|
|
577
|
+
{isPeru ? null : (
|
|
578
|
+
<span
|
|
579
|
+
className="bold-text"
|
|
580
|
+
ref={(node) =>
|
|
581
|
+
commonService.startCountdown(node, 599)
|
|
582
|
+
}
|
|
583
|
+
style={{
|
|
584
|
+
fontVariantNumeric: "tabular-nums",
|
|
585
|
+
display: "inline-block",
|
|
586
|
+
}}
|
|
587
|
+
/>
|
|
588
|
+
)}
|
|
583
589
|
</span>
|
|
584
590
|
</div>
|
|
585
591
|
</div>
|
package/src/ui/OfferBanner.tsx
CHANGED
|
@@ -35,6 +35,7 @@ interface OfferBannerProps {
|
|
|
35
35
|
coachKey?: number;
|
|
36
36
|
isExpand?: any;
|
|
37
37
|
ui_type?: number;
|
|
38
|
+
isPeru?: boolean;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
@@ -97,6 +98,7 @@ interface NewUiOfferBannerProps {
|
|
|
97
98
|
isNewUiEnabled?: any;
|
|
98
99
|
showLoginButton?: boolean;
|
|
99
100
|
ui_type?: number;
|
|
101
|
+
isPeru?: boolean;
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
const NewUiOfferBanner: React.FC<NewUiOfferBannerProps> = ({
|
|
@@ -109,6 +111,7 @@ const NewUiOfferBanner: React.FC<NewUiOfferBannerProps> = ({
|
|
|
109
111
|
isNewUiEnabled,
|
|
110
112
|
showLoginButton,
|
|
111
113
|
ui_type,
|
|
114
|
+
isPeru,
|
|
112
115
|
}) => (
|
|
113
116
|
<div className="flex items-center">
|
|
114
117
|
<AnimationIcon getAnimationIcon={getAnimationIcon} name="bombAnimation" />
|
|
@@ -130,12 +133,17 @@ const NewUiOfferBanner: React.FC<NewUiOfferBannerProps> = ({
|
|
|
130
133
|
|
|
131
134
|
</span>{" "}
|
|
132
135
|
{offerText && ui_type !== 2 ? "| " : ui_type === 2 ? "" : ""}
|
|
133
|
-
Termina en
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
{ui_type === 2 && isPeru ? offerText : "Termina en"}
|
|
137
|
+
{isPeru ? null : (
|
|
138
|
+
<span
|
|
139
|
+
className="bold-text text-end"
|
|
140
|
+
ref={(node) => CommonService.startCountdown(node, 599)}
|
|
141
|
+
style={{
|
|
142
|
+
fontVariantNumeric: "tabular-nums",
|
|
143
|
+
display: "inline-block",
|
|
144
|
+
}}
|
|
145
|
+
/>
|
|
146
|
+
)}
|
|
139
147
|
</div>
|
|
140
148
|
</div>
|
|
141
149
|
);
|
|
@@ -224,6 +232,7 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
224
232
|
isLinatal,
|
|
225
233
|
coachKey,
|
|
226
234
|
isExpand,
|
|
235
|
+
isPeru,
|
|
227
236
|
}) => {
|
|
228
237
|
const isDiscountBelow20 =
|
|
229
238
|
(serviceItem as any)?.discount_value > 0 &&
|
|
@@ -270,6 +279,7 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
270
279
|
isNewUiEnabled={isNewUiEnabled}
|
|
271
280
|
showLoginButton={serviceItem?.show_register_button}
|
|
272
281
|
ui_type={serviceItem?.ui_type}
|
|
282
|
+
isPeru={isPeru}
|
|
273
283
|
/>
|
|
274
284
|
);
|
|
275
285
|
}
|
|
@@ -278,7 +288,7 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
278
288
|
|
|
279
289
|
return (
|
|
280
290
|
<div
|
|
281
|
-
className={`text-white w-full absolute ${coachKey ? "-bottom-[32px]" : isExpand ? "-bottom-[32px]" : "-bottom-[
|
|
291
|
+
className={`text-white w-full absolute ${coachKey ? "-bottom-[32px]" : isExpand ? "-bottom-[32px]" : "-bottom-[32px]"} rounded-b-[14px] text-[14px] h-[58px] flex items-end pb-[7px]`}
|
|
282
292
|
style={{
|
|
283
293
|
background:
|
|
284
294
|
(isNewUiEnabled && serviceItem?.ui_type === 2) ||
|