kupos-ui-components-lib 10.4.65 → 10.4.66
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/ServiceItemPb.d.ts +4 -0
- package/dist/ServiceItemPb.js +486 -0
- package/dist/assets/images/anims/service_list/60_percent_anim.json +1 -0
- package/dist/assets/images/directo-icon.png +0 -0
- package/dist/components/FilterSortBar/SingleFilterSheet.d.ts +15 -0
- package/dist/components/FilterSortBar/SingleFilterSheet.js +21 -0
- package/dist/components/PaymentOptions/PaymentOptionsDesktop.d.ts +4 -0
- package/dist/components/PaymentOptions/PaymentOptionsDesktop.js +5 -0
- package/dist/components/PaymentOptions/PaymentOptionsMobile.d.ts +4 -0
- package/dist/components/PaymentOptions/PaymentOptionsMobile.js +5 -0
- package/dist/components/PaymentOptions/ResponsivePaymentOptions.d.ts +3 -0
- package/dist/components/PaymentOptions/ResponsivePaymentOptions.js +10 -0
- package/dist/components/PaymentOptions/index.d.ts +5 -0
- package/dist/components/PaymentOptions/index.js +4 -0
- package/dist/components/PaymentOptions/mobileTypes.d.ts +0 -0
- package/dist/components/PaymentOptions/mobileTypes.js +0 -0
- package/dist/components/PaymentOptions/type.d.ts +4 -0
- package/dist/components/PaymentOptions/type.js +1 -0
- package/dist/components/ServiceItem/ExpandedDropdown.d.ts +19 -0
- package/dist/components/ServiceItem/ExpandedDropdown.js +28 -0
- package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
- package/dist/components/ServiceItem/ServiceItemDesktop.js +3 -3
- package/dist/components/ServiceItem/ServiceItemDesktopPeru.d.ts +6 -0
- package/dist/components/ServiceItem/ServiceItemDesktopPeru.js +612 -0
- package/dist/components/ServiceItem/types.d.ts +1 -0
- package/dist/example.d.ts +5 -0
- package/dist/example.js +240 -0
- package/dist/styles.css +3 -0
- package/dist/ui/SeatSection/SeatSection.d.ts +2 -1
- package/dist/ui/SeatSection/SeatSection.js +15 -4
- package/dist/ui/ServiceType.d.ts +9 -0
- package/dist/ui/ServiceType.js +9 -0
- package/dist/ui/TopAmenities/PromoCountdown.d.ts +18 -0
- package/dist/ui/TopAmenities/PromoCountdown.js +55 -0
- package/package.json +1 -1
- package/src/components/ServiceItem/ServiceItemDesktop.tsx +3 -0
- package/src/components/ServiceItem/types.ts +2 -0
- package/src/ui/SeatSection/SeatSection.tsx +55 -17
package/dist/example.js
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { KuposUIComponent } from "./index";
|
|
3
|
+
// Sample data for demonstration
|
|
4
|
+
const sampleServiceItem = {
|
|
5
|
+
id: "12345",
|
|
6
|
+
operator_details: [
|
|
7
|
+
"https://example.com/logo.png",
|
|
8
|
+
"4.5",
|
|
9
|
+
"Operator Name", // operator name
|
|
10
|
+
],
|
|
11
|
+
travel_date: "2025-08-01T09:00:00Z",
|
|
12
|
+
arrival_date: "2025-08-01T12:00:00Z",
|
|
13
|
+
dep_time: "09:00",
|
|
14
|
+
arr_time: "12:00",
|
|
15
|
+
available_seats: 5,
|
|
16
|
+
seat_types: [
|
|
17
|
+
{ label: "Salon Cama", fare: 50 },
|
|
18
|
+
{ label: "Premium", fare: 75 },
|
|
19
|
+
{ label: "Economy", fare: 40 },
|
|
20
|
+
],
|
|
21
|
+
offer_text: "Limited time offer: 20% off!",
|
|
22
|
+
is_direct_trip: true,
|
|
23
|
+
icons: {
|
|
24
|
+
origin: "https://example.com/origin.png",
|
|
25
|
+
destination: "https://example.com/destination.png",
|
|
26
|
+
rating: "https://example.com/star.png",
|
|
27
|
+
hours: "https://example.com/clock.png",
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
// Sample data for new ServiceItem component
|
|
31
|
+
const sampleNewServiceItem = {
|
|
32
|
+
id: "service123",
|
|
33
|
+
name: "Premium Car Wash",
|
|
34
|
+
description: "Complete exterior and interior cleaning with premium wax and polish",
|
|
35
|
+
price: 49.99,
|
|
36
|
+
currency: "$",
|
|
37
|
+
imageUrl: "https://example.com/carwash.jpg",
|
|
38
|
+
rating: 4.8,
|
|
39
|
+
available: true,
|
|
40
|
+
featured: true,
|
|
41
|
+
duration: "45 min",
|
|
42
|
+
location: "Downtown",
|
|
43
|
+
provider: {
|
|
44
|
+
name: "Sparkle Clean",
|
|
45
|
+
imageUrl: "https://example.com/sparkle.jpg",
|
|
46
|
+
rating: 4.9
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
// Sample data for PaymentSideBar
|
|
50
|
+
const samplePaymentData = {
|
|
51
|
+
orderSummary: {
|
|
52
|
+
subtotal: 49.99,
|
|
53
|
+
taxes: 5.00,
|
|
54
|
+
discount: 10.00,
|
|
55
|
+
total: 44.99
|
|
56
|
+
},
|
|
57
|
+
paymentMethods: [
|
|
58
|
+
{ id: "card", name: "Credit Card", icon: "💳" },
|
|
59
|
+
{ id: "paypal", name: "PayPal", icon: "🅿️" },
|
|
60
|
+
{ id: "apple", name: "Apple Pay", icon: "🍎" }
|
|
61
|
+
],
|
|
62
|
+
customerDetails: {
|
|
63
|
+
name: "John Doe",
|
|
64
|
+
email: "john@example.com",
|
|
65
|
+
phone: "+1 555-123-4567"
|
|
66
|
+
},
|
|
67
|
+
orderDetails: [
|
|
68
|
+
{ name: "Premium Car Wash", price: 49.99, quantity: 1 }
|
|
69
|
+
]
|
|
70
|
+
};
|
|
71
|
+
// Sample data for ServiceList
|
|
72
|
+
const sampleServiceList = [
|
|
73
|
+
{
|
|
74
|
+
id: "service123",
|
|
75
|
+
name: "Premium Car Wash",
|
|
76
|
+
description: "Complete exterior and interior cleaning with premium wax and polish",
|
|
77
|
+
price: 49.99,
|
|
78
|
+
currency: "$",
|
|
79
|
+
imageUrl: "https://example.com/carwash.jpg",
|
|
80
|
+
rating: 4.8,
|
|
81
|
+
available: true,
|
|
82
|
+
featured: true
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: "service456",
|
|
86
|
+
name: "Basic Car Wash",
|
|
87
|
+
description: "Quick exterior wash and vacuum",
|
|
88
|
+
price: 19.99,
|
|
89
|
+
currency: "$",
|
|
90
|
+
imageUrl: "https://example.com/basicwash.jpg",
|
|
91
|
+
rating: 4.2,
|
|
92
|
+
available: true,
|
|
93
|
+
featured: false
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: "service789",
|
|
97
|
+
name: "Interior Detailing",
|
|
98
|
+
description: "Deep cleaning of all interior surfaces",
|
|
99
|
+
price: 89.99,
|
|
100
|
+
currency: "$",
|
|
101
|
+
imageUrl: "https://example.com/detailing.jpg",
|
|
102
|
+
rating: 4.9,
|
|
103
|
+
available: false,
|
|
104
|
+
featured: false
|
|
105
|
+
}
|
|
106
|
+
];
|
|
107
|
+
const sampleFilters = {
|
|
108
|
+
categories: ["Wash", "Detailing", "Maintenance"],
|
|
109
|
+
priceRange: { min: 0, max: 100 },
|
|
110
|
+
sortBy: "price",
|
|
111
|
+
sortOrder: "asc"
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Example component showing how to use KuposUIComponent with different typeOfComponent values
|
|
115
|
+
*/
|
|
116
|
+
export default function Example() {
|
|
117
|
+
return (React.createElement("div", { className: "example-container", style: { padding: "20px", maxWidth: "1200px", margin: "0 auto" } },
|
|
118
|
+
React.createElement("h1", null, "KuposUI Component Examples"),
|
|
119
|
+
React.createElement("section", { style: { marginBottom: "40px" } },
|
|
120
|
+
React.createElement("h2", null, "Service Item Example"),
|
|
121
|
+
React.createElement(KuposUIComponent, { typeOfComponent: "serviceitem", variant: "desktop", serviceItem: sampleServiceItem, onBookButtonPress: () => console.log("Book button pressed!"), colors: {
|
|
122
|
+
kuposButtonColor: "#FF5722",
|
|
123
|
+
priceColor: "#4CAF50",
|
|
124
|
+
tooltipColor: "#333333",
|
|
125
|
+
ratingBorderColor: "#FFC107",
|
|
126
|
+
ratingBottomColor: "#FFF8E1",
|
|
127
|
+
secondaryBgColor: "#E0E0E0",
|
|
128
|
+
secondaryTextColor: "#757575",
|
|
129
|
+
primaryButtonTextColor: "#FFFFFF"
|
|
130
|
+
}, translation: {
|
|
131
|
+
buyButton: "Buy",
|
|
132
|
+
soldOutButton: "Sold Out",
|
|
133
|
+
hours: "hrs",
|
|
134
|
+
petFriendly: "Pet Friendly",
|
|
135
|
+
flexible: "Flexible",
|
|
136
|
+
title: "Important Information",
|
|
137
|
+
continueButton: "Continue",
|
|
138
|
+
okContinueButton: "OK, Continue",
|
|
139
|
+
chooseAnotherTripButton: "Choose Another Trip"
|
|
140
|
+
} })),
|
|
141
|
+
React.createElement("section", { style: { marginBottom: "40px" } },
|
|
142
|
+
React.createElement("h2", null, "Payment Sidebar Example"),
|
|
143
|
+
React.createElement("div", { style: { display: "flex", gap: "20px" } },
|
|
144
|
+
React.createElement("div", { style: { flex: 1 } },
|
|
145
|
+
React.createElement("h3", null, "Desktop Variant"),
|
|
146
|
+
React.createElement(KuposUIComponent, { typeOfComponent: "paymentsidebar", variant: "desktop", orderSummary: samplePaymentData.orderSummary, paymentMethods: samplePaymentData.paymentMethods, customerDetails: samplePaymentData.customerDetails, orderDetails: samplePaymentData.orderDetails, onPaymentMethodSelect: (id) => console.log(`Selected payment method: ${id}`), onPayButtonClick: () => console.log("Pay button clicked"), colors: {
|
|
147
|
+
primaryColor: "#4CAF50",
|
|
148
|
+
secondaryColor: "#2196F3",
|
|
149
|
+
backgroundColor: "#f5f5f5",
|
|
150
|
+
textColor: "#333",
|
|
151
|
+
cardBackgroundColor: "#fff"
|
|
152
|
+
} })),
|
|
153
|
+
React.createElement("div", { style: { flex: 1 } },
|
|
154
|
+
React.createElement("h3", null, "Mobile Variant"),
|
|
155
|
+
React.createElement(KuposUIComponent, { typeOfComponent: "paymentsidebar", variant: "mobile", orderSummary: samplePaymentData.orderSummary, paymentMethods: samplePaymentData.paymentMethods, customerDetails: samplePaymentData.customerDetails, orderDetails: samplePaymentData.orderDetails, onPaymentMethodSelect: (id) => console.log(`Selected payment method: ${id}`), onPayButtonClick: () => console.log("Pay button clicked"), colors: {
|
|
156
|
+
primaryColor: "#4CAF50",
|
|
157
|
+
secondaryColor: "#2196F3",
|
|
158
|
+
backgroundColor: "#f5f5f5",
|
|
159
|
+
textColor: "#333",
|
|
160
|
+
cardBackgroundColor: "#fff"
|
|
161
|
+
} })))),
|
|
162
|
+
React.createElement("section", { style: { marginBottom: "40px" } },
|
|
163
|
+
React.createElement("h2", null, "Service List Example"),
|
|
164
|
+
React.createElement("div", { style: { display: "flex", gap: "20px" } },
|
|
165
|
+
React.createElement("div", { style: { flex: 1 } },
|
|
166
|
+
React.createElement("h3", null, "Desktop Variant"),
|
|
167
|
+
React.createElement(KuposUIComponent, { typeOfComponent: "servicelist", variant: "desktop", services: sampleServiceList, onServiceSelect: (id) => console.log(`Selected service: ${id}`), onServiceView: (id) => console.log(`Viewing service: ${id}`), showFilters: true, filters: sampleFilters, onFilterChange: (filters) => console.log('Filters changed:', filters), colors: {
|
|
168
|
+
primaryColor: "#4CAF50",
|
|
169
|
+
secondaryColor: "#2196F3",
|
|
170
|
+
backgroundColor: "#f5f5f5",
|
|
171
|
+
textColor: "#333",
|
|
172
|
+
cardBackgroundColor: "#fff",
|
|
173
|
+
highlightColor: "#FFC107"
|
|
174
|
+
} })),
|
|
175
|
+
React.createElement("div", { style: { flex: 1 } },
|
|
176
|
+
React.createElement("h3", null, "Mobile Variant"),
|
|
177
|
+
React.createElement(KuposUIComponent, { typeOfComponent: "servicelist", variant: "mobile", services: sampleServiceList, onServiceSelect: (id) => console.log(`Selected service: ${id}`), onServiceView: (id) => console.log(`Viewing service: ${id}`), showFilters: true, filters: sampleFilters, onFilterChange: (filters) => console.log('Filters changed:', filters), colors: {
|
|
178
|
+
primaryColor: "#4CAF50",
|
|
179
|
+
secondaryColor: "#2196F3",
|
|
180
|
+
backgroundColor: "#f5f5f5",
|
|
181
|
+
textColor: "#333",
|
|
182
|
+
cardBackgroundColor: "#fff",
|
|
183
|
+
highlightColor: "#FFC107"
|
|
184
|
+
} })))),
|
|
185
|
+
React.createElement("section", { style: { marginBottom: "40px" } },
|
|
186
|
+
React.createElement("h2", null, "New Service Item Example"),
|
|
187
|
+
React.createElement("div", { style: { display: "flex", gap: "20px" } },
|
|
188
|
+
React.createElement("div", { style: { flex: 1 } },
|
|
189
|
+
React.createElement("h3", null, "Desktop Variant"),
|
|
190
|
+
React.createElement(KuposUIComponent, Object.assign({ typeOfComponent: "serviceitem", variant: "desktop" }, sampleNewServiceItem, { onBookButtonPress: () => console.log("Book button pressed!"), onViewDetails: () => console.log("View details clicked!"), colors: {
|
|
191
|
+
primaryColor: "#FF5722",
|
|
192
|
+
secondaryColor: "#2196F3",
|
|
193
|
+
backgroundColor: "#f5f5f5",
|
|
194
|
+
textColor: "#333",
|
|
195
|
+
cardBackgroundColor: "#fff",
|
|
196
|
+
highlightColor: "#FFC107"
|
|
197
|
+
}, t: (key) => key }))),
|
|
198
|
+
React.createElement("div", { style: { flex: 1 } },
|
|
199
|
+
React.createElement("h3", null, "Mobile Variant"),
|
|
200
|
+
React.createElement(KuposUIComponent, Object.assign({ typeOfComponent: "serviceitem", variant: "mobile" }, sampleNewServiceItem, { onBookButtonPress: () => console.log("Mobile book button pressed!"), onViewDetails: () => console.log("Mobile view details clicked!"), colors: {
|
|
201
|
+
primaryColor: "#FF5722",
|
|
202
|
+
secondaryColor: "#2196F3",
|
|
203
|
+
backgroundColor: "#f5f5f5",
|
|
204
|
+
textColor: "#333",
|
|
205
|
+
cardBackgroundColor: "#fff",
|
|
206
|
+
highlightColor: "#FFC107"
|
|
207
|
+
}, t: (key) => key }))))),
|
|
208
|
+
React.createElement("section", { style: { marginBottom: "40px" } },
|
|
209
|
+
React.createElement("h2", null, "Original Service Item Example"),
|
|
210
|
+
React.createElement("div", { style: { display: "flex", gap: "20px" } },
|
|
211
|
+
React.createElement("div", { style: { flex: 1 } },
|
|
212
|
+
React.createElement("h3", null, "Desktop Variant"),
|
|
213
|
+
React.createElement(KuposUIComponent, { typeOfComponent: "serviceitem", variant: "desktop", serviceItem: sampleServiceItem, onBookButtonPress: () => console.log("Book button pressed!"), colors: {
|
|
214
|
+
kuposButtonColor: "#FF5722",
|
|
215
|
+
priceColor: "#4CAF50",
|
|
216
|
+
tooltipColor: "#333333",
|
|
217
|
+
ratingBorderColor: "#FFC107",
|
|
218
|
+
ratingBottomColor: "#FFF8E1",
|
|
219
|
+
secondaryBgColor: "#E0E0E0",
|
|
220
|
+
secondaryTextColor: "#757575",
|
|
221
|
+
primaryButtonTextColor: "#FFFFFF"
|
|
222
|
+
}, translation: {
|
|
223
|
+
buyButton: "Buy",
|
|
224
|
+
soldOutButton: "Sold Out",
|
|
225
|
+
hours: "hrs",
|
|
226
|
+
petFriendly: "Pet Friendly",
|
|
227
|
+
flexible: "Flexible"
|
|
228
|
+
} })),
|
|
229
|
+
React.createElement("div", { style: { flex: 1 } },
|
|
230
|
+
React.createElement("h3", null, "Mobile Variant"),
|
|
231
|
+
React.createElement(KuposUIComponent, { typeOfComponent: "serviceitem", variant: "mobile", serviceItem: sampleServiceItem, onBookButtonPress: () => console.log("Mobile book button pressed!"), colors: {
|
|
232
|
+
kuposButtonColor: "#FF5722",
|
|
233
|
+
priceColor: "#4CAF50",
|
|
234
|
+
tooltipColor: "#333333"
|
|
235
|
+
}, translation: {
|
|
236
|
+
buyButton: "Buy",
|
|
237
|
+
soldOutButton: "Sold Out",
|
|
238
|
+
hours: "hrs"
|
|
239
|
+
} }))))));
|
|
240
|
+
}
|
package/dist/styles.css
CHANGED
|
@@ -16,6 +16,7 @@ interface SeatSectionProps {
|
|
|
16
16
|
removeDuplicateSeats?: boolean;
|
|
17
17
|
isPeru?: boolean;
|
|
18
18
|
showDesdeLabel?: boolean;
|
|
19
|
+
showSeatsWithDiscount?: boolean;
|
|
19
20
|
serviceItem?: any;
|
|
20
21
|
renderIcon?: (iconKey: string, size?: string) => React.ReactNode;
|
|
21
22
|
discountSeatPriceColor?: string;
|
|
@@ -28,5 +29,5 @@ interface SeatSectionProps {
|
|
|
28
29
|
discountSeatCrossPriceColor?: string;
|
|
29
30
|
isShowSeatIcon?: boolean;
|
|
30
31
|
}
|
|
31
|
-
declare function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, selectedSeatKey, onSeatSelect, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, isSeatIcon, isTrain, topLabelColor, tooltipColor, discountSeatCrossPriceColor, isShowSeatIcon, showDesdeLabel, }: SeatSectionProps): React.ReactElement;
|
|
32
|
+
declare function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, selectedSeatKey, onSeatSelect, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, isSeatIcon, isTrain, topLabelColor, tooltipColor, discountSeatCrossPriceColor, isShowSeatIcon, showDesdeLabel, showSeatsWithDiscount, }: SeatSectionProps): React.ReactElement;
|
|
32
33
|
export default SeatSection;
|
|
@@ -100,7 +100,7 @@ function addSeatDegree(label) {
|
|
|
100
100
|
return label;
|
|
101
101
|
return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
|
|
102
102
|
}
|
|
103
|
-
function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, selectedSeatKey, onSeatSelect, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, isSeatIcon, isTrain, topLabelColor, tooltipColor, discountSeatCrossPriceColor, isShowSeatIcon, showDesdeLabel = false, }) {
|
|
103
|
+
function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, selectedSeatKey, onSeatSelect, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, isSeatIcon, isTrain, topLabelColor, tooltipColor, discountSeatCrossPriceColor, isShowSeatIcon, showDesdeLabel = false, showSeatsWithDiscount = false, }) {
|
|
104
104
|
var _a;
|
|
105
105
|
const uniqueSeats = getUniqueSeats(seatTypes, isTrain);
|
|
106
106
|
const sortedSeatTypes = getSortedSeatTypes(seatTypes, isTrain);
|
|
@@ -367,17 +367,28 @@ function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currenc
|
|
|
367
367
|
const discountSeatIcon = (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) === 1 && isShowSeatIcon
|
|
368
368
|
? getSeatLabelIcon(discountSeat.label, serviceItem)
|
|
369
369
|
: null;
|
|
370
|
+
// List the seat types in place of the "Antes / Desde" labels
|
|
371
|
+
const showDiscountSeatRows = showSeatsWithDiscount && (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) !== 1;
|
|
372
|
+
const discountSeatRows = (showSeatTypeRows ? uniqueSeats : [discountSeat]).filter((s) => !SEAT_EXCEPTIONS.includes(s.label));
|
|
370
373
|
return (React.createElement("div", { className: "grid grid-cols-2 items-center text-[13.33px] relative", style: { opacity: isSoldOut ? 0.5 : 1 } },
|
|
371
|
-
(
|
|
374
|
+
showDiscountSeatRows ? (React.createElement("div", { className: "col-start-1 row-start-2 row-span-2 flex flex-col justify-center", style: { gap: "8px" } }, discountSeatRows.map((val, key) => (React.createElement("span", { key: key, className: "text-[13.33px] font-normal leading-[20px] text-[#464647] whitespace-nowrap flex items-center" },
|
|
375
|
+
isShowSeatIcon && !isMovilBus && (React.createElement("img", { src: getSeatLabelIcon(val.label, serviceItem), alt: "seattype", style: {
|
|
376
|
+
width: "20px",
|
|
377
|
+
height: "20px",
|
|
378
|
+
marginRight: "5px",
|
|
379
|
+
} })),
|
|
380
|
+
isMovilBus
|
|
381
|
+
? CommonService.truncateSeatLabel(val.label)
|
|
382
|
+
: CommonService.capitalize(addSeatDegree(val.label))))))) : (serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) === 1 ? null : (React.createElement("div", { className: "col-start-1 row-start-2 flex items-center" },
|
|
372
383
|
React.createElement("span", { className: "text-[13.33px] font-normal leading-[22px] text-[#ccc]" }, "Antes"))),
|
|
373
|
-
React.createElement("div", { className: "col-start-1 row-start-3 flex h-[20px] items-end" },
|
|
384
|
+
showDiscountSeatRows ? null : (React.createElement("div", { className: "col-start-1 row-start-3 flex h-[20px] items-end" },
|
|
374
385
|
React.createElement("span", { className: "text-[13.33px] font-normal leading-[20px] text-[#464647] whitespace-nowrap flex items-center" },
|
|
375
386
|
discountSeatIcon && (React.createElement("img", { src: discountSeatIcon, alt: "seattype", style: {
|
|
376
387
|
width: "20px",
|
|
377
388
|
height: "20px",
|
|
378
389
|
marginRight: "5px",
|
|
379
390
|
} })),
|
|
380
|
-
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) === 1 ? discountSeat.label : "Desde")),
|
|
391
|
+
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) === 1 ? discountSeat.label : "Desde"))),
|
|
381
392
|
React.createElement("div", { className: "col-start-2 row-start-1 flex items-center justify-center absolute", style: { top: "-22px", left: "50%", transform: "translateX(-50%)" } },
|
|
382
393
|
(serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.ui_type) !== 1 &&
|
|
383
394
|
!isPeru &&
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
declare const ServiceType: ({ serviceItem, translation, renderIcon, isSoldOut, colors, }: {
|
|
3
|
+
serviceItem: any;
|
|
4
|
+
translation: any;
|
|
5
|
+
renderIcon: any;
|
|
6
|
+
isSoldOut: any;
|
|
7
|
+
colors: any;
|
|
8
|
+
}) => React.JSX.Element;
|
|
9
|
+
export default ServiceType;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
const ServiceType = ({ serviceItem, translation, renderIcon, isSoldOut, colors, }) => (React.createElement("div", { className: "flex items-baseline relative whitespace-nowrap " },
|
|
3
|
+
React.createElement("div", { className: `w-[18px] mr-[4px] ${isSoldOut ? "grayscale" : ""}`, style: { opacity: isSoldOut ? 0.5 : 1 } }),
|
|
4
|
+
React.createElement("div", { className: "group text-[13.33px] cursor-pointer" },
|
|
5
|
+
React.createElement("span", { style: { opacity: isSoldOut ? 0.5 : 1 } }, serviceItem === null || serviceItem === void 0 ? void 0 : serviceItem.service_type),
|
|
6
|
+
React.createElement("div", { className: "hidden group-hover:block absolute top-[24px] left-1/2 -translate-x-1/2 text-white p-3 rounded-[14px] whitespace-normal z-10 mt-2.5 w-[188px] text-center break-normal shadow-service text-[12px]", style: { backgroundColor: colors.bottomStripColor } },
|
|
7
|
+
React.createElement("div", { className: "tooltip-arrow absolute -top-[7px] left-1/2 -translate-x-1/2 w-0 h-0 border-l-8 border-r-8 border-b-8 border-l-transparent border-r-transparent", style: { borderBottomColor: colors.bottomStripColor } }),
|
|
8
|
+
"Duraci\u00F3n estimada del viaje"))));
|
|
9
|
+
export default ServiceType;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface PromoCountdownProps {
|
|
3
|
+
countdownSeconds: number;
|
|
4
|
+
}
|
|
5
|
+
interface PromoCountdownState {
|
|
6
|
+
remaining: number;
|
|
7
|
+
}
|
|
8
|
+
declare class PromoCountdown extends React.Component<PromoCountdownProps, PromoCountdownState> {
|
|
9
|
+
private timer;
|
|
10
|
+
constructor(props: PromoCountdownProps);
|
|
11
|
+
componentDidMount(): void;
|
|
12
|
+
componentDidUpdate(prevProps: PromoCountdownProps): void;
|
|
13
|
+
componentWillUnmount(): void;
|
|
14
|
+
private clearTimer;
|
|
15
|
+
private startTimer;
|
|
16
|
+
render(): React.JSX.Element;
|
|
17
|
+
}
|
|
18
|
+
export default PromoCountdown;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
class PromoCountdown extends React.Component {
|
|
3
|
+
constructor(props) {
|
|
4
|
+
super(props);
|
|
5
|
+
this.timer = null;
|
|
6
|
+
this.state = { remaining: props.countdownSeconds };
|
|
7
|
+
}
|
|
8
|
+
componentDidMount() {
|
|
9
|
+
this.startTimer();
|
|
10
|
+
}
|
|
11
|
+
componentDidUpdate(prevProps) {
|
|
12
|
+
if (prevProps.countdownSeconds !== this.props.countdownSeconds) {
|
|
13
|
+
this.setState({ remaining: this.props.countdownSeconds }, () => {
|
|
14
|
+
this.startTimer();
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
componentWillUnmount() {
|
|
19
|
+
this.clearTimer();
|
|
20
|
+
}
|
|
21
|
+
clearTimer() {
|
|
22
|
+
if (this.timer) {
|
|
23
|
+
clearInterval(this.timer);
|
|
24
|
+
this.timer = null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
startTimer() {
|
|
28
|
+
this.clearTimer();
|
|
29
|
+
if (this.state.remaining <= 0)
|
|
30
|
+
return;
|
|
31
|
+
this.timer = setInterval(() => {
|
|
32
|
+
this.setState((prev) => {
|
|
33
|
+
if (prev.remaining <= 1) {
|
|
34
|
+
this.clearTimer();
|
|
35
|
+
return { remaining: 0 };
|
|
36
|
+
}
|
|
37
|
+
return { remaining: prev.remaining - 1 };
|
|
38
|
+
});
|
|
39
|
+
}, 1000);
|
|
40
|
+
}
|
|
41
|
+
render() {
|
|
42
|
+
const { remaining } = this.state;
|
|
43
|
+
const hrs = Math.floor(remaining / 3600);
|
|
44
|
+
const mins = Math.floor((remaining % 3600) / 60);
|
|
45
|
+
const secs = remaining % 60;
|
|
46
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
47
|
+
return (React.createElement("span", { className: "bold-text" },
|
|
48
|
+
pad(hrs),
|
|
49
|
+
":",
|
|
50
|
+
pad(mins),
|
|
51
|
+
":",
|
|
52
|
+
pad(secs)));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export default PromoCountdown;
|
package/package.json
CHANGED
|
@@ -155,6 +155,7 @@ function ServiceItemPB({
|
|
|
155
155
|
isShowSeatIcon = false,
|
|
156
156
|
showDesdeLabel = false,
|
|
157
157
|
showServiceTypeUnderLogo = false,
|
|
158
|
+
showSeatsWithDiscount = false,
|
|
158
159
|
}: ServiceItemProps & { currencySign?: string }): React.ReactElement {
|
|
159
160
|
const handleSeatSelect = (
|
|
160
161
|
key: any,
|
|
@@ -721,6 +722,7 @@ function ServiceItemPB({
|
|
|
721
722
|
}
|
|
722
723
|
isShowSeatIcon={isShowSeatIcon}
|
|
723
724
|
showDesdeLabel={showDesdeLabel}
|
|
725
|
+
showSeatsWithDiscount={showSeatsWithDiscount}
|
|
724
726
|
/>
|
|
725
727
|
</div>
|
|
726
728
|
|
|
@@ -735,6 +737,7 @@ function ServiceItemPB({
|
|
|
735
737
|
soldOutLabel={translation?.soldOutButton}
|
|
736
738
|
soldOutIcon={renderIcon("soldOutIcon", "14px")}
|
|
737
739
|
onClick={checkMidnight}
|
|
740
|
+
buttonTextColor ={colors.primaryButtonTextColor}
|
|
738
741
|
/>
|
|
739
742
|
{showSeatSelectionError === serviceItem.id && isTrain && (
|
|
740
743
|
<div className="flex justify-center mr-[11px] w-[100%] right-[0px] absolute left-[0] top-[40px]">
|
|
@@ -290,5 +290,7 @@ export interface ServiceItemProps {
|
|
|
290
290
|
isShowSeatIcon?: boolean;
|
|
291
291
|
// shows a small "Desde" label above the price in the seat section
|
|
292
292
|
showDesdeLabel?: boolean;
|
|
293
|
+
// keeps listing the seat types next to the discounted price
|
|
294
|
+
showSeatsWithDiscount?: boolean;
|
|
293
295
|
showServiceTypeUnderLogo?: boolean;
|
|
294
296
|
}
|
|
@@ -21,6 +21,7 @@ interface SeatSectionProps {
|
|
|
21
21
|
removeDuplicateSeats?: boolean;
|
|
22
22
|
isPeru?: boolean;
|
|
23
23
|
showDesdeLabel?: boolean;
|
|
24
|
+
showSeatsWithDiscount?: boolean;
|
|
24
25
|
serviceItem?: any;
|
|
25
26
|
renderIcon?: (iconKey: string, size?: string) => React.ReactNode;
|
|
26
27
|
discountSeatPriceColor?: string;
|
|
@@ -172,6 +173,7 @@ function SeatSection({
|
|
|
172
173
|
discountSeatCrossPriceColor,
|
|
173
174
|
isShowSeatIcon,
|
|
174
175
|
showDesdeLabel = false,
|
|
176
|
+
showSeatsWithDiscount = false,
|
|
175
177
|
}: SeatSectionProps): React.ReactElement {
|
|
176
178
|
const uniqueSeats = getUniqueSeats(seatTypes, isTrain);
|
|
177
179
|
const sortedSeatTypes = getSortedSeatTypes(seatTypes, isTrain);
|
|
@@ -692,12 +694,46 @@ function SeatSection({
|
|
|
692
694
|
? getSeatLabelIcon(discountSeat.label, serviceItem)
|
|
693
695
|
: null;
|
|
694
696
|
|
|
697
|
+
// List the seat types in place of the "Antes / Desde" labels
|
|
698
|
+
const showDiscountSeatRows =
|
|
699
|
+
showSeatsWithDiscount && serviceItem?.ui_type !== 1;
|
|
700
|
+
const discountSeatRows = (
|
|
701
|
+
showSeatTypeRows ? uniqueSeats : [discountSeat]
|
|
702
|
+
).filter((s) => !SEAT_EXCEPTIONS.includes(s.label));
|
|
703
|
+
|
|
695
704
|
return (
|
|
696
705
|
<div
|
|
697
706
|
className="grid grid-cols-2 items-center text-[13.33px] relative"
|
|
698
707
|
style={{ opacity: isSoldOut ? 0.5 : 1 }}
|
|
699
708
|
>
|
|
700
|
-
{
|
|
709
|
+
{showDiscountSeatRows ? (
|
|
710
|
+
<div
|
|
711
|
+
className="col-start-1 row-start-2 row-span-2 flex flex-col justify-center"
|
|
712
|
+
style={{ gap: "8px" }}
|
|
713
|
+
>
|
|
714
|
+
{discountSeatRows.map((val, key) => (
|
|
715
|
+
<span
|
|
716
|
+
key={key}
|
|
717
|
+
className="text-[13.33px] font-normal leading-[20px] text-[#464647] whitespace-nowrap flex items-center"
|
|
718
|
+
>
|
|
719
|
+
{isShowSeatIcon && !isMovilBus && (
|
|
720
|
+
<img
|
|
721
|
+
src={getSeatLabelIcon(val.label, serviceItem)}
|
|
722
|
+
alt="seattype"
|
|
723
|
+
style={{
|
|
724
|
+
width: "20px",
|
|
725
|
+
height: "20px",
|
|
726
|
+
marginRight: "5px",
|
|
727
|
+
}}
|
|
728
|
+
/>
|
|
729
|
+
)}
|
|
730
|
+
{isMovilBus
|
|
731
|
+
? CommonService.truncateSeatLabel(val.label)
|
|
732
|
+
: CommonService.capitalize(addSeatDegree(val.label))}
|
|
733
|
+
</span>
|
|
734
|
+
))}
|
|
735
|
+
</div>
|
|
736
|
+
) : serviceItem?.ui_type === 1 ? null : (
|
|
701
737
|
<div className="col-start-1 row-start-2 flex items-center">
|
|
702
738
|
<span className="text-[13.33px] font-normal leading-[22px] text-[#ccc]">
|
|
703
739
|
Antes
|
|
@@ -705,22 +741,24 @@ function SeatSection({
|
|
|
705
741
|
</div>
|
|
706
742
|
)}
|
|
707
743
|
|
|
708
|
-
|
|
709
|
-
<
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
744
|
+
{showDiscountSeatRows ? null : (
|
|
745
|
+
<div className="col-start-1 row-start-3 flex h-[20px] items-end">
|
|
746
|
+
<span className="text-[13.33px] font-normal leading-[20px] text-[#464647] whitespace-nowrap flex items-center">
|
|
747
|
+
{discountSeatIcon && (
|
|
748
|
+
<img
|
|
749
|
+
src={discountSeatIcon}
|
|
750
|
+
alt="seattype"
|
|
751
|
+
style={{
|
|
752
|
+
width: "20px",
|
|
753
|
+
height: "20px",
|
|
754
|
+
marginRight: "5px",
|
|
755
|
+
}}
|
|
756
|
+
/>
|
|
757
|
+
)}
|
|
758
|
+
{serviceItem?.ui_type === 1 ? discountSeat.label : "Desde"}
|
|
759
|
+
</span>
|
|
760
|
+
</div>
|
|
761
|
+
)}
|
|
724
762
|
|
|
725
763
|
<div
|
|
726
764
|
className="col-start-2 row-start-1 flex items-center justify-center absolute"
|