kupos-ui-components-lib 10.4.8 → 10.4.10

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 (32) hide show
  1. package/dist/components/ServiceItem/PeruServiceItemDesktop.js +4 -4
  2. package/dist/components/ServiceItem/PeruServiceItemMobile.d.ts +7 -0
  3. package/dist/components/ServiceItem/PeruServiceItemMobile.js +233 -0
  4. package/dist/components/ServiceItem/ServiceItemDesktop.js +4 -4
  5. package/dist/components/ServiceItem/ServiceItemMobile.d.ts +1 -1
  6. package/dist/components/ServiceItem/ServiceItemMobile.js +3 -2
  7. package/dist/components/ServiceItem/mobileTypes.d.ts +1 -0
  8. package/dist/styles.css +9 -3
  9. package/dist/ui/FeatureServiceUI/FeatureServiceUi.js +2 -2
  10. package/dist/ui/PaymentCardMobile/PaymentCardMobile.d.ts +4 -0
  11. package/dist/ui/PaymentCardMobile/PaymentCardMobile.js +531 -0
  12. package/dist/ui/PaymentCardMobile/index.d.ts +1 -0
  13. package/dist/ui/PaymentCardMobile/index.js +1 -0
  14. package/dist/ui/PeruOfferBanner.d.ts +24 -0
  15. package/dist/ui/PeruOfferBanner.js +94 -0
  16. package/dist/ui/SeatSection/PeruSeatSection.d.ts +22 -0
  17. package/dist/ui/SeatSection/PeruSeatSection.js +247 -0
  18. package/dist/ui/SlidingModal/SlidingModal.d.ts +9 -0
  19. package/dist/ui/SlidingModal/SlidingModal.js +100 -0
  20. package/dist/ui/SlidingModal/index.d.ts +2 -0
  21. package/dist/ui/SlidingModal/index.js +1 -0
  22. package/dist/ui/mobileweb/SeatSectionMobile.js +15 -1
  23. package/package.json +1 -1
  24. package/src/components/ServiceItem/PeruServiceItemDesktop.tsx +7 -6
  25. package/src/components/ServiceItem/PeruServiceItemMobile.tsx +596 -0
  26. package/src/components/ServiceItem/ServiceItemDesktop.tsx +2 -2
  27. package/src/components/ServiceItem/ServiceItemMobile.tsx +44 -1
  28. package/src/components/ServiceItem/mobileTypes.ts +1 -0
  29. package/src/ui/FeatureServiceUI/FeatureServiceUi.tsx +2 -2
  30. package/src/ui/PeruOfferBanner.tsx +298 -0
  31. package/src/ui/SeatSection/PeruSeatSection.tsx +487 -0
  32. package/src/ui/mobileweb/SeatSectionMobile.tsx +46 -1
@@ -471,7 +471,7 @@ const FeatureServiceUi = ({
471
471
  // backgroundColor: "#fff",
472
472
  border: "1px solid #363c48",
473
473
  backgroundColor: "#1a202e",
474
- padding: "14px 10px",
474
+ padding: "25px 10px",
475
475
  }}
476
476
  >
477
477
  <img
@@ -548,7 +548,7 @@ const FeatureServiceUi = ({
548
548
  }}
549
549
  >
550
550
  <span
551
- className="text-[#FF8F45] bold-text text-[26px] leading-tight"
551
+ className="text-[#FF8F45] bold-text text-[30px] leading-tight"
552
552
  style={{
553
553
  animation: "pulse-zoom 2s ease-in-out infinite",
554
554
  whiteSpace: "nowrap",
@@ -0,0 +1,298 @@
1
+ import React from "react";
2
+ import LottiePlayer from "../assets/LottiePlayer";
3
+ import CommonService from "../utils/CommonService";
4
+ import { ServiceItemProps } from "../components/ServiceItem/types";
5
+
6
+ // ─── Types ────────────────────────────────────────────────────────────────────
7
+
8
+ type ServiceItemSlice = Pick<
9
+ ServiceItemProps["serviceItem"],
10
+ | "is_dp_enabled"
11
+ | "offer_text"
12
+ | "dp_discount_percents"
13
+ | "dp_discounted_seats"
14
+ | "show_register_button"
15
+ >;
16
+
17
+ interface OfferBannerColors {
18
+ bottomStripColor?: string;
19
+ }
20
+
21
+ interface PeruOfferBannerProps {
22
+ offerGradient: string;
23
+ isSoldOut: boolean;
24
+ serviceItem: ServiceItemSlice;
25
+ renderIcon: (name: string, size: string) => React.ReactNode;
26
+ isLoggedIn: boolean;
27
+ showLoginModal: () => void;
28
+ viewersConfig: ServiceItemProps["viewersConfig"];
29
+ getAnimationIcon: (name: string) => unknown;
30
+ showLoginOption?: boolean;
31
+ colors: OfferBannerColors;
32
+ isLinatal?: boolean;
33
+ coachKey?: number;
34
+ isExpand?: any;
35
+ isNewUiEnabled?: boolean;
36
+ }
37
+
38
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
39
+
40
+ const OFFER_TEXT_MAX_LENGTH = 30;
41
+
42
+ function truncateOfferText(text: string): string {
43
+ return text.length > OFFER_TEXT_MAX_LENGTH
44
+ ? `${text.slice(0, OFFER_TEXT_MAX_LENGTH)}...`
45
+ : text;
46
+ }
47
+
48
+ function hasDpDiscounts(serviceItem: ServiceItemSlice): boolean {
49
+ return (
50
+ Object.keys(serviceItem?.dp_discount_percents ?? {}).length > 0 ||
51
+ (serviceItem?.dp_discounted_seats ?? []).length > 0
52
+ );
53
+ }
54
+
55
+ // ─── Sub-components ───────────────────────────────────────────────────────────
56
+
57
+ interface AnimationIconProps {
58
+ getAnimationIcon: PeruOfferBannerProps["getAnimationIcon"];
59
+ name: string;
60
+ width?: string;
61
+ height?: string;
62
+ }
63
+
64
+ const AnimationIcon: React.FC<AnimationIconProps> = ({
65
+ getAnimationIcon,
66
+ name,
67
+ width = "18px",
68
+ height = "18px",
69
+ }) => (
70
+ <LottiePlayer
71
+ animationData={getAnimationIcon(name)}
72
+ width={width}
73
+ height={height}
74
+ />
75
+ );
76
+
77
+ // Shown when DP is enabled but no discounts / discounted seats are present
78
+ const PopularServiceBanner: React.FC<{
79
+ getAnimationIcon: PeruOfferBannerProps["getAnimationIcon"];
80
+ }> = ({ getAnimationIcon }) => (
81
+ <div className="flex items-center gap-[5px]">
82
+ <AnimationIcon getAnimationIcon={getAnimationIcon} name="starAnimation" />
83
+ <span>Servicio popular entre los usuarios</span>
84
+ </div>
85
+ );
86
+
87
+ // Shown when an offer text exists
88
+ interface OfferBannerContentProps {
89
+ offerText: string;
90
+ isLoggedIn: boolean;
91
+ showLoginModal: () => void;
92
+ showLoginOption?: boolean;
93
+ getAnimationIcon: PeruOfferBannerProps["getAnimationIcon"];
94
+ hideRegister?: boolean;
95
+ showLoginButton?: boolean;
96
+ }
97
+
98
+ const OfferBannerContent: React.FC<OfferBannerContentProps> = ({
99
+ offerText,
100
+ isLoggedIn,
101
+ showLoginModal,
102
+ showLoginOption,
103
+ getAnimationIcon,
104
+ hideRegister,
105
+ showLoginButton,
106
+ }) => (
107
+ <div className="flex items-center">
108
+ <AnimationIcon getAnimationIcon={getAnimationIcon} name="bombAnimation" />
109
+ <div className="flex items-center mt-[0px]">
110
+ <span
111
+ className="bold-text"
112
+ style={{ marginLeft: offerText ? "6px" : "3px" }}
113
+ >
114
+ {offerText}{" "}
115
+ {isLoggedIn && showLoginOption
116
+ ? null
117
+ : showLoginOption &&
118
+ showLoginButton && (
119
+ <span onClick={showLoginModal} className="cursor-pointer">
120
+ - registro
121
+ </span>
122
+ )}{" "}
123
+ &nbsp;
124
+ </span>{" "}
125
+ {offerText ? "| " : ""}
126
+ Termina en&nbsp;
127
+ <span
128
+ className="bold-text text-end"
129
+ ref={(node) => CommonService.startCountdown(node, 599)}
130
+ style={{ fontVariantNumeric: "tabular-nums", display: "inline-block" }}
131
+ />
132
+ </div>
133
+ </div>
134
+ );
135
+
136
+ // Shown for legacy promo offers
137
+ interface LegacyOfferBannerProps {
138
+ offerText: string;
139
+ getAnimationIcon: PeruOfferBannerProps["getAnimationIcon"];
140
+ }
141
+
142
+ const LegacyOfferBanner: React.FC<LegacyOfferBannerProps> = ({
143
+ offerText,
144
+ getAnimationIcon,
145
+ }) => (
146
+ <div className="flex items-center">
147
+ <AnimationIcon getAnimationIcon={getAnimationIcon} name="promoAnim" />
148
+ <div className="flex items-center mb-[2px]">
149
+ <span
150
+ className="bold-text"
151
+ style={{ marginLeft: offerText ? "6px" : "3px" }}
152
+ >
153
+ {offerText}
154
+ </span>
155
+ </div>
156
+ </div>
157
+ );
158
+
159
+ // Right-side viewers / buying count
160
+ interface ViewersCountProps {
161
+ serviceItem: ServiceItemSlice;
162
+ viewersConfig: ServiceItemProps["viewersConfig"];
163
+ getAnimationIcon: PeruOfferBannerProps["getAnimationIcon"];
164
+ }
165
+
166
+ const ViewersCount: React.FC<ViewersCountProps> = ({
167
+ serviceItem,
168
+ viewersConfig,
169
+ getAnimationIcon,
170
+ }) => {
171
+ const showScarcity = hasDpDiscounts(serviceItem);
172
+
173
+ return (
174
+ <div className="flex items-center">
175
+ <AnimationIcon
176
+ getAnimationIcon={getAnimationIcon}
177
+ name="dotAnimation"
178
+ width="12px"
179
+ height="12px"
180
+ />
181
+ <span className="ml-[6px]">
182
+ <span
183
+ className="bold-text"
184
+ ref={(node) => CommonService.startViewerCount(node, viewersConfig)}
185
+ style={{ fontVariantNumeric: "tabular-nums" }}
186
+ />{" "}
187
+ <span>
188
+ {viewersConfig?.label || " viendo"} |{" "}
189
+ <span>
190
+ {showScarcity && "Quedan pocos • "}
191
+ <span
192
+ className="bold-text"
193
+ ref={(node) => CommonService.startComprandoCount(node, 4, 16)}
194
+ style={{ fontVariantNumeric: "tabular-nums" }}
195
+ />{" "}
196
+ comprando
197
+ </span>
198
+ </span>
199
+ </span>
200
+ </div>
201
+ );
202
+ };
203
+
204
+ // ─── Main Component ───────────────────────────────────────────────────────────
205
+
206
+ const PeruOfferBanner: React.FC<PeruOfferBannerProps> = ({
207
+ offerGradient,
208
+ isSoldOut,
209
+ serviceItem,
210
+ isLoggedIn,
211
+ showLoginModal,
212
+ viewersConfig,
213
+ getAnimationIcon,
214
+ showLoginOption,
215
+ colors,
216
+ isLinatal,
217
+ coachKey,
218
+ isExpand,
219
+ isNewUiEnabled,
220
+ }) => {
221
+ const isDiscountBelow20 =
222
+ (serviceItem as any)?.discount_value > 0 &&
223
+ (serviceItem as any)?.discount_value < 20;
224
+ const offerText = isDiscountBelow20 ? "" : serviceItem?.offer_text || "";
225
+
226
+ const isLegacyOffer =
227
+ !!offerText &&
228
+ !isNewUiEnabled;
229
+
230
+ // const showViewers = serviceItem?.is_dp_enabled;
231
+ const showViewers = isNewUiEnabled;
232
+
233
+ const background = isLegacyOffer ? colors?.bottomStripColor : offerGradient;
234
+
235
+ const renderLeftContent = () => {
236
+ const hasDp = hasDpDiscounts(serviceItem);
237
+
238
+ if (serviceItem?.is_dp_enabled && !hasDp) {
239
+ return <PopularServiceBanner getAnimationIcon={getAnimationIcon} />;
240
+ }
241
+
242
+ // If new UI is enabled, show offer with registro and countdown
243
+ if (isNewUiEnabled && offerText) {
244
+ return (
245
+ <OfferBannerContent
246
+ offerText={offerText}
247
+ isLoggedIn={isLoggedIn}
248
+ showLoginModal={showLoginModal}
249
+ showLoginOption={showLoginOption}
250
+ getAnimationIcon={getAnimationIcon}
251
+ hideRegister={hasDp}
252
+ showLoginButton={serviceItem?.show_register_button}
253
+ />
254
+ );
255
+ }
256
+
257
+ // If new UI is disabled, show offer text only
258
+ if (offerText) {
259
+ return (
260
+ <LegacyOfferBanner
261
+ offerText={offerText}
262
+ getAnimationIcon={getAnimationIcon}
263
+ />
264
+ );
265
+ }
266
+
267
+ return null;
268
+ };
269
+
270
+ return (
271
+ <div
272
+ className={`text-white w-full absolute ${coachKey ? "-bottom-[32px]" : isExpand ? "-bottom-[32px]" : "-bottom-[40px]"} rounded-b-[14px] text-[14px] h-[58px] flex items-end pb-[7px]`}
273
+ style={{
274
+ background:
275
+ (serviceItem?.is_dp_enabled && serviceItem?.dp_discount_percents)
276
+ ? offerGradient
277
+ : background,
278
+ opacity: isSoldOut ? 0.5 : 1,
279
+ zIndex: isLinatal ? "-1" : "0",
280
+ }}
281
+ >
282
+ <div className="flex items-center w-full gap-[20px] px-[15px] justify-between">
283
+ <div className="flex items-center justify-start">
284
+ {renderLeftContent()}
285
+ </div>
286
+ {showViewers && (
287
+ <ViewersCount
288
+ serviceItem={serviceItem}
289
+ viewersConfig={viewersConfig}
290
+ getAnimationIcon={getAnimationIcon}
291
+ />
292
+ )}
293
+ </div>
294
+ </div>
295
+ );
296
+ };
297
+
298
+ export default PeruOfferBanner;