kupos-ui-components-lib 9.11.10 → 10.0.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.
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import LottiePlayer from "../../assets/LottiePlayer";
|
|
3
3
|
import commonService from "../../utils/CommonService";
|
|
4
|
+
if (typeof document !== "undefined") {
|
|
5
|
+
if (!document.getElementById("feature-spin-style")) {
|
|
6
|
+
const style = document.createElement("style");
|
|
7
|
+
style.id = "feature-spin-style";
|
|
8
|
+
style.textContent =
|
|
9
|
+
"@keyframes feature-spin { to { transform: rotate(360deg); } }";
|
|
10
|
+
document.head.appendChild(style);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
4
13
|
const HARDCODED_OPERATORS = [
|
|
5
14
|
{
|
|
6
15
|
logo: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Turbus_logo.svg/320px-Turbus_logo.svg.png",
|
|
@@ -309,7 +318,7 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, isSoldOut, getAnimationIc
|
|
|
309
318
|
React.createElement("span", { style: { color: "#FF5C60" } }, "viendo"),
|
|
310
319
|
" |",
|
|
311
320
|
" ",
|
|
312
|
-
React.createElement("span", { className: "bold-text", ref: (node) => commonService.
|
|
321
|
+
React.createElement("span", { className: "bold-text", ref: (node) => commonService.startComprandoDealCount(node, 4, 16), style: { fontVariantNumeric: "tabular-nums" } }),
|
|
313
322
|
" ",
|
|
314
323
|
"han comprado"))),
|
|
315
324
|
React.createElement("div", { className: "flex flex-col justify-center gap-[12px] py-[2px] pl-[22px] pr-[10px] relative mb-[16px]" },
|
|
@@ -353,16 +362,42 @@ const FeatureServiceUi = ({ serviceItem, showTopLabel, isSoldOut, getAnimationIc
|
|
|
353
362
|
"m\u00E1x. ",
|
|
354
363
|
maxSeatsPerBooking,
|
|
355
364
|
" pasajes"))),
|
|
356
|
-
React.createElement("button", { type: "button",
|
|
365
|
+
React.createElement("button", { type: "button", ref: (btn) => {
|
|
366
|
+
if (!btn)
|
|
367
|
+
return;
|
|
368
|
+
btn.onclick = () => {
|
|
369
|
+
if (btn.disabled)
|
|
370
|
+
return;
|
|
371
|
+
btn.disabled = true;
|
|
372
|
+
btn.style.cursor = "not-allowed";
|
|
373
|
+
btn.style.opacity = "0.85";
|
|
374
|
+
const normal = btn.querySelector('[data-btn-state="normal"]');
|
|
375
|
+
const loading = btn.querySelector('[data-btn-state="loading"]');
|
|
376
|
+
if (normal)
|
|
377
|
+
normal.style.display = "none";
|
|
378
|
+
if (loading)
|
|
379
|
+
loading.style.display = "flex";
|
|
380
|
+
onBookButtonPress === null || onBookButtonPress === void 0 ? void 0 : onBookButtonPress(ticketQuantity, serviceItem);
|
|
381
|
+
};
|
|
382
|
+
}, className: "flex items-center gap-[6px] px-[20px] py-[10px] rounded-[16px] text-white bold-text text-[13px] mt-[4px] justify-center border-none cursor-pointer text-center", style: {
|
|
357
383
|
backgroundColor: "#FF5C60",
|
|
358
384
|
whiteSpace: "nowrap",
|
|
385
|
+
minWidth: "120px",
|
|
359
386
|
} },
|
|
360
|
-
React.createElement(
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
387
|
+
React.createElement("span", { "data-btn-state": "normal", style: { display: "flex", alignItems: "center", gap: "6px" } },
|
|
388
|
+
React.createElement(LottiePlayer, { animationData: getAnimationIcon("thunderAnimation"), width: "16px", height: "16px" }),
|
|
389
|
+
React.createElement("span", { className: "whitespace-nowrap" }, "\u00A1Lo quiero!")),
|
|
390
|
+
React.createElement("span", { "data-btn-state": "loading", style: { display: "none", alignItems: "center", gap: "6px" } },
|
|
391
|
+
React.createElement("span", { style: {
|
|
392
|
+
display: "inline-block",
|
|
393
|
+
width: "16px",
|
|
394
|
+
height: "16px",
|
|
395
|
+
border: "2px solid rgba(255,255,255,0.4)",
|
|
396
|
+
borderTopColor: "#fff",
|
|
397
|
+
borderRadius: "50%",
|
|
398
|
+
animation: "feature-spin 0.7s linear infinite",
|
|
399
|
+
flexShrink: 0,
|
|
400
|
+
} })))),
|
|
366
401
|
React.createElement("div", { className: `absolute bottom-[11px] right-[18px] cursor-pointer transition-transform duration-300 ease-in-out ${isItemExpanded ? "rotate-180" : ""}`, onClick: onToggleExpand },
|
|
367
402
|
React.createElement("img", { src: (_f = serviceItem.icons) === null || _f === void 0 ? void 0 : _f.downArrow, alt: "down arrow", style: {
|
|
368
403
|
width: "14px",
|
|
@@ -29,6 +29,7 @@ declare const commonService: {
|
|
|
29
29
|
startCountdown: (node: HTMLSpanElement | null, countdownSeconds?: number) => void;
|
|
30
30
|
startDealCountdown: (node: HTMLSpanElement | null, countdownSeconds: number) => void;
|
|
31
31
|
startComprandoCount: (node: HTMLSpanElement | null, min?: number, max?: number) => void;
|
|
32
|
+
startComprandoDealCount: (node: HTMLSpanElement | null, min?: number, max?: number) => void;
|
|
32
33
|
timeToMinutes: (time: string) => number;
|
|
33
34
|
minutesToTime: (minutes: number) => string;
|
|
34
35
|
generateTimeSlots: (from: string, to: string, windowHours: number) => Array<{
|
|
@@ -411,6 +411,41 @@ const commonService = {
|
|
|
411
411
|
node.dataset.comprandoId = String(id);
|
|
412
412
|
node.dataset.comprandoConfig = configKey;
|
|
413
413
|
},
|
|
414
|
+
startComprandoDealCount: (node, min = 4, max = 16) => {
|
|
415
|
+
if (!node)
|
|
416
|
+
return;
|
|
417
|
+
const configKey = `${min}-${max}`;
|
|
418
|
+
if (node.dataset.comprandoDealId &&
|
|
419
|
+
node.dataset.comprandoDealConfig === configKey) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const prevId = node.dataset.comprandoDealId;
|
|
423
|
+
if (prevId)
|
|
424
|
+
clearInterval(Number(prevId));
|
|
425
|
+
const initialValue = Math.floor(Math.random() * (max - min + 1)) + min;
|
|
426
|
+
node.textContent = String(initialValue);
|
|
427
|
+
const id = setInterval(() => {
|
|
428
|
+
const current = Number(node.textContent) || initialValue;
|
|
429
|
+
const changePercent = 0.05; // 5% change
|
|
430
|
+
const baseChange = Math.ceil(current * changePercent);
|
|
431
|
+
const rand = Math.random();
|
|
432
|
+
let change = baseChange;
|
|
433
|
+
if (baseChange <= 1) {
|
|
434
|
+
change = rand < 0.7 ? 1 : rand < 0.9 ? 2 : 3;
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
const variation = rand < 0.4 ? 0 : rand < 0.7 ? 1 : rand < 0.9 ? 2 : 3;
|
|
438
|
+
change = baseChange + variation;
|
|
439
|
+
}
|
|
440
|
+
// Only increase, never decrease
|
|
441
|
+
let next = current + change;
|
|
442
|
+
// Clamp within max
|
|
443
|
+
next = Math.min(max, next);
|
|
444
|
+
node.textContent = String(next);
|
|
445
|
+
}, 5000); // Update every 5 seconds
|
|
446
|
+
node.dataset.comprandoDealId = String(id);
|
|
447
|
+
node.dataset.comprandoDealConfig = configKey;
|
|
448
|
+
},
|
|
414
449
|
timeToMinutes: (time) => {
|
|
415
450
|
const [h, m] = time.split(":").map(Number);
|
|
416
451
|
return h * 60 + (m || 0);
|
package/package.json
CHANGED
|
@@ -2,6 +2,16 @@ import React from "react";
|
|
|
2
2
|
import LottiePlayer from "../../assets/LottiePlayer";
|
|
3
3
|
import commonService from "../../utils/CommonService";
|
|
4
4
|
|
|
5
|
+
if (typeof document !== "undefined") {
|
|
6
|
+
if (!document.getElementById("feature-spin-style")) {
|
|
7
|
+
const style = document.createElement("style");
|
|
8
|
+
style.id = "feature-spin-style";
|
|
9
|
+
style.textContent =
|
|
10
|
+
"@keyframes feature-spin { to { transform: rotate(360deg); } }";
|
|
11
|
+
document.head.appendChild(style);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
5
15
|
const HARDCODED_OPERATORS = [
|
|
6
16
|
{
|
|
7
17
|
logo: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Turbus_logo.svg/320px-Turbus_logo.svg.png",
|
|
@@ -523,7 +533,7 @@ const FeatureServiceUi = ({
|
|
|
523
533
|
<span
|
|
524
534
|
className="bold-text"
|
|
525
535
|
ref={(node) =>
|
|
526
|
-
commonService.
|
|
536
|
+
commonService.startComprandoDealCount(node, 4, 16)
|
|
527
537
|
}
|
|
528
538
|
style={{ fontVariantNumeric: "tabular-nums" }}
|
|
529
539
|
/>{" "}
|
|
@@ -628,20 +638,59 @@ const FeatureServiceUi = ({
|
|
|
628
638
|
|
|
629
639
|
<button
|
|
630
640
|
type="button"
|
|
631
|
-
|
|
632
|
-
|
|
641
|
+
ref={(btn) => {
|
|
642
|
+
if (!btn) return;
|
|
643
|
+
btn.onclick = () => {
|
|
644
|
+
if (btn.disabled) return;
|
|
645
|
+
btn.disabled = true;
|
|
646
|
+
btn.style.cursor = "not-allowed";
|
|
647
|
+
btn.style.opacity = "0.85";
|
|
648
|
+
const normal = btn.querySelector(
|
|
649
|
+
'[data-btn-state="normal"]',
|
|
650
|
+
) as HTMLElement | null;
|
|
651
|
+
const loading = btn.querySelector(
|
|
652
|
+
'[data-btn-state="loading"]',
|
|
653
|
+
) as HTMLElement | null;
|
|
654
|
+
if (normal) normal.style.display = "none";
|
|
655
|
+
if (loading) loading.style.display = "flex";
|
|
656
|
+
onBookButtonPress?.(ticketQuantity, serviceItem);
|
|
657
|
+
};
|
|
658
|
+
}}
|
|
659
|
+
className="flex items-center gap-[6px] px-[20px] py-[10px] rounded-[16px] text-white bold-text text-[13px] mt-[4px] justify-center border-none cursor-pointer text-center"
|
|
633
660
|
style={{
|
|
634
661
|
backgroundColor: "#FF5C60",
|
|
635
662
|
whiteSpace: "nowrap",
|
|
663
|
+
minWidth: "120px",
|
|
636
664
|
}}
|
|
637
665
|
>
|
|
638
|
-
<
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
666
|
+
<span
|
|
667
|
+
data-btn-state="normal"
|
|
668
|
+
style={{ display: "flex", alignItems: "center", gap: "6px" }}
|
|
669
|
+
>
|
|
670
|
+
<LottiePlayer
|
|
671
|
+
animationData={getAnimationIcon("thunderAnimation")}
|
|
672
|
+
width="16px"
|
|
673
|
+
height="16px"
|
|
674
|
+
/>
|
|
675
|
+
<span className="whitespace-nowrap">¡Lo quiero!</span>
|
|
676
|
+
</span>
|
|
677
|
+
<span
|
|
678
|
+
data-btn-state="loading"
|
|
679
|
+
style={{ display: "none", alignItems: "center", gap: "6px" }}
|
|
680
|
+
>
|
|
681
|
+
<span
|
|
682
|
+
style={{
|
|
683
|
+
display: "inline-block",
|
|
684
|
+
width: "16px",
|
|
685
|
+
height: "16px",
|
|
686
|
+
border: "2px solid rgba(255,255,255,0.4)",
|
|
687
|
+
borderTopColor: "#fff",
|
|
688
|
+
borderRadius: "50%",
|
|
689
|
+
animation: "feature-spin 0.7s linear infinite",
|
|
690
|
+
flexShrink: 0,
|
|
691
|
+
}}
|
|
692
|
+
/>
|
|
693
|
+
</span>
|
|
645
694
|
</button>
|
|
646
695
|
</div>
|
|
647
696
|
|
|
@@ -482,6 +482,54 @@ const commonService = {
|
|
|
482
482
|
node.dataset.comprandoConfig = configKey;
|
|
483
483
|
},
|
|
484
484
|
|
|
485
|
+
startComprandoDealCount: (
|
|
486
|
+
node: HTMLSpanElement | null,
|
|
487
|
+
min: number = 4,
|
|
488
|
+
max: number = 16,
|
|
489
|
+
) => {
|
|
490
|
+
if (!node) return;
|
|
491
|
+
|
|
492
|
+
const configKey = `${min}-${max}`;
|
|
493
|
+
if (
|
|
494
|
+
node.dataset.comprandoDealId &&
|
|
495
|
+
node.dataset.comprandoDealConfig === configKey
|
|
496
|
+
) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const prevId = node.dataset.comprandoDealId;
|
|
501
|
+
if (prevId) clearInterval(Number(prevId));
|
|
502
|
+
|
|
503
|
+
const initialValue = Math.floor(Math.random() * (max - min + 1)) + min;
|
|
504
|
+
node.textContent = String(initialValue);
|
|
505
|
+
|
|
506
|
+
const id = setInterval(() => {
|
|
507
|
+
const current = Number(node.textContent) || initialValue;
|
|
508
|
+
const changePercent = 0.05; // 5% change
|
|
509
|
+
const baseChange = Math.ceil(current * changePercent);
|
|
510
|
+
|
|
511
|
+
const rand = Math.random();
|
|
512
|
+
let change = baseChange;
|
|
513
|
+
if (baseChange <= 1) {
|
|
514
|
+
change = rand < 0.7 ? 1 : rand < 0.9 ? 2 : 3;
|
|
515
|
+
} else {
|
|
516
|
+
const variation = rand < 0.4 ? 0 : rand < 0.7 ? 1 : rand < 0.9 ? 2 : 3;
|
|
517
|
+
change = baseChange + variation;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Only increase, never decrease
|
|
521
|
+
let next = current + change;
|
|
522
|
+
|
|
523
|
+
// Clamp within max
|
|
524
|
+
next = Math.min(max, next);
|
|
525
|
+
|
|
526
|
+
node.textContent = String(next);
|
|
527
|
+
}, 5000); // Update every 5 seconds
|
|
528
|
+
|
|
529
|
+
node.dataset.comprandoDealId = String(id);
|
|
530
|
+
node.dataset.comprandoDealConfig = configKey;
|
|
531
|
+
},
|
|
532
|
+
|
|
485
533
|
timeToMinutes: (time: string): number => {
|
|
486
534
|
const [h, m] = time.split(":").map(Number);
|
|
487
535
|
return h * 60 + (m || 0);
|