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 +7 -0
- package/dist/ui/FeatureServiceUI/FeatureServiceUi.js +5 -4
- package/dist/ui/SeatSection/SeatSection.js +11 -3
- package/dist/ui/mobileweb/SeatSectionMobile.js +9 -1
- package/dist/utils/CommonService.d.ts +1 -0
- package/dist/utils/CommonService.js +33 -0
- package/package.json +1 -1
- package/src/ui/FeatureServiceUI/FeatureServiceUi.tsx +12 -10
- package/src/ui/SeatSection/SeatSection.tsx +25 -4
- package/src/ui/mobileweb/SeatSectionMobile.tsx +11 -1
- package/src/utils/CommonService.ts +39 -0
package/dist/styles.css
CHANGED
|
@@ -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 -
|
|
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.
|
|
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" } }, "
|
|
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
|
@@ -120,13 +120,15 @@ const FeatureServiceUi = ({
|
|
|
120
120
|
const displayOriginalPrice = selectedSlotService
|
|
121
121
|
? selectedSlotService.original_price
|
|
122
122
|
: originalPrice;
|
|
123
|
-
const displaySavingsPercent =
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
selectedSlotService.original_price
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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,
|