kupos-ui-components-lib 9.9.1 → 9.9.2
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/KuposUIComponent.d.ts +3 -0
- package/dist/components/ServiceItem/PeruServiceItemDesktop.d.ts +1 -1
- package/dist/components/ServiceItem/PeruServiceItemDesktop.js +2 -2
- package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemDesktop.js +30 -31
- package/dist/components/ServiceItem/ServiceItemMobile.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemMobile.js +43 -17
- package/dist/components/ServiceItem/mobileTypes.d.ts +48 -1
- package/dist/components/ServiceItem/types.d.ts +27 -9
- package/dist/styles.css +215 -6
- package/dist/ui/ExpendedDropDown/ExpandedDropdown.d.ts +1 -2
- package/dist/ui/ExpendedDropDown/ExpandedDropdown.js +2 -4
- package/dist/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.js +22 -41
- package/dist/ui/FeatureServiceUI/FeatureServiceUi.js +24 -44
- package/dist/ui/OfferBanner.d.ts +2 -0
- package/dist/ui/OfferBanner.js +19 -14
- package/dist/ui/SeatSection/SeatSection.d.ts +1 -7
- package/dist/ui/SeatSection/SeatSection.js +12 -44
- package/dist/utils/CommonService.d.ts +3 -0
- package/dist/utils/CommonService.js +18 -1
- package/package.json +1 -1
- package/src/KuposUIComponent.tsx +3 -0
- package/src/assets/images/anims/service_list/flame_anim.json +1 -0
- package/src/assets/images/anims/service_list/thunder_icon.json +1 -0
- package/src/assets/images/anims/service_list/users_anim.json +1 -0
- package/src/components/ServiceItem/PeruServiceItemDesktop.tsx +35 -24
- package/src/components/ServiceItem/ServiceItemDesktop.tsx +65 -53
- package/src/components/ServiceItem/ServiceItemMobile.tsx +387 -288
- package/src/components/ServiceItem/mobileTypes.ts +50 -7
- package/src/components/ServiceItem/types.ts +39 -25
- package/src/styles.css +15 -0
- package/src/ui/ExpendedDropDown/ExpandedDropdown.tsx +2 -4
- package/src/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.tsx +575 -0
- package/src/ui/FeatureServiceUI/FeatureServiceUi.tsx +610 -0
- package/src/ui/OfferBanner.tsx +31 -10
- package/src/ui/SeatSection/SeatSection.tsx +21 -88
- package/src/utils/CommonService.ts +26 -1
package/src/ui/OfferBanner.tsx
CHANGED
|
@@ -18,7 +18,9 @@ interface OfferBannerProps {
|
|
|
18
18
|
showLoginModal: any;
|
|
19
19
|
viewersConfig: ServiceItemProps["viewersConfig"];
|
|
20
20
|
getAnimationIcon: (name: string) => any;
|
|
21
|
-
showLoginOption?: boolean
|
|
21
|
+
showLoginOption?: boolean
|
|
22
|
+
isNewUiEnabled?: boolean;
|
|
23
|
+
colors: any;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
@@ -31,12 +33,14 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
31
33
|
viewersConfig,
|
|
32
34
|
getAnimationIcon,
|
|
33
35
|
showLoginOption,
|
|
36
|
+
isNewUiEnabled,
|
|
37
|
+
colors,
|
|
34
38
|
}) => {
|
|
35
39
|
return (
|
|
36
40
|
<div
|
|
37
|
-
className="text-white p-[10px_15px] text-left w-full flex items-center absolute -bottom-[
|
|
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]"
|
|
38
42
|
style={{
|
|
39
|
-
background: offerGradient,
|
|
43
|
+
background: serviceItem?.offer_text && !isNewUiEnabled ? colors?.bottomStripColor : offerGradient,
|
|
40
44
|
opacity: isSoldOut ? 0.5 : 1,
|
|
41
45
|
// zIndex: 0,
|
|
42
46
|
}}
|
|
@@ -57,6 +61,7 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
57
61
|
<span>Servicio popular entre los usuarios</span>
|
|
58
62
|
</div>
|
|
59
63
|
) : (
|
|
64
|
+
(isNewUiEnabled && serviceItem?.offer_text) ? (
|
|
60
65
|
<div className="flex items-center">
|
|
61
66
|
<LottiePlayer
|
|
62
67
|
animationData={getAnimationIcon("bombAnimation")}
|
|
@@ -73,18 +78,14 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
73
78
|
{(serviceItem?.offer_text || "").length > 30
|
|
74
79
|
? (serviceItem?.offer_text || "").slice(0, 30) + "..."
|
|
75
80
|
: serviceItem?.offer_text || ""}{" "}
|
|
76
|
-
{isLoggedIn && showLoginOption ? null :
|
|
77
|
-
serviceItem?.dp_discount_percents ?? {},
|
|
78
|
-
).length > 0 ||
|
|
79
|
-
(serviceItem?.dp_discounted_seats ?? []).length >
|
|
80
|
-
0 ? null : (
|
|
81
|
+
{isLoggedIn && showLoginOption ? null : (
|
|
81
82
|
<span onClick={showLoginModal} className="cursor-pointer">
|
|
82
83
|
- registro
|
|
83
84
|
</span>
|
|
84
85
|
)}{" "}
|
|
85
86
|
|
|
86
87
|
</span>{" "}
|
|
87
|
-
{serviceItem?.offer_text ? "|
|
|
88
|
+
{serviceItem?.offer_text ? "|" : ""}
|
|
88
89
|
Termina en
|
|
89
90
|
<span
|
|
90
91
|
className="bold-text text-end"
|
|
@@ -95,9 +96,28 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
95
96
|
}}
|
|
96
97
|
/>
|
|
97
98
|
</div>
|
|
98
|
-
</div>
|
|
99
|
+
</div>)
|
|
100
|
+
: (serviceItem?.offer_text && !isNewUiEnabled) && (
|
|
101
|
+
<div className="flex items-center">
|
|
102
|
+
<LottiePlayer
|
|
103
|
+
animationData={getAnimationIcon("promoAnim")}
|
|
104
|
+
width="18px"
|
|
105
|
+
height="18px"
|
|
106
|
+
/>
|
|
107
|
+
<div className="flex items-center mt-[2px]">
|
|
108
|
+
<span
|
|
109
|
+
className="bold-text"
|
|
110
|
+
style={{
|
|
111
|
+
marginLeft: serviceItem?.offer_text ? "6px" : "3px",
|
|
112
|
+
}}
|
|
113
|
+
>
|
|
114
|
+
{(serviceItem?.offer_text || "")}
|
|
115
|
+
</span>{" "}
|
|
116
|
+
</div>
|
|
117
|
+
</div>)
|
|
99
118
|
)}
|
|
100
119
|
</div>
|
|
120
|
+
{(isNewUiEnabled || serviceItem?.is_dp_enabled) && (
|
|
101
121
|
<div className="flex items-center">
|
|
102
122
|
{/* {renderIcon("personIcon", "16px")} */}
|
|
103
123
|
<LottiePlayer
|
|
@@ -135,6 +155,7 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
135
155
|
</span>
|
|
136
156
|
</span>
|
|
137
157
|
</div>
|
|
158
|
+
)}
|
|
138
159
|
</div>
|
|
139
160
|
</div>
|
|
140
161
|
);
|
|
@@ -7,8 +7,6 @@ interface SeatType {
|
|
|
7
7
|
label: string;
|
|
8
8
|
fare: number;
|
|
9
9
|
key: any;
|
|
10
|
-
apiSeatType?: string;
|
|
11
|
-
api_seat_type?: string;
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
interface SeatSectionProps {
|
|
@@ -23,15 +21,6 @@ interface SeatSectionProps {
|
|
|
23
21
|
serviceItem?: any;
|
|
24
22
|
renderIcon?: (iconKey: string, size?: string) => React.ReactNode;
|
|
25
23
|
discountSeatPriceColor?: string;
|
|
26
|
-
isTrain?: boolean;
|
|
27
|
-
selectedSeatKey?: any;
|
|
28
|
-
onSeatSelect?: (
|
|
29
|
-
key: any,
|
|
30
|
-
price: number,
|
|
31
|
-
seatKey: string,
|
|
32
|
-
apiSeatType?: string,
|
|
33
|
-
) => void;
|
|
34
|
-
topLabelColor?: string;
|
|
35
24
|
}
|
|
36
25
|
|
|
37
26
|
function getAllSeatTypes(seatTypes: SeatType[]) {
|
|
@@ -42,8 +31,6 @@ function getAllSeatTypes(seatTypes: SeatType[]) {
|
|
|
42
31
|
let seatTypesWithPrices = seatTypes.filter(Boolean).map((val) => ({
|
|
43
32
|
label: val?.label,
|
|
44
33
|
price: val?.fare,
|
|
45
|
-
key: val?.key,
|
|
46
|
-
apiSeatType: val?.apiSeatType || val?.api_seat_type,
|
|
47
34
|
}));
|
|
48
35
|
|
|
49
36
|
seatTypesWithPrices.sort((a, b) => a.price - b.price);
|
|
@@ -51,7 +38,7 @@ function getAllSeatTypes(seatTypes: SeatType[]) {
|
|
|
51
38
|
return seatTypesWithPrices;
|
|
52
39
|
}
|
|
53
40
|
|
|
54
|
-
function getSortedSeatTypes(seatTypes: SeatType[]
|
|
41
|
+
function getSortedSeatTypes(seatTypes: SeatType[]) {
|
|
55
42
|
if (!seatTypes?.length) {
|
|
56
43
|
return [{ label: "Salon cama", price: 0 }];
|
|
57
44
|
}
|
|
@@ -65,11 +52,7 @@ function getSortedSeatTypes(seatTypes: SeatType[], isTrain: any) {
|
|
|
65
52
|
seatTypesWithPrices[2] = seatTypesWithPrices[premiumIndex];
|
|
66
53
|
}
|
|
67
54
|
|
|
68
|
-
|
|
69
|
-
seatTypesWithPrices = seatTypesWithPrices.slice(0, 4);
|
|
70
|
-
} else {
|
|
71
|
-
seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
|
|
72
|
-
}
|
|
55
|
+
seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
|
|
73
56
|
|
|
74
57
|
const seenPrices = new Set<number>();
|
|
75
58
|
seatTypesWithPrices = seatTypesWithPrices.filter((seat) => {
|
|
@@ -114,18 +97,14 @@ function SeatSection({
|
|
|
114
97
|
priceColor,
|
|
115
98
|
currencySign,
|
|
116
99
|
removeDuplicateSeats,
|
|
117
|
-
selectedSeatKey,
|
|
118
|
-
onSeatSelect,
|
|
119
100
|
isPeru,
|
|
120
101
|
serviceItem,
|
|
121
102
|
renderIcon,
|
|
122
103
|
dpSeatColor,
|
|
123
104
|
discountSeatPriceColor,
|
|
124
|
-
isTrain,
|
|
125
|
-
topLabelColor,
|
|
126
105
|
}: SeatSectionProps): React.ReactElement {
|
|
127
106
|
const uniqueSeats = getUniqueSeats(seatTypes);
|
|
128
|
-
const sortedSeatTypes = getSortedSeatTypes(seatTypes
|
|
107
|
+
const sortedSeatTypes = getSortedSeatTypes(seatTypes);
|
|
129
108
|
const numberOfSeats = getNumberOfSeats(seatTypes);
|
|
130
109
|
const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
|
|
131
110
|
|
|
@@ -137,68 +116,22 @@ function SeatSection({
|
|
|
137
116
|
const renderSeatNames = () => {
|
|
138
117
|
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
139
118
|
|
|
140
|
-
return seats.map((val, key: number) =>
|
|
141
|
-
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
? () =>
|
|
148
|
-
val.label === selectedSeatKey
|
|
149
|
-
? onSeatSelect?.(null, 0, "", "")
|
|
150
|
-
: onSeatSelect?.(
|
|
151
|
-
val.label,
|
|
152
|
-
val.price,
|
|
153
|
-
val.key,
|
|
154
|
-
(val as any).apiSeatType,
|
|
155
|
-
)
|
|
156
|
-
: undefined
|
|
157
|
-
}
|
|
119
|
+
return seats.map((val, key: number) =>
|
|
120
|
+
SEAT_EXCEPTIONS.includes(val.label) ? null : (
|
|
121
|
+
<span
|
|
122
|
+
key={key}
|
|
123
|
+
className={`flex items-center justify-between text-[13.33px] ${
|
|
124
|
+
isSoldOut ? "text-[#c0c0c0]" : ""
|
|
125
|
+
}`}
|
|
158
126
|
>
|
|
159
|
-
{
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
marginRight: "10px",
|
|
168
|
-
display: "flex",
|
|
169
|
-
alignItems: "center",
|
|
170
|
-
justifyContent: "center",
|
|
171
|
-
}}
|
|
172
|
-
>
|
|
173
|
-
{val.label === selectedSeatKey && (
|
|
174
|
-
<div
|
|
175
|
-
style={{
|
|
176
|
-
backgroundColor: topLabelColor,
|
|
177
|
-
borderRadius: "50%",
|
|
178
|
-
width: "7px",
|
|
179
|
-
height: "7px",
|
|
180
|
-
}}
|
|
181
|
-
/>
|
|
182
|
-
)}
|
|
183
|
-
</div>
|
|
184
|
-
)}
|
|
185
|
-
<span
|
|
186
|
-
key={key}
|
|
187
|
-
className={`flex items-center justify-between text-[13.33px] ${
|
|
188
|
-
isSoldOut ? "text-[#c0c0c0]" : ""
|
|
189
|
-
}`}
|
|
190
|
-
>
|
|
191
|
-
{typeof val.label === "string" || typeof val.label === "number"
|
|
192
|
-
? removeDuplicateSeats && isPeru
|
|
193
|
-
? CommonService.truncateSeatLabel(val.label)
|
|
194
|
-
: isTrain
|
|
195
|
-
? CommonService.truncateSeatLabel(val.label)
|
|
196
|
-
: val.label
|
|
197
|
-
: null}
|
|
198
|
-
</span>
|
|
199
|
-
</div>
|
|
200
|
-
);
|
|
201
|
-
});
|
|
127
|
+
{typeof val.label === "string" || typeof val.label === "number"
|
|
128
|
+
? removeDuplicateSeats && isPeru
|
|
129
|
+
? CommonService.truncateSeatLabel(val.label)
|
|
130
|
+
: val.label
|
|
131
|
+
: null}
|
|
132
|
+
</span>
|
|
133
|
+
),
|
|
134
|
+
);
|
|
202
135
|
};
|
|
203
136
|
|
|
204
137
|
const renderSeatPrices = () => {
|
|
@@ -344,7 +277,7 @@ function SeatSection({
|
|
|
344
277
|
{!isNaN(Number(dpDiscountPercent)) &&
|
|
345
278
|
Number(dpDiscountPercent) > 0 && (
|
|
346
279
|
<span
|
|
347
|
-
className=
|
|
280
|
+
className={`rounded-[100px] ${discountSeatPriceColor} bg-[#ff5964] px-[6px] text-[12px] bold-text leading-[20px] text-white`}
|
|
348
281
|
style={{
|
|
349
282
|
animation: "pulse-zoom 2s ease-in-out infinite",
|
|
350
283
|
whiteSpace: "nowrap",
|
|
@@ -386,7 +319,7 @@ function SeatSection({
|
|
|
386
319
|
>
|
|
387
320
|
<div
|
|
388
321
|
className="absolute"
|
|
389
|
-
style={{ left: isPeru ? "-
|
|
322
|
+
style={{ left: isPeru ? "-1px" : "-19px", bottom: "1px" }}
|
|
390
323
|
>
|
|
391
324
|
{renderIcon("fireIcon", "16px")}
|
|
392
325
|
</div>
|
|
@@ -543,7 +476,7 @@ function SeatSection({
|
|
|
543
476
|
<div
|
|
544
477
|
className="absolute"
|
|
545
478
|
style={{
|
|
546
|
-
left: isPeru ? "-
|
|
479
|
+
left: isPeru ? "-1px" : "-18px",
|
|
547
480
|
bottom: "1px",
|
|
548
481
|
}}
|
|
549
482
|
>
|
|
@@ -290,6 +290,9 @@ const commonService = {
|
|
|
290
290
|
discount_type?: string;
|
|
291
291
|
discount_value?: number;
|
|
292
292
|
max_discount?: number;
|
|
293
|
+
discounts?: Array<{
|
|
294
|
+
new_ui_enabled?: boolean;
|
|
295
|
+
}>;
|
|
293
296
|
},
|
|
294
297
|
): { originalPrice: number; discountedPrice: number } => {
|
|
295
298
|
const price =
|
|
@@ -302,6 +305,16 @@ const commonService = {
|
|
|
302
305
|
}
|
|
303
306
|
|
|
304
307
|
const { discount_type, discount_value, max_discount } = serviceItem;
|
|
308
|
+
// Check if there's a discount with new_ui_enabled = true
|
|
309
|
+
const newUiEnabled = serviceItem.discounts?.some(
|
|
310
|
+
(d) => d.new_ui_enabled === true
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
// Only apply discount if new_ui_enabled is true OR if regular discount exists
|
|
315
|
+
if (!newUiEnabled && (!discount_type || discount_value == null)) {
|
|
316
|
+
return { originalPrice: price, discountedPrice: price };
|
|
317
|
+
}
|
|
305
318
|
|
|
306
319
|
const fixedDiscount =
|
|
307
320
|
discount_type === "fixed" && discount_value != null ? discount_value : 0;
|
|
@@ -329,10 +342,15 @@ const commonService = {
|
|
|
329
342
|
) => {
|
|
330
343
|
if (!node || !viewersConfig) return;
|
|
331
344
|
|
|
345
|
+
const { min, max, interval = 5000 } = viewersConfig;
|
|
346
|
+
const configKey = `${min}-${max}-${interval}`;
|
|
347
|
+
if (node.dataset.viewerId && node.dataset.viewerConfig === configKey) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
332
351
|
const prevId = node.dataset.viewerId;
|
|
333
352
|
if (prevId) clearInterval(Number(prevId));
|
|
334
353
|
|
|
335
|
-
const { min, max, interval = 5000 } = viewersConfig;
|
|
336
354
|
const clamp = (v: number) => Math.min(max, Math.max(min, v));
|
|
337
355
|
const initialValue = Math.floor(Math.random() * (max - min + 1)) + min;
|
|
338
356
|
|
|
@@ -347,6 +365,7 @@ const commonService = {
|
|
|
347
365
|
}, interval);
|
|
348
366
|
|
|
349
367
|
node.dataset.viewerId = String(id);
|
|
368
|
+
node.dataset.viewerConfig = configKey;
|
|
350
369
|
},
|
|
351
370
|
|
|
352
371
|
startCountdown: (
|
|
@@ -388,6 +407,11 @@ const commonService = {
|
|
|
388
407
|
) => {
|
|
389
408
|
if (!node) return;
|
|
390
409
|
|
|
410
|
+
const configKey = `${min}-${max}`;
|
|
411
|
+
if (node.dataset.comprandoId && node.dataset.comprandoConfig === configKey) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
391
415
|
const prevId = node.dataset.comprandoId;
|
|
392
416
|
if (prevId) clearInterval(Number(prevId));
|
|
393
417
|
|
|
@@ -408,6 +432,7 @@ const commonService = {
|
|
|
408
432
|
}, 5000); // Update every 5 seconds
|
|
409
433
|
|
|
410
434
|
node.dataset.comprandoId = String(id);
|
|
435
|
+
node.dataset.comprandoConfig = configKey;
|
|
411
436
|
},
|
|
412
437
|
};
|
|
413
438
|
|