kupos-ui-components-lib 10.0.2 → 10.0.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.
@@ -23,7 +23,7 @@ const HARDCODED_OPERATORS = [
23
23
  },
24
24
  ];
25
25
  const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut, cityOrigin, cityDestination, renderIcon, viewersConfig, isFeatureDropDownExpand, onToggleExpand, ticketQuantity = 1, onIncreaseTicketQuantity, onDecreaseTicketQuantity, onBookButtonPress, selectedTimeSlot, onTimeSlotChange, isTimeDropdownOpen, onTimeDropdownToggle, wowDealData = undefined, }) => {
26
- var _a, _b, _c, _d, _e, _f;
26
+ var _a, _b, _c, _d, _e, _f, _g;
27
27
  // Use wow_deal data if available, otherwise fall back to serviceItem operators or hardcoded
28
28
  const operators = ((_a = wowDealData === null || wowDealData === void 0 ? void 0 : wowDealData.services) === null || _a === void 0 ? void 0 : _a.length) > 0
29
29
  ? wowDealData.services.slice(0, 3).map((service) => ({
@@ -87,7 +87,8 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
87
87
  ? selectedSlotService.original_price
88
88
  : originalPrice;
89
89
  const displaySavingsPercent = selectedSlotService && selectedSlotService.original_price
90
- ? Math.round(((selectedSlotService.original_price - selectedSlotService.final_price) /
90
+ ? Math.round(((selectedSlotService.original_price -
91
+ selectedSlotService.final_price) /
91
92
  selectedSlotService.original_price) *
92
93
  100)
93
94
  : savingsPercent;
@@ -97,6 +98,8 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
97
98
  isFeatureDropDownExpand === true;
98
99
  const isThisTimeDropdownOpen = isTimeDropdownOpen === serviceItem.id;
99
100
  const canDecreaseTicketQuantity = ticketQuantity > 1;
101
+ const availableSeats = (_c = selectedSlotService === null || selectedSlotService === void 0 ? void 0 : selectedSlotService.available_seats) !== null && _c !== void 0 ? _c : maxSeatsPerBooking;
102
+ const canIncreaseTicketQuantity = ticketQuantity < availableSeats;
100
103
  const HOW_IT_WORKS_STEPS = [
101
104
  {
102
105
  icon: "flexible",
@@ -171,10 +174,10 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
171
174
  React.createElement("div", { className: " text-[white]" },
172
175
  React.createElement("div", { className: "flex flex-col gap-[10px] relative" },
173
176
  React.createElement("div", { className: "flex items-center gap-[6px]" },
174
- React.createElement("img", { src: (_c = serviceItem.icons) === null || _c === void 0 ? void 0 : _c.whiteOrigin, alt: "origin", className: `w-[13px] h-[13px] shrink-0 ${isSoldOut ? "grayscale" : ""}` }),
177
+ React.createElement("img", { src: (_d = serviceItem.icons) === null || _d === void 0 ? void 0 : _d.whiteOrigin, alt: "origin", className: `w-[13px] h-[13px] shrink-0 ${isSoldOut ? "grayscale" : ""}` }),
175
178
  React.createElement("span", { className: "text-[14px] bold-text" }, cityOrigin === null || cityOrigin === void 0 ? void 0 : cityOrigin.label.split(",")[0]),
176
179
  React.createElement("span", { className: "mx-[6px] text-[14px] bold-text" }, "\u2192"),
177
- React.createElement("img", { src: (_d = serviceItem.icons) === null || _d === void 0 ? void 0 : _d.whiteDestination, alt: "destination", className: `w-[13px] h-[13px] shrink-0 ${isSoldOut ? "grayscale" : ""}`, style: { opacity: isSoldOut ? 0.5 : 1 } }),
180
+ React.createElement("img", { src: (_e = serviceItem.icons) === null || _e === void 0 ? void 0 : _e.whiteDestination, alt: "destination", className: `w-[13px] h-[13px] shrink-0 ${isSoldOut ? "grayscale" : ""}`, style: { opacity: isSoldOut ? 0.5 : 1 } }),
178
181
  React.createElement("span", { className: "text-[14px] bold-text" }, cityDestination === null || cityDestination === void 0 ? void 0 : cityDestination.label.split(",")[0])),
179
182
  React.createElement("div", { className: "flex items-center gap-[6px]" },
180
183
  React.createElement("div", { className: "kupos-time-dd relative", tabIndex: 0, onBlur: (e) => {
@@ -184,7 +187,7 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
184
187
  }, style: { outline: "none" } },
185
188
  React.createElement("button", { type: "button", onClick: () => onTimeDropdownToggle === null || onTimeDropdownToggle === void 0 ? void 0 : onTimeDropdownToggle(isThisTimeDropdownOpen ? null : serviceItem.id), className: "flex cursor-pointer select-none items-center gap-[6px] border-none bg-transparent p-0 bold-text text-[13px] text-[white]" },
186
189
  React.createElement("span", null, departureRange),
187
- React.createElement("img", { src: (_e = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _e === void 0 ? void 0 : _e.downArrow, alt: "down arrow", className: `kupos-time-chevron transition-transform duration-200 ${isThisTimeDropdownOpen ? "rotate-180" : "rotate-0"}`, style: {
190
+ React.createElement("img", { src: (_f = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _f === void 0 ? void 0 : _f.downArrow, alt: "down arrow", className: `kupos-time-chevron transition-transform duration-200 ${isThisTimeDropdownOpen ? "rotate-180" : "rotate-0"}`, style: {
188
191
  width: "12px",
189
192
  height: "8px",
190
193
  filter: "brightness(0) invert(1)",
@@ -295,7 +298,13 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
295
298
  ? "cursor-pointer bg-[#2d374d]"
296
299
  : "cursor-not-allowed bg-[#222b3d] opacity-50"}` }, "-"),
297
300
  React.createElement("span", { className: "bold-text text-[14px] text-[white]" }, ticketQuantity),
298
- React.createElement("button", { type: "button", "aria-label": "Aumentar pasajes", onClick: () => onIncreaseTicketQuantity === null || onIncreaseTicketQuantity === void 0 ? void 0 : onIncreaseTicketQuantity(serviceItem), className: "flex h-[26px] w-[26px] cursor-pointer items-center justify-center rounded-full border-none bg-[#2d374d] text-[16px] leading-none text-[white]" }, "+"))),
301
+ React.createElement("button", { type: "button", "aria-label": "Aumentar pasajes", onClick: () => onIncreaseTicketQuantity === null || onIncreaseTicketQuantity === void 0 ? void 0 : onIncreaseTicketQuantity(serviceItem), disabled: !canIncreaseTicketQuantity, className: `flex h-[26px] w-[26px] cursor-pointer items-center justify-center rounded-full border-none text-[16px] leading-none text-[white] ${canIncreaseTicketQuantity
302
+ ? "cursor-pointer bg-[#2d374d]"
303
+ : "cursor-not-allowed bg-[#222b3d] opacity-50"}` }, "+")),
304
+ !canIncreaseTicketQuantity && (React.createElement("span", { className: "text-[10px] text-[#FF5C60]" },
305
+ "m\u00E1x. ",
306
+ availableSeats,
307
+ " pasajes"))),
299
308
  React.createElement("div", { className: "mt-[10px] flex justify-between items-center rounded-[14px]", style: {
300
309
  // height: "80px",
301
310
  border: "1px solid #363c48",
@@ -304,7 +313,7 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
304
313
  } },
305
314
  React.createElement("div", { className: "flex flex-col" },
306
315
  React.createElement("span", { className: "text-[18px] font-normal leading-[20px] text-[#9f9f9f] relative", style: { position: "relative" } },
307
- `$${(displayOriginalPrice * ticketQuantity).toLocaleString()}`,
316
+ commonService.currencyRounded(displayOriginalPrice * ticketQuantity),
308
317
  React.createElement("span", { style: {
309
318
  position: "absolute",
310
319
  left: "-2px",
@@ -315,14 +324,31 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
315
324
  transform: "rotate(-10deg)",
316
325
  transformOrigin: "center",
317
326
  } })),
318
- React.createElement("span", { className: "text-[white] bold-text text-[24px] leading-none mt-[4px]" }, `$${(displayFinalPrice * ticketQuantity).toLocaleString()}`)),
327
+ React.createElement("span", { className: "text-[white] bold-text text-[24px] leading-none mt-[4px]" }, commonService.currencyRounded(displayFinalPrice * ticketQuantity))),
319
328
  React.createElement("span", { className: "text-[#FF8F45] bold-text text-[22px] leading-tight", style: {
320
329
  animation: "pulse-zoom 2s ease-in-out infinite",
321
330
  whiteSpace: "nowrap",
322
331
  } },
323
332
  displaySavingsPercent,
324
333
  "% OFF")),
325
- React.createElement("button", { type: "button", onClick: onBookButtonPress, className: "flex items-center gap-[6px] px-[20px] py-[10px] rounded-[16px] text-[white] bold-text text-[13px] mt-[10px] justify-center border-none cursor-pointer", style: {
334
+ React.createElement("button", { type: "button", ref: (btn) => {
335
+ if (!btn)
336
+ return;
337
+ btn.onclick = () => {
338
+ if (btn.disabled)
339
+ return;
340
+ btn.disabled = true;
341
+ btn.style.cursor = "not-allowed";
342
+ btn.style.opacity = "0.85";
343
+ const normal = btn.querySelector('[data-btn-state="normal"]');
344
+ const loading = btn.querySelector('[data-btn-state="loading"]');
345
+ if (normal)
346
+ normal.style.display = "none";
347
+ if (loading)
348
+ loading.style.display = "flex";
349
+ onBookButtonPress === null || onBookButtonPress === void 0 ? void 0 : onBookButtonPress(ticketQuantity, serviceItem, servicesInActiveSlot);
350
+ };
351
+ }, className: "flex items-center gap-[6px] px-[20px] py-[10px] rounded-[16px] text-[white] bold-text text-[13px] mt-[10px] justify-center border-none cursor-pointer", style: {
326
352
  backgroundColor: "#FF5C60",
327
353
  whiteSpace: "nowrap",
328
354
  width: "100%",
@@ -330,7 +356,7 @@ const FeatureServiceUiMobile = ({ serviceItem, showTopLabel, colors, isSoldOut,
330
356
  React.createElement(LottiePlayer, { animationData: serviceItem.icons.thunderAnim, width: "16px", height: "16px" }),
331
357
  React.createElement("span", { className: "whitespace-nowrap" }, "\u00A1Lo quiero!")),
332
358
  React.createElement("div", { className: "flex justify-end mt-[10px]", onClick: onToggleExpand },
333
- React.createElement("img", { src: (_f = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _f === void 0 ? void 0 : _f.downArrow, alt: "down arrow", className: `transition-transform duration-300 ease-in-out ${isItemExpanded ? "rotate-180" : ""}`, style: {
359
+ React.createElement("img", { src: (_g = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.icons) === null || _g === void 0 ? void 0 : _g.downArrow, alt: "down arrow", className: `transition-transform duration-300 ease-in-out ${isItemExpanded ? "rotate-180" : ""}`, style: {
334
360
  width: "14px",
335
361
  height: "8px",
336
362
  filter: "brightness(0) invert(1)",
@@ -243,7 +243,7 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
243
243
  } }))),
244
244
  React.createElement("div", { className: "col-start-2 row-start-3 flex h-[30px] items-end justify-center relative" },
245
245
  React.createElement("span", { className: "flex items-center gap-[6px] text-[22px] bold-text leading-[30px]", style: { color: isSoldOut ? "#c0c0c0" : dpSeatColor || "#ff5964" } },
246
- React.createElement("div", { className: "absolute", style: { left: isPeru ? "-1px" : "-19px", bottom: "1px" } }, renderIcon("fireIcon", "16px")),
246
+ React.createElement("div", { className: "absolute", style: { left: isPeru ? "-19px" : "-19px", bottom: "1px" } }, renderIcon("fireIcon", "16px")),
247
247
  availableSeats <= 0
248
248
  ? CommonService.currency(0, currencySign)
249
249
  : CommonService.discountedCurrency(Number(seatTypeFare), currencySign)))));
@@ -315,7 +315,7 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
315
315
  React.createElement("div", { className: "col-start-2 row-start-3 flex h-[30px] items-end justify-center relative" },
316
316
  React.createElement("span", { className: "flex items-center gap-[6px] text-[22px] bold-text leading-[30px]", style: { color: isSoldOut ? "#c0c0c0" : discountSeatPriceColor } },
317
317
  React.createElement("div", { className: "absolute", style: {
318
- left: isPeru ? "-1px" : "-18px",
318
+ left: isPeru ? "-16px" : "-18px",
319
319
  bottom: "1px",
320
320
  } }, renderIcon("fireIcon", "16px")),
321
321
  availableSeats <= 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kupos-ui-components-lib",
3
- "version": "10.0.2",
3
+ "version": "10.0.4",
4
4
  "description": "A reusable UI components package",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -121,13 +121,15 @@ const FeatureServiceUiMobile = ({
121
121
  const displayOriginalPrice = selectedSlotService
122
122
  ? selectedSlotService.original_price
123
123
  : originalPrice;
124
- const displaySavingsPercent = selectedSlotService && selectedSlotService.original_price
125
- ? Math.round(
126
- ((selectedSlotService.original_price - selectedSlotService.final_price) /
127
- selectedSlotService.original_price) *
128
- 100,
129
- )
130
- : savingsPercent;
124
+ const displaySavingsPercent =
125
+ selectedSlotService && selectedSlotService.original_price
126
+ ? Math.round(
127
+ ((selectedSlotService.original_price -
128
+ selectedSlotService.final_price) /
129
+ selectedSlotService.original_price) *
130
+ 100,
131
+ )
132
+ : savingsPercent;
131
133
 
132
134
  // The label shown on the dropdown button
133
135
  const departureRange =
@@ -139,6 +141,9 @@ const FeatureServiceUiMobile = ({
139
141
  const isThisTimeDropdownOpen = isTimeDropdownOpen === serviceItem.id;
140
142
 
141
143
  const canDecreaseTicketQuantity = ticketQuantity > 1;
144
+ const availableSeats =
145
+ selectedSlotService?.available_seats ?? maxSeatsPerBooking;
146
+ const canIncreaseTicketQuantity = ticketQuantity < availableSeats;
142
147
 
143
148
  const HOW_IT_WORKS_STEPS = [
144
149
  {
@@ -495,11 +500,21 @@ const FeatureServiceUiMobile = ({
495
500
  type="button"
496
501
  aria-label="Aumentar pasajes"
497
502
  onClick={() => onIncreaseTicketQuantity?.(serviceItem)}
498
- className="flex h-[26px] w-[26px] cursor-pointer items-center justify-center rounded-full border-none bg-[#2d374d] text-[16px] leading-none text-[white]"
503
+ disabled={!canIncreaseTicketQuantity}
504
+ className={`flex h-[26px] w-[26px] cursor-pointer items-center justify-center rounded-full border-none text-[16px] leading-none text-[white] ${
505
+ canIncreaseTicketQuantity
506
+ ? "cursor-pointer bg-[#2d374d]"
507
+ : "cursor-not-allowed bg-[#222b3d] opacity-50"
508
+ }`}
499
509
  >
500
510
  +
501
511
  </button>
502
512
  </div>
513
+ {!canIncreaseTicketQuantity && (
514
+ <span className="text-[10px] text-[#FF5C60]">
515
+ máx. {availableSeats} pasajes
516
+ </span>
517
+ )}
503
518
  </div>
504
519
 
505
520
  <div
@@ -516,7 +531,9 @@ const FeatureServiceUiMobile = ({
516
531
  className="text-[18px] font-normal leading-[20px] text-[#9f9f9f] relative"
517
532
  style={{ position: "relative" }}
518
533
  >
519
- {`$${(displayOriginalPrice * ticketQuantity).toLocaleString()}`}
534
+ {commonService.currencyRounded(
535
+ displayOriginalPrice * ticketQuantity,
536
+ )}
520
537
  <span
521
538
  style={{
522
539
  position: "absolute",
@@ -533,7 +550,9 @@ const FeatureServiceUiMobile = ({
533
550
  />
534
551
  </span>
535
552
  <span className="text-[white] bold-text text-[24px] leading-none mt-[4px]">
536
- {`$${(displayFinalPrice * ticketQuantity).toLocaleString()}`}
553
+ {commonService.currencyRounded(
554
+ displayFinalPrice * ticketQuantity,
555
+ )}
537
556
  </span>
538
557
  </div>
539
558
  <span
@@ -549,7 +568,28 @@ const FeatureServiceUiMobile = ({
549
568
 
550
569
  <button
551
570
  type="button"
552
- onClick={onBookButtonPress}
571
+ ref={(btn) => {
572
+ if (!btn) return;
573
+ btn.onclick = () => {
574
+ if (btn.disabled) return;
575
+ btn.disabled = true;
576
+ btn.style.cursor = "not-allowed";
577
+ btn.style.opacity = "0.85";
578
+ const normal = btn.querySelector(
579
+ '[data-btn-state="normal"]',
580
+ ) as HTMLElement | null;
581
+ const loading = btn.querySelector(
582
+ '[data-btn-state="loading"]',
583
+ ) as HTMLElement | null;
584
+ if (normal) normal.style.display = "none";
585
+ if (loading) loading.style.display = "flex";
586
+ onBookButtonPress?.(
587
+ ticketQuantity,
588
+ serviceItem,
589
+ servicesInActiveSlot,
590
+ );
591
+ };
592
+ }}
553
593
  className="flex items-center gap-[6px] px-[20px] py-[10px] rounded-[16px] text-[white] bold-text text-[13px] mt-[10px] justify-center border-none cursor-pointer"
554
594
  style={{
555
595
  backgroundColor: "#FF5C60",
@@ -478,7 +478,7 @@ function SeatSection({
478
478
  >
479
479
  <div
480
480
  className="absolute"
481
- style={{ left: isPeru ? "-1px" : "-19px", bottom: "1px" }}
481
+ style={{ left: isPeru ? "-19px" : "-19px", bottom: "1px" }}
482
482
  >
483
483
  {renderIcon("fireIcon", "16px")}
484
484
  </div>
@@ -636,7 +636,7 @@ function SeatSection({
636
636
  <div
637
637
  className="absolute"
638
638
  style={{
639
- left: isPeru ? "-1px" : "-18px",
639
+ left: isPeru ? "-16px" : "-18px",
640
640
  bottom: "1px",
641
641
  }}
642
642
  >