kupos-ui-components-lib 9.9.7 → 9.9.8
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 +156 -176
- package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemDesktop.js +29 -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 -2
- package/dist/components/ServiceItem/types.d.ts +27 -8
- package/dist/styles.css +219 -16
- package/dist/ui/ExpendedDropDown/ExpandedDropdown.d.ts +1 -2
- package/dist/ui/ExpendedDropDown/ExpandedDropdown.js +2 -4
- package/dist/ui/FeaturServiceUiMobile/FeatureServiceUiMobile.js +3 -10
- package/dist/ui/OfferBanner.d.ts +2 -0
- package/dist/ui/OfferBanner.js +22 -15
- package/dist/ui/SeatSection/SeatSection.d.ts +1 -7
- package/dist/ui/SeatSection/SeatSection.js +12 -41
- package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +1 -2
- package/dist/ui/mobileweb/DateTimeSectionMobile.js +6 -12
- package/dist/ui/mobileweb/SeatSectionMobile.d.ts +1 -2
- package/dist/ui/mobileweb/SeatSectionMobile.js +14 -21
- package/dist/utils/CommonService.d.ts +4 -1
- package/dist/utils/CommonService.js +19 -6
- 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 +404 -277
- package/src/components/ServiceItem/ServiceItemDesktop.tsx +71 -51
- package/src/components/ServiceItem/ServiceItemMobile.tsx +387 -290
- package/src/components/ServiceItem/mobileTypes.ts +50 -8
- package/src/components/ServiceItem/types.ts +32 -13
- 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 +634 -0
- package/src/ui/OfferBanner.tsx +71 -43
- package/src/ui/SeatSection/SeatSection.tsx +21 -86
- package/src/ui/mobileweb/DateTimeSectionMobile.tsx +35 -44
- package/src/ui/mobileweb/SeatSectionMobile.tsx +11 -23
- package/src/utils/CommonService.ts +27 -8
package/src/ui/OfferBanner.tsx
CHANGED
|
@@ -19,6 +19,8 @@ interface OfferBannerProps {
|
|
|
19
19
|
viewersConfig: ServiceItemProps["viewersConfig"];
|
|
20
20
|
getAnimationIcon: (name: string) => any;
|
|
21
21
|
showLoginOption?: boolean;
|
|
22
|
+
isNewUiEnabled?: boolean;
|
|
23
|
+
colors: any;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
@@ -31,12 +33,17 @@ 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-[
|
|
41
|
+
className="text-white p-[15px_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:
|
|
43
|
+
background:
|
|
44
|
+
serviceItem?.offer_text && !isNewUiEnabled
|
|
45
|
+
? colors?.bottomStripColor
|
|
46
|
+
: offerGradient,
|
|
40
47
|
opacity: isSoldOut ? 0.5 : 1,
|
|
41
48
|
// zIndex: 0,
|
|
42
49
|
}}
|
|
@@ -56,7 +63,7 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
56
63
|
{/* starAnimation */}
|
|
57
64
|
<span>Servicio popular entre los usuarios</span>
|
|
58
65
|
</div>
|
|
59
|
-
) : (
|
|
66
|
+
) : isNewUiEnabled && serviceItem?.offer_text ? (
|
|
60
67
|
<div className="flex items-center">
|
|
61
68
|
<LottiePlayer
|
|
62
69
|
animationData={getAnimationIcon("bombAnimation")}
|
|
@@ -73,18 +80,14 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
73
80
|
{(serviceItem?.offer_text || "").length > 30
|
|
74
81
|
? (serviceItem?.offer_text || "").slice(0, 30) + "..."
|
|
75
82
|
: serviceItem?.offer_text || ""}{" "}
|
|
76
|
-
{isLoggedIn && showLoginOption ? null :
|
|
77
|
-
serviceItem?.dp_discount_percents ?? {},
|
|
78
|
-
).length > 0 ||
|
|
79
|
-
(serviceItem?.dp_discounted_seats ?? []).length >
|
|
80
|
-
0 ? null : (
|
|
83
|
+
{isLoggedIn && showLoginOption ? null : (
|
|
81
84
|
<span onClick={showLoginModal} className="cursor-pointer">
|
|
82
85
|
- registro
|
|
83
86
|
</span>
|
|
84
87
|
)}{" "}
|
|
85
88
|
|
|
86
89
|
</span>{" "}
|
|
87
|
-
{serviceItem?.offer_text ? "|
|
|
90
|
+
{serviceItem?.offer_text ? "|" : ""}
|
|
88
91
|
Termina en
|
|
89
92
|
<span
|
|
90
93
|
className="bold-text text-end"
|
|
@@ -96,45 +99,70 @@ const OfferBanner: React.FC<OfferBannerProps> = ({
|
|
|
96
99
|
/>
|
|
97
100
|
</div>
|
|
98
101
|
</div>
|
|
102
|
+
) : (
|
|
103
|
+
serviceItem?.offer_text &&
|
|
104
|
+
!isNewUiEnabled && (
|
|
105
|
+
<div className="flex items-center">
|
|
106
|
+
<LottiePlayer
|
|
107
|
+
animationData={getAnimationIcon("promoAnim")}
|
|
108
|
+
width="18px"
|
|
109
|
+
height="18px"
|
|
110
|
+
/>
|
|
111
|
+
<div className="flex items-center mt-[2px]">
|
|
112
|
+
<span
|
|
113
|
+
className="bold-text"
|
|
114
|
+
style={{
|
|
115
|
+
marginLeft: serviceItem?.offer_text ? "6px" : "3px",
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
{serviceItem?.offer_text || ""}
|
|
119
|
+
</span>{" "}
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
)
|
|
99
123
|
)}
|
|
100
124
|
</div>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
125
|
+
{(isNewUiEnabled || serviceItem?.is_dp_enabled) && (
|
|
126
|
+
<div className="flex items-center">
|
|
127
|
+
{/* {renderIcon("personIcon", "16px")} */}
|
|
128
|
+
<LottiePlayer
|
|
129
|
+
animationData={getAnimationIcon("dotAnimation")}
|
|
130
|
+
width="12px"
|
|
131
|
+
height="12px"
|
|
132
|
+
/>
|
|
108
133
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
+
<span className="ml-[6px]">
|
|
135
|
+
<span
|
|
136
|
+
className="bold-text"
|
|
137
|
+
ref={(node) =>
|
|
138
|
+
CommonService.startViewerCount(node, viewersConfig)
|
|
139
|
+
}
|
|
140
|
+
style={{ fontVariantNumeric: "tabular-nums" }}
|
|
141
|
+
/>{" "}
|
|
142
|
+
{/* <span className="bold-text">personas</span>{" "} */}
|
|
143
|
+
<span>
|
|
144
|
+
{" "}
|
|
145
|
+
{viewersConfig?.label || " viendo"} |{" "}
|
|
146
|
+
<span className="">
|
|
147
|
+
{serviceItem?.is_dp_enabled &&
|
|
148
|
+
Object.keys(serviceItem?.dp_discount_percents ?? {})
|
|
149
|
+
.length === 0 &&
|
|
150
|
+
(serviceItem?.dp_discounted_seats ?? []).length === 0
|
|
151
|
+
? null
|
|
152
|
+
: "Quedan pocos • "}
|
|
153
|
+
<span
|
|
154
|
+
className="bold-text"
|
|
155
|
+
ref={(node) =>
|
|
156
|
+
CommonService.startComprandoCount(node, 4, 16)
|
|
157
|
+
}
|
|
158
|
+
style={{ fontVariantNumeric: "tabular-nums" }}
|
|
159
|
+
/>{" "}
|
|
160
|
+
comprando
|
|
161
|
+
</span>
|
|
134
162
|
</span>
|
|
135
163
|
</span>
|
|
136
|
-
</
|
|
137
|
-
|
|
164
|
+
</div>
|
|
165
|
+
)}
|
|
138
166
|
</div>
|
|
139
167
|
</div>
|
|
140
168
|
);
|
|
@@ -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,9 +52,7 @@ function getSortedSeatTypes(seatTypes: SeatType[], isTrain: any) {
|
|
|
65
52
|
seatTypesWithPrices[2] = seatTypesWithPrices[premiumIndex];
|
|
66
53
|
}
|
|
67
54
|
|
|
68
|
-
|
|
69
|
-
seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
|
|
70
|
-
}
|
|
55
|
+
seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
|
|
71
56
|
|
|
72
57
|
const seenPrices = new Set<number>();
|
|
73
58
|
seatTypesWithPrices = seatTypesWithPrices.filter((seat) => {
|
|
@@ -112,18 +97,14 @@ function SeatSection({
|
|
|
112
97
|
priceColor,
|
|
113
98
|
currencySign,
|
|
114
99
|
removeDuplicateSeats,
|
|
115
|
-
selectedSeatKey,
|
|
116
|
-
onSeatSelect,
|
|
117
100
|
isPeru,
|
|
118
101
|
serviceItem,
|
|
119
102
|
renderIcon,
|
|
120
103
|
dpSeatColor,
|
|
121
104
|
discountSeatPriceColor,
|
|
122
|
-
isTrain,
|
|
123
|
-
topLabelColor,
|
|
124
105
|
}: SeatSectionProps): React.ReactElement {
|
|
125
106
|
const uniqueSeats = getUniqueSeats(seatTypes);
|
|
126
|
-
const sortedSeatTypes = getSortedSeatTypes(seatTypes
|
|
107
|
+
const sortedSeatTypes = getSortedSeatTypes(seatTypes);
|
|
127
108
|
const numberOfSeats = getNumberOfSeats(seatTypes);
|
|
128
109
|
const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
|
|
129
110
|
|
|
@@ -135,68 +116,22 @@ function SeatSection({
|
|
|
135
116
|
const renderSeatNames = () => {
|
|
136
117
|
const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
|
|
137
118
|
|
|
138
|
-
return seats.map((val, key: number) =>
|
|
139
|
-
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
? () =>
|
|
146
|
-
val.label === selectedSeatKey
|
|
147
|
-
? onSeatSelect?.(null, 0, "", "")
|
|
148
|
-
: onSeatSelect?.(
|
|
149
|
-
val.label,
|
|
150
|
-
val.price,
|
|
151
|
-
val.key,
|
|
152
|
-
(val as any).apiSeatType,
|
|
153
|
-
)
|
|
154
|
-
: undefined
|
|
155
|
-
}
|
|
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
|
+
}`}
|
|
156
126
|
>
|
|
157
|
-
{
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
marginRight: "10px",
|
|
166
|
-
display: "flex",
|
|
167
|
-
alignItems: "center",
|
|
168
|
-
justifyContent: "center",
|
|
169
|
-
}}
|
|
170
|
-
>
|
|
171
|
-
{val.label === selectedSeatKey && (
|
|
172
|
-
<div
|
|
173
|
-
style={{
|
|
174
|
-
backgroundColor: topLabelColor,
|
|
175
|
-
borderRadius: "50%",
|
|
176
|
-
width: "7px",
|
|
177
|
-
height: "7px",
|
|
178
|
-
}}
|
|
179
|
-
/>
|
|
180
|
-
)}
|
|
181
|
-
</div>
|
|
182
|
-
)}
|
|
183
|
-
<span
|
|
184
|
-
key={key}
|
|
185
|
-
className={`flex items-center justify-between text-[13.33px] ${
|
|
186
|
-
isSoldOut ? "text-[#c0c0c0]" : ""
|
|
187
|
-
}`}
|
|
188
|
-
>
|
|
189
|
-
{typeof val.label === "string" || typeof val.label === "number"
|
|
190
|
-
? removeDuplicateSeats && isPeru
|
|
191
|
-
? CommonService.truncateSeatLabel(val.label)
|
|
192
|
-
: isTrain
|
|
193
|
-
? CommonService.truncateSeatLabel(val.label, 8)
|
|
194
|
-
: val.label
|
|
195
|
-
: null}
|
|
196
|
-
</span>
|
|
197
|
-
</div>
|
|
198
|
-
);
|
|
199
|
-
});
|
|
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
|
+
);
|
|
200
135
|
};
|
|
201
136
|
|
|
202
137
|
const renderSeatPrices = () => {
|
|
@@ -342,7 +277,7 @@ function SeatSection({
|
|
|
342
277
|
{!isNaN(Number(dpDiscountPercent)) &&
|
|
343
278
|
Number(dpDiscountPercent) > 0 && (
|
|
344
279
|
<span
|
|
345
|
-
className=
|
|
280
|
+
className={`rounded-[100px] ${discountSeatPriceColor} bg-[#ff5964] px-[6px] text-[12px] bold-text leading-[20px] text-white`}
|
|
346
281
|
style={{
|
|
347
282
|
animation: "pulse-zoom 2s ease-in-out infinite",
|
|
348
283
|
whiteSpace: "nowrap",
|
|
@@ -384,7 +319,7 @@ function SeatSection({
|
|
|
384
319
|
>
|
|
385
320
|
<div
|
|
386
321
|
className="absolute"
|
|
387
|
-
style={{ left: isPeru ? "-
|
|
322
|
+
style={{ left: isPeru ? "-1px" : "-19px", bottom: "1px" }}
|
|
388
323
|
>
|
|
389
324
|
{renderIcon("fireIcon", "16px")}
|
|
390
325
|
</div>
|
|
@@ -541,7 +476,7 @@ function SeatSection({
|
|
|
541
476
|
<div
|
|
542
477
|
className="absolute"
|
|
543
478
|
style={{
|
|
544
|
-
left: isPeru ? "-
|
|
479
|
+
left: isPeru ? "-1px" : "-18px",
|
|
545
480
|
bottom: "1px",
|
|
546
481
|
}}
|
|
547
482
|
>
|
|
@@ -25,7 +25,6 @@ interface DateTimeSectionMobileProps {
|
|
|
25
25
|
tooltipBgColor?: string;
|
|
26
26
|
showLastSeats?: boolean;
|
|
27
27
|
discountSeatPriceColor?: string;
|
|
28
|
-
isTrain?: boolean;
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
const pad = (n: number) => (n < 10 ? "0" + n : String(n));
|
|
@@ -68,43 +67,41 @@ const TimeRow: React.FC<TimeRowProps> = ({
|
|
|
68
67
|
isSoldOut,
|
|
69
68
|
}) => {
|
|
70
69
|
const formattedDate = DateService.getServiceItemDate(date);
|
|
71
|
-
const dotPositionClass = formattedDate.includes("dom")
|
|
72
|
-
|
|
73
|
-
:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
<div className="font-[900] relative black-text">{timeContent}</div>
|
|
104
|
-
</div>
|
|
70
|
+
const dotPositionClass = formattedDate.includes("dom") ? "max-[399px]:left-[53%]" : "";
|
|
71
|
+
return <div
|
|
72
|
+
className={`flex items-center min-[420]:text-[13px] text-[12px] justify-between ${
|
|
73
|
+
isSoldOut ? "text-[#c0c0c0]" : ""
|
|
74
|
+
}`}
|
|
75
|
+
>
|
|
76
|
+
<div className="flex items-center" style={{ flex: 1 }}>
|
|
77
|
+
<div>
|
|
78
|
+
{" "}
|
|
79
|
+
{label ? (
|
|
80
|
+
<div className="w-[60px]">{label}</div>
|
|
81
|
+
) : (
|
|
82
|
+
<div className="w-[12px] h-auto mr-[5px]">
|
|
83
|
+
<img
|
|
84
|
+
src={icon}
|
|
85
|
+
alt={alt}
|
|
86
|
+
className={`w-[12px] h-auto mr-[5px] ${
|
|
87
|
+
isSoldOut ? "grayscale" : ""
|
|
88
|
+
}`}
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
91
|
+
)}
|
|
92
|
+
</div>
|
|
93
|
+
<div
|
|
94
|
+
className="flex items-center relative capitalize justify-between"
|
|
95
|
+
style={{ flex: 1 }}
|
|
96
|
+
>
|
|
97
|
+
<span className="cursor-pointer black-text">
|
|
98
|
+
{formattedDate}
|
|
99
|
+
</span>
|
|
100
|
+
<div className={`absolute left-[50%] ${dotPositionClass}`}>•</div>
|
|
101
|
+
<div className="font-[900] relative black-text">{timeContent}</div>
|
|
105
102
|
</div>
|
|
106
103
|
</div>
|
|
107
|
-
|
|
104
|
+
</div>;
|
|
108
105
|
};
|
|
109
106
|
|
|
110
107
|
function DateTimeSectionMobile({
|
|
@@ -130,7 +127,6 @@ function DateTimeSectionMobile({
|
|
|
130
127
|
tooltipBgColor,
|
|
131
128
|
showLastSeats,
|
|
132
129
|
discountSeatPriceColor,
|
|
133
|
-
isTrain,
|
|
134
130
|
}: DateTimeSectionMobileProps): React.ReactElement {
|
|
135
131
|
const { cleaned: cleanedDepTime, hasAM, hasPM } = getCleanedDepTime(depTime);
|
|
136
132
|
|
|
@@ -157,12 +153,8 @@ function DateTimeSectionMobile({
|
|
|
157
153
|
>
|
|
158
154
|
{/* DATE AND TIME */}
|
|
159
155
|
<div
|
|
160
|
-
className=
|
|
161
|
-
style={{
|
|
162
|
-
justifyContent: isCiva && "center",
|
|
163
|
-
minHeight: isTrain ? undefined : "2.5rem",
|
|
164
|
-
alignSelf: isTrain ? "stretch" : undefined,
|
|
165
|
-
}}
|
|
156
|
+
className="min-h-[2.5rem] flex flex-col justify-between gap-[4px] w-[50%] "
|
|
157
|
+
style={{ justifyContent: isCiva && "center" }}
|
|
166
158
|
>
|
|
167
159
|
<TimeRow
|
|
168
160
|
label={orignLabel}
|
|
@@ -206,7 +198,6 @@ function DateTimeSectionMobile({
|
|
|
206
198
|
tooltipBgColor={tooltipBgColor}
|
|
207
199
|
showLastSeats={showLastSeats}
|
|
208
200
|
discountSeatPriceColor={discountSeatPriceColor}
|
|
209
|
-
isTrain={isTrain}
|
|
210
201
|
/>
|
|
211
202
|
</div>
|
|
212
203
|
);
|
|
@@ -31,7 +31,6 @@ interface SeatSectionMobileProps {
|
|
|
31
31
|
tooltipBgColor?: string;
|
|
32
32
|
showLastSeats?: boolean;
|
|
33
33
|
discountSeatPriceColor?: string;
|
|
34
|
-
isTrain?: boolean;
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
interface SeatRowProps {
|
|
@@ -43,7 +42,6 @@ interface SeatRowProps {
|
|
|
43
42
|
seatPriceColor: string;
|
|
44
43
|
hasMultipleTypes: boolean;
|
|
45
44
|
textSize: string;
|
|
46
|
-
isTrain?: boolean;
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
const SeatRow: React.FC<SeatRowProps> = ({
|
|
@@ -55,7 +53,6 @@ const SeatRow: React.FC<SeatRowProps> = ({
|
|
|
55
53
|
seatPriceColor,
|
|
56
54
|
hasMultipleTypes,
|
|
57
55
|
textSize,
|
|
58
|
-
isTrain,
|
|
59
56
|
}) => {
|
|
60
57
|
if (EXCEPTIONS.includes(type.label)) return null;
|
|
61
58
|
|
|
@@ -72,9 +69,7 @@ const SeatRow: React.FC<SeatRowProps> = ({
|
|
|
72
69
|
className={`min-[420]:text-[13px] ${textSize} `}
|
|
73
70
|
style={{ color: labelColor }}
|
|
74
71
|
>
|
|
75
|
-
{
|
|
76
|
-
? commonService.truncateSeatLabel(displayLabel, 8)
|
|
77
|
-
: displayLabel}
|
|
72
|
+
{displayLabel}
|
|
78
73
|
</span>
|
|
79
74
|
<span
|
|
80
75
|
className={`min-[420]:text-[13px] ${textSize} bold-text`}
|
|
@@ -123,7 +118,6 @@ function SeatSectionMobile({
|
|
|
123
118
|
tooltipBgColor,
|
|
124
119
|
showLastSeats,
|
|
125
120
|
discountSeatPriceColor,
|
|
126
|
-
isTrain,
|
|
127
121
|
}: SeatSectionMobileProps): React.ReactElement {
|
|
128
122
|
const hasMultipleTypes = (seatTypesData?.length ?? 0) > 2;
|
|
129
123
|
|
|
@@ -284,17 +278,15 @@ function SeatSectionMobile({
|
|
|
284
278
|
seatPriceColor={seatPriceColor}
|
|
285
279
|
hasMultipleTypes={hasMultipleTypes}
|
|
286
280
|
textSize="text-[11px]"
|
|
287
|
-
isTrain={isTrain}
|
|
288
281
|
/>
|
|
289
282
|
));
|
|
290
283
|
}
|
|
291
284
|
|
|
292
|
-
|
|
285
|
+
return seatTypesData
|
|
293
286
|
?.filter((item) => getFilteredSeats(item.label))
|
|
294
|
-
?.sort((a, b) => a.fare - b.fare)
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
(type, i) => (
|
|
287
|
+
?.sort((a, b) => a.fare - b.fare)
|
|
288
|
+
?.slice(0, 2)
|
|
289
|
+
?.map((type, i) => (
|
|
298
290
|
<SeatRow
|
|
299
291
|
key={i}
|
|
300
292
|
type={type}
|
|
@@ -305,20 +297,16 @@ function SeatSectionMobile({
|
|
|
305
297
|
seatPriceColor={seatPriceColor}
|
|
306
298
|
hasMultipleTypes={hasMultipleTypes}
|
|
307
299
|
textSize="text-[12px]"
|
|
308
|
-
isTrain={isTrain}
|
|
309
300
|
/>
|
|
310
|
-
)
|
|
311
|
-
);
|
|
301
|
+
));
|
|
312
302
|
};
|
|
313
303
|
|
|
314
304
|
const seats = removeDuplicateSeats
|
|
315
305
|
? getUniqueSeats(seatTypesData, 3)
|
|
316
|
-
:
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
return isTrain ? filtered : filtered?.slice(0, 2);
|
|
321
|
-
})();
|
|
306
|
+
: seatTypesData
|
|
307
|
+
?.filter((item) => getFilteredSeats(item.label))
|
|
308
|
+
?.sort((a, b) => a.fare - b.fare)
|
|
309
|
+
?.slice(0, 2);
|
|
322
310
|
|
|
323
311
|
const discountedSeats = seats?.map((seat) => ({
|
|
324
312
|
...seat,
|
|
@@ -553,7 +541,7 @@ function SeatSectionMobile({
|
|
|
553
541
|
</div>
|
|
554
542
|
) : (
|
|
555
543
|
<div
|
|
556
|
-
className=
|
|
544
|
+
className="flex flex-col justify-between h-[2.5rem] "
|
|
557
545
|
style={{
|
|
558
546
|
gap: isSoldOut ? "0px" : "5px",
|
|
559
547
|
justifyContent: hasMultipleTypes ? "space-between" : "center",
|
|
@@ -39,15 +39,9 @@ const commonService = {
|
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
|
|
42
|
-
truncateSeatLabel: (label: string | number
|
|
42
|
+
truncateSeatLabel: (label: string | number): string => {
|
|
43
43
|
if (typeof label !== "string") return String(label);
|
|
44
44
|
if (label.includes("(")) return label;
|
|
45
|
-
|
|
46
|
-
// If maxLength provided, hard-truncate regardless of word count
|
|
47
|
-
if (maxLength != null && label.length > maxLength) {
|
|
48
|
-
return label.slice(0, maxLength) + "...";
|
|
49
|
-
}
|
|
50
|
-
|
|
51
45
|
const words = label.trim().split(/\s+/);
|
|
52
46
|
|
|
53
47
|
const truncateWord = (word: string) =>
|
|
@@ -296,6 +290,9 @@ const commonService = {
|
|
|
296
290
|
discount_type?: string;
|
|
297
291
|
discount_value?: number;
|
|
298
292
|
max_discount?: number;
|
|
293
|
+
discounts?: Array<{
|
|
294
|
+
new_ui_enabled?: boolean;
|
|
295
|
+
}>;
|
|
299
296
|
},
|
|
300
297
|
): { originalPrice: number; discountedPrice: number } => {
|
|
301
298
|
const price =
|
|
@@ -308,6 +305,16 @@ const commonService = {
|
|
|
308
305
|
}
|
|
309
306
|
|
|
310
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
|
+
}
|
|
311
318
|
|
|
312
319
|
const fixedDiscount =
|
|
313
320
|
discount_type === "fixed" && discount_value != null ? discount_value : 0;
|
|
@@ -335,10 +342,15 @@ const commonService = {
|
|
|
335
342
|
) => {
|
|
336
343
|
if (!node || !viewersConfig) return;
|
|
337
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
|
+
|
|
338
351
|
const prevId = node.dataset.viewerId;
|
|
339
352
|
if (prevId) clearInterval(Number(prevId));
|
|
340
353
|
|
|
341
|
-
const { min, max, interval = 5000 } = viewersConfig;
|
|
342
354
|
const clamp = (v: number) => Math.min(max, Math.max(min, v));
|
|
343
355
|
const initialValue = Math.floor(Math.random() * (max - min + 1)) + min;
|
|
344
356
|
|
|
@@ -353,6 +365,7 @@ const commonService = {
|
|
|
353
365
|
}, interval);
|
|
354
366
|
|
|
355
367
|
node.dataset.viewerId = String(id);
|
|
368
|
+
node.dataset.viewerConfig = configKey;
|
|
356
369
|
},
|
|
357
370
|
|
|
358
371
|
startCountdown: (
|
|
@@ -394,6 +407,11 @@ const commonService = {
|
|
|
394
407
|
) => {
|
|
395
408
|
if (!node) return;
|
|
396
409
|
|
|
410
|
+
const configKey = `${min}-${max}`;
|
|
411
|
+
if (node.dataset.comprandoId && node.dataset.comprandoConfig === configKey) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
397
415
|
const prevId = node.dataset.comprandoId;
|
|
398
416
|
if (prevId) clearInterval(Number(prevId));
|
|
399
417
|
|
|
@@ -414,6 +432,7 @@ const commonService = {
|
|
|
414
432
|
}, 5000); // Update every 5 seconds
|
|
415
433
|
|
|
416
434
|
node.dataset.comprandoId = String(id);
|
|
435
|
+
node.dataset.comprandoConfig = configKey;
|
|
417
436
|
},
|
|
418
437
|
};
|
|
419
438
|
|