kupos-ui-components-lib 9.11.4 → 9.11.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.
Files changed (31) hide show
  1. package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
  2. package/dist/components/ServiceItem/ServiceItemDesktop.js +6 -24
  3. package/dist/components/ServiceItem/ServiceItemMobile.d.ts +1 -1
  4. package/dist/components/ServiceItem/ServiceItemMobile.js +1 -1
  5. package/dist/components/ServiceItem/mobileTypes.d.ts +0 -1
  6. package/dist/components/ServiceItem/types.d.ts +0 -7
  7. package/dist/styles.css +11 -6
  8. package/dist/ui/BottomAmenities/BottomAmenities.d.ts +1 -2
  9. package/dist/ui/BottomAmenities/BottomAmenities.js +2 -4
  10. package/dist/ui/DateTimeSection/DateTimeSection.js +4 -4
  11. package/dist/ui/FeatureServiceUI/FeatureServiceUi.js +5 -5
  12. package/dist/ui/SeatSection/SeatSection.d.ts +1 -7
  13. package/dist/ui/SeatSection/SeatSection.js +15 -47
  14. package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +1 -2
  15. package/dist/ui/mobileweb/DateTimeSectionMobile.js +7 -13
  16. package/dist/ui/mobileweb/SeatSectionMobile.d.ts +1 -2
  17. package/dist/ui/mobileweb/SeatSectionMobile.js +16 -23
  18. package/dist/utils/CommonService.d.ts +1 -1
  19. package/dist/utils/CommonService.js +2 -6
  20. package/package.json +1 -1
  21. package/src/components/ServiceItem/ServiceItemDesktop.tsx +3 -49
  22. package/src/components/ServiceItem/ServiceItemMobile.tsx +1 -2
  23. package/src/components/ServiceItem/mobileTypes.ts +26 -31
  24. package/src/components/ServiceItem/types.ts +0 -12
  25. package/src/ui/BottomAmenities/BottomAmenities.tsx +1 -5
  26. package/src/ui/DateTimeSection/DateTimeSection.tsx +4 -4
  27. package/src/ui/FeatureServiceUI/FeatureServiceUi.tsx +8 -5
  28. package/src/ui/SeatSection/SeatSection.tsx +26 -94
  29. package/src/ui/mobileweb/DateTimeSectionMobile.tsx +34 -47
  30. package/src/ui/mobileweb/SeatSectionMobile.tsx +14 -28
  31. package/src/utils/CommonService.ts +2 -8
@@ -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
  tooltipColor?: string;
36
25
  }
37
26
 
@@ -43,8 +32,6 @@ function getAllSeatTypes(seatTypes: SeatType[]) {
43
32
  let seatTypesWithPrices = seatTypes.filter(Boolean).map((val) => ({
44
33
  label: val?.label,
45
34
  price: val?.fare,
46
- key: val?.key,
47
- apiSeatType: val?.apiSeatType || val?.api_seat_type,
48
35
  }));
49
36
 
50
37
  seatTypesWithPrices.sort((a, b) => a.price - b.price);
@@ -52,7 +39,7 @@ function getAllSeatTypes(seatTypes: SeatType[]) {
52
39
  return seatTypesWithPrices;
53
40
  }
54
41
 
55
- function getSortedSeatTypes(seatTypes: SeatType[], isTrain: any) {
42
+ function getSortedSeatTypes(seatTypes: SeatType[]) {
56
43
  if (!seatTypes?.length) {
57
44
  return [{ label: "Salon cama", price: 0 }];
58
45
  }
@@ -66,9 +53,7 @@ function getSortedSeatTypes(seatTypes: SeatType[], isTrain: any) {
66
53
  seatTypesWithPrices[2] = seatTypesWithPrices[premiumIndex];
67
54
  }
68
55
 
69
- if (!isTrain) {
70
- seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
71
- }
56
+ seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
72
57
 
73
58
  const seenPrices = new Set<number>();
74
59
  seatTypesWithPrices = seatTypesWithPrices.filter((seat) => {
@@ -113,19 +98,15 @@ function SeatSection({
113
98
  priceColor,
114
99
  currencySign,
115
100
  removeDuplicateSeats,
116
- selectedSeatKey,
117
- onSeatSelect,
118
101
  isPeru,
119
102
  serviceItem,
120
103
  renderIcon,
121
104
  dpSeatColor,
122
105
  discountSeatPriceColor,
123
- isTrain,
124
- topLabelColor,
125
106
  tooltipColor,
126
107
  }: SeatSectionProps): React.ReactElement {
127
108
  const uniqueSeats = getUniqueSeats(seatTypes);
128
- const sortedSeatTypes = getSortedSeatTypes(seatTypes, isTrain);
109
+ const sortedSeatTypes = getSortedSeatTypes(seatTypes);
129
110
  const numberOfSeats = getNumberOfSeats(seatTypes);
130
111
  const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
131
112
 
@@ -137,73 +118,28 @@ function SeatSection({
137
118
  const renderSeatNames = () => {
138
119
  const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
139
120
 
140
- return seats.map((val, key: number) => {
141
- return SEAT_EXCEPTIONS.includes(val.label) ? null : (
142
- <div
143
- className="flex items-center"
144
- style={isTrain ? { cursor: "pointer" } : undefined}
145
- onClick={
146
- isTrain && !isSoldOut
147
- ? () =>
148
- val.label === selectedSeatKey
149
- ? onSeatSelect?.(null, 0, "", "")
150
- : onSeatSelect?.(
151
- val.label,
152
- val.price,
153
- val.key,
154
- (val as any).apiSeatType,
155
- )
156
- : undefined
157
- }
121
+ return seats.map((val, key: number) =>
122
+ SEAT_EXCEPTIONS.includes(val.label) ? null : (
123
+ <span
124
+ key={key}
125
+ className={`flex items-center justify-between text-[13.33px] ${
126
+ isSoldOut ? "text-[#c0c0c0]" : ""
127
+ }`}
158
128
  >
159
- {isTrain && (
160
- <div
161
- style={{
162
- border: `1px solid ${val.label === selectedSeatKey ? topLabelColor : "#ccc"}`,
163
- borderRadius: "50%",
164
- width: "14px",
165
- height: "14px",
166
- minWidth: "14px",
167
- marginRight: "10px",
168
- display: "flex",
169
- alignItems: "center",
170
- justifyContent: "center",
171
- }}
172
- >
173
- {val.label === selectedSeatKey && (
174
- <div
175
- style={{
176
- backgroundColor: topLabelColor,
177
- borderRadius: "50%",
178
- width: "7px",
179
- height: "7px",
180
- }}
181
- />
182
- )}
183
- </div>
184
- )}
185
- <span
186
- key={key}
187
- className={`flex items-center justify-between text-[13.33px] whitespace-nowrap ${
188
- isSoldOut ? "text-[#c0c0c0]" : ""
189
- }`}
190
- >
191
- {typeof val.label === "string" || typeof val.label === "number"
192
- ? removeDuplicateSeats && isPeru
193
- ? CommonService.truncateSeatLabel(val.label)
194
- : isTrain
195
- ? CommonService.capitalize(String(val.label))
196
- : val.label
197
- : null}
198
- </span>
199
- </div>
200
- );
201
- });
129
+ {typeof val.label === "string" || typeof val.label === "number"
130
+ ? removeDuplicateSeats && isPeru
131
+ ? CommonService.truncateSeatLabel(val.label)
132
+ : val.label
133
+ : null}
134
+ </span>
135
+ ),
136
+ );
202
137
  };
203
138
 
204
139
  const renderSeatPrices = () => {
205
140
  if (isPeru) {
206
- const isMovilBus = serviceItem?.operator_service_name === "MovilBus";
141
+ const isMovilBus =
142
+ serviceItem?.operator_service_name === "MovilBus" || "Movil Bus";
207
143
 
208
144
  // Multiple unique seat types → show a price row for each (MovilBus only)
209
145
  if (isMovilBus && uniqueSeats.length > 1) {
@@ -302,7 +238,6 @@ function SeatSection({
302
238
  }
303
239
  return null;
304
240
  })();
305
- console.log("🚀 ~ SeatSection ~ serviceItem:", serviceItem);
306
241
 
307
242
  // Hide the % OFF badge when max_discount is capping the percentage discount
308
243
  // (i.e. both percentage and max_discount exist, and the raw % amount exceeds the cap)
@@ -324,7 +259,8 @@ function SeatSection({
324
259
 
325
260
  const renderLabels = () => {
326
261
  if (isPeru) {
327
- const isMovilBus = serviceItem?.operator_service_name === "MovilBus";
262
+ const isMovilBus =
263
+ serviceItem?.operator_service_name === "MovilBus" || "Movil Bus";
328
264
 
329
265
  // Multiple unique seat types → show a label row for each (MovilBus only)
330
266
  if (isMovilBus && uniqueSeats.length > 1) {
@@ -355,7 +291,7 @@ function SeatSection({
355
291
  : null;
356
292
 
357
293
  const operatorServiceName =
358
- serviceItem?.operator_service_name === "MovilBus";
294
+ serviceItem?.operator_service_name === "MovilBus" || "Movil Bus";
359
295
 
360
296
  return (
361
297
  <>
@@ -372,9 +308,7 @@ function SeatSection({
372
308
 
373
309
  <span className="text-[13.33px] flex flex-col">
374
310
  {operatorServiceName ? (
375
- <span className="text-[13.33px] whitespace-nowrap">
376
- {seatLabel}
377
- </span>
311
+ <span className="text-[13.33px]">{seatLabel}</span>
378
312
  ) : (
379
313
  <span className="text-[13.33px]">Desde</span>
380
314
  )}
@@ -597,7 +531,7 @@ function SeatSection({
597
531
  style={{ textAlign: "center" }}
598
532
  >
599
533
  <span
600
- className="text-[13.33px] font-normal leading-[20px] text-[#9f9f9f] relative whitespace-nowrap"
534
+ className="text-[13.33px] font-normal leading-[20px] text-[#9f9f9f] relative"
601
535
  style={{
602
536
  position: "relative",
603
537
  }}
@@ -659,9 +593,7 @@ function SeatSection({
659
593
  color: isSoldOut ? "#c0c0c0" : priceColor,
660
594
  top: 0,
661
595
  bottom: 0,
662
- left: isTrain
663
- ? "73%"
664
- : "clamp(60%, 65% + (100vw - 1300px) * 0.1, 65%)",
596
+ left: "clamp(60%, 65% + (100vw - 1300px) * 0.1, 65%)",
665
597
  right: 0,
666
598
  justifyContent: isCentered ? "center" : "",
667
599
  gap: "10px",
@@ -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,47 +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
- ? "max-[399px]:left-[53%]"
73
- : "";
74
- return (
75
- <div
76
- className={`flex items-center min-[420]:text-[13px] text-[12px] justify-between ${
77
- isSoldOut ? "text-[#c0c0c0]" : ""
78
- }`}
79
- >
80
- <div className="flex items-center" style={{ flex: 1 }}>
81
- <div>
82
- {" "}
83
- {label ? (
84
- <div className="w-[60px]">{label}</div>
85
- ) : (
86
- <div className="w-[12px] h-auto mr-[5px]">
87
- <img
88
- src={icon}
89
- alt={alt}
90
- className={`w-[12px] h-auto mr-[5px] ${
91
- isSoldOut ? "grayscale" : ""
92
- }`}
93
- />
94
- </div>
95
- )}
96
- </div>
97
- <div
98
- className="flex items-center relative capitalize justify-between"
99
- style={{ flex: 1 }}
100
- >
101
- <span className="cursor-pointer black-text whitespace-nowrap">
102
- {formattedDate}
103
- </span>
104
- <div className={`absolute left-[50%] ${dotPositionClass}`}>•</div>
105
- <div className="font-[900] relative black-text whitespace-nowrap">
106
- {timeContent}
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
+ />
107
90
  </div>
108
- </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>
109
102
  </div>
110
103
  </div>
111
- );
104
+ </div>;
112
105
  };
113
106
 
114
107
  function DateTimeSectionMobile({
@@ -134,7 +127,6 @@ function DateTimeSectionMobile({
134
127
  tooltipBgColor,
135
128
  showLastSeats,
136
129
  discountSeatPriceColor,
137
- isTrain,
138
130
  }: DateTimeSectionMobileProps): React.ReactElement {
139
131
  const { cleaned: cleanedDepTime, hasAM, hasPM } = getCleanedDepTime(depTime);
140
132
 
@@ -161,12 +153,8 @@ function DateTimeSectionMobile({
161
153
  >
162
154
  {/* DATE AND TIME */}
163
155
  <div
164
- className={`flex flex-col gap-[4px] w-[50%] ${isTrain ? "justify-center" : "justify-between"}`}
165
- style={{
166
- justifyContent: isCiva && "center",
167
- minHeight: isTrain ? undefined : "2.5rem",
168
- alignSelf: isTrain ? "stretch" : undefined,
169
- }}
156
+ className="min-h-[2.5rem] flex flex-col justify-between gap-[4px] w-[50%] "
157
+ style={{ justifyContent: isCiva && "center" }}
170
158
  >
171
159
  <TimeRow
172
160
  label={orignLabel}
@@ -210,7 +198,6 @@ function DateTimeSectionMobile({
210
198
  tooltipBgColor={tooltipBgColor}
211
199
  showLastSeats={showLastSeats}
212
200
  discountSeatPriceColor={discountSeatPriceColor}
213
- isTrain={isTrain}
214
201
  />
215
202
  </div>
216
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,12 +69,7 @@ const SeatRow: React.FC<SeatRowProps> = ({
72
69
  className={`min-[420]:text-[13px] ${textSize} `}
73
70
  style={{ color: labelColor }}
74
71
  >
75
- {isTrain
76
- ? commonService.truncateSeatLabel(
77
- commonService.capitalize(displayLabel),
78
- 8,
79
- )
80
- : displayLabel}
72
+ {displayLabel}
81
73
  </span>
82
74
  <span
83
75
  className={`min-[420]:text-[13px] ${textSize} bold-text`}
@@ -126,7 +118,6 @@ function SeatSectionMobile({
126
118
  tooltipBgColor,
127
119
  showLastSeats,
128
120
  discountSeatPriceColor,
129
- isTrain,
130
121
  }: SeatSectionMobileProps): React.ReactElement {
131
122
  const hasMultipleTypes = (seatTypesData?.length ?? 0) > 2;
132
123
 
@@ -158,7 +149,8 @@ function SeatSectionMobile({
158
149
  if (lowestFare === null) return null;
159
150
 
160
151
  const priceColor = isSoldOut ? "#bbb" : seatPriceColor;
161
- const isMovilBus = serviceItem?.operator_service_name === "MovilBus";
152
+ const isMovilBus =
153
+ serviceItem?.operator_service_name === "MovilBus" || "Movil Bus";
162
154
 
163
155
  // Fetch ALL unique seats (no slice limit) for the multi-row MovilBus case
164
156
  const uniqueSeats = getUniqueSeats(seatTypesData ?? [], Infinity as number);
@@ -178,7 +170,7 @@ function SeatSectionMobile({
178
170
  className="w-[100%] flex flex-row justify-between items-center"
179
171
  >
180
172
  <span
181
- className="min-[420]:text-[13px] text-[12px] bold-text whitespace-nowrap"
173
+ className="min-[420]:text-[13px] text-[12px] bold-text"
182
174
  style={{ color: isSoldOut ? "#bbb" : "#464647" }}
183
175
  >
184
176
  {commonService.truncateSeatLabel(seat.label)}
@@ -331,17 +323,15 @@ function SeatSectionMobile({
331
323
  seatPriceColor={seatPriceColor}
332
324
  hasMultipleTypes={hasMultipleTypes}
333
325
  textSize="text-[11px]"
334
- isTrain={isTrain}
335
326
  />
336
327
  ));
337
328
  }
338
329
 
339
- const filteredSeats = seatTypesData
330
+ return seatTypesData
340
331
  ?.filter((item) => getFilteredSeats(item.label))
341
- ?.sort((a, b) => a.fare - b.fare);
342
-
343
- return (isTrain ? filteredSeats : filteredSeats?.slice(0, 2))?.map(
344
- (type, i) => (
332
+ ?.sort((a, b) => a.fare - b.fare)
333
+ ?.slice(0, 2)
334
+ ?.map((type, i) => (
345
335
  <SeatRow
346
336
  key={i}
347
337
  type={type}
@@ -352,20 +342,16 @@ function SeatSectionMobile({
352
342
  seatPriceColor={seatPriceColor}
353
343
  hasMultipleTypes={hasMultipleTypes}
354
344
  textSize="text-[12px]"
355
- isTrain={isTrain}
356
345
  />
357
- ),
358
- );
346
+ ));
359
347
  };
360
348
 
361
349
  const seats = removeDuplicateSeats
362
350
  ? getUniqueSeats(seatTypesData, 3)
363
- : (() => {
364
- const filtered = seatTypesData
365
- ?.filter((item) => getFilteredSeats(item.label))
366
- ?.sort((a, b) => a.fare - b.fare);
367
- return isTrain ? filtered : filtered?.slice(0, 2);
368
- })();
351
+ : seatTypesData
352
+ ?.filter((item) => getFilteredSeats(item.label))
353
+ ?.sort((a, b) => a.fare - b.fare)
354
+ ?.slice(0, 2);
369
355
 
370
356
  const discountedSeats = seats?.map((seat) => ({
371
357
  ...seat,
@@ -617,7 +603,7 @@ function SeatSectionMobile({
617
603
  </div>
618
604
  ) : (
619
605
  <div
620
- className={`flex flex-col justify-between ${isTrain ? "" : "h-[2.5rem]"} `}
606
+ className="flex flex-col justify-between h-[2.5rem] "
621
607
  style={{
622
608
  gap: isSoldOut ? "0px" : "5px",
623
609
  justifyContent: hasMultipleTypes ? "space-between" : "center",
@@ -39,15 +39,9 @@ const commonService = {
39
39
  }
40
40
  },
41
41
 
42
- truncateSeatLabel: (label: string | number, maxLength?: number): string => {
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) =>
@@ -419,7 +413,7 @@ const commonService = {
419
413
  let remaining = Math.max(0, Math.floor(countdownSeconds));
420
414
 
421
415
  const formatTime = (totalSeconds: number) => {
422
- if (totalSeconds <= 0) return "Expirado";
416
+ if (totalSeconds <= 0) return "00:00";
423
417
  const h = Math.floor(totalSeconds / 3600);
424
418
  const m = Math.floor((totalSeconds % 3600) / 60);
425
419
  const s = totalSeconds % 60;