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.
Files changed (37) hide show
  1. package/dist/KuposUIComponent.d.ts +3 -0
  2. package/dist/components/ServiceItem/PeruServiceItemDesktop.d.ts +1 -1
  3. package/dist/components/ServiceItem/PeruServiceItemDesktop.js +2 -2
  4. package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
  5. package/dist/components/ServiceItem/ServiceItemDesktop.js +30 -31
  6. package/dist/components/ServiceItem/ServiceItemMobile.d.ts +1 -1
  7. package/dist/components/ServiceItem/ServiceItemMobile.js +43 -17
  8. package/dist/components/ServiceItem/mobileTypes.d.ts +48 -1
  9. package/dist/components/ServiceItem/types.d.ts +27 -9
  10. package/dist/styles.css +215 -6
  11. package/dist/ui/ExpendedDropDown/ExpandedDropdown.d.ts +1 -2
  12. package/dist/ui/ExpendedDropDown/ExpandedDropdown.js +2 -4
  13. package/dist/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.js +22 -41
  14. package/dist/ui/FeatureServiceUI/FeatureServiceUi.js +24 -44
  15. package/dist/ui/OfferBanner.d.ts +2 -0
  16. package/dist/ui/OfferBanner.js +19 -14
  17. package/dist/ui/SeatSection/SeatSection.d.ts +1 -7
  18. package/dist/ui/SeatSection/SeatSection.js +12 -44
  19. package/dist/utils/CommonService.d.ts +3 -0
  20. package/dist/utils/CommonService.js +18 -1
  21. package/package.json +1 -1
  22. package/src/KuposUIComponent.tsx +3 -0
  23. package/src/assets/images/anims/service_list/flame_anim.json +1 -0
  24. package/src/assets/images/anims/service_list/thunder_icon.json +1 -0
  25. package/src/assets/images/anims/service_list/users_anim.json +1 -0
  26. package/src/components/ServiceItem/PeruServiceItemDesktop.tsx +35 -24
  27. package/src/components/ServiceItem/ServiceItemDesktop.tsx +65 -53
  28. package/src/components/ServiceItem/ServiceItemMobile.tsx +387 -288
  29. package/src/components/ServiceItem/mobileTypes.ts +50 -7
  30. package/src/components/ServiceItem/types.ts +39 -25
  31. package/src/styles.css +15 -0
  32. package/src/ui/ExpendedDropDown/ExpandedDropdown.tsx +2 -4
  33. package/src/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.tsx +575 -0
  34. package/src/ui/FeatureServiceUI/FeatureServiceUi.tsx +610 -0
  35. package/src/ui/OfferBanner.tsx +31 -10
  36. package/src/ui/SeatSection/SeatSection.tsx +21 -88
  37. package/src/utils/CommonService.ts +26 -1
@@ -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-[36px] pt-[50px] rounded-b-[14px] text-[14px]"
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 : Object.keys(
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
  &nbsp;
86
87
  </span>{" "}
87
- {serviceItem?.offer_text ? "| " : ""}
88
+ {serviceItem?.offer_text ? "|" : ""}
88
89
  Termina en&nbsp;
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[], isTrain: any) {
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
- if (isTrain) {
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, isTrain);
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
- return SEAT_EXCEPTIONS.includes(val.label) ? null : (
142
- <div
143
- className="flex items-center"
144
- style={isTrain ? { cursor: "pointer" } : undefined}
145
- onClick={
146
- isTrain && !isSoldOut
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
- {isTrain && (
160
- <div
161
- style={{
162
- border: `1px solid ${val.label === selectedSeatKey ? topLabelColor : "#ccc"}`,
163
- borderRadius: "50%",
164
- width: "14px",
165
- height: "14px",
166
- minWidth: "14px",
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="rounded-[100px] bg-[#ff5964] px-[6px] text-[12px] bold-text leading-[20px] text-white"
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 ? "-19px" : "-19px", bottom: "1px" }}
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 ? "-18px" : "-18px",
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