kupos-ui-components-lib 9.10.2 → 9.10.4

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.
@@ -391,10 +391,10 @@ function PeruServiceItemDesktop({ serviceItem, onBookButtonPress, colors, metaDa
391
391
  : serviceItem.seat_types || [];
392
392
  const discountedSeats = seats.map((seat) => (Object.assign(Object.assign({}, seat), CommonService.calculateDiscountedPrice(seat.fare, serviceItem))));
393
393
  const hasDiscount = discountedSeats.some((seat) => seat.originalPrice !== seat.discountedPrice);
394
- return (React.createElement("div", { className: `relative hover:z-[150] ${hasOfferText ? "mb-[55px]" : "mb-[10px]"} ${(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_direct_trip) ||
394
+ return (React.createElement("div", { className: `relative hover:z-[150] ${hasOfferText || hasDpEnabled || isNewUiEnabled ? "mb-[65px]" : "mb-[20px]"} ${(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_direct_trip) ||
395
395
  (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.train_type_label) === "Tren Express (Nuevo)" ||
396
396
  showTopLabel
397
- ? "mt-[24px]"
397
+ ? "mt-[30px]"
398
398
  : "mt-[20px]"} ` },
399
399
  ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) || hasDpEnabled) && !isSoldOut && (React.createElement(OfferBanner, { offerGradient: offerGradient, isSoldOut: isSoldOut, serviceItem: serviceItem, renderIcon: renderIcon, isLoggedIn: isLoggedIn, showLoginModal: showLoginModal, viewersConfig: viewersConfig, getAnimationIcon: getAnimationIcon, showLoginOption: showLoginOption, isNewUiEnabled: isNewUiEnabled, colors: colors })),
400
400
  React.createElement("div", { id: `service-card-${serviceItem.id}`, className: `bg-white mx-auto relative ${(hasOfferText && isNewUiEnabled && !isSoldOut) || hasDpEnabled
@@ -89,6 +89,7 @@ const ANIMATION_MAP = {
89
89
  };
90
90
  function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, children, busStage, serviceDetailsLoading, cityOrigin, cityDestination, translation, orignLabel, destinationLabel, currencySign, isCiva, showRating, showLastSeats, removeArrivalTime, removeDuplicateSeats, isPeruSites, showAvailableSeats, isSeatIcon, isLinatal, isPeru, t = (key) => key, siteType, isAllinBus, isExpand, setIsExpand, coachKey, viewersConfig, isNewUi, showLoginModal, isLoggedIn, showLoginOption, isFeatureDropDownExpand, setIsFeatureDropDownExpand, ticketQuantity, onIncreaseTicketQuantity, onDecreaseTicketQuantity, onRemateUiButtonClick, selectedTimeSlot, onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData, isFlores, }) {
91
91
  var _a, _b, _c;
92
+ console.log("🚀 ~ ServiceItemPB ~ serviceItem:", serviceItem);
92
93
  const getAnimationIcon = (icon) => {
93
94
  var _a;
94
95
  const animation = ANIMATION_MAP[icon];
@@ -261,7 +262,7 @@ function ServiceItemPB({ serviceItem, onBookButtonPress, colors, metaData, child
261
262
  setIsFeatureDropDownExpand(isFeatureDropDownExpand === serviceItem.id ||
262
263
  isFeatureDropDownExpand === true
263
264
  ? null
264
- : serviceItem.id), selectedTimeSlot: selectedTimeSlot, onTimeSlotChange: onTimeSlotChange, isTimeDropdownOpen: isTimeDropdownOpen, onTimeDropdownToggle: onTimeDropdownToggle, wowDealData: wowDealData })) : (React.createElement("div", { className: `relative hover:z-[150] ${hasOfferText || hasDpEnabled || isNewUiEnabled ? "mb-[55px]" : "mb-[10px]"} ${(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_direct_trip) ||
265
+ : serviceItem.id), selectedTimeSlot: selectedTimeSlot, onTimeSlotChange: onTimeSlotChange, isTimeDropdownOpen: isTimeDropdownOpen, onTimeDropdownToggle: onTimeDropdownToggle, wowDealData: wowDealData })) : (React.createElement("div", { className: `relative hover:z-[150] ${hasOfferText || hasDpEnabled || isNewUiEnabled ? "mb-[65px]" : "mb-[20px]"} ${(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_direct_trip) ||
265
266
  (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.train_type_label) === "Tren Express (Nuevo)" ||
266
267
  showTopLabel
267
268
  ? "mt-[30px]"
@@ -136,7 +136,10 @@ function ServiceItemMobile({ serviceItem, onBookButtonPress, colors, busStage, o
136
136
  setIsExpanded(isItemExpanded ? null : serviceItem.id);
137
137
  }, isPeru: isPeru, femaleAnim: serviceItem.icons.femaleAnim, ladiesBookedSeats: serviceItem.ladies_booked_seats, isDpEnabled: serviceItem.is_dp_enabled })),
138
138
  React.createElement(ServiceBadgesMobile, { showTopLabel: showTopLabel, isSoldOut: isSoldOut, colors: colors, renderIcon: renderIcon, serviceItem: serviceItem, isConexion: isConexion })),
139
- (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) && !isNewUiEnabled && !isSoldOut && (React.createElement("div", { className: "px-[12px] pt-[22px] pb-[8px] relative -z-9 -mt-[15px]", style: {
139
+ (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) &&
140
+ !isNewUiEnabled &&
141
+ !isSoldOut &&
142
+ !(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) && (React.createElement("div", { className: "px-[12px] pt-[22px] pb-[8px] relative -z-9 -mt-[15px]", style: {
140
143
  background: colors === null || colors === void 0 ? void 0 : colors.bottomStripColor,
141
144
  borderRadius: "0 0 14px 14px",
142
145
  zIndex: -1,
@@ -15,9 +15,9 @@ const SurveyDesktop = ({ isOpen, isSubmitted, selectedScore, onScoreChange, feed
15
15
  React.createElement(React.Fragment, null,
16
16
  React.createElement("button", { onClick: onClose, "aria-label": "Close survey", className: "absolute top-[15px] right-[25px] bg-transparent border-none cursor-pointer text-[22px] text-gray-400 flex items-center justify-center p-1 z-10 transition-colors duration-200 hover:text-gray-600" },
17
17
  React.createElement("img", { src: icons.closeIcon, alt: "Close", className: "w-[16px] h-[16px] block" })),
18
- (icons === null || icons === void 0 ? void 0 : icons.surveyIcon) && (React.createElement("div", { className: "flex justify-center mb-3 mt-2" },
18
+ (icons === null || icons === void 0 ? void 0 : icons.surveyIcon) && (React.createElement("div", { className: "flex justify-center mb-2 mt-2" },
19
19
  React.createElement("img", { src: icons.surveyIcon, alt: "Survey Illustration", className: "w-[90px] h-[90px] block" }))),
20
- React.createElement("h2", { className: "text-[18px] bold-text leading-[1.25] text-center mt-4 mb-2" }, "Ay\u00FAdanos a mejorar"),
20
+ React.createElement("h2", { className: "text-[18px] bold-text leading-[1.25] text-center mb-2" }, "Ay\u00FAdanos a mejorar"),
21
21
  React.createElement("p", { className: "text-[13.33px] text-center leading-[1.4] mb-6 max-w-[460px] mx-auto" },
22
22
  "Bas\u00E1ndote en tu experiencia de compra.",
23
23
  React.createElement("br", null),
@@ -15,17 +15,17 @@ const SurveyMobile = ({ isOpen, isSubmitted, selectedScore, onScoreChange, feedb
15
15
  React.createElement(React.Fragment, null,
16
16
  React.createElement("button", { onClick: onClose, "aria-label": "Close survey", className: "absolute top-[15px] right-[25px] bg-transparent border-none cursor-pointer text-[22px] text-gray-400 flex items-center justify-center p-1 z-10 transition-colors duration-200 hover:text-gray-600" },
17
17
  React.createElement("img", { src: icons.closeIcon, alt: "Close", className: "w-[16px] h-[16px] block" })),
18
- (icons === null || icons === void 0 ? void 0 : icons.surveyIcon) && (React.createElement("div", { className: "flex justify-center mb-3 mt-2" },
18
+ (icons === null || icons === void 0 ? void 0 : icons.surveyIcon) && (React.createElement("div", { className: "flex justify-center mb-2 mt-2" },
19
19
  React.createElement("img", { src: icons.surveyIcon, alt: "Survey Illustration", className: "w-[90px] h-[90px] block" }))),
20
- React.createElement("h2", { className: "text-[18px] bold-text leading-[1.25] text-center mt-4 mb-2" }, "Ay\u00FAdanos a mejorar"),
21
- React.createElement("p", { className: "text-[13.33px] text-center leading-[1.4] mb-6 max-w-[460px] mx-auto" },
20
+ React.createElement("h2", { className: "text-[18px] bold-text leading-[1.25] text-center mb-2" }, "Ay\u00FAdanos a mejorar"),
21
+ React.createElement("p", { className: "text-[13.33px] text-center leading-[1.4] mb-8 max-w-[460px] mx-auto" },
22
22
  "Bas\u00E1ndote en tu experiencia de compra.",
23
23
  React.createElement("br", null),
24
24
  "\u00BFNos recomendar\u00EDas a un amigo?"),
25
25
  React.createElement(ScoreButtons, { selectedScore: selectedScore, onScoreChange: onScoreChange, buttonHeight: 44, fontSize: 13, gap: 6, colors: colors }),
26
26
  React.createElement(FeedbackTextarea, { config: config, feedback: feedback, onFeedbackChange: onFeedbackChange }),
27
- React.createElement("div", { className: "flex justify-center mt-[20px]" },
28
- React.createElement("div", { className: "w-[180px]" },
27
+ React.createElement("div", { className: "flex justify-center mt-[50px] mb-[50px]" },
28
+ React.createElement("div", { className: "w-[100px]" },
29
29
  React.createElement(KuposButton, { isSoldOut: selectedScore == null, isLoading: isLoading || false, buttonColor: "#FF8E43", buyLabel: "Enviar", soldOutLabel: "Enviar", onClick: handleSubmit }))))));
30
30
  };
31
31
  export default SurveyMobile;
package/dist/styles.css CHANGED
@@ -246,6 +246,9 @@
246
246
  .mt-\[30px\] {
247
247
  margin-top: 30px;
248
248
  }
249
+ .mt-\[50px\] {
250
+ margin-top: 50px;
251
+ }
249
252
  .-mr-\[12px\] {
250
253
  margin-right: calc(12px * -1);
251
254
  }
@@ -306,6 +309,9 @@
306
309
  .mb-\[55px\] {
307
310
  margin-bottom: 55px;
308
311
  }
312
+ .mb-\[65px\] {
313
+ margin-bottom: 65px;
314
+ }
309
315
  .-ml-\[12px\] {
310
316
  margin-left: calc(12px * -1);
311
317
  }
@@ -170,7 +170,7 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, isSoldOut, getAnimationIc
170
170
  React.createElement("div", { className: "flex items-center gap-[8px]" },
171
171
  React.createElement("img", { src: (_f = serviceItem.icons) === null || _f === void 0 ? void 0 : _f.whiteDestination, alt: "destination", className: `w-[14px] h-[14px] shrink-0 ${isSoldOut ? "grayscale" : ""}`, style: { opacity: isSoldOut ? 0.5 : 1 } }),
172
172
  React.createElement("span", { className: "text-[13px] bold-text" }, cityDestination === null || cityDestination === void 0 ? void 0 : cityDestination.label.split(",")[0]))),
173
- React.createElement("div", { className: "flex flex-col gap-[8px]" },
173
+ React.createElement("div", { className: "flex flex-col gap-[10px]" },
174
174
  React.createElement("div", { className: "text-[12px] bold-text" }, travelDate
175
175
  ? new Date(travelDate).toLocaleDateString("es-CL", {
176
176
  weekday: "long",
@@ -192,15 +192,13 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, isSoldOut, getAnimationIc
192
192
  } }, "Tu compra est\u00E1 100% asegurada.")))),
193
193
  React.createElement("div", { className: "min-w-0 px-[22px] flex flex-col items-center justify-between gap-[16px] py-[2px] border-r border-[#363c48] border-l border-[#363c48]" },
194
194
  React.createElement("div", { className: "text-center" },
195
- React.createElement("div", { className: "bold-text text-[14px]" },
195
+ React.createElement("div", { className: "bold-text text-[13px]" },
196
196
  operatorsCompetingCount,
197
- " operadores compitiendo",
198
- React.createElement("br", null),
199
- " por tu compra")),
197
+ " operadores compitiendo por tu compra")),
200
198
  React.createElement("div", { className: "grid w-full grid-cols-3 items-stretch gap-[14px] " }, operators.map((op, idx) => (React.createElement("div", { key: idx, className: "flex min-w-0 flex-col items-center justify-center gap-[8px] rounded-[8px]", style: {
201
199
  // height: "80px",
202
200
  border: "1px solid #363c48",
203
- backgroundColor: "#1a202e",
201
+ backgroundColor: "#fff",
204
202
  padding: "14px 10px",
205
203
  } },
206
204
  React.createElement("img", { src: op.logo, alt: op.name, onError: (e) => {
@@ -209,13 +207,16 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, isSoldOut, getAnimationIc
209
207
  ((_a = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_details) === null || _a === void 0 ? void 0 : _a[0]) ||
210
208
  "/images/service-list/bus-icon.svg";
211
209
  }, className: `h-[24px] max-w-full object-contain ${isSoldOut ? "grayscale" : ""}` }),
212
- React.createElement("span", { className: "text-[11px] truncate max-w-full text-center" }, op.name),
210
+ React.createElement("span", { className: "text-[11px] truncate max-w-full text-center text-[#464647]" }, op.name),
213
211
  React.createElement("div", { className: "bg-[#FF8F45] text-white text-[12px] font-bold px-[10px] py-[4px] rounded-[4px] bold-text whitespace-nowrap" },
214
212
  React.createElement("span", null, op === null || op === void 0 ? void 0 : op.time)),
215
- React.createElement("span", { className: "text-[10px] mt-[6px]" }, op === null || op === void 0 ? void 0 : op.seatsAvailable))))),
216
- React.createElement("div", { className: "flex w-full items-center justify-center gap-[6px] text-[12px]", style: {
213
+ React.createElement("span", { className: "text-[10px] mt-[6px] text-[#464647]" }, op === null || op === void 0 ? void 0 : op.seatsAvailable))))),
214
+ React.createElement("div", { className: "flex w-full items-center justify-center gap-[6px] text-[12px] rounded-full", style: {
217
215
  padding: "8px 14px",
218
216
  marginBottom: "6px",
217
+ border: "1px solid #363c48",
218
+ backgroundColor: "#1a202e",
219
+ // padding: "14px 10px",
219
220
  } },
220
221
  React.createElement(LottiePlayer
221
222
  // animationData={serviceItem.icons.flexibleAnim}
@@ -1,17 +1,21 @@
1
1
  import React from "react";
2
2
  import { ServiceItemProps } from "../components/ServiceItem/types";
3
+ type ServiceItemSlice = Pick<ServiceItemProps["serviceItem"], "is_dp_enabled" | "offer_text" | "dp_discount_percents" | "dp_discounted_seats">;
4
+ interface OfferBannerColors {
5
+ bottomStripColor?: string;
6
+ }
3
7
  interface OfferBannerProps {
4
8
  offerGradient: string;
5
9
  isSoldOut: boolean;
6
- serviceItem: Pick<ServiceItemProps["serviceItem"], "is_dp_enabled" | "offer_text" | "dp_discount_percents" | "dp_discounted_seats">;
10
+ serviceItem: ServiceItemSlice;
7
11
  renderIcon: (name: string, size: string) => React.ReactNode;
8
- isLoggedIn: any;
9
- showLoginModal: any;
12
+ isLoggedIn: boolean;
13
+ showLoginModal: () => void;
10
14
  viewersConfig: ServiceItemProps["viewersConfig"];
11
- getAnimationIcon: (name: string) => any;
15
+ getAnimationIcon: (name: string) => unknown;
12
16
  showLoginOption?: boolean;
13
17
  isNewUiEnabled?: boolean;
14
- colors: any;
18
+ colors: OfferBannerColors;
15
19
  }
16
20
  declare const OfferBanner: React.FC<OfferBannerProps>;
17
21
  export default OfferBanner;
@@ -1,66 +1,79 @@
1
1
  import React from "react";
2
2
  import LottiePlayer from "../assets/LottiePlayer";
3
3
  import CommonService from "../utils/CommonService";
4
- const OfferBanner = ({ offerGradient, isSoldOut, serviceItem, renderIcon, isLoggedIn, showLoginModal, viewersConfig, getAnimationIcon, showLoginOption, isNewUiEnabled, colors, }) => {
5
- var _a, _b, _c, _d;
6
- return (React.createElement("div", { className: "text-white p-[10px_15px] text-left w-full flex items-center absolute -bottom-[44px] pt-[50px] rounded-b-[14px] text-[14px] mt-[10px]", style: {
7
- background: (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) && !isNewUiEnabled
8
- ? colors === null || colors === void 0 ? void 0 : colors.bottomStripColor
9
- : offerGradient,
10
- opacity: isSoldOut ? 0.5 : 1,
11
- // zIndex: 0,
12
- } },
13
- React.createElement("div", { className: "flex justify-between items-center w-full" },
14
- React.createElement("div", { className: "flex items-center " }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) &&
15
- Object.keys((_a = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents) !== null && _a !== void 0 ? _a : {}).length === 0 &&
16
- ((_b = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) !== null && _b !== void 0 ? _b : []).length === 0 ? (React.createElement("div", { className: "flex items-center gap-[5px]" },
17
- React.createElement(LottiePlayer, { animationData: getAnimationIcon("starAnimation"), width: "18px", height: "18px" }),
18
- React.createElement("span", null, "Servicio popular entre los usuarios"))) : isNewUiEnabled && (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) ? (React.createElement("div", { className: "flex items-center" },
19
- React.createElement(LottiePlayer, { animationData: getAnimationIcon("bombAnimation"), width: "18px", height: "18px" }),
20
- React.createElement("div", { className: "flex items-center mt-[2px]" },
21
- React.createElement("span", { className: "bold-text", style: {
22
- marginLeft: (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) ? "6px" : "3px",
23
- } },
24
- ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) || "").length > 30
25
- ? ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) || "").slice(0, 30) + "..."
26
- : (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) || "",
27
- " ",
28
- isLoggedIn && showLoginOption ? null : (React.createElement("span", { onClick: showLoginModal, className: "cursor-pointer" }, "- registro")),
29
- " ",
30
- "\u00A0"),
4
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
5
+ const OFFER_TEXT_MAX_LENGTH = 30;
6
+ function truncateOfferText(text) {
7
+ return text.length > OFFER_TEXT_MAX_LENGTH
8
+ ? `${text.slice(0, OFFER_TEXT_MAX_LENGTH)}...`
9
+ : text;
10
+ }
11
+ function hasDpDiscounts(serviceItem) {
12
+ var _a, _b;
13
+ return (Object.keys((_a = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents) !== null && _a !== void 0 ? _a : {}).length > 0 ||
14
+ ((_b = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) !== null && _b !== void 0 ? _b : []).length > 0);
15
+ }
16
+ const AnimationIcon = ({ getAnimationIcon, name, width = "18px", height = "18px", }) => (React.createElement(LottiePlayer, { animationData: getAnimationIcon(name), width: width, height: height }));
17
+ // Shown when DP is enabled but no discounts / discounted seats are present
18
+ const PopularServiceBanner = ({ getAnimationIcon }) => (React.createElement("div", { className: "flex items-center gap-[5px]" },
19
+ React.createElement(AnimationIcon, { getAnimationIcon: getAnimationIcon, name: "starAnimation" }),
20
+ React.createElement("span", null, "Servicio popular entre los usuarios")));
21
+ const NewUiOfferBanner = ({ offerText, isLoggedIn, showLoginModal, showLoginOption, getAnimationIcon, hideRegister, }) => (React.createElement("div", { className: "flex items-center" },
22
+ React.createElement(AnimationIcon, { getAnimationIcon: getAnimationIcon, name: "bombAnimation" }),
23
+ React.createElement("div", { className: "flex items-center mt-[2px]" },
24
+ React.createElement("span", { className: "bold-text", style: { marginLeft: offerText ? "6px" : "3px" } },
25
+ truncateOfferText(offerText),
26
+ " ",
27
+ !hideRegister && (isLoggedIn && showLoginOption ? null : (React.createElement("span", { onClick: showLoginModal, className: "cursor-pointer" }, "- registro"))),
28
+ " ",
29
+ "\u00A0"),
30
+ " ",
31
+ offerText ? "|" : "",
32
+ "Termina en\u00A0",
33
+ React.createElement("span", { className: "bold-text text-end", ref: (node) => CommonService.startCountdown(node, 599), style: { fontVariantNumeric: "tabular-nums", display: "inline-block" } }))));
34
+ const LegacyOfferBanner = ({ offerText, getAnimationIcon, }) => (React.createElement("div", { className: "flex items-center" },
35
+ React.createElement(AnimationIcon, { getAnimationIcon: getAnimationIcon, name: "promoAnim" }),
36
+ React.createElement("div", { className: "flex items-center mt-[2px]" },
37
+ React.createElement("span", { className: "bold-text", style: { marginLeft: offerText ? "6px" : "3px" } }, offerText))));
38
+ const ViewersCount = ({ serviceItem, viewersConfig, getAnimationIcon, }) => {
39
+ const showScarcity = hasDpDiscounts(serviceItem);
40
+ return (React.createElement("div", { className: "flex items-center" },
41
+ React.createElement(AnimationIcon, { getAnimationIcon: getAnimationIcon, name: "dotAnimation", width: "12px", height: "12px" }),
42
+ React.createElement("span", { className: "ml-[6px]" },
43
+ React.createElement("span", { className: "bold-text", ref: (node) => CommonService.startViewerCount(node, viewersConfig), style: { fontVariantNumeric: "tabular-nums" } }),
44
+ " ",
45
+ React.createElement("span", null,
46
+ (viewersConfig === null || viewersConfig === void 0 ? void 0 : viewersConfig.label) || " viendo",
47
+ " |",
48
+ " ",
49
+ React.createElement("span", null,
50
+ showScarcity && "Quedan pocos • ",
51
+ React.createElement("span", { className: "bold-text", ref: (node) => CommonService.startComprandoCount(node, 4, 16), style: { fontVariantNumeric: "tabular-nums" } }),
31
52
  " ",
32
- (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) ? "|" : "",
33
- "Termina en\u00A0",
34
- React.createElement("span", { className: "bold-text text-end", ref: (node) => CommonService.startCountdown(node, 599), style: {
35
- fontVariantNumeric: "tabular-nums",
36
- display: "inline-block",
37
- } })))) : ((serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) &&
38
- !isNewUiEnabled && (React.createElement("div", { className: "flex items-center" },
39
- React.createElement(LottiePlayer, { animationData: getAnimationIcon("promoAnim"), width: "18px", height: "18px" }),
40
- React.createElement("div", { className: "flex items-center mt-[2px]" },
41
- React.createElement("span", { className: "bold-text", style: {
42
- marginLeft: (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) ? "6px" : "3px",
43
- } }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) || ""),
44
- " "))))),
45
- (isNewUiEnabled || (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled)) && (React.createElement("div", { className: "flex items-center" },
46
- React.createElement(LottiePlayer, { animationData: getAnimationIcon("dotAnimation"), width: "12px", height: "12px" }),
47
- React.createElement("span", { className: "ml-[6px]" },
48
- React.createElement("span", { className: "bold-text", ref: (node) => CommonService.startViewerCount(node, viewersConfig), style: { fontVariantNumeric: "tabular-nums" } }),
49
- " ",
50
- React.createElement("span", null,
51
- " ",
52
- (viewersConfig === null || viewersConfig === void 0 ? void 0 : viewersConfig.label) || " viendo",
53
- " |",
54
- " ",
55
- React.createElement("span", { className: "" },
56
- (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) &&
57
- Object.keys((_c = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discount_percents) !== null && _c !== void 0 ? _c : {})
58
- .length === 0 &&
59
- ((_d = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.dp_discounted_seats) !== null && _d !== void 0 ? _d : []).length === 0
60
- ? null
61
- : "Quedan pocos • ",
62
- React.createElement("span", { className: "bold-text", ref: (node) => CommonService.startComprandoCount(node, 4, 16), style: { fontVariantNumeric: "tabular-nums" } }),
63
- " ",
64
- "comprando"))))))));
53
+ "comprando")))));
54
+ };
55
+ // ─── Main Component ───────────────────────────────────────────────────────────
56
+ const OfferBanner = ({ offerGradient, isSoldOut, serviceItem, isLoggedIn, showLoginModal, viewersConfig, getAnimationIcon, showLoginOption, isNewUiEnabled, colors, }) => {
57
+ const isLegacyOffer = !!(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text) && !isNewUiEnabled && !(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled);
58
+ const isDpEnabledWithoutDiscounts = (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled) && !hasDpDiscounts(serviceItem);
59
+ const showViewers = isNewUiEnabled || (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.is_dp_enabled);
60
+ const background = isLegacyOffer ? colors === null || colors === void 0 ? void 0 : colors.bottomStripColor : offerGradient;
61
+ const renderLeftContent = () => {
62
+ if (isDpEnabledWithoutDiscounts) {
63
+ return React.createElement(PopularServiceBanner, { getAnimationIcon: getAnimationIcon });
64
+ }
65
+ const hasDp = hasDpDiscounts(serviceItem);
66
+ if (hasDp || (isNewUiEnabled && (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.offer_text))) {
67
+ return (React.createElement(NewUiOfferBanner, { offerText: serviceItem.offer_text || "", isLoggedIn: isLoggedIn, showLoginModal: showLoginModal, showLoginOption: showLoginOption, getAnimationIcon: getAnimationIcon, hideRegister: hasDp }));
68
+ }
69
+ if (isLegacyOffer) {
70
+ return (React.createElement(LegacyOfferBanner, { offerText: serviceItem.offer_text, getAnimationIcon: getAnimationIcon }));
71
+ }
72
+ return null;
73
+ };
74
+ return (React.createElement("div", { className: "text-white p-[10px_15px] text-left w-full flex items-center absolute -bottom-[44px] pt-[50px] rounded-b-[14px] text-[14px] mt-[10px]", style: { background, opacity: isSoldOut ? 0.5 : 1 } },
75
+ React.createElement("div", { className: "flex justify-between items-center w-full" },
76
+ React.createElement("div", { className: "flex items-center" }, renderLeftContent()),
77
+ showViewers && (React.createElement(ViewersCount, { serviceItem: serviceItem, viewersConfig: viewersConfig, getAnimationIcon: getAnimationIcon })))));
65
78
  };
66
79
  export default OfferBanner;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kupos-ui-components-lib",
3
- "version": "9.10.2",
3
+ "version": "9.10.4",
4
4
  "description": "A reusable UI components package",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -605,11 +605,11 @@ function PeruServiceItemDesktop({
605
605
 
606
606
  return (
607
607
  <div
608
- className={`relative hover:z-[150] ${hasOfferText ? "mb-[55px]" : "mb-[10px]"} ${
608
+ className={`relative hover:z-[150] ${hasOfferText || hasDpEnabled || isNewUiEnabled ? "mb-[65px]" : "mb-[20px]"} ${
609
609
  serviceItem?.is_direct_trip ||
610
610
  serviceItem?.train_type_label === "Tren Express (Nuevo)" ||
611
611
  showTopLabel
612
- ? "mt-[24px]"
612
+ ? "mt-[30px]"
613
613
  : "mt-[20px]"
614
614
  } `}
615
615
  >
@@ -144,6 +144,7 @@ function ServiceItemPB({
144
144
  wowDealData,
145
145
  isFlores,
146
146
  }: ServiceItemProps & { currencySign?: string }): React.ReactElement {
147
+ console.log("🚀 ~ ServiceItemPB ~ serviceItem:", serviceItem);
147
148
  const getAnimationIcon = (icon: string) => {
148
149
  const animation = ANIMATION_MAP[icon];
149
150
  if (!animation) return null;
@@ -487,7 +488,7 @@ function ServiceItemPB({
487
488
  />
488
489
  ) : (
489
490
  <div
490
- className={`relative hover:z-[150] ${hasOfferText || hasDpEnabled || isNewUiEnabled ? "mb-[55px]" : "mb-[10px]"} ${
491
+ className={`relative hover:z-[150] ${hasOfferText || hasDpEnabled || isNewUiEnabled ? "mb-[65px]" : "mb-[20px]"} ${
491
492
  serviceItem?.is_direct_trip ||
492
493
  serviceItem?.train_type_label === "Tren Express (Nuevo)" ||
493
494
  showTopLabel
@@ -386,46 +386,49 @@ function ServiceItemMobile({
386
386
  </div>
387
387
 
388
388
  {/* 🔹 EXPANDABLE DROPDOWN (below the card) */}
389
- {serviceItem?.offer_text && !isNewUiEnabled && !isSoldOut && (
390
- <div
391
- className="px-[12px] pt-[22px] pb-[8px] relative -z-9 -mt-[15px]"
392
- style={{
393
- background: colors?.bottomStripColor,
394
- borderRadius: "0 0 14px 14px",
395
- zIndex: -1,
396
- }}
397
- >
389
+ {serviceItem?.offer_text &&
390
+ !isNewUiEnabled &&
391
+ !isSoldOut &&
392
+ !serviceItem?.is_dp_enabled && (
398
393
  <div
399
- className="flex flex-col gap-[8px] text-[12px] min-[420px]:text-[12px] text-[#464647]"
400
- style={{ lineHeight: 1.6 }}
394
+ className="px-[12px] pt-[22px] pb-[8px] relative -z-9 -mt-[15px]"
395
+ style={{
396
+ background: colors?.bottomStripColor,
397
+ borderRadius: "0 0 14px 14px",
398
+ zIndex: -1,
399
+ }}
401
400
  >
402
- <div className="flex justify-between items-center">
403
- <div
404
- className={`flex ${(serviceItem?.offer_text || "").length > 10 ? "items-start" : "items-center"}`}
405
- >
406
- <div className={isLongOfferText ? "mt-[2px]" : ""}>
407
- <LottiePlayer
408
- animationData={serviceItem.icons.promoAnim}
409
- width="14px"
410
- height="14px"
411
- />
412
- </div>
401
+ <div
402
+ className="flex flex-col gap-[8px] text-[12px] min-[420px]:text-[12px] text-[#464647]"
403
+ style={{ lineHeight: 1.6 }}
404
+ >
405
+ <div className="flex justify-between items-center">
413
406
  <div
414
- className={`ml-[4px] flex-1 outline-none ${isLongOfferText ? "mt-[2px]" : ""}`}
415
- style={{
416
- color: "#fff",
417
- lineHeight: 1.4,
418
- }}
407
+ className={`flex ${(serviceItem?.offer_text || "").length > 10 ? "items-start" : "items-center"}`}
419
408
  >
420
- <span className="whitespace-nowrap min-[380px]:text-[12px]">
421
- {serviceItem?.offer_text}
422
- </span>
409
+ <div className={isLongOfferText ? "mt-[2px]" : ""}>
410
+ <LottiePlayer
411
+ animationData={serviceItem.icons.promoAnim}
412
+ width="14px"
413
+ height="14px"
414
+ />
415
+ </div>
416
+ <div
417
+ className={`ml-[4px] flex-1 outline-none ${isLongOfferText ? "mt-[2px]" : ""}`}
418
+ style={{
419
+ color: "#fff",
420
+ lineHeight: 1.4,
421
+ }}
422
+ >
423
+ <span className="whitespace-nowrap min-[380px]:text-[12px]">
424
+ {serviceItem?.offer_text}
425
+ </span>
426
+ </div>
423
427
  </div>
424
428
  </div>
425
429
  </div>
426
430
  </div>
427
- </div>
428
- )}
431
+ )}
429
432
 
430
433
  {/* 🔹 EXPANDABLE DROPDOWN (below the card) */}
431
434
  {((serviceItem?.offer_text && isNewUiEnabled) ||
@@ -63,7 +63,7 @@ const SurveyDesktop = ({
63
63
 
64
64
  {/* Centered Illustration */}
65
65
  {icons?.surveyIcon && (
66
- <div className="flex justify-center mb-3 mt-2">
66
+ <div className="flex justify-center mb-2 mt-2">
67
67
  <img
68
68
  src={icons.surveyIcon}
69
69
  alt="Survey Illustration"
@@ -73,7 +73,7 @@ const SurveyDesktop = ({
73
73
  )}
74
74
 
75
75
  {/* Centered Title */}
76
- <h2 className="text-[18px] bold-text leading-[1.25] text-center mt-4 mb-2">
76
+ <h2 className="text-[18px] bold-text leading-[1.25] text-center mb-2">
77
77
  Ayúdanos a mejorar
78
78
  </h2>
79
79
 
@@ -66,7 +66,7 @@ const SurveyMobile = ({
66
66
 
67
67
  {/* Centered Illustration */}
68
68
  {icons?.surveyIcon && (
69
- <div className="flex justify-center mb-3 mt-2">
69
+ <div className="flex justify-center mb-2 mt-2">
70
70
  <img
71
71
  src={icons.surveyIcon}
72
72
  alt="Survey Illustration"
@@ -76,12 +76,12 @@ const SurveyMobile = ({
76
76
  )}
77
77
 
78
78
  {/* Centered Title */}
79
- <h2 className="text-[18px] bold-text leading-[1.25] text-center mt-4 mb-2">
79
+ <h2 className="text-[18px] bold-text leading-[1.25] text-center mb-2">
80
80
  Ayúdanos a mejorar
81
81
  </h2>
82
82
 
83
83
  {/* Centered Subtitle */}
84
- <p className="text-[13.33px] text-center leading-[1.4] mb-6 max-w-[460px] mx-auto">
84
+ <p className="text-[13.33px] text-center leading-[1.4] mb-8 max-w-[460px] mx-auto">
85
85
  Basándote en tu experiencia de compra.
86
86
  <br />
87
87
  ¿Nos recomendarías a un amigo?
@@ -104,8 +104,8 @@ const SurveyMobile = ({
104
104
  onFeedbackChange={onFeedbackChange}
105
105
  />
106
106
 
107
- <div className="flex justify-center mt-[20px]">
108
- <div className="w-[180px]">
107
+ <div className="flex justify-center mt-[50px] mb-[50px]">
108
+ <div className="w-[100px]">
109
109
  <KuposButton
110
110
  isSoldOut={selectedScore == null}
111
111
  isLoading={isLoading || false}
@@ -250,7 +250,7 @@ const FeatureServiceUi = ({
250
250
  </div>
251
251
  </div>
252
252
 
253
- <div className="flex flex-col gap-[8px]">
253
+ <div className="flex flex-col gap-[10px]">
254
254
  <div className="text-[12px] bold-text">
255
255
  {travelDate
256
256
  ? new Date(travelDate).toLocaleDateString("es-CL", {
@@ -363,9 +363,8 @@ const FeatureServiceUi = ({
363
363
  {/* MIDDLE: competing operators + viewers */}
364
364
  <div className="min-w-0 px-[22px] flex flex-col items-center justify-between gap-[16px] py-[2px] border-r border-[#363c48] border-l border-[#363c48]">
365
365
  <div className="text-center">
366
- <div className="bold-text text-[14px]">
367
- {operatorsCompetingCount} operadores compitiendo
368
- <br /> por tu compra
366
+ <div className="bold-text text-[13px]">
367
+ {operatorsCompetingCount} operadores compitiendo por tu compra
369
368
  </div>
370
369
  </div>
371
370
 
@@ -377,7 +376,7 @@ const FeatureServiceUi = ({
377
376
  style={{
378
377
  // height: "80px",
379
378
  border: "1px solid #363c48",
380
- backgroundColor: "#1a202e",
379
+ backgroundColor: "#fff",
381
380
  padding: "14px 10px",
382
381
  }}
383
382
  >
@@ -393,13 +392,13 @@ const FeatureServiceUi = ({
393
392
  isSoldOut ? "grayscale" : ""
394
393
  }`}
395
394
  />
396
- <span className="text-[11px] truncate max-w-full text-center">
395
+ <span className="text-[11px] truncate max-w-full text-center text-[#464647]">
397
396
  {op.name}
398
397
  </span>
399
398
  <div className="bg-[#FF8F45] text-white text-[12px] font-bold px-[10px] py-[4px] rounded-[4px] bold-text whitespace-nowrap">
400
399
  <span>{op?.time}</span>
401
400
  </div>
402
- <span className="text-[10px] mt-[6px]">
401
+ <span className="text-[10px] mt-[6px] text-[#464647]">
403
402
  {op?.seatsAvailable}
404
403
  </span>
405
404
  </div>
@@ -407,10 +406,13 @@ const FeatureServiceUi = ({
407
406
  </div>
408
407
 
409
408
  <div
410
- className="flex w-full items-center justify-center gap-[6px] text-[12px]"
409
+ className="flex w-full items-center justify-center gap-[6px] text-[12px] rounded-full"
411
410
  style={{
412
411
  padding: "8px 14px",
413
412
  marginBottom: "6px",
413
+ border: "1px solid #363c48",
414
+ backgroundColor: "#1a202e",
415
+ // padding: "14px 10px",
414
416
  }}
415
417
  >
416
418
  <LottiePlayer
@@ -3,31 +3,201 @@ import LottiePlayer from "../assets/LottiePlayer";
3
3
  import CommonService from "../utils/CommonService";
4
4
  import { ServiceItemProps } from "../components/ServiceItem/types";
5
5
 
6
+ // ─── Types ────────────────────────────────────────────────────────────────────
7
+
8
+ type ServiceItemSlice = Pick<
9
+ ServiceItemProps["serviceItem"],
10
+ | "is_dp_enabled"
11
+ | "offer_text"
12
+ | "dp_discount_percents"
13
+ | "dp_discounted_seats"
14
+ >;
15
+
16
+ interface OfferBannerColors {
17
+ bottomStripColor?: string;
18
+ }
19
+
6
20
  interface OfferBannerProps {
7
21
  offerGradient: string;
8
22
  isSoldOut: boolean;
9
- serviceItem: Pick<
10
- ServiceItemProps["serviceItem"],
11
- | "is_dp_enabled"
12
- | "offer_text"
13
- | "dp_discount_percents"
14
- | "dp_discounted_seats"
15
- >;
23
+ serviceItem: ServiceItemSlice;
16
24
  renderIcon: (name: string, size: string) => React.ReactNode;
17
- isLoggedIn: any;
18
- showLoginModal: any;
25
+ isLoggedIn: boolean;
26
+ showLoginModal: () => void;
19
27
  viewersConfig: ServiceItemProps["viewersConfig"];
20
- getAnimationIcon: (name: string) => any;
28
+ getAnimationIcon: (name: string) => unknown;
21
29
  showLoginOption?: boolean;
22
30
  isNewUiEnabled?: boolean;
23
- colors: any;
31
+ colors: OfferBannerColors;
32
+ }
33
+
34
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
35
+
36
+ const OFFER_TEXT_MAX_LENGTH = 30;
37
+
38
+ function truncateOfferText(text: string): string {
39
+ return text.length > OFFER_TEXT_MAX_LENGTH
40
+ ? `${text.slice(0, OFFER_TEXT_MAX_LENGTH)}...`
41
+ : text;
42
+ }
43
+
44
+ function hasDpDiscounts(serviceItem: ServiceItemSlice): boolean {
45
+ return (
46
+ Object.keys(serviceItem?.dp_discount_percents ?? {}).length > 0 ||
47
+ (serviceItem?.dp_discounted_seats ?? []).length > 0
48
+ );
49
+ }
50
+
51
+ // ─── Sub-components ───────────────────────────────────────────────────────────
52
+
53
+ interface AnimationIconProps {
54
+ getAnimationIcon: OfferBannerProps["getAnimationIcon"];
55
+ name: string;
56
+ width?: string;
57
+ height?: string;
58
+ }
59
+
60
+ const AnimationIcon: React.FC<AnimationIconProps> = ({
61
+ getAnimationIcon,
62
+ name,
63
+ width = "18px",
64
+ height = "18px",
65
+ }) => (
66
+ <LottiePlayer
67
+ animationData={getAnimationIcon(name)}
68
+ width={width}
69
+ height={height}
70
+ />
71
+ );
72
+
73
+ // Shown when DP is enabled but no discounts / discounted seats are present
74
+ const PopularServiceBanner: React.FC<{
75
+ getAnimationIcon: OfferBannerProps["getAnimationIcon"];
76
+ }> = ({ getAnimationIcon }) => (
77
+ <div className="flex items-center gap-[5px]">
78
+ <AnimationIcon getAnimationIcon={getAnimationIcon} name="starAnimation" />
79
+ <span>Servicio popular entre los usuarios</span>
80
+ </div>
81
+ );
82
+
83
+ // Shown when the new UI is enabled and an offer text exists
84
+ interface NewUiOfferBannerProps {
85
+ offerText: string;
86
+ isLoggedIn: boolean;
87
+ showLoginModal: () => void;
88
+ showLoginOption?: boolean;
89
+ getAnimationIcon: OfferBannerProps["getAnimationIcon"];
90
+ hideRegister?: boolean;
91
+ }
92
+
93
+ const NewUiOfferBanner: React.FC<NewUiOfferBannerProps> = ({
94
+ offerText,
95
+ isLoggedIn,
96
+ showLoginModal,
97
+ showLoginOption,
98
+ getAnimationIcon,
99
+ hideRegister,
100
+ }) => (
101
+ <div className="flex items-center">
102
+ <AnimationIcon getAnimationIcon={getAnimationIcon} name="bombAnimation" />
103
+ <div className="flex items-center mt-[2px]">
104
+ <span
105
+ className="bold-text"
106
+ style={{ marginLeft: offerText ? "6px" : "3px" }}
107
+ >
108
+ {truncateOfferText(offerText)}{" "}
109
+ {!hideRegister && (isLoggedIn && showLoginOption ? null : (
110
+ <span onClick={showLoginModal} className="cursor-pointer">
111
+ - registro
112
+ </span>
113
+ ))}{" "}
114
+ &nbsp;
115
+ </span>{" "}
116
+ {offerText ? "|" : ""}
117
+ Termina en&nbsp;
118
+ <span
119
+ className="bold-text text-end"
120
+ ref={(node) => CommonService.startCountdown(node, 599)}
121
+ style={{ fontVariantNumeric: "tabular-nums", display: "inline-block" }}
122
+ />
123
+ </div>
124
+ </div>
125
+ );
126
+
127
+ // Shown for legacy (non-new-UI) promo offers
128
+ interface LegacyOfferBannerProps {
129
+ offerText: string;
130
+ getAnimationIcon: OfferBannerProps["getAnimationIcon"];
24
131
  }
25
132
 
133
+ const LegacyOfferBanner: React.FC<LegacyOfferBannerProps> = ({
134
+ offerText,
135
+ getAnimationIcon,
136
+ }) => (
137
+ <div className="flex items-center">
138
+ <AnimationIcon getAnimationIcon={getAnimationIcon} name="promoAnim" />
139
+ <div className="flex items-center mt-[2px]">
140
+ <span
141
+ className="bold-text"
142
+ style={{ marginLeft: offerText ? "6px" : "3px" }}
143
+ >
144
+ {offerText}
145
+ </span>
146
+ </div>
147
+ </div>
148
+ );
149
+
150
+ // Right-side viewers / buying count
151
+ interface ViewersCountProps {
152
+ serviceItem: ServiceItemSlice;
153
+ viewersConfig: ServiceItemProps["viewersConfig"];
154
+ getAnimationIcon: OfferBannerProps["getAnimationIcon"];
155
+ }
156
+
157
+ const ViewersCount: React.FC<ViewersCountProps> = ({
158
+ serviceItem,
159
+ viewersConfig,
160
+ getAnimationIcon,
161
+ }) => {
162
+ const showScarcity = hasDpDiscounts(serviceItem);
163
+
164
+ return (
165
+ <div className="flex items-center">
166
+ <AnimationIcon
167
+ getAnimationIcon={getAnimationIcon}
168
+ name="dotAnimation"
169
+ width="12px"
170
+ height="12px"
171
+ />
172
+ <span className="ml-[6px]">
173
+ <span
174
+ className="bold-text"
175
+ ref={(node) => CommonService.startViewerCount(node, viewersConfig)}
176
+ style={{ fontVariantNumeric: "tabular-nums" }}
177
+ />{" "}
178
+ <span>
179
+ {viewersConfig?.label || " viendo"} |{" "}
180
+ <span>
181
+ {showScarcity && "Quedan pocos • "}
182
+ <span
183
+ className="bold-text"
184
+ ref={(node) => CommonService.startComprandoCount(node, 4, 16)}
185
+ style={{ fontVariantNumeric: "tabular-nums" }}
186
+ />{" "}
187
+ comprando
188
+ </span>
189
+ </span>
190
+ </span>
191
+ </div>
192
+ );
193
+ };
194
+
195
+ // ─── Main Component ───────────────────────────────────────────────────────────
196
+
26
197
  const OfferBanner: React.FC<OfferBannerProps> = ({
27
198
  offerGradient,
28
199
  isSoldOut,
29
200
  serviceItem,
30
- renderIcon,
31
201
  isLoggedIn,
32
202
  showLoginModal,
33
203
  viewersConfig,
@@ -36,132 +206,59 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
36
206
  isNewUiEnabled,
37
207
  colors,
38
208
  }) => {
209
+ const isLegacyOffer =
210
+ !!serviceItem?.offer_text && !isNewUiEnabled && !serviceItem?.is_dp_enabled;
211
+
212
+ const isDpEnabledWithoutDiscounts =
213
+ serviceItem?.is_dp_enabled && !hasDpDiscounts(serviceItem);
214
+
215
+ const showViewers = isNewUiEnabled || serviceItem?.is_dp_enabled;
216
+
217
+ const background = isLegacyOffer ? colors?.bottomStripColor : offerGradient;
218
+
219
+ const renderLeftContent = () => {
220
+ if (isDpEnabledWithoutDiscounts) {
221
+ return <PopularServiceBanner getAnimationIcon={getAnimationIcon} />;
222
+ }
223
+
224
+ const hasDp = hasDpDiscounts(serviceItem);
225
+
226
+ if (hasDp || (isNewUiEnabled && serviceItem?.offer_text)) {
227
+ return (
228
+ <NewUiOfferBanner
229
+ offerText={serviceItem.offer_text || ""}
230
+ isLoggedIn={isLoggedIn}
231
+ showLoginModal={showLoginModal}
232
+ showLoginOption={showLoginOption}
233
+ getAnimationIcon={getAnimationIcon}
234
+ hideRegister={hasDp}
235
+ />
236
+ );
237
+ }
238
+ if (isLegacyOffer) {
239
+ return (
240
+ <LegacyOfferBanner
241
+ offerText={serviceItem.offer_text!}
242
+ getAnimationIcon={getAnimationIcon}
243
+ />
244
+ );
245
+ }
246
+ return null;
247
+ };
248
+
39
249
  return (
40
250
  <div
41
- className="text-white p-[10px_15px] text-left w-full flex items-center absolute -bottom-[44px] pt-[50px] rounded-b-[14px] text-[14px] mt-[10px]"
42
- style={{
43
- background:
44
- serviceItem?.offer_text && !isNewUiEnabled
45
- ? colors?.bottomStripColor
46
- : offerGradient,
47
- opacity: isSoldOut ? 0.5 : 1,
48
- // zIndex: 0,
49
- }}
251
+ className="text-white p-[10px_15px] text-left w-full flex items-center absolute -bottom-[44px] pt-[50px] rounded-b-[14px] text-[14px] mt-[10px]"
252
+ style={{ background, opacity: isSoldOut ? 0.5 : 1 }}
50
253
  >
51
- <div className="flex justify-between items-center w-full">
52
- <div className="flex items-center ">
53
- {serviceItem?.is_dp_enabled &&
54
- Object.keys(serviceItem?.dp_discount_percents ?? {}).length === 0 &&
55
- (serviceItem?.dp_discounted_seats ?? []).length === 0 ? (
56
- <div className="flex items-center gap-[5px]">
57
- {/* {renderIcon("whiteFireIcon", "14px")} */}
58
- <LottiePlayer
59
- animationData={getAnimationIcon("starAnimation")}
60
- width="18px"
61
- height="18px"
62
- />
63
- {/* starAnimation */}
64
- <span>Servicio popular entre los usuarios</span>
65
- </div>
66
- ) : isNewUiEnabled && serviceItem?.offer_text ? (
67
- <div className="flex items-center">
68
- <LottiePlayer
69
- animationData={getAnimationIcon("bombAnimation")}
70
- width="18px"
71
- height="18px"
72
- />
73
- <div className="flex items-center mt-[2px]">
74
- <span
75
- className="bold-text"
76
- style={{
77
- marginLeft: serviceItem?.offer_text ? "6px" : "3px",
78
- }}
79
- >
80
- {(serviceItem?.offer_text || "").length > 30
81
- ? (serviceItem?.offer_text || "").slice(0, 30) + "..."
82
- : serviceItem?.offer_text || ""}{" "}
83
- {isLoggedIn && showLoginOption ? null : (
84
- <span onClick={showLoginModal} className="cursor-pointer">
85
- - registro
86
- </span>
87
- )}{" "}
88
- &nbsp;
89
- </span>{" "}
90
- {serviceItem?.offer_text ? "|" : ""}
91
- Termina en&nbsp;
92
- <span
93
- className="bold-text text-end"
94
- ref={(node) => CommonService.startCountdown(node, 599)}
95
- style={{
96
- fontVariantNumeric: "tabular-nums",
97
- display: "inline-block",
98
- }}
99
- />
100
- </div>
101
- </div>
102
- ) : (
103
- serviceItem?.offer_text &&
104
- !isNewUiEnabled && (
105
- <div className="flex items-center">
106
- <LottiePlayer
107
- animationData={getAnimationIcon("promoAnim")}
108
- width="18px"
109
- height="18px"
110
- />
111
- <div className="flex items-center mt-[2px]">
112
- <span
113
- className="bold-text"
114
- style={{
115
- marginLeft: serviceItem?.offer_text ? "6px" : "3px",
116
- }}
117
- >
118
- {serviceItem?.offer_text || ""}
119
- </span>{" "}
120
- </div>
121
- </div>
122
- )
123
- )}
124
- </div>
125
- {(isNewUiEnabled || serviceItem?.is_dp_enabled) && (
126
- <div className="flex items-center">
127
- {/* {renderIcon("personIcon", "16px")} */}
128
- <LottiePlayer
129
- animationData={getAnimationIcon("dotAnimation")}
130
- width="12px"
131
- height="12px"
132
- />
133
-
134
- <span className="ml-[6px]">
135
- <span
136
- className="bold-text"
137
- ref={(node) =>
138
- CommonService.startViewerCount(node, viewersConfig)
139
- }
140
- style={{ fontVariantNumeric: "tabular-nums" }}
141
- />{" "}
142
- {/* <span className="bold-text">personas</span>{" "} */}
143
- <span>
144
- {" "}
145
- {viewersConfig?.label || " viendo"} |{" "}
146
- <span className="">
147
- {serviceItem?.is_dp_enabled &&
148
- Object.keys(serviceItem?.dp_discount_percents ?? {})
149
- .length === 0 &&
150
- (serviceItem?.dp_discounted_seats ?? []).length === 0
151
- ? null
152
- : "Quedan pocos • "}
153
- <span
154
- className="bold-text"
155
- ref={(node) =>
156
- CommonService.startComprandoCount(node, 4, 16)
157
- }
158
- style={{ fontVariantNumeric: "tabular-nums" }}
159
- />{" "}
160
- comprando
161
- </span>
162
- </span>
163
- </span>
164
- </div>
254
+ <div className="flex justify-between items-center w-full">
255
+ <div className="flex items-center">{renderLeftContent()}</div>
256
+ {showViewers && (
257
+ <ViewersCount
258
+ serviceItem={serviceItem}
259
+ viewersConfig={viewersConfig}
260
+ getAnimationIcon={getAnimationIcon}
261
+ />
165
262
  )}
166
263
  </div>
167
264
  </div>