kupos-ui-components-lib 10.4.9 → 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 (30) 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 +6 -0
  9. package/dist/ui/PaymentCardMobile/PaymentCardMobile.d.ts +4 -0
  10. package/dist/ui/PaymentCardMobile/PaymentCardMobile.js +531 -0
  11. package/dist/ui/PaymentCardMobile/index.d.ts +1 -0
  12. package/dist/ui/PaymentCardMobile/index.js +1 -0
  13. package/dist/ui/PeruOfferBanner.d.ts +24 -0
  14. package/dist/ui/PeruOfferBanner.js +94 -0
  15. package/dist/ui/SeatSection/PeruSeatSection.d.ts +22 -0
  16. package/dist/ui/SeatSection/PeruSeatSection.js +247 -0
  17. package/dist/ui/SlidingModal/SlidingModal.d.ts +9 -0
  18. package/dist/ui/SlidingModal/SlidingModal.js +100 -0
  19. package/dist/ui/SlidingModal/index.d.ts +2 -0
  20. package/dist/ui/SlidingModal/index.js +1 -0
  21. package/dist/ui/mobileweb/SeatSectionMobile.js +15 -1
  22. package/package.json +1 -1
  23. package/src/components/ServiceItem/PeruServiceItemDesktop.tsx +7 -6
  24. package/src/components/ServiceItem/PeruServiceItemMobile.tsx +596 -0
  25. package/src/components/ServiceItem/ServiceItemDesktop.tsx +2 -2
  26. package/src/components/ServiceItem/ServiceItemMobile.tsx +44 -1
  27. package/src/components/ServiceItem/mobileTypes.ts +1 -0
  28. package/src/ui/PeruOfferBanner.tsx +298 -0
  29. package/src/ui/SeatSection/PeruSeatSection.tsx +487 -0
  30. package/src/ui/mobileweb/SeatSectionMobile.tsx +46 -1
@@ -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;