kupos-ui-components-lib 9.3.9 → 9.4.0

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.
@@ -14,6 +14,7 @@ interface SeatSectionProps {
14
14
  availableSeats: number;
15
15
  isSoldOut: boolean;
16
16
  priceColor?: string;
17
+ dpSeatColor?: string;
17
18
  currencySign?: string;
18
19
  removeDuplicateSeats?: boolean;
19
20
  isPeru?: boolean;
@@ -98,6 +99,7 @@ function SeatSection({
98
99
  isPeru,
99
100
  serviceItem,
100
101
  renderIcon,
102
+ dpSeatColor,
101
103
  }: SeatSectionProps): React.ReactElement {
102
104
  const uniqueSeats = getUniqueSeats(seatTypes);
103
105
  const sortedSeatTypes = getSortedSeatTypes(seatTypes);
@@ -220,30 +222,102 @@ function SeatSection({
220
222
  return renderSeatNames();
221
223
  };
222
224
 
225
+ if (serviceItem?.is_dp_enabled) {
226
+ const dpSeats = (
227
+ removeDuplicateSeats ? uniqueSeats : sortedSeatTypes
228
+ ).filter((s) => !SEAT_EXCEPTIONS.includes(s.label));
229
+ const lowestFare =
230
+ dpSeats.length > 0 ? Math.min(...dpSeats.map((s) => Number(s.price))) : 0;
231
+
232
+ return (
233
+ <div className="flex items-center justify-between text-[13.33px] ">
234
+ <div>
235
+ <span className="text-[13.33px] font-normal leading-[24px] text-[#464647]">
236
+ Desde
237
+ </span>
238
+ </div>
239
+ <div>
240
+ <span
241
+ className="flex items-center gap-[6px] text-[22px] bold-text leading-[30px] relative"
242
+ style={{ color: isSoldOut ? "#c0c0c0" : dpSeatColor }}
243
+ >
244
+ <div className="absolute bottom-[85%]">
245
+ <span
246
+ className="rounded-[100px] bg-[#ff5964] px-[6px] w-fit text-[12px] bold-text leading-[20px] text-white"
247
+ style={{
248
+ animation: "pulse-zoom 2s ease-in-out infinite",
249
+ whiteSpace: "nowrap",
250
+ color: dpSeatColor,
251
+ }}
252
+ >
253
+ Mejor precio
254
+ </span>
255
+ </div>
256
+ <div className="absolute -left-[20px]">
257
+ {renderIcon("fireIcon", "16px")}
258
+ </div>
259
+ {availableSeats <= 0
260
+ ? CommonService.currency(0, currencySign)
261
+ : CommonService.discountedCurrency(lowestFare, currencySign)}
262
+ </span>
263
+ </div>
264
+ </div>
265
+ // <div className="flex items-center justify-between text-[13.33px]">
266
+ // <span className="text-[13.33px] font-normal leading-[24px] text-[#464647]">
267
+ // Desde
268
+ // </span>
269
+ // <div className="flex flex-col items-center gap-[2px]">
270
+ // <span
271
+ // className="rounded-[100px] bg-[#ff5964] px-[6px] w-fit text-[12px] bold-text leading-[20px] text-white"
272
+ // style={{
273
+ // animation: "pulse-zoom 2s ease-in-out infinite",
274
+ // whiteSpace: "nowrap",
275
+ // color: dpSeatColor,
276
+ // }}
277
+ // >
278
+ // Mejor precio
279
+ // </span>
280
+ // <span
281
+ // className="flex items-center gap-[6px] text-[22px] bold-text leading-[30px] relative"
282
+ // style={{ color: isSoldOut ? "#c0c0c0" : dpSeatColor }}
283
+ // >
284
+ // <div className="absolute -left-[20px]">
285
+ // {renderIcon("fireIcon", "16px")}
286
+ // </div>
287
+ // {availableSeats <= 0
288
+ // ? CommonService.currency(0, currencySign)
289
+ // : CommonService.discountedCurrency(lowestFare, currencySign)}
290
+ // </span>
291
+ // </div>
292
+ // </div>
293
+ );
294
+ }
295
+
223
296
  if (hasDiscount && discountSeat) {
224
297
  return (
225
- <div className="grid items-center text-[13.33px] relative">
298
+ <div className="grid grid-cols-2 items-center text-[13.33px] relative">
226
299
  <div className="col-start-1 row-start-2 flex items-center">
227
- <span className="text-[13.33px] font-normal leading-[22px] text-[#c2c2c2]">
300
+ <span className="text-[13.33px] font-normal leading-[22px] text-[#ccc]">
228
301
  Antes
229
302
  </span>
230
303
  </div>
231
304
 
232
- <div className="col-start-1 row-start-3 flex h-[30px] items-end">
233
- <span className="text-[13.33px] font-normal leading-[24px] text-[#464647]">
305
+ <div className="col-start-1 row-start-3 flex h-[20px] items-end">
306
+ <span className="text-[13.33px] font-normal leading-[20px] text-[#464647]">
234
307
  Desde
235
308
  </span>
236
309
  </div>
237
310
 
238
311
  <div
239
312
  className="col-start-2 row-start-1 flex items-center justify-center absolute"
240
- style={{ top: "-22px", right: "25%" }}
313
+ style={{ top: "-22px", left: "50%", transform: "translateX(-50%)" }}
241
314
  >
242
315
  {discountValue != null && (
243
316
  <span
244
317
  className="rounded-[100px] bg-[#ff5964] px-[6px] text-[12px] bold-text leading-[20px] text-white"
245
318
  style={{
246
319
  animation: "pulse-zoom 2s ease-in-out infinite",
320
+ whiteSpace: "nowrap",
247
321
  }}
248
322
  >
249
323
  {discountValue}% OFF
@@ -277,13 +351,15 @@ function SeatSection({
277
351
  </span>
278
352
  </div>
279
353
 
280
- <div className="col-start-2 row-start-3 flex h-[30px] items-end justify-center">
354
+ <div className="col-start-2 row-start-3 flex h-[30px] items-end justify-center relative">
281
355
  <span
282
356
  className="flex items-center gap-[6px] text-[22px] bold-text leading-[30px]"
283
357
  style={{ color: isSoldOut ? "#c0c0c0" : "#ff5964" }}
284
358
  >
285
359
  {/* <span className="text-[18px] leading-[24px]">🔥</span> */}
286
- {renderIcon("fireIcon", "16px")}
360
+ <div className="absolute -left-[8px]">
361
+ {renderIcon("fireIcon", "16px")}
362
+ </div>
287
363
  {availableSeats <= 0
288
364
  ? CommonService.currency(0, currencySign)
289
365
  : CommonService.discountedCurrency(
@@ -24,7 +24,7 @@ const ServiceBadges: React.FC<ServiceBadgesProps> = ({
24
24
  serviceItem,
25
25
  }) => {
26
26
  return (
27
- <div className="absolute -top-[11px] left-0 w-full flex items-center justify-end gap-[12px] pr-[22px] z-10">
27
+ <div className="absolute -top-[10px] left-0 w-full flex items-center justify-end gap-[12px] pr-[22px] z-10">
28
28
  {showTopLabel && (
29
29
  <div
30
30
  className={`flex items-center gap-[10px] py-[4px] px-[14px] rounded-[38px] text-[12.5px] z-10`}
@@ -23,6 +23,7 @@ interface DateTimeSectionMobileProps {
23
23
  removeDuplicateSeats?: boolean;
24
24
  serviceItem?: any;
25
25
  tooltipBgColor?: string;
26
+ showLastSeats?: boolean;
26
27
  }
27
28
 
28
29
  const pad = (n: number) => (n < 10 ? "0" + n : String(n));
@@ -121,6 +122,7 @@ function DateTimeSectionMobile({
121
122
  removeDuplicateSeats,
122
123
  serviceItem,
123
124
  tooltipBgColor,
125
+ showLastSeats,
124
126
  }: DateTimeSectionMobileProps): React.ReactElement {
125
127
  const { cleaned: cleanedDepTime, hasAM, hasPM } = getCleanedDepTime(depTime);
126
128
 
@@ -190,6 +192,7 @@ function DateTimeSectionMobile({
190
192
  removeDuplicateSeats={removeDuplicateSeats}
191
193
  serviceItem={serviceItem}
192
194
  tooltipBgColor={tooltipBgColor}
195
+ showLastSeats={showLastSeats}
193
196
  />
194
197
  </div>
195
198
  );
@@ -29,6 +29,7 @@ interface SeatSectionMobileProps {
29
29
  removeDuplicateSeats?: boolean;
30
30
  serviceItem?: any;
31
31
  tooltipBgColor?: string;
32
+ showLastSeats?: boolean;
32
33
  }
33
34
 
34
35
  interface SeatRowProps {
@@ -114,6 +115,7 @@ function SeatSectionMobile({
114
115
  removeDuplicateSeats,
115
116
  serviceItem,
116
117
  tooltipBgColor,
118
+ showLastSeats,
117
119
  }: SeatSectionMobileProps): React.ReactElement {
118
120
  const hasMultipleTypes = (seatTypesData?.length ?? 0) > 2;
119
121
 
@@ -183,6 +185,81 @@ function SeatSectionMobile({
183
185
  );
184
186
  };
185
187
 
188
+ const renderDpSeats = () => {
189
+ const lowestFare = getLowestFare();
190
+ if (lowestFare === null) return null;
191
+
192
+ const { discountedPrice } = commonService.calculateDiscountedPrice(
193
+ lowestFare,
194
+ serviceItem,
195
+ );
196
+ const priceColor = isSoldOut ? "#bbb" : tooltipBgColor;
197
+
198
+ return (
199
+ <div className="relative flex flex-col justify-center h-full">
200
+ <div
201
+ className="absolute right-[0px]"
202
+ style={{
203
+ animation: "pulse-zoom 2s ease-in-out infinite",
204
+ top:
205
+ serviceItem?.available_seats < 10 &&
206
+ serviceItem?.available_seats > 0
207
+ ? "-20px"
208
+ : "-10px",
209
+ }}
210
+ >
211
+ <span
212
+ className="rounded-[100px] px-[8px] text-[11px] bold-text leading-[20px] text-[#fff]"
213
+ style={{
214
+ backgroundColor: tooltipBgColor,
215
+ }}
216
+ >
217
+ Mejor precio
218
+ </span>
219
+ </div>
220
+ <div className="w-[100%] flex flex-row justify-between items-center">
221
+ <span
222
+ className="min-[420]:text-[13px] text-[12px]"
223
+ style={{ color: isSoldOut ? "#bbb" : "#464647" }}
224
+ >
225
+ Desde
226
+ </span>
227
+ <span
228
+ className="flex items-center gap-[4px] min-[420]:text-[13px] text-[14px] bold-text"
229
+ style={{ color: priceColor }}
230
+ >
231
+ {serviceItem?.icons?.fireIcon ? (
232
+ <img
233
+ src={serviceItem.icons.fireIcon}
234
+ alt="dp"
235
+ className="h-[14px] w-[14px] object-contain"
236
+ style={{ filter: isSoldOut ? "grayscale(1)" : "" }}
237
+ />
238
+ ) : null}
239
+ {commonService.currency(discountedPrice, currencySign)}
240
+ </span>
241
+ </div>
242
+ {showLastSeats ? (
243
+ <div className="flex justify-end">
244
+ {serviceItem?.available_seats < 10 &&
245
+ serviceItem?.available_seats > 0 && (
246
+ <div className="text-[10px] text-[#464647] text-center mt-[3px]">
247
+ ¡Últimos Asientos!
248
+ </div>
249
+ )}
250
+ </div>
251
+ ) : null}
252
+ {isSoldOut ? (
253
+ <div className="flex justify-end">
254
+ <span className="min-[420]:text-[13px] text-[12px] text-[#ccc]">
255
+ Agotado
256
+ </span>
257
+ </div>
258
+ ) : null}
259
+ </div>
260
+ );
261
+ };
262
+
186
263
  const renderSeats = () => {
187
264
  if (isPeru) {
188
265
  return renderPeruSeats();
@@ -262,7 +339,14 @@ function SeatSectionMobile({
262
339
 
263
340
  return (
264
341
  <div className="content-center relative" style={{ width: "40%" }}>
265
- {hasDiscount && discountSeat ? (
342
+ {serviceItem?.is_dp_enabled ? (
343
+ <div
344
+ className="flex flex-col justify-between h-[2.5rem]"
345
+ style={{ gap: isSoldOut ? "0px" : "5px" }}
346
+ >
347
+ {renderDpSeats()}
348
+ </div>
349
+ ) : hasDiscount && discountSeat ? (
266
350
  <div className="relative grid grid-cols-[auto_auto] justify-between gap-x-[8px] ">
267
351
  {discountValue != null && (
268
352
  <div
@@ -348,6 +432,16 @@ function SeatSectionMobile({
348
432
  }}
349
433
  >
350
434
  {renderSeats()}
435
+ {showLastSeats ? (
436
+ <div className="flex justify-end ">
437
+ {serviceItem?.available_seats < 10 &&
438
+ serviceItem?.available_seats > 0 && (
439
+ <div className="text-[10px] text-[#464647] text-center">
440
+ ¡ Últimos Asientos!
441
+ </div>
442
+ )}
443
+ </div>
444
+ ) : null}
351
445
 
352
446
  {isSoldOut ? (
353
447
  <div className="flex justify-end">
@@ -24,7 +24,7 @@ const ServiceBadgesMobile: React.FC<ServiceBadgesMobileProps> = ({
24
24
  isConexion,
25
25
  }) => {
26
26
  return (
27
- <div className="absolute -top-[9px] left-0 w-full flex items-center justify-end gap-[12px] pr-[17px] z-10">
27
+ <div className="absolute -top-[10px] left-0 w-full flex items-center justify-end gap-[12px] pr-[17px] z-10">
28
28
  {showTopLabel && (
29
29
  <div
30
30
  className={`flex items-center gap-[2px] py-[4px] px-[10px] rounded-[38px] min-[420]:text-[12px] text-[10px] z-20`}