kupos-ui-components-lib 9.10.10 → 9.11.0

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/styles.css CHANGED
@@ -1274,6 +1274,13 @@
1274
1274
  }
1275
1275
  }
1276
1276
  }
1277
+ .hover\:z-\[200\] {
1278
+ &:hover {
1279
+ @media (hover: hover) {
1280
+ z-index: 200;
1281
+ }
1282
+ }
1283
+ }
1277
1284
  .hover\:z-\[500\] {
1278
1285
  &:hover {
1279
1286
  @media (hover: hover) {
@@ -86,7 +86,8 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, isSoldOut, getAnimationIc
86
86
  ? selectedSlotService.original_price
87
87
  : originalPrice;
88
88
  const displaySavingsPercent = selectedSlotService && selectedSlotService.original_price
89
- ? Math.round(((selectedSlotService.original_price - selectedSlotService.final_price) /
89
+ ? Math.round(((selectedSlotService.original_price -
90
+ selectedSlotService.final_price) /
90
91
  selectedSlotService.original_price) *
91
92
  100)
92
93
  : savingsPercent;
@@ -173,7 +174,7 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, isSoldOut, getAnimationIc
173
174
  animationData: getAnimationIcon("flameAnimation"), width: "18px", height: "18px" })),
174
175
  React.createElement("span", { className: "bold-text" }, "Remate"),
175
176
  "\u00A0t\u00E9rmina en \u00A0",
176
- React.createElement("span", { className: "bold-text text-end", ref: (node) => commonService.startCountdown(node, getCountdownSeconds()), style: {
177
+ React.createElement("span", { className: "bold-text text-end", ref: (node) => commonService.startDealCountdown(node, getCountdownSeconds()), style: {
177
178
  fontVariantNumeric: "tabular-nums",
178
179
  display: "inline-block",
179
180
  color: "#FF5C60",
@@ -210,7 +211,7 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, isSoldOut, getAnimationIc
210
211
  filter: "brightness(0) invert(1)",
211
212
  } })),
212
213
  isThisTimeDropdownOpen && (React.createElement(React.Fragment, null,
213
- React.createElement("div", { className: "absolute left-0 top-[calc(100%+10px)]", style: {
214
+ React.createElement("div", { className: "absolute left-0 top-[calc(100%+10px)] hover:z-[200]", style: {
214
215
  zIndex: 20,
215
216
  backgroundColor: "#fff",
216
217
  borderRadius: "14px",
@@ -282,7 +283,7 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, isSoldOut, getAnimationIc
282
283
  ((_a = serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_details) === null || _a === void 0 ? void 0 : _a[0]) ||
283
284
  "/images/service-list/bus-icon.svg";
284
285
  }, className: `h-[24px] max-w-full object-contain ${isSoldOut ? "grayscale" : ""}` }),
285
- React.createElement("span", { className: "text-[11px] truncate max-w-full text-center text-[white]" }, op.name),
286
+ React.createElement("span", { className: "text-[11px] truncate max-w-full text-center text-[white] whitespace-nowrap " }, op.name),
286
287
  React.createElement("div", { className: "bg-[#FF8F45] text-white text-[12px] font-bold px-[10px] py-[4px] rounded-[4px] bold-text whitespace-nowrap" },
287
288
  React.createElement("span", null, op === null || op === void 0 ? void 0 : op.time)),
288
289
  React.createElement("span", { className: "text-[10px] mt-[6px] text-[white]" }, op === null || op === void 0 ? void 0 : op.seatsAvailable))))),
@@ -58,6 +58,7 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
58
58
  var _a;
59
59
  const uniqueSeats = getUniqueSeats(seatTypes);
60
60
  const sortedSeatTypes = getSortedSeatTypes(seatTypes);
61
+ console.log("🚀 ~ SeatSection ~ sortedSeatTypes:", sortedSeatTypes);
61
62
  const numberOfSeats = getNumberOfSeats(seatTypes);
62
63
  const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
63
64
  const formatPrice = (price) => availableSeats <= 0
@@ -116,13 +117,20 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
116
117
  })();
117
118
  const renderLabels = () => {
118
119
  if (isPeru) {
120
+ const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
121
+ const filteredSeats = seats.filter((s) => !SEAT_EXCEPTIONS.includes(s.label));
122
+ const seatLabel = filteredSeats.length > 0
123
+ ? removeDuplicateSeats
124
+ ? CommonService.truncateSeatLabel(filteredSeats[0].label)
125
+ : filteredSeats[0].label
126
+ : null;
127
+ const operatorServiceName = (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_service_name) === "MovilBus";
128
+ const bottomLabel = operatorServiceName || "Desde";
119
129
  return (React.createElement(React.Fragment, null,
120
130
  hasDiscount && (React.createElement("span", { className: "text-[13.33px]", style: {
121
131
  color: "#999",
122
- // position: "relative",
123
- // bottom: numberOfSeats ? "10px" : "",
124
132
  } }, "Antes")),
125
- React.createElement("span", { className: "text-[13.33px]" }, "Desde")));
133
+ React.createElement("span", { className: "text-[13.33px] flex flex-col" }, operatorServiceName ? (React.createElement("span", { className: "text-[13.33px]" }, seatLabel)) : (React.createElement("span", { className: "text-[13.33px]" }, "Desde")))));
126
134
  }
127
135
  return renderSeatNames();
128
136
  };
@@ -65,12 +65,20 @@ function SeatSectionMobile({ seatTypes: seatTypesData, isSoldOut, isPeru, seatPr
65
65
  return null;
66
66
  const priceColor = isSoldOut ? "#bbb" : seatPriceColor;
67
67
  const { originalPrice, discountedPrice } = commonService.calculateDiscountedPrice(lowestFare, serviceItem);
68
+ const isMovilBus = (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_service_name) === "MovilBus";
69
+ const uniqueSeats = getUniqueSeats(seatTypesData !== null && seatTypesData !== void 0 ? seatTypesData : [], 1);
70
+ const seatLabel = uniqueSeats.length > 0
71
+ ? commonService.truncateSeatLabel(uniqueSeats[0].label)
72
+ : null;
73
+ const bottomLabel = isMovilBus ? seatLabel || "Desde" : "Desde";
68
74
  return (React.createElement(React.Fragment, null,
69
75
  originalPrice !== discountedPrice && (React.createElement("div", { className: "w-[100%] flex flex-row justify-between items-center" },
70
76
  React.createElement("span", { className: "min-[420]:text-[13px] text-[12px]", style: { color: "#bbb" } }, "Antes"),
71
77
  React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] line-through", style: { color: "#bbb" } }, commonService.currency(originalPrice, currencySign)))),
72
78
  React.createElement("div", { className: "w-[100%] flex flex-row justify-between items-center" },
73
- React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: isSoldOut ? "#bbb" : "#464647" } }, "Desde"),
79
+ React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: isSoldOut ? "#bbb" : "#464647" } }, (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.operator_service_name) === "MovilBus"
80
+ ? seatLabel
81
+ : "Desde"),
74
82
  React.createElement("span", { className: "min-[420]:text-[13px] text-[12px] bold-text", style: { color: priceColor } }, commonService.currency(discountedPrice, currencySign)))));
75
83
  };
76
84
  const renderDpSeats = () => {
@@ -27,6 +27,7 @@ declare const commonService: {
27
27
  interval?: number;
28
28
  }) => void;
29
29
  startCountdown: (node: HTMLSpanElement | null, countdownSeconds?: number) => void;
30
+ startDealCountdown: (node: HTMLSpanElement | null, countdownSeconds: number) => void;
30
31
  startComprandoCount: (node: HTMLSpanElement | null, min?: number, max?: number) => void;
31
32
  timeToMinutes: (time: string) => number;
32
33
  minutesToTime: (minutes: number) => string;
@@ -348,6 +348,39 @@ const commonService = {
348
348
  }, 1000);
349
349
  node.dataset.countdownId = String(id);
350
350
  },
351
+ startDealCountdown: (node, countdownSeconds) => {
352
+ if (!node)
353
+ return;
354
+ if (node.dataset.dealTimerStarted)
355
+ return;
356
+ node.dataset.dealTimerStarted = "true";
357
+ const prevId = node.dataset.dealCountdownId;
358
+ if (prevId)
359
+ clearInterval(Number(prevId));
360
+ let remaining = Math.max(0, Math.floor(countdownSeconds));
361
+ const formatTime = (totalSeconds) => {
362
+ if (totalSeconds <= 0)
363
+ return "Expirado";
364
+ const h = Math.floor(totalSeconds / 3600);
365
+ const m = Math.floor((totalSeconds % 3600) / 60);
366
+ const s = totalSeconds % 60;
367
+ if (h > 0) {
368
+ return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
369
+ }
370
+ return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
371
+ };
372
+ node.textContent = formatTime(remaining);
373
+ if (remaining <= 0)
374
+ return;
375
+ const id = setInterval(() => {
376
+ remaining -= 1;
377
+ node.textContent = formatTime(remaining);
378
+ if (remaining <= 0) {
379
+ clearInterval(Number(node.dataset.dealCountdownId));
380
+ }
381
+ }, 1000);
382
+ node.dataset.dealCountdownId = String(id);
383
+ },
351
384
  startComprandoCount: (node, min = 4, max = 16) => {
352
385
  if (!node)
353
386
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kupos-ui-components-lib",
3
- "version": "9.10.10",
3
+ "version": "9.11.0",
4
4
  "description": "A reusable UI components package",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -120,13 +120,15 @@ const FeatureServiceUi = ({
120
120
  const displayOriginalPrice = selectedSlotService
121
121
  ? selectedSlotService.original_price
122
122
  : originalPrice;
123
- const displaySavingsPercent = selectedSlotService && selectedSlotService.original_price
124
- ? Math.round(
125
- ((selectedSlotService.original_price - selectedSlotService.final_price) /
126
- selectedSlotService.original_price) *
127
- 100,
128
- )
129
- : savingsPercent;
123
+ const displaySavingsPercent =
124
+ selectedSlotService && selectedSlotService.original_price
125
+ ? Math.round(
126
+ ((selectedSlotService.original_price -
127
+ selectedSlotService.final_price) /
128
+ selectedSlotService.original_price) *
129
+ 100,
130
+ )
131
+ : savingsPercent;
130
132
 
131
133
  // The label shown on the dropdown button
132
134
  const departureRange =
@@ -231,7 +233,7 @@ const FeatureServiceUi = ({
231
233
  <span
232
234
  className="bold-text text-end"
233
235
  ref={(node) =>
234
- commonService.startCountdown(node, getCountdownSeconds())
236
+ commonService.startDealCountdown(node, getCountdownSeconds())
235
237
  }
236
238
  style={{
237
239
  fontVariantNumeric: "tabular-nums",
@@ -326,7 +328,7 @@ const FeatureServiceUi = ({
326
328
  {isThisTimeDropdownOpen && (
327
329
  <>
328
330
  <div
329
- className="absolute left-0 top-[calc(100%+10px)]"
331
+ className="absolute left-0 top-[calc(100%+10px)] hover:z-[200]"
330
332
  style={{
331
333
  zIndex: 20,
332
334
  backgroundColor: "#fff",
@@ -472,7 +474,7 @@ const FeatureServiceUi = ({
472
474
  isSoldOut ? "grayscale" : ""
473
475
  }`}
474
476
  />
475
- <span className="text-[11px] truncate max-w-full text-center text-[white]">
477
+ <span className="text-[11px] truncate max-w-full text-center text-[white] whitespace-nowrap ">
476
478
  {op.name}
477
479
  </span>
478
480
  <div className="bg-[#FF8F45] text-white text-[12px] font-bold px-[10px] py-[4px] rounded-[4px] bold-text whitespace-nowrap">
@@ -107,6 +107,7 @@ function SeatSection({
107
107
  }: SeatSectionProps): React.ReactElement {
108
108
  const uniqueSeats = getUniqueSeats(seatTypes);
109
109
  const sortedSeatTypes = getSortedSeatTypes(seatTypes);
110
+ console.log("🚀 ~ SeatSection ~ sortedSeatTypes:", sortedSeatTypes);
110
111
  const numberOfSeats = getNumberOfSeats(seatTypes);
111
112
  const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
112
113
 
@@ -217,6 +218,21 @@ function SeatSection({
217
218
 
218
219
  const renderLabels = () => {
219
220
  if (isPeru) {
221
+ const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
222
+ const filteredSeats = seats.filter(
223
+ (s) => !SEAT_EXCEPTIONS.includes(s.label),
224
+ );
225
+ const seatLabel =
226
+ filteredSeats.length > 0
227
+ ? removeDuplicateSeats
228
+ ? CommonService.truncateSeatLabel(filteredSeats[0].label)
229
+ : filteredSeats[0].label
230
+ : null;
231
+
232
+ const operatorServiceName =
233
+ serviceItem?.operator_service_name === "MovilBus";
234
+ const bottomLabel = operatorServiceName || "Desde";
235
+
220
236
  return (
221
237
  <>
222
238
  {hasDiscount && (
@@ -224,14 +240,19 @@ function SeatSection({
224
240
  className="text-[13.33px]"
225
241
  style={{
226
242
  color: "#999",
227
- // position: "relative",
228
- // bottom: numberOfSeats ? "10px" : "",
229
243
  }}
230
244
  >
231
245
  Antes
232
246
  </span>
233
247
  )}
234
- <span className="text-[13.33px]">Desde</span>
248
+
249
+ <span className="text-[13.33px] flex flex-col">
250
+ {operatorServiceName ? (
251
+ <span className="text-[13.33px]">{seatLabel}</span>
252
+ ) : (
253
+ <span className="text-[13.33px]">Desde</span>
254
+ )}
255
+ </span>
235
256
  </>
236
257
  );
237
258
  }
@@ -318,7 +339,7 @@ function SeatSection({
318
339
  <div className="col-start-2 row-start-3 flex h-[30px] items-end justify-center relative">
319
340
  <span
320
341
  className="flex items-center gap-[6px] text-[22px] bold-text leading-[30px]"
321
- style={{ color: isSoldOut ? "#c0c0c0" : dpSeatColor||"#ff5964" }}
342
+ style={{ color: isSoldOut ? "#c0c0c0" : dpSeatColor || "#ff5964" }}
322
343
  >
323
344
  <div
324
345
  className="absolute"
@@ -152,6 +152,14 @@ function SeatSectionMobile({
152
152
  const { originalPrice, discountedPrice } =
153
153
  commonService.calculateDiscountedPrice(lowestFare, serviceItem);
154
154
 
155
+ const isMovilBus = serviceItem?.operator_service_name === "MovilBus";
156
+ const uniqueSeats = getUniqueSeats(seatTypesData ?? [], 1);
157
+ const seatLabel =
158
+ uniqueSeats.length > 0
159
+ ? commonService.truncateSeatLabel(uniqueSeats[0].label)
160
+ : null;
161
+ const bottomLabel = isMovilBus ? seatLabel || "Desde" : "Desde";
162
+
155
163
  return (
156
164
  <>
157
165
  {originalPrice !== discountedPrice && (
@@ -175,7 +183,9 @@ function SeatSectionMobile({
175
183
  className="min-[420]:text-[13px] text-[12px] bold-text"
176
184
  style={{ color: isSoldOut ? "#bbb" : "#464647" }}
177
185
  >
178
- Desde
186
+ {serviceItem?.operator_service_name === "MovilBus"
187
+ ? seatLabel
188
+ : "Desde"}
179
189
  </span>
180
190
  <span
181
191
  className="min-[420]:text-[13px] text-[12px] bold-text"
@@ -399,6 +399,45 @@ const commonService = {
399
399
  node.dataset.countdownId = String(id);
400
400
  },
401
401
 
402
+ startDealCountdown: (
403
+ node: HTMLSpanElement | null,
404
+ countdownSeconds: number,
405
+ ) => {
406
+ if (!node) return;
407
+ if (node.dataset.dealTimerStarted) return;
408
+ node.dataset.dealTimerStarted = "true";
409
+
410
+ const prevId = node.dataset.dealCountdownId;
411
+ if (prevId) clearInterval(Number(prevId));
412
+
413
+ let remaining = Math.max(0, Math.floor(countdownSeconds));
414
+
415
+ const formatTime = (totalSeconds: number) => {
416
+ if (totalSeconds <= 0) return "Expirado";
417
+ const h = Math.floor(totalSeconds / 3600);
418
+ const m = Math.floor((totalSeconds % 3600) / 60);
419
+ const s = totalSeconds % 60;
420
+ if (h > 0) {
421
+ return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
422
+ }
423
+ return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
424
+ };
425
+
426
+ node.textContent = formatTime(remaining);
427
+
428
+ if (remaining <= 0) return;
429
+
430
+ const id = setInterval(() => {
431
+ remaining -= 1;
432
+ node.textContent = formatTime(remaining);
433
+ if (remaining <= 0) {
434
+ clearInterval(Number(node.dataset.dealCountdownId));
435
+ }
436
+ }, 1000);
437
+
438
+ node.dataset.dealCountdownId = String(id);
439
+ },
440
+
402
441
  startComprandoCount: (
403
442
  node: HTMLSpanElement | null,
404
443
  min: number = 4,