kupos-ui-components-lib 9.9.4 → 9.9.6
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/FeatureServiceUI/FeatureServiceUi.js +19 -4
- 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 +5 -7
- package/dist/ui/mobileweb/SeatSectionMobile.d.ts +1 -2
- package/dist/ui/mobileweb/SeatSectionMobile.js +10 -15
- 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 +33 -38
- package/src/ui/mobileweb/SeatSectionMobile.tsx +7 -12
- 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
|
|
|
@@ -202,7 +198,6 @@ function DateTimeSectionMobile({
|
|
|
202
198
|
tooltipBgColor={tooltipBgColor}
|
|
203
199
|
showLastSeats={showLastSeats}
|
|
204
200
|
discountSeatPriceColor={discountSeatPriceColor}
|
|
205
|
-
isTrain={isTrain}
|
|
206
201
|
/>
|
|
207
202
|
</div>
|
|
208
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 {
|
|
@@ -119,7 +118,6 @@ function SeatSectionMobile({
|
|
|
119
118
|
tooltipBgColor,
|
|
120
119
|
showLastSeats,
|
|
121
120
|
discountSeatPriceColor,
|
|
122
|
-
isTrain,
|
|
123
121
|
}: SeatSectionMobileProps): React.ReactElement {
|
|
124
122
|
const hasMultipleTypes = (seatTypesData?.length ?? 0) > 2;
|
|
125
123
|
|
|
@@ -284,11 +282,10 @@ function SeatSectionMobile({
|
|
|
284
282
|
));
|
|
285
283
|
}
|
|
286
284
|
|
|
287
|
-
|
|
285
|
+
return seatTypesData
|
|
288
286
|
?.filter((item) => getFilteredSeats(item.label))
|
|
289
|
-
?.sort((a, b) => a.fare - b.fare)
|
|
290
|
-
|
|
291
|
-
return (isTrain ? filteredSeats : filteredSeats?.slice(0, 2))
|
|
287
|
+
?.sort((a, b) => a.fare - b.fare)
|
|
288
|
+
?.slice(0, 2)
|
|
292
289
|
?.map((type, i) => (
|
|
293
290
|
<SeatRow
|
|
294
291
|
key={i}
|
|
@@ -306,12 +303,10 @@ function SeatSectionMobile({
|
|
|
306
303
|
|
|
307
304
|
const seats = removeDuplicateSeats
|
|
308
305
|
? getUniqueSeats(seatTypesData, 3)
|
|
309
|
-
:
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return isTrain ? filtered : filtered?.slice(0, 2);
|
|
314
|
-
})();
|
|
306
|
+
: seatTypesData
|
|
307
|
+
?.filter((item) => getFilteredSeats(item.label))
|
|
308
|
+
?.sort((a, b) => a.fare - b.fare)
|
|
309
|
+
?.slice(0, 2);
|
|
315
310
|
|
|
316
311
|
const discountedSeats = seats?.map((seat) => ({
|
|
317
312
|
...seat,
|
|
@@ -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
|
|