kupos-ui-components-lib 9.10.0 → 9.10.2

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 (54) hide show
  1. package/dist/KuposUIComponent.d.ts +14 -1
  2. package/dist/KuposUIComponent.js +3 -0
  3. package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
  4. package/dist/components/ServiceItem/ServiceItemDesktop.js +2 -20
  5. package/dist/components/ServiceItem/ServiceItemMobile.d.ts +1 -1
  6. package/dist/components/ServiceItem/ServiceItemMobile.js +2 -2
  7. package/dist/components/ServiceItem/mobileTypes.d.ts +0 -2
  8. package/dist/components/ServiceItem/types.d.ts +0 -7
  9. package/dist/components/Survey/SurveyDesktop.js +17 -16
  10. package/dist/components/Survey/SurveyMobile.js +17 -16
  11. package/dist/index.d.ts +5 -1
  12. package/dist/index.js +9 -1
  13. package/dist/styles.css +32 -6
  14. package/dist/ui/SeatSection/SeatSection.d.ts +1 -7
  15. package/dist/ui/SeatSection/SeatSection.js +9 -38
  16. package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +1 -2
  17. package/dist/ui/mobileweb/DateTimeSectionMobile.js +6 -12
  18. package/dist/ui/mobileweb/SeatSectionMobile.d.ts +1 -2
  19. package/dist/ui/mobileweb/SeatSectionMobile.js +14 -21
  20. package/dist/ui/mobileweb/ServiceBadgesMobile.js +2 -2
  21. package/dist/utils/CommonService.d.ts +1 -1
  22. package/dist/utils/CommonService.js +1 -5
  23. package/package.json +1 -1
  24. package/src/KuposUIComponent.tsx +22 -1
  25. package/src/assets/images/anims/service_list/succes_anim.json +1 -0
  26. package/src/components/ServiceItem/ServiceItemDesktop.tsx +0 -43
  27. package/src/components/ServiceItem/ServiceItemMobile.tsx +1 -3
  28. package/src/components/ServiceItem/mobileTypes.ts +26 -32
  29. package/src/components/ServiceItem/types.ts +0 -12
  30. package/src/components/Survey/ResponsiveSurvey.tsx +14 -0
  31. package/src/components/Survey/SurveyDesktop.tsx +121 -0
  32. package/src/components/Survey/SurveyMobile.tsx +125 -0
  33. package/src/components/Survey/index.ts +5 -0
  34. package/src/components/Survey/types.ts +22 -0
  35. package/src/index.ts +23 -0
  36. package/src/ui/BottomSheet/BottomSheet.tsx +131 -0
  37. package/src/ui/BottomSheet/index.ts +2 -0
  38. package/src/ui/Modal/Modal.tsx +92 -0
  39. package/src/ui/Modal/ModalHeader.tsx +58 -0
  40. package/src/ui/Modal/index.ts +4 -0
  41. package/src/ui/SeatSection/SeatSection.tsx +18 -86
  42. package/src/ui/Survey/FeedbackBanner.tsx +36 -0
  43. package/src/ui/Survey/FeedbackTextarea.tsx +84 -0
  44. package/src/ui/Survey/HeartIcon.tsx +18 -0
  45. package/src/ui/Survey/ScoreButtons.tsx +91 -0
  46. package/src/ui/Survey/SurveyFooter.tsx +145 -0
  47. package/src/ui/Survey/SurveyHeader.tsx +72 -0
  48. package/src/ui/Survey/ThankYouCard.tsx +100 -0
  49. package/src/ui/Survey/constants.ts +59 -0
  50. package/src/ui/Survey/index.ts +9 -0
  51. package/src/ui/mobileweb/DateTimeSectionMobile.tsx +35 -44
  52. package/src/ui/mobileweb/SeatSectionMobile.tsx +11 -26
  53. package/src/ui/mobileweb/ServiceBadgesMobile.tsx +2 -2
  54. package/src/utils/CommonService.ts +1 -7
@@ -0,0 +1,125 @@
1
+ import React from "react";
2
+ import { SurveyProps } from "./types";
3
+ import { BottomSheet } from "../../ui/BottomSheet";
4
+ import {
5
+ ThankYouCard,
6
+ SurveyHeader,
7
+ ScoreButtons,
8
+ FeedbackBanner,
9
+ FeedbackTextarea,
10
+ SurveyFooter,
11
+ getFeedbackConfig,
12
+ } from "../../ui/Survey";
13
+ import KuposButton from "../../ui/KuposButton/KuposButton";
14
+
15
+ const SurveyMobile = ({
16
+ isOpen,
17
+ isSubmitted,
18
+ selectedScore,
19
+ onScoreChange,
20
+ feedback = "",
21
+ onFeedbackChange,
22
+ onClose,
23
+ onSkip,
24
+ onSubmit,
25
+ colors,
26
+ icons,
27
+ isLoading,
28
+ }: SurveyProps) => {
29
+ if (!isOpen) return null;
30
+
31
+ const config = getFeedbackConfig(selectedScore);
32
+
33
+ const handleSubmit = () => {
34
+ if (selectedScore != null) {
35
+ onSubmit?.(selectedScore, feedback);
36
+ }
37
+ };
38
+
39
+ return (
40
+ <BottomSheet
41
+ isOpen={isOpen ?? false}
42
+ onClose={onClose}
43
+ showHandle={true}
44
+ showBackdrop={false}
45
+ blurBackground={true}
46
+ blurAmount="2px"
47
+ padding={isSubmitted ? 0 : "0 20px 32px"}
48
+ >
49
+ {/* {isSubmitted ? (
50
+ <ThankYouCard onClose={onClose} titleFontSize="1.35rem" />
51
+ ) : ( */}
52
+ <>
53
+ {/* <SurveyHeader onClose={onClose} /> */}
54
+ {/* Close Button */}
55
+ <button
56
+ onClick={onClose}
57
+ aria-label="Close survey"
58
+ className="absolute top-[15px] right-[25px] bg-transparent border-none cursor-pointer text-[22px] text-gray-400 flex items-center justify-center p-1 z-10 transition-colors duration-200 hover:text-gray-600"
59
+ >
60
+ <img
61
+ src={icons.closeIcon}
62
+ alt="Close"
63
+ className="w-[16px] h-[16px] block"
64
+ />
65
+ </button>
66
+
67
+ {/* Centered Illustration */}
68
+ {icons?.surveyIcon && (
69
+ <div className="flex justify-center mb-3 mt-2">
70
+ <img
71
+ src={icons.surveyIcon}
72
+ alt="Survey Illustration"
73
+ className="w-[90px] h-[90px] block"
74
+ />
75
+ </div>
76
+ )}
77
+
78
+ {/* Centered Title */}
79
+ <h2 className="text-[18px] bold-text leading-[1.25] text-center mt-4 mb-2">
80
+ Ayúdanos a mejorar
81
+ </h2>
82
+
83
+ {/* Centered Subtitle */}
84
+ <p className="text-[13.33px] text-center leading-[1.4] mb-6 max-w-[460px] mx-auto">
85
+ Basándote en tu experiencia de compra.
86
+ <br />
87
+ ¿Nos recomendarías a un amigo?
88
+ </p>
89
+
90
+ <ScoreButtons
91
+ selectedScore={selectedScore}
92
+ onScoreChange={onScoreChange}
93
+ buttonHeight={44}
94
+ fontSize={13}
95
+ gap={6}
96
+ colors={colors}
97
+ />
98
+
99
+ {/* <FeedbackBanner config={config} /> */}
100
+
101
+ <FeedbackTextarea
102
+ config={config}
103
+ feedback={feedback}
104
+ onFeedbackChange={onFeedbackChange}
105
+ />
106
+
107
+ <div className="flex justify-center mt-[20px]">
108
+ <div className="w-[180px]">
109
+ <KuposButton
110
+ isSoldOut={selectedScore == null}
111
+ isLoading={isLoading || false}
112
+ buttonColor={"#FF8E43"}
113
+ buyLabel="Enviar"
114
+ soldOutLabel="Enviar"
115
+ onClick={handleSubmit}
116
+ />
117
+ </div>
118
+ </div>
119
+ </>
120
+ {/* )} */}
121
+ </BottomSheet>
122
+ );
123
+ };
124
+
125
+ export default SurveyMobile;
@@ -0,0 +1,5 @@
1
+ import SurveyDesktop from "./SurveyDesktop";
2
+ import SurveyMobile from "./SurveyMobile";
3
+ import ResponsiveSurvey from "./ResponsiveSurvey";
4
+ export { SurveyDesktop, SurveyMobile, ResponsiveSurvey };
5
+ export type { SurveyProps } from "./types";
@@ -0,0 +1,22 @@
1
+ export interface SurveyProps {
2
+ variant?: "mobile" | "desktop";
3
+ isOpen?: boolean;
4
+ selectedScore?: number | null;
5
+ onScoreChange?: (score: number) => void;
6
+ feedback?: string;
7
+ onFeedbackChange?: (text: string) => void;
8
+ onClose?: () => void;
9
+ onSkip?: () => void;
10
+ onSubmit?: (score: number, feedback: string) => void;
11
+ isSubmitted?: boolean;
12
+ isLoading?: boolean;
13
+ colors?: {
14
+ secondaryColor?: string;
15
+ tertiaryColor?: string;
16
+ primaryColor?: string;
17
+ };
18
+ icons?: {
19
+ surveyIcon?: string;
20
+ closeIcon?: string;
21
+ };
22
+ }
package/src/index.ts CHANGED
@@ -25,6 +25,16 @@ import {
25
25
  ResponsiveFilterBar,
26
26
  } from "./components/FilterBar";
27
27
 
28
+ // Import Survey components
29
+ import {
30
+ SurveyDesktop,
31
+ SurveyMobile,
32
+ ResponsiveSurvey,
33
+ } from "./components/Survey";
34
+
35
+ // Import Modal components
36
+ import { Modal, ModalHeader } from "./ui/Modal";
37
+
28
38
  export {
29
39
  ServiceItemDesktop,
30
40
  ServiceItemMobile,
@@ -46,6 +56,16 @@ export {
46
56
  FilterBarDesktop,
47
57
  FilterBarMobile,
48
58
  ResponsiveFilterBar,
59
+
60
+
61
+ //Survey components
62
+ SurveyDesktop,
63
+ SurveyMobile,
64
+ ResponsiveSurvey,
65
+
66
+ // Modal components
67
+ Modal,
68
+ ModalHeader,
49
69
  };
50
70
 
51
71
  // Also export types
@@ -54,3 +74,6 @@ export type { MobileServiceItemProps } from "./components/ServiceItem/mobileType
54
74
  export type { PaymentSideBarProps } from "./components/PaymentSideBar/types";
55
75
  export type { ServiceListProps } from "./components/ServiceList/types";
56
76
  export type { FilterBarProps } from "./components/FilterBar/tyoes";
77
+ export type { SurveyProps } from "./components/Survey/types";
78
+ export type { ModalProps, ModalVariant, ModalSize, ModalHeaderProps } from "./ui/Modal";
79
+
@@ -0,0 +1,131 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom";
3
+
4
+ export interface BottomSheetProps {
5
+ isOpen: boolean;
6
+ onClose?: () => void;
7
+ children: React.ReactNode;
8
+ showHandle?: boolean;
9
+ showBackdrop?: boolean;
10
+ backdropColor?: string;
11
+ blurBackground?: boolean;
12
+ blurAmount?: string;
13
+ closeOnBackdrop?: boolean;
14
+ padding?: string | number;
15
+ maxHeight?: string;
16
+ borderRadius?: string;
17
+ }
18
+
19
+ const STYLE_ID = "__kupos_bottom_sheet_style__";
20
+
21
+ const injectStyle = () => {
22
+ if (typeof document === "undefined") return;
23
+ if (document.getElementById(STYLE_ID)) return;
24
+ const style = document.createElement("style");
25
+ style.id = STYLE_ID;
26
+ style.textContent = `
27
+ @keyframes __ks_slideUp {
28
+ from { transform: translateY(100%); }
29
+ to { transform: translateY(0); }
30
+ }
31
+ @keyframes __ks_fadeIn {
32
+ from { opacity: 0; }
33
+ to { opacity: 1; }
34
+ }
35
+ .__ks_sheet {
36
+ animation: __ks_slideUp 0.38s cubic-bezier(0.32, 0.72, 0, 1) both;
37
+ }
38
+ .__ks_backdrop {
39
+ animation: __ks_fadeIn 0.3s ease both;
40
+ }
41
+ `;
42
+ document.head.appendChild(style);
43
+ };
44
+
45
+ const BottomSheet = ({
46
+ isOpen,
47
+ onClose,
48
+ children,
49
+ showHandle = true,
50
+ showBackdrop = false,
51
+ backdropColor = "rgba(0,0,0,0.45)",
52
+ blurBackground = false,
53
+ blurAmount = "6px",
54
+ closeOnBackdrop = true,
55
+ padding = "20px 20px 32px",
56
+ maxHeight = "92vh",
57
+ borderRadius = "24px 24px 0 0",
58
+ }: BottomSheetProps) => {
59
+ if (!isOpen) return null;
60
+
61
+ injectStyle();
62
+
63
+ const sheet = (
64
+ <>
65
+ {(showBackdrop || blurBackground) && (
66
+ <div
67
+ className="__ks_backdrop"
68
+ onClick={closeOnBackdrop ? onClose : undefined}
69
+ style={{
70
+ position: "fixed",
71
+ top: 0,
72
+ left: 0,
73
+ right: 0,
74
+ bottom: 0,
75
+ zIndex: 9998,
76
+ backgroundColor: showBackdrop ? backdropColor : "rgba(0,0,0,0.4)",
77
+ backdropFilter: blurBackground ? `blur(${blurAmount})` : undefined,
78
+ WebkitBackdropFilter: blurBackground
79
+ ? `blur(${blurAmount})`
80
+ : undefined,
81
+ }}
82
+ />
83
+ )}
84
+
85
+ <div
86
+ className="__ks_sheet"
87
+ style={{
88
+ position: "fixed",
89
+ left: 0,
90
+ right: 0,
91
+ bottom: 0,
92
+ zIndex: 9999,
93
+ background: "#FFFFFF",
94
+ maxHeight,
95
+ borderRadius,
96
+ overflowY: "auto",
97
+ boxSizing: "border-box" as const,
98
+ boxShadow: "0 -8px 40px rgba(0,0,0,0.15)",
99
+ }}
100
+ >
101
+ {showHandle && (
102
+ <div
103
+ style={{
104
+ display: "flex",
105
+ justifyContent: "center",
106
+ padding: "12px 0 4px",
107
+ }}
108
+ >
109
+ <div
110
+ style={{
111
+ width: 40,
112
+ height: 4,
113
+ borderRadius: 999,
114
+ backgroundColor: "#E5E7EB",
115
+ }}
116
+ />
117
+ </div>
118
+ )}
119
+
120
+ <div style={{ padding }}>{children}</div>
121
+ </div>
122
+ </>
123
+ );
124
+
125
+ if (typeof document !== "undefined") {
126
+ return ReactDOM.createPortal(sheet, document.body) as React.ReactElement;
127
+ }
128
+ return sheet;
129
+ };
130
+
131
+ export default BottomSheet;
@@ -0,0 +1,2 @@
1
+ export { default as BottomSheet } from "./BottomSheet";
2
+ export type { BottomSheetProps } from "./BottomSheet";
@@ -0,0 +1,92 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom";
3
+
4
+ export type ModalVariant = "center" | "bottom-sheet";
5
+ export type ModalSize = "sm" | "md" | "lg" | "xl" | "full";
6
+
7
+ export interface ModalProps {
8
+ isOpen: boolean;
9
+ onClose?: () => void;
10
+ children: React.ReactNode;
11
+ variant?: ModalVariant;
12
+ size?: ModalSize;
13
+ closeOnBackdrop?: boolean;
14
+ padding?: string | number;
15
+ borderRadius?: string | number;
16
+ backdropColor?: string;
17
+ maxWidth?: number | string;
18
+ }
19
+
20
+ const SIZE_MAP: Record<ModalSize, number | string> = {
21
+ sm: 400,
22
+ md: 520,
23
+ lg: 640,
24
+ xl: 800,
25
+ full: "100%",
26
+ };
27
+
28
+ const Modal = ({
29
+ isOpen,
30
+ onClose,
31
+ children,
32
+ variant = "center",
33
+ size = "md",
34
+ closeOnBackdrop = true,
35
+ padding = "28px 32px 24px",
36
+ borderRadius,
37
+ backdropColor = "rgba(0,0,0,0.45)",
38
+ maxWidth,
39
+ }: ModalProps) => {
40
+ if (!isOpen) return null;
41
+
42
+ const resolvedMaxWidth = maxWidth ?? SIZE_MAP[size];
43
+ const resolvedRadius =
44
+ borderRadius ?? (variant === "bottom-sheet" ? "24px 24px 0 0" : 24);
45
+
46
+ const overlayStyle: React.CSSProperties = {
47
+ position: "fixed",
48
+ top: 0,
49
+ left: 0,
50
+ right: 0,
51
+ bottom: 0,
52
+ zIndex: 9999,
53
+ display: "flex",
54
+ alignItems: variant === "bottom-sheet" ? "flex-end" : "center",
55
+ justifyContent: "center",
56
+ padding: variant === "bottom-sheet" ? 0 : 16,
57
+ backgroundColor: backdropColor,
58
+ };
59
+
60
+ const cardStyle: React.CSSProperties = {
61
+ background: "#FFFFFF",
62
+ width: "100%",
63
+ maxWidth: resolvedMaxWidth,
64
+ maxHeight: variant === "bottom-sheet" ? "92vh" : undefined,
65
+ borderRadius: resolvedRadius,
66
+ padding,
67
+ position: "relative",
68
+ boxSizing: "border-box",
69
+ overflowY: variant === "bottom-sheet" ? "auto" : undefined,
70
+ };
71
+
72
+ const modal = (
73
+ <div
74
+ style={overlayStyle}
75
+ onClick={closeOnBackdrop ? onClose : undefined}
76
+ >
77
+ <div
78
+ style={cardStyle}
79
+ onClick={(e) => e.stopPropagation()}
80
+ >
81
+ {children}
82
+ </div>
83
+ </div>
84
+ );
85
+
86
+ if (typeof document !== "undefined") {
87
+ return ReactDOM.createPortal(modal, document.body) as React.ReactElement;
88
+ }
89
+ return modal;
90
+ };
91
+
92
+ export default Modal;
@@ -0,0 +1,58 @@
1
+ import React from "react";
2
+
3
+ export interface ModalHeaderProps {
4
+ title?: React.ReactNode;
5
+ onClose?: () => void;
6
+ children?: React.ReactNode;
7
+ }
8
+
9
+ const ModalHeader = ({ title, onClose, children }: ModalHeaderProps) => (
10
+ <div
11
+ style={{
12
+ display: "flex",
13
+ alignItems: "center",
14
+ justifyContent: "space-between",
15
+ marginBottom: 20,
16
+ }}
17
+ >
18
+ <div style={{ flex: 1 }}>
19
+ {title && (
20
+ <span
21
+ style={{
22
+ fontSize: "1rem",
23
+ fontWeight: 700,
24
+ color: "#111827",
25
+ }}
26
+ >
27
+ {title}
28
+ </span>
29
+ )}
30
+ {children}
31
+ </div>
32
+
33
+ {onClose && (
34
+ <button
35
+ onClick={onClose}
36
+ style={{
37
+ width: 36,
38
+ height: 36,
39
+ borderRadius: "50%",
40
+ background: "#F3F4F6",
41
+ border: "none",
42
+ cursor: "pointer",
43
+ fontSize: 14,
44
+ color: "#6B7280",
45
+ display: "flex",
46
+ alignItems: "center",
47
+ justifyContent: "center",
48
+ flexShrink: 0,
49
+ marginLeft: 12,
50
+ }}
51
+ >
52
+
53
+ </button>
54
+ )}
55
+ </div>
56
+ );
57
+
58
+ export default ModalHeader;
@@ -0,0 +1,4 @@
1
+ export { default as Modal } from "./Modal";
2
+ export { default as ModalHeader } from "./ModalHeader";
3
+ export type { ModalProps, ModalVariant, ModalSize } from "./Modal";
4
+ export type { ModalHeaderProps } from "./ModalHeader";
@@ -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
  }
36
25
 
37
26
  function getAllSeatTypes(seatTypes: SeatType[]) {
@@ -42,8 +31,6 @@ function getAllSeatTypes(seatTypes: SeatType[]) {
42
31
  let seatTypesWithPrices = seatTypes.filter(Boolean).map((val) => ({
43
32
  label: val?.label,
44
33
  price: val?.fare,
45
- key: val?.key,
46
- apiSeatType: val?.apiSeatType || val?.api_seat_type,
47
34
  }));
48
35
 
49
36
  seatTypesWithPrices.sort((a, b) => a.price - b.price);
@@ -51,7 +38,7 @@ function getAllSeatTypes(seatTypes: SeatType[]) {
51
38
  return seatTypesWithPrices;
52
39
  }
53
40
 
54
- function getSortedSeatTypes(seatTypes: SeatType[], isTrain: any) {
41
+ function getSortedSeatTypes(seatTypes: SeatType[]) {
55
42
  if (!seatTypes?.length) {
56
43
  return [{ label: "Salon cama", price: 0 }];
57
44
  }
@@ -65,9 +52,7 @@ function getSortedSeatTypes(seatTypes: SeatType[], isTrain: any) {
65
52
  seatTypesWithPrices[2] = seatTypesWithPrices[premiumIndex];
66
53
  }
67
54
 
68
- if (!isTrain) {
69
- seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
70
- }
55
+ seatTypesWithPrices = seatTypesWithPrices.slice(0, 2);
71
56
 
72
57
  const seenPrices = new Set<number>();
73
58
  seatTypesWithPrices = seatTypesWithPrices.filter((seat) => {
@@ -112,18 +97,14 @@ function SeatSection({
112
97
  priceColor,
113
98
  currencySign,
114
99
  removeDuplicateSeats,
115
- selectedSeatKey,
116
- onSeatSelect,
117
100
  isPeru,
118
101
  serviceItem,
119
102
  renderIcon,
120
103
  dpSeatColor,
121
104
  discountSeatPriceColor,
122
- isTrain,
123
- topLabelColor,
124
105
  }: SeatSectionProps): React.ReactElement {
125
106
  const uniqueSeats = getUniqueSeats(seatTypes);
126
- const sortedSeatTypes = getSortedSeatTypes(seatTypes, isTrain);
107
+ const sortedSeatTypes = getSortedSeatTypes(seatTypes);
127
108
  const numberOfSeats = getNumberOfSeats(seatTypes);
128
109
  const isCentered = numberOfSeats < 2 || removeDuplicateSeats;
129
110
 
@@ -135,71 +116,22 @@ function SeatSection({
135
116
  const renderSeatNames = () => {
136
117
  const seats = removeDuplicateSeats ? uniqueSeats : sortedSeatTypes;
137
118
 
138
- return seats.map((val, key: number) => {
139
- return SEAT_EXCEPTIONS.includes(val.label) ? null : (
140
- <div
141
- className="flex items-center"
142
- style={isTrain ? { cursor: "pointer" } : undefined}
143
- onClick={
144
- isTrain && !isSoldOut
145
- ? () =>
146
- val.label === selectedSeatKey
147
- ? onSeatSelect?.(null, 0, "", "")
148
- : onSeatSelect?.(
149
- val.label,
150
- val.price,
151
- val.key,
152
- (val as any).apiSeatType,
153
- )
154
- : undefined
155
- }
119
+ return seats.map((val, key: number) =>
120
+ SEAT_EXCEPTIONS.includes(val.label) ? null : (
121
+ <span
122
+ key={key}
123
+ className={`flex items-center justify-between text-[13.33px] ${
124
+ isSoldOut ? "text-[#c0c0c0]" : ""
125
+ }`}
156
126
  >
157
- {isTrain && (
158
- <div
159
- style={{
160
- border: `1px solid ${val.label === selectedSeatKey ? topLabelColor : "#ccc"}`,
161
- borderRadius: "50%",
162
- width: "14px",
163
- height: "14px",
164
- minWidth: "14px",
165
- marginRight: "10px",
166
- display: "flex",
167
- alignItems: "center",
168
- justifyContent: "center",
169
- }}
170
- >
171
- {val.label === selectedSeatKey && (
172
- <div
173
- style={{
174
- backgroundColor: topLabelColor,
175
- borderRadius: "50%",
176
- width: "7px",
177
- height: "7px",
178
- }}
179
- />
180
- )}
181
- </div>
182
- )}
183
- <span
184
- key={key}
185
- className={`flex items-center justify-between text-[13.33px] ${
186
- isSoldOut ? "text-[#c0c0c0]" : ""
187
- }`}
188
- >
189
- {typeof val.label === "string" || typeof val.label === "number"
190
- ? removeDuplicateSeats && isPeru
191
- ? CommonService.truncateSeatLabel(val.label)
192
- : isTrain
193
- ? CommonService.truncateSeatLabel(
194
- CommonService.capitalize(String(val.label)),
195
- 8,
196
- )
197
- : val.label
198
- : null}
199
- </span>
200
- </div>
201
- );
202
- });
127
+ {typeof val.label === "string" || typeof val.label === "number"
128
+ ? removeDuplicateSeats && isPeru
129
+ ? CommonService.truncateSeatLabel(val.label)
130
+ : val.label
131
+ : null}
132
+ </span>
133
+ ),
134
+ );
203
135
  };
204
136
 
205
137
  const renderSeatPrices = () => {
@@ -0,0 +1,36 @@
1
+ import React from "react";
2
+ import { FeedbackConfig } from "./constants";
3
+
4
+ interface FeedbackBannerProps {
5
+ config: FeedbackConfig | null;
6
+ }
7
+
8
+ const FeedbackBanner = ({ config }: FeedbackBannerProps) => {
9
+ if (!config) return null;
10
+ return (
11
+ <div
12
+ style={{
13
+ display: "flex",
14
+ alignItems: "center",
15
+ gap: 12,
16
+ borderRadius: 20,
17
+ padding: "12px 16px",
18
+ marginTop: 16,
19
+ backgroundColor: config.bannerBg,
20
+ }}
21
+ >
22
+ <span style={{ fontSize: 22 }}>{config.emoji}</span>
23
+ <span
24
+ style={{
25
+ fontWeight: 600,
26
+ fontSize: "13.33px",
27
+ color: config.bannerText,
28
+ }}
29
+ >
30
+ {config.message}
31
+ </span>
32
+ </div>
33
+ );
34
+ };
35
+
36
+ export default FeedbackBanner;