kupos-ui-components-lib 10.4.65 → 10.4.67

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 (40) hide show
  1. package/dist/ServiceItemPb.d.ts +4 -0
  2. package/dist/ServiceItemPb.js +486 -0
  3. package/dist/assets/images/anims/service_list/60_percent_anim.json +1 -0
  4. package/dist/assets/images/directo-icon.png +0 -0
  5. package/dist/components/FilterSortBar/SingleFilterSheet.d.ts +15 -0
  6. package/dist/components/FilterSortBar/SingleFilterSheet.js +21 -0
  7. package/dist/components/PaymentOptions/PaymentOptionsDesktop.d.ts +4 -0
  8. package/dist/components/PaymentOptions/PaymentOptionsDesktop.js +5 -0
  9. package/dist/components/PaymentOptions/PaymentOptionsMobile.d.ts +4 -0
  10. package/dist/components/PaymentOptions/PaymentOptionsMobile.js +5 -0
  11. package/dist/components/PaymentOptions/ResponsivePaymentOptions.d.ts +3 -0
  12. package/dist/components/PaymentOptions/ResponsivePaymentOptions.js +10 -0
  13. package/dist/components/PaymentOptions/index.d.ts +5 -0
  14. package/dist/components/PaymentOptions/index.js +4 -0
  15. package/dist/components/PaymentOptions/mobileTypes.d.ts +0 -0
  16. package/dist/components/PaymentOptions/mobileTypes.js +0 -0
  17. package/dist/components/PaymentOptions/type.d.ts +4 -0
  18. package/dist/components/PaymentOptions/type.js +1 -0
  19. package/dist/components/ServiceItem/ExpandedDropdown.d.ts +19 -0
  20. package/dist/components/ServiceItem/ExpandedDropdown.js +28 -0
  21. package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
  22. package/dist/components/ServiceItem/ServiceItemDesktop.js +3 -3
  23. package/dist/components/ServiceItem/ServiceItemDesktopPeru.d.ts +6 -0
  24. package/dist/components/ServiceItem/ServiceItemDesktopPeru.js +612 -0
  25. package/dist/components/ServiceItem/types.d.ts +1 -0
  26. package/dist/example.d.ts +5 -0
  27. package/dist/example.js +240 -0
  28. package/dist/styles.css +3 -0
  29. package/dist/ui/PaymentCardMobile/PaymentCardMobile.js +2 -5
  30. package/dist/ui/SeatSection/SeatSection.d.ts +2 -1
  31. package/dist/ui/SeatSection/SeatSection.js +15 -4
  32. package/dist/ui/ServiceType.d.ts +9 -0
  33. package/dist/ui/ServiceType.js +9 -0
  34. package/dist/ui/TopAmenities/PromoCountdown.d.ts +18 -0
  35. package/dist/ui/TopAmenities/PromoCountdown.js +55 -0
  36. package/package.json +1 -1
  37. package/src/components/ServiceItem/ServiceItemDesktop.tsx +3 -0
  38. package/src/components/ServiceItem/types.ts +2 -0
  39. package/src/ui/PaymentCardMobile/PaymentCardMobile.tsx +2 -5
  40. package/src/ui/SeatSection/SeatSection.tsx +55 -17
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+ /**
3
+ * Example component showing how to use KuposUIComponent with different typeOfComponent values
4
+ */
5
+ export default function Example(): React.JSX.Element;
@@ -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
@@ -183,6 +183,9 @@
183
183
  .col-start-2 {
184
184
  grid-column-start: 2;
185
185
  }
186
+ .row-span-2 {
187
+ grid-row: span 2 / span 2;
188
+ }
186
189
  .row-start-1 {
187
190
  grid-row-start: 1;
188
191
  }
@@ -494,14 +494,11 @@ export const PaymentCardMobile = (props) => {
494
494
  currency ? currency : "",
495
495
  " ",
496
496
  CommonService.currency(isPeru
497
- ? Math.round(Math.max(0, ((removeDiscountAtomValue
498
- ? 0
499
- : (netFare !== null && netFare !== void 0 ? netFare : 0)) -
500
- (walletMoney !== null && walletMoney !== void 0 ? walletMoney : 0)) *
497
+ ? Math.round(Math.max(0, (removeDiscountAtomValue ? 0 : (netFare !== null && netFare !== void 0 ? netFare : 0)) *
501
498
  100)) / 100
502
499
  : removeDiscountAtomValue
503
500
  ? 0
504
- : Math.max(0, (netFare !== null && netFare !== void 0 ? netFare : 0) - (walletMoney !== null && walletMoney !== void 0 ? walletMoney : 0)), currencySign))))));
501
+ : Math.max(0, netFare !== null && netFare !== void 0 ? netFare : 0), currencySign))))));
505
502
  } }),
506
503
  React.createElement("div", { style: {
507
504
  display: "flex",
@@ -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
- (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" },
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kupos-ui-components-lib",
3
- "version": "10.4.65",
3
+ "version": "10.4.67",
4
4
  "description": "A reusable UI components package",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -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
  }
@@ -966,16 +966,13 @@ export const PaymentCardMobile: React.FC<PaymentSideBarProps> = (props) => {
966
966
  ? Math.round(
967
967
  Math.max(
968
968
  0,
969
- ((removeDiscountAtomValue
970
- ? 0
971
- : (netFare ?? 0)) -
972
- (walletMoney ?? 0)) *
969
+ (removeDiscountAtomValue ? 0 : (netFare ?? 0)) *
973
970
  100,
974
971
  ),
975
972
  ) / 100
976
973
  : removeDiscountAtomValue
977
974
  ? 0
978
- : Math.max(0, (netFare ?? 0) - (walletMoney ?? 0)),
975
+ : Math.max(0, netFare ?? 0),
979
976
  currencySign,
980
977
  )}
981
978
  </span>
@@ -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
- {serviceItem?.ui_type === 1 ? null : (
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
- <div className="col-start-1 row-start-3 flex h-[20px] items-end">
709
- <span className="text-[13.33px] font-normal leading-[20px] text-[#464647] whitespace-nowrap flex items-center">
710
- {discountSeatIcon && (
711
- <img
712
- src={discountSeatIcon}
713
- alt="seattype"
714
- style={{
715
- width: "20px",
716
- height: "20px",
717
- marginRight: "5px",
718
- }}
719
- />
720
- )}
721
- {serviceItem?.ui_type === 1 ? discountSeat.label : "Desde"}
722
- </span>
723
- </div>
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"