kupos-ui-components-lib 9.7.1 → 9.7.3

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.
@@ -0,0 +1,1042 @@
1
+ import React from "react";
2
+ import LottiePlayer from "../../assets/LottiePlayer";
3
+ import commonService from "../../utils/CommonService";
4
+
5
+ const HARDCODED_OPERATORS = [
6
+ {
7
+ logo: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Turbus_logo.svg/320px-Turbus_logo.svg.png",
8
+ name: "Turbus",
9
+ time: "7:00 am",
10
+ seatsAvailable: "3 disponibles",
11
+ },
12
+ {
13
+ logo: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Pullman_Bus_logo.svg/320px-Pullman_Bus_logo.svg.png",
14
+ name: "Pullmanbus",
15
+ time: "8:00 am",
16
+ seatsAvailable: "5 disponibles",
17
+ },
18
+ {
19
+ logo: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Turbus_logo.svg/320px-Turbus_logo.svg.png",
20
+ name: "Expreso Santa C...",
21
+ time: "9:00 am",
22
+ seatsAvailable: "3 disponibles",
23
+ },
24
+ ];
25
+
26
+ const HARDCODED_COUNTDOWN = "09:55";
27
+
28
+ const HOW_IT_WORKS_STEPS = [
29
+ {
30
+ icon: "flexible",
31
+ name: "1. Salida flexible",
32
+ text: "Viajas en un horario entre las 07:00 y las 10:00 AM del día elegido.",
33
+ },
34
+ {
35
+ icon: "bus",
36
+ name: "2. Empresa asignada",
37
+ text: "Una de las empresas disponibles confirma tu viaje una vez pagado.",
38
+ },
39
+ {
40
+ icon: "price",
41
+ name: "3. Precio garantizado",
42
+ text: "Al seleccionar este servicio aseguras el precio reducido.",
43
+ },
44
+ {
45
+ icon: "ticket",
46
+ name: "4. ¡Listo!",
47
+ text: "Recibe todos los detalles de tu viaje al instante tras la compra.",
48
+ },
49
+ ];
50
+
51
+ const FeatureServiceUiMobile = ({
52
+ serviceItem,
53
+ showTopLabel,
54
+ colors,
55
+ isSoldOut,
56
+ cityOrigin,
57
+ cityDestination,
58
+ renderIcon,
59
+ viewersConfig,
60
+ isFeatureDropDownExpand,
61
+ onToggleExpand,
62
+ ticketQuantity = 1,
63
+ onIncreaseTicketQuantity,
64
+ onDecreaseTicketQuantity,
65
+ onBookButtonPress,
66
+ }) => {
67
+ const operators =
68
+ serviceItem?.operators?.length > 0
69
+ ? serviceItem.operators
70
+ : HARDCODED_OPERATORS;
71
+
72
+ const isItemExpanded =
73
+ serviceItem.id === isFeatureDropDownExpand ||
74
+ isFeatureDropDownExpand === true;
75
+ const canDecreaseTicketQuantity = ticketQuantity > 1;
76
+
77
+ const HOW_IT_WORKS_STEPS = [
78
+ {
79
+ icon: "flexible",
80
+ name: "1. Salida flexible",
81
+ text: "Viajas en un horario entre las 07:00 y las 10:00 AM del día elegido.",
82
+ },
83
+ {
84
+ icon: "bus",
85
+ name: "2. Empresa asignada",
86
+ text: "Una de las empresas disponibles confirma tu viaje una vez pagado.",
87
+ },
88
+ {
89
+ icon: "price",
90
+ name: "3. Precio garantizado",
91
+ text: "Al seleccionar este servicio aseguras el precio reducido.",
92
+ },
93
+ {
94
+ icon: "ticket",
95
+ name: "4. ¡Listo!",
96
+ text: "Recibe todos los detalles de tu viaje al instante tras la compra.",
97
+ },
98
+ ];
99
+
100
+ const FeatureStepIcon = ({ icon }) => {
101
+ switch (icon) {
102
+ case "flexible":
103
+ return renderIcon("flexibleIcon", "20px");
104
+ case "bus":
105
+ return renderIcon("empressaIcon", "20px");
106
+ case "price":
107
+ return renderIcon("precioIcon", "20px");
108
+ default:
109
+ return renderIcon("listoIcon", "20px");
110
+ }
111
+ };
112
+
113
+ return (
114
+ <div
115
+ // ${
116
+ // serviceItem.offer_text ? "mb-[55px]" : "mb-[10px]"
117
+ // }
118
+ className={`relative mb-[10px]
119
+ ${
120
+ serviceItem?.is_direct_trip ||
121
+ serviceItem?.train_type_label === "Tren Express (Nuevo)" ||
122
+ showTopLabel
123
+ ? "mt-[24px]"
124
+ : "mt-[20px]"
125
+ }`}
126
+ >
127
+ <div
128
+ className=""
129
+ style={{
130
+ border: "1px solid #c0c0c0",
131
+ padding: "12px",
132
+ borderRadius: "14px",
133
+ }}
134
+ >
135
+ <div className="flex flex-col items-center px-[12px] pb-[8px] text-[13.33px] gap-[8px]">
136
+ <div>
137
+ <span>
138
+ {renderIcon("fireIcon", "14px")}{" "}
139
+ <span className="bold-text">Remate</span> términa en{" "}
140
+ <span
141
+ className="bold-text text-end"
142
+ ref={(node) => commonService.startCountdown(node, 599)}
143
+ style={{
144
+ fontVariantNumeric: "tabular-nums",
145
+ display: "inline-block",
146
+ color: "#FF5C60",
147
+ minWidth: "40px",
148
+ }}
149
+ />
150
+ </span>
151
+ </div>
152
+ <div className="flex items-center gap-[10px]">
153
+ <span>Salida flexible</span>
154
+ <div
155
+ className="bold-text font-[9px]"
156
+ style={{
157
+ backgroundColor: "#FF5C60",
158
+ padding: "1px 8px",
159
+ borderRadius: "4px",
160
+ color: "#fff",
161
+ animation: "pulse-zoom 2s ease-in-out infinite",
162
+ whiteSpace: "nowrap",
163
+ }}
164
+ >
165
+ <span>AHORRAS 60%</span>
166
+ </div>
167
+ </div>
168
+ </div>
169
+ <div
170
+ id={`service-card-${serviceItem.id}`}
171
+ className="bg-[#0C1421] text-white mx-auto relative rounded-[14px] p-[14px] text-[13.33px]"
172
+ >
173
+ <div className="flex flex-col gap-[10px]">
174
+ <div className=" text-[white]">
175
+ <div className="flex flex-col gap-[10px] relative">
176
+ <div className="flex items-center gap-[6px]">
177
+ <img
178
+ src={serviceItem.icons?.whiteOrigin}
179
+ alt="origin"
180
+ className={`w-[14px] h-[14px] shrink-0 ${
181
+ isSoldOut ? "grayscale" : ""
182
+ }`}
183
+ />
184
+ <span className="text-[13px] bold-text">
185
+ {cityOrigin?.label.split(",")[0]}
186
+ <span className="mx-[6px]">→</span>
187
+ {cityDestination?.label.split(",")[0]}
188
+ </span>
189
+ </div>
190
+ <div
191
+ style={{
192
+ width: "1px",
193
+ flex: 1,
194
+ backgroundColor: "#fff",
195
+ margin: "3px 0",
196
+ minHeight: "8px",
197
+ position: "absolute",
198
+ top: "13px",
199
+ left: "7px",
200
+ }}
201
+ />
202
+ <div className="flex items-center gap-[6px]">
203
+ <img
204
+ src={serviceItem.icons?.whiteDestination}
205
+ alt="destination"
206
+ className={`w-[14px] h-[14px] shrink-0 ${
207
+ isSoldOut ? "grayscale" : ""
208
+ }`}
209
+ style={{ opacity: isSoldOut ? 0.5 : 1 }}
210
+ />
211
+ <span className="text-[13px]">
212
+ 23 de mayo,{" "}
213
+ <span className="bold-text">Entre 07:00 AM y 10:00 AM</span>
214
+ </span>
215
+ </div>
216
+ </div>
217
+ {/* <div className="flex gap-[8px]">
218
+ <div className="flex flex-col items-center">
219
+ <img
220
+ src={serviceItem.icons?.whiteOrigin}
221
+ alt="origin"
222
+ className={`w-[14px] h-[14px] shrink-0 ${
223
+ isSoldOut ? "grayscale" : ""
224
+ }`}
225
+ />
226
+ <div
227
+ style={{
228
+ width: "1px",
229
+ flex: 1,
230
+ backgroundColor: "#fff",
231
+ margin: "3px 0",
232
+ minHeight: "8px",
233
+ }}
234
+ />
235
+ <img
236
+ src={serviceItem.icons?.whiteDestination}
237
+ alt="destination"
238
+ className={`w-[14px] h-[14px] shrink-0 ${
239
+ isSoldOut ? "grayscale" : ""
240
+ }`}
241
+ style={{ opacity: isSoldOut ? 0.5 : 1 }}
242
+ />
243
+ </div>
244
+ <div className="flex flex-col gap-[8px]">
245
+ <span className="text-[13px] bold-text">
246
+ {cityOrigin?.label.split(",")[0]}
247
+ <span className="mx-[6px]">→</span>
248
+ {cityDestination?.label.split(",")[0]}
249
+ </span>
250
+ <span className="text-[13px]">
251
+ 23 de mayo,{" "}
252
+ <span className="bold-text">Entre 07:00 AM y 10:00 AM</span>
253
+ </span>
254
+ </div>
255
+ </div> */}
256
+ </div>
257
+
258
+ <div className="border-t border-[#363c48] my-[8px]" />
259
+
260
+ <div>
261
+ <span className="text-[15px] bold-text text-[white] flex items-center justify-center mb-[10px]">
262
+ 3 operadores compitiendo por tu compra
263
+ </span>
264
+ <div className="flex gap-[8px] text-[white]">
265
+ {operators.map((op, idx) => (
266
+ <div
267
+ key={idx}
268
+ className="flex min-w-0 flex-col items-center justify-center gap-[8px] rounded-[8px]"
269
+ style={{
270
+ // height: "80px",
271
+ border: "1px solid #363c48",
272
+ backgroundColor: "#1a202e",
273
+ padding: "14px 10px",
274
+ }}
275
+ >
276
+ <img
277
+ src={serviceItem.operator_details[0]}
278
+ alt={op.name}
279
+ className={`h-[24px] max-w-full object-contain ${
280
+ isSoldOut ? "grayscale" : ""
281
+ }`}
282
+ />
283
+ <span className="text-[11px] truncate max-w-full text-center">
284
+ {serviceItem.operator_details[2]}
285
+ </span>
286
+ <div className="bg-[#FF8F45] text-[12px] font-bold px-[10px] py-[4px] rounded-[4px] bold-text whitespace-nowrap">
287
+ <span>{op?.time}</span>
288
+ </div>
289
+ <span className="text-[10px] mt-[6px]">
290
+ {op?.seatsAvailable}
291
+ </span>
292
+ </div>
293
+ ))}
294
+ </div>
295
+
296
+ <div
297
+ className="flex w-full items-center justify-center gap-[6px] text-[12px] mt-[12px]"
298
+ style={{
299
+ border: "1px solid #363c48",
300
+ backgroundColor: "#1a202e",
301
+ padding: "4px 14px",
302
+ borderRadius: "24px",
303
+ }}
304
+ >
305
+ <LottiePlayer
306
+ animationData={serviceItem.icons.personsAnim}
307
+ // animationData={getAnimationIcon("usersAnimation")}
308
+ width="18px"
309
+ height="18px"
310
+ />
311
+ <span>
312
+ <span className="bold-text text-[white]">
313
+ {" "}
314
+ <span
315
+ className="bold-text"
316
+ ref={(node) =>
317
+ commonService.startViewerCount(node, viewersConfig)
318
+ }
319
+ style={{
320
+ fontVariantNumeric: "tabular-nums",
321
+ color: "#FF5C60",
322
+ }}
323
+ />{" "}
324
+ </span>{" "}
325
+ <span className="text-[white]">viendo |</span>{" "}
326
+ <span
327
+ className="bold-text text-[white]"
328
+ ref={(node) =>
329
+ commonService.startComprandoCount(node, 4, 16)
330
+ }
331
+ style={{ fontVariantNumeric: "tabular-nums" }}
332
+ />{" "}
333
+ <span className="text-[white]">han comprado</span>
334
+ </span>
335
+ </div>
336
+
337
+ <div className="mt-[10px] flex flex-col items-center gap-[8px]">
338
+ <span className="text-[12px] text-[white]">
339
+ ¿Cuántos pasajes quieres?
340
+ </span>
341
+ <div
342
+ className="flex w-[50%] items-center justify-between"
343
+ style={{
344
+ border: "1px solid #363c48",
345
+ backgroundColor: "#1a202e",
346
+ padding: "6px 14px",
347
+ borderRadius: "14px",
348
+ }}
349
+ >
350
+ <button
351
+ type="button"
352
+ aria-label="Disminuir pasajes"
353
+ disabled={!canDecreaseTicketQuantity}
354
+ onClick={() => onDecreaseTicketQuantity?.(serviceItem)}
355
+ className={`flex h-[34px] w-[34px] items-center justify-center rounded-full border-none text-[25px] leading-none text-[white] ${
356
+ canDecreaseTicketQuantity
357
+ ? "cursor-pointer bg-[#2d374d]"
358
+ : "cursor-not-allowed bg-[#222b3d] opacity-50"
359
+ }`}
360
+ >
361
+ -
362
+ </button>
363
+ <span className="bold-text text-[20px] text-white">
364
+ {ticketQuantity}
365
+ </span>
366
+ <button
367
+ type="button"
368
+ aria-label="Aumentar pasajes"
369
+ onClick={() => onIncreaseTicketQuantity?.(serviceItem)}
370
+ className="flex h-[34px] w-[34px] cursor-pointer items-center justify-center rounded-full border-none bg-[#2d374d] text-[25px] leading-none text-[white]"
371
+ >
372
+ +
373
+ </button>
374
+ </div>
375
+ </div>
376
+
377
+ <div
378
+ className="mt-[10px] flex justify-between items-center rounded-[14px]"
379
+ style={{
380
+ // height: "80px",
381
+ border: "1px solid #363c48",
382
+ backgroundColor: "#1a202e",
383
+ padding: "14px 10px",
384
+ }}
385
+ >
386
+ <div className="flex flex-col">
387
+ <span
388
+ className="text-[20px] font-normal leading-[20px] text-[#9f9f9f] relative"
389
+ style={{ position: "relative" }}
390
+ >
391
+ $10.000
392
+ <span
393
+ style={{
394
+ position: "absolute",
395
+ left: "-2px",
396
+ top: "50%",
397
+ width: "calc(80% + 4px)",
398
+ height: "1px",
399
+
400
+ backgroundColor: "#FF5C60",
401
+
402
+ transform: "rotate(-10deg)",
403
+ transformOrigin: "center",
404
+ }}
405
+ />
406
+ </span>
407
+ <span className="text-[white] bold-text text-[28px] leading-none mt-[4px]">
408
+ {`$${(4000 * ticketQuantity).toLocaleString()}`}
409
+ </span>
410
+ </div>
411
+ <div>
412
+ <span
413
+ className="text-[#FF8F45] bold-text text-[26px] leading-tight"
414
+ style={{
415
+ animation: "pulse-zoom 2s ease-in-out infinite",
416
+ whiteSpace: "nowrap",
417
+ }}
418
+ >
419
+ 60% OFF
420
+ </span>
421
+ </div>
422
+ </div>
423
+
424
+ <button
425
+ type="button"
426
+ onClick={onBookButtonPress}
427
+ className="flex items-center gap-[6px] px-[20px] py-[10px] rounded-[16px] text-[white] bold-text text-[13px] mt-[10px] justify-center border-none cursor-pointer"
428
+ style={{
429
+ backgroundColor: "#FF5C60",
430
+ animation: "pulse-zoom 2s ease-in-out infinite",
431
+ whiteSpace: "nowrap",
432
+ width: "100%",
433
+ }}
434
+ >
435
+ <LottiePlayer
436
+ animationData={serviceItem.icons.thunderAnim}
437
+ width="18px"
438
+ height="18px"
439
+ />
440
+ <span className="whitespace-nowrap">¡Lo quiero!</span>
441
+ </button>
442
+
443
+ <div
444
+ className={`flex justify-end mt-[10px] transition-transform duration-300 ease-in-out ${isItemExpanded ? "rotate-180" : ""}`}
445
+ onClick={onToggleExpand}
446
+ >
447
+ <img
448
+ src={serviceItem?.icons?.downArrow}
449
+ alt="down arrow"
450
+ style={{
451
+ width: "14px",
452
+ height: "8px",
453
+ filter: "brightness(0) invert(1)",
454
+ }}
455
+ />
456
+ </div>
457
+ </div>
458
+
459
+ {/* <div>
460
+ <div className="flex items-center text-[white]">
461
+ <span>Vie, 04/11</span>
462
+ <span className="h-[20px] flex items-center justify-center mx-[10px]">
463
+
464
+ </span>
465
+ <span>07:00 AM - 10:00 AM</span>
466
+ </div>
467
+ <div
468
+ style={{
469
+ // height: "80px",
470
+ border: "1px solid #363c48",
471
+ backgroundColor: "#1a202e",
472
+ padding: "14px 10px",
473
+ borderRadius: "14px",
474
+ marginTop: "14px",
475
+ }}
476
+ >
477
+ <div className="flex flex-col justify-center items-center text-[white]">
478
+ <span className="text-[15px] bold-text">
479
+ 3 operadores compitiendo por tu compra
480
+ </span>
481
+
482
+ <span className="mt-[8px]">
483
+ Empresa a confirmar después de tu pago
484
+ </span>
485
+ </div>
486
+ <div className="grid w-full grid-cols-3 items-stretch gap-[14px] mb-[12px] mt-[12px] text-[white]">
487
+ {operators.map((op, idx) => (
488
+ <div
489
+ key={idx}
490
+ className="flex min-w-0 flex-col items-center justify-center gap-[8px] rounded-[8px]"
491
+ style={{
492
+ // height: "80px",
493
+ border: "1px solid #363c48",
494
+ backgroundColor: "#1a202e",
495
+ padding: "14px 10px",
496
+ }}
497
+ >
498
+ <img
499
+ src={serviceItem.operator_details[0]}
500
+ alt={op.name}
501
+ className={`h-[24px] max-w-full object-contain ${
502
+ isSoldOut ? "grayscale" : ""
503
+ }`}
504
+ />
505
+ <span className="text-[11px] truncate max-w-full text-center">
506
+ {serviceItem.operator_details[2]}
507
+ </span>
508
+ <div className="bg-[#FF8F45] text-[12px] font-bold px-[10px] py-[4px] rounded-[4px] bold-text whitespace-nowrap">
509
+ <span>{op?.time}</span>
510
+ </div>
511
+ <span className="text-[10px] mt-[6px]">
512
+ {op?.seatsAvailable}
513
+ </span>
514
+ </div>
515
+ ))}
516
+ </div>
517
+ <div className="flex items-center gap-[4px]">
518
+ {renderIcon("sheildIcon", "14px")}
519
+ <span className="text-[white]">
520
+ Tu asiento confirmado al instante.
521
+ </span>
522
+ </div>
523
+ </div>
524
+ </div>
525
+ <div>
526
+ <div className="mt-[4px] flex flex-col items-center gap-[8px]">
527
+ <span className="text-[12px] text-[white]">
528
+ ¿Cuántos pasajes quieres?
529
+ </span>
530
+ <div
531
+ className="flex w-full items-center justify-between"
532
+ style={{
533
+ border: "1px solid #363c48",
534
+ backgroundColor: "#1a202e",
535
+ padding: "6px 14px",
536
+ borderRadius: "14px",
537
+ }}
538
+ >
539
+ <button
540
+ type="button"
541
+ aria-label="Disminuir pasajes"
542
+ disabled={!canDecreaseTicketQuantity}
543
+ onClick={() => onDecreaseTicketQuantity?.(serviceItem)}
544
+ className={`flex h-[34px] w-[34px] items-center justify-center rounded-full border-none text-[25px] leading-none text-[white] ${
545
+ canDecreaseTicketQuantity
546
+ ? "cursor-pointer bg-[#2d374d]"
547
+ : "cursor-not-allowed bg-[#222b3d] opacity-50"
548
+ }`}
549
+ >
550
+ -
551
+ </button>
552
+ <span className="bold-text text-[20px] text-[white]">
553
+ {ticketQuantity}
554
+ </span>
555
+ <button
556
+ type="button"
557
+ aria-label="Aumentar pasajes"
558
+ onClick={() => onIncreaseTicketQuantity?.(serviceItem)}
559
+ className="flex h-[34px] w-[34px] cursor-pointer items-center justify-center rounded-full border-none bg-[#2d374d] text-[25px] leading-none text-[white]"
560
+ >
561
+ +
562
+ </button>
563
+ </div>
564
+ <button
565
+ type="button"
566
+ onClick={onBookButtonPress}
567
+ className="flex items-center gap-[6px] px-[20px] py-[10px] rounded-[16px] text-[white] bold-text text-[13px] mt-[4px] justify-center border-none cursor-pointer"
568
+ style={{
569
+ backgroundColor: "#FF5C60",
570
+ animation: "pulse-zoom 2s ease-in-out infinite",
571
+ whiteSpace: "nowrap",
572
+ width: "100%",
573
+ }}
574
+ >
575
+ <LottiePlayer
576
+ animationData={serviceItem.icons.thunderAnim}
577
+ width="18px"
578
+ height="18px"
579
+ />
580
+ <span className="whitespace-nowrap">¡Lo quiero!</span>
581
+ </button>
582
+ </div>
583
+ </div>
584
+ <div className="flex justify-between items-center">
585
+ <div className="flex items-center">
586
+ <LottiePlayer
587
+ animationData={serviceItem.icons.dotAnimation}
588
+ width="12px"
589
+ height="12px"
590
+ />
591
+ <span className="ml-[5px]">
592
+ <span className="bold-text text-[white]">
593
+ {" "}
594
+ <span
595
+ className="bold-text"
596
+ ref={(node) =>
597
+ commonService.startViewerCount(node, viewersConfig)
598
+ }
599
+ style={{
600
+ fontVariantNumeric: "tabular-nums",
601
+ }}
602
+ />{" "}
603
+ </span>{" "}
604
+ <span className="text-[white]">viendo |</span>{" "}
605
+ <span
606
+ className="bold-text text-[white]"
607
+ ref={(node) =>
608
+ commonService.startComprandoCount(node, 4, 16)
609
+ }
610
+ style={{ fontVariantNumeric: "tabular-nums" }}
611
+ />{" "}
612
+ <span className="text-[white]">han comprado</span>
613
+ </span>
614
+ </div>
615
+ <div
616
+ className={`transition-transform duration-300 ease-in-out ${isItemExpanded ? "rotate-180" : ""}`}
617
+ onClick={onToggleExpand}
618
+ >
619
+ <img
620
+ src={serviceItem?.icons?.downArrow}
621
+ alt="down arrow"
622
+ style={{
623
+ width: "14px",
624
+ height: "8px",
625
+ filter: "brightness(0) invert(1)",
626
+ }}
627
+ />
628
+ </div>
629
+ </div> */}
630
+ </div>
631
+ </div>
632
+
633
+ {isItemExpanded && (
634
+ <div
635
+ className="flex flex-col gap-[10px]"
636
+ style={{
637
+ opacity: isItemExpanded ? 1 : 0,
638
+ transition: "opacity 250ms ease-in-out",
639
+ }}
640
+ >
641
+ <div
642
+ className={` text-[12px] ${
643
+ isItemExpanded ? "pt-[14px] pb-[6px]" : "py-0"
644
+ }`}
645
+ style={{ transition: "padding 300ms ease-in-out" }}
646
+ >
647
+ <span className="bold-text">¿Cómo funciona?</span>
648
+
649
+ <div className="flex flex-col">
650
+ {HOW_IT_WORKS_STEPS.map((step) => (
651
+ <div className="flex items-start gap-[8px] mt-[10px]">
652
+ <div>
653
+ <FeatureStepIcon icon={step.icon} />
654
+ </div>
655
+ <div className="flex flex-col">
656
+ <span className="bold-text">{step.name}</span>
657
+ <span>{step.text}</span>
658
+ </div>
659
+ </div>
660
+ // <div
661
+ // key={step.name}
662
+ // className="flex flex-col items-center text-center text-[#272727]"
663
+ // >
664
+ // <FeatureStepIcon icon={step.icon} />
665
+ // <span className="bold-text mt-[10px] text-[12px] leading-[14px]">
666
+ // {step.name}
667
+ // </span>
668
+ // <span className="mt-[2px] max-w-[220px] text-[12px] leading-[14px] text-[#4a4a4a]">
669
+ // {step.text}
670
+ // </span>
671
+ // </div>
672
+ ))}
673
+ </div>
674
+ </div>
675
+ </div>
676
+ )}
677
+ </div>
678
+ {/* <div
679
+ className=""
680
+ style={{
681
+ border: "1px solid #c0c0c0",
682
+ padding: "14px",
683
+ borderRadius: "14px",
684
+ }}
685
+ >
686
+ <div className="flex justify-between items-center px-[14px] pb-[10px] text-[13.33px]">
687
+ <div className="flex items-center gap-[10px]">
688
+ <span>Salida flexible</span>
689
+ <div
690
+ className="bold-text font-[9px]"
691
+ style={{
692
+ backgroundColor: "#FF5C60",
693
+ padding: "1px 8px",
694
+ borderRadius: "4px",
695
+ color: "#fff",
696
+ animation: "pulse-zoom 2s ease-in-out infinite",
697
+ whiteSpace: "nowrap",
698
+ }}
699
+ >
700
+ <span>AHORRAS 60%</span>
701
+ </div>
702
+ </div>
703
+ <div>
704
+ <span>
705
+ {renderIcon("fireIcon", "14px")}{" "}
706
+ <span className="bold-text">Remate</span> términa en{" "}
707
+ <span
708
+ className="bold-text text-end"
709
+ ref={(node) => commonService.startCountdown(node, 599)}
710
+ style={{
711
+ fontVariantNumeric: "tabular-nums",
712
+ display: "inline-block",
713
+ color: "#FF5C60",
714
+ minWidth: "40px",
715
+ }}
716
+ />
717
+ </span>
718
+ </div>
719
+ </div>
720
+ <div
721
+ id={`service-card-${serviceItem.id}`}
722
+ className="bg-[#0C1421] text-white mx-auto relative rounded-[14px] p-[14px] text-[13.33px]"
723
+ >
724
+ <div className="grid grid-cols-[23%_50%_27%] items-stretch">
725
+ <div className="flex flex-col justify-between gap-[20px] my-[14px] pr-[22px]">
726
+ <div className="flex flex-col gap-[8px]">
727
+ <div className="flex items-center gap-[8px]">
728
+ <img
729
+ src={serviceItem.icons?.whiteOrigin}
730
+ alt="origin"
731
+ className={`w-[14px] h-[14px] shrink-0 ${
732
+ isSoldOut ? "grayscale" : ""
733
+ }`}
734
+ />
735
+ <span className="text-[13px] bold-text">
736
+ {cityOrigin?.label.split(",")[0]}
737
+ </span>
738
+ </div>
739
+ <div className="flex items-center gap-[8px]">
740
+ <img
741
+ src={serviceItem.icons?.whiteDestination}
742
+ alt="destination"
743
+ className={`w-[14px] h-[14px] shrink-0 ${
744
+ isSoldOut ? "grayscale" : ""
745
+ }`}
746
+ style={{ opacity: isSoldOut ? 0.5 : 1 }}
747
+ />
748
+ <span className="text-[13px] bold-text">
749
+ {cityDestination?.label.split(",")[0]}
750
+ </span>
751
+ </div>
752
+ </div>
753
+
754
+ <div className="flex flex-col gap-[8px]">
755
+ <div className="text-[12px] bold-text whitespace-nowrap">
756
+ Entre 07:00 AM y 10:00 AM
757
+ </div>
758
+ <div className="text-[11px] bold-text">Viernes 23 de mayo</div>
759
+ </div>
760
+
761
+ <div className="flex flex-col items-start gap-[10px] text-[12px] ">
762
+ <div className="flex items-justify gap-[8px]">
763
+ <AssuranceIcon type="pending" />
764
+
765
+ <span
766
+ className="text-[10px]"
767
+ style={{
768
+ lineHeight: 1.3,
769
+ }}
770
+ >
771
+ Empresa y hora a confirmar luego del pago.
772
+ </span>
773
+ </div>
774
+ <div className="flex items-justify gap-[8px]">
775
+ <AssuranceIcon type="secured" />
776
+
777
+ <span
778
+ className="text-[10px]"
779
+ style={{
780
+ lineHeight: 1.3,
781
+ }}
782
+ >
783
+ Tu compra está 100% asegurada.
784
+ </span>
785
+ </div>
786
+ </div>
787
+ </div>
788
+
789
+ <div className="min-w-0 px-[22px] flex flex-col items-center justify-between gap-[16px] py-[2px] border-r border-[#363c48] border-l border-[#363c48]">
790
+ <div className="text-center">
791
+ <div className="bold-text text-[14px]">
792
+ 3 operadores compitiendo por tu compra
793
+ </div>
794
+ </div>
795
+
796
+ <div className="grid w-full grid-cols-3 items-stretch gap-[14px] mb-[12px]">
797
+ {operators.map((op, idx) => (
798
+ <div
799
+ key={idx}
800
+ className="flex min-w-0 flex-col items-center justify-center gap-[8px] rounded-[8px]"
801
+ style={{
802
+ border: "1px solid #363c48",
803
+ backgroundColor: "#1a202e",
804
+ padding: "14px 10px",
805
+ }}
806
+ >
807
+ <img
808
+ src={serviceItem.operator_details[0]}
809
+ alt={op.name}
810
+ className={`h-[24px] max-w-full object-contain ${
811
+ isSoldOut ? "grayscale" : ""
812
+ }`}
813
+ />
814
+ <span className="text-[11px] truncate max-w-full text-center">
815
+ {serviceItem.operator_details[2]}
816
+ </span>
817
+ <div className="bg-[#FF8F45] text-white text-[12px] font-bold px-[10px] py-[4px] rounded-[4px] bold-text whitespace-nowrap">
818
+ <span>{op?.time}</span>
819
+ </div>
820
+ <span className="text-[10px] mt-[6px]">
821
+ {op?.seatsAvailable}
822
+ </span>
823
+ </div>
824
+ ))}
825
+ </div>
826
+
827
+ <div
828
+ className="flex w-full items-center justify-center gap-[6px] text-[12px]"
829
+ style={{
830
+ border: "1px solid #363c48",
831
+ backgroundColor: "#1a202e",
832
+ padding: "8px 14px",
833
+ borderRadius: "24px",
834
+ }}
835
+ >
836
+ <LottiePlayer
837
+ animationData={serviceItem?.icons?.personsAnim}
838
+ width="18px"
839
+ height="18px"
840
+ />
841
+ <span>
842
+ <span className="bold-text text-white">
843
+ {" "}
844
+ <span
845
+ className="bold-text"
846
+ ref={(node) =>
847
+ commonService.startViewerCount(node, viewersConfig)
848
+ }
849
+ style={{
850
+ fontVariantNumeric: "tabular-nums",
851
+ color: "#FF5C60",
852
+ }}
853
+ />{" "}
854
+ </span>{" "}
855
+ viendo |{" "}
856
+ <span
857
+ className="bold-text"
858
+ ref={(node) =>
859
+ commonService.startComprandoCount(node, 4, 16)
860
+ }
861
+ style={{ fontVariantNumeric: "tabular-nums" }}
862
+ />{" "}
863
+ han comprado
864
+ </span>
865
+ </div>
866
+ </div>
867
+
868
+ <div className="flex flex-col justify-center gap-[12px] py-[2px] pl-[22px] pr-[10px] relative mb-[16px]">
869
+ <div
870
+ className="flex flex-col gap-[6px] "
871
+ style={{
872
+ alignItems: "center",
873
+ }}
874
+ >
875
+ <span
876
+ className="text-[#FF8F45] bold-text text-[26px] leading-tight"
877
+ style={{
878
+ animation: "pulse-zoom 2s ease-in-out infinite",
879
+ whiteSpace: "nowrap",
880
+ }}
881
+ >
882
+ 60% OFF
883
+ </span>
884
+
885
+ <span
886
+ className="text-[13.33px] font-normal leading-[20px] text-[#9f9f9f] relative"
887
+ style={{ position: "relative" }}
888
+ >
889
+ $10.000
890
+ <span
891
+ style={{
892
+ position: "absolute",
893
+ left: "-2px",
894
+ top: "50%",
895
+ width: "calc(100% + 4px)",
896
+ height: "1px",
897
+
898
+ backgroundColor: "#FF5C60",
899
+
900
+ transform: "rotate(-10deg)",
901
+ transformOrigin: "center",
902
+ }}
903
+ />
904
+ </span>
905
+ <span className="text-white bold-text text-[28px] leading-none">
906
+ {`$${(4000 * ticketQuantity).toLocaleString()}`}
907
+ </span>
908
+ </div>
909
+
910
+ <div className="mt-[4px] flex flex-col items-center gap-[8px]">
911
+ <span className="text-[12px] text-white">
912
+ ¿Cuántos pasajes quieres?
913
+ </span>
914
+ <div
915
+ className="flex w-full items-center justify-between"
916
+ style={{
917
+ border: "1px solid #363c48",
918
+ backgroundColor: "#1a202e",
919
+ padding: "6px 14px",
920
+ borderRadius: "14px",
921
+ }}
922
+ >
923
+ <button
924
+ type="button"
925
+ aria-label="Disminuir pasajes"
926
+ disabled={!canDecreaseTicketQuantity}
927
+ onClick={() => onDecreaseTicketQuantity?.(serviceItem)}
928
+ className={`flex h-[34px] w-[34px] items-center justify-center rounded-full border-none text-[25px] leading-none text-white ${
929
+ canDecreaseTicketQuantity
930
+ ? "cursor-pointer bg-[#2d374d]"
931
+ : "cursor-not-allowed bg-[#222b3d] opacity-50"
932
+ }`}
933
+ >
934
+ -
935
+ </button>
936
+ <span className="bold-text text-[20px] text-white">
937
+ {ticketQuantity}
938
+ </span>
939
+ <button
940
+ type="button"
941
+ aria-label="Aumentar pasajes"
942
+ onClick={() => onIncreaseTicketQuantity?.(serviceItem)}
943
+ className="flex h-[34px] w-[34px] cursor-pointer items-center justify-center rounded-full border-none bg-[#2d374d] text-[25px] leading-none text-white"
944
+ >
945
+ +
946
+ </button>
947
+ </div>
948
+ </div>
949
+
950
+ <button
951
+ type="button"
952
+ onClick={onBookButtonPress}
953
+ className="flex items-center gap-[6px] px-[20px] py-[10px] rounded-[16px] text-white bold-text text-[13px] mt-[4px] justify-center border-none cursor-pointer"
954
+ style={{
955
+ backgroundColor: "#FF5C60",
956
+ animation: "pulse-zoom 2s ease-in-out infinite",
957
+ whiteSpace: "nowrap",
958
+ }}
959
+ >
960
+ <LottiePlayer
961
+ animationData={serviceItem?.icons?.thunderAnim}
962
+ width="18px"
963
+ height="18px"
964
+ />
965
+ <span className="whitespace-nowrap">¡Lo quiero!</span>
966
+ </button>
967
+ </div>
968
+
969
+ <div
970
+ className={`absolute bottom-[11px] right-[18px] cursor-pointer transition-transform duration-300 ease-in-out ${isItemExpanded ? "rotate-180" : ""}`}
971
+ onClick={onToggleExpand}
972
+ >
973
+ <img
974
+ src={serviceItem.icons?.downArrow}
975
+ alt="down arrow"
976
+ style={{
977
+ width: "14px",
978
+ height: "8px",
979
+ filter: "brightness(0) invert(1)",
980
+ }}
981
+ />
982
+ </div>
983
+ </div>
984
+ </div>
985
+ <div
986
+ className="grid"
987
+ style={{
988
+ gridTemplateRows: isItemExpanded ? "1fr" : "0fr",
989
+ opacity: isItemExpanded ? 1 : 0,
990
+ transition:
991
+ "grid-template-rows 300ms ease-in-out, opacity 250ms ease-in-out",
992
+ }}
993
+ >
994
+ <div
995
+ className={`min-h-0 overflow-hidden px-[16px] text-[13.33px] ${
996
+ isItemExpanded ? "pt-[14px] pb-[6px]" : "py-0"
997
+ }`}
998
+ style={{ transition: "padding 300ms ease-in-out" }}
999
+ >
1000
+ <span className="bold-text">¿Cómo funciona?</span>
1001
+
1002
+ <div className="mt-[14px] grid grid-cols-4 gap-[20px] px-[16px] ">
1003
+ {HOW_IT_WORKS_STEPS.map((step) => (
1004
+ <div
1005
+ key={step.name}
1006
+ className="flex flex-col items-center text-center text-[#272727]"
1007
+ >
1008
+ <FeatureStepIcon icon={step.icon} />
1009
+ <span className="bold-text mt-[10px] text-[12px] leading-[14px]">
1010
+ {step.name}
1011
+ </span>
1012
+ <span className="mt-[2px] max-w-[220px] text-[12px] leading-[14px] text-[#4a4a4a]">
1013
+ {step.text}
1014
+ </span>
1015
+ </div>
1016
+ ))}
1017
+ </div>
1018
+ </div>
1019
+ </div>
1020
+ </div> */}
1021
+
1022
+ {/* TOP BADGE — "Remate | Termina en 09:55 min" hardcoded, no countdown hook */}
1023
+ {/* {showTopLabel && (
1024
+ <div className="absolute -top-[11px] left-0 w-full flex items-center justify-end gap-[12px] pr-[15px] z-10 ">
1025
+ <div className="flex items-center gap-[6px] py-[5px] px-[14px] rounded-[38px] text-[12.5px] bg-[#FF8F45] text-white whitespace-nowrap">
1026
+ <LottiePlayer
1027
+ animationData={getAnimationIcon("bombAnimation")}
1028
+ width="14px"
1029
+ height="14px"
1030
+ />
1031
+ <span>
1032
+ <strong>Remate</strong> | Termina en{" "}
1033
+ <strong>{HARDCODED_COUNTDOWN}</strong> min
1034
+ </span>
1035
+ </div>
1036
+ </div>
1037
+ )} */}
1038
+ </div>
1039
+ );
1040
+ };
1041
+
1042
+ export default FeatureServiceUiMobile;