kupos-ui-components-lib 9.0.4 → 9.0.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 (57) hide show
  1. package/README copy.md +223 -67
  2. package/dist/assets/images/anims/service_list/bomb.json +1 -0
  3. package/dist/assets/images/anims/service_list/directo.json +1 -1
  4. package/dist/assets/images/anims/service_list/priority_stage.json +1 -1
  5. package/dist/components/ServiceItem/ExpandedDropdown.d.ts +19 -0
  6. package/dist/components/ServiceItem/ExpandedDropdown.js +28 -0
  7. package/dist/components/ServiceItem/ServiceItemDesktop.d.ts +1 -1
  8. package/dist/components/ServiceItem/ServiceItemDesktop.js +125 -262
  9. package/dist/components/ServiceItem/ServiceItemMobile.js +44 -291
  10. package/dist/components/ServiceItem/mobileTypes.d.ts +3 -0
  11. package/dist/components/ServiceItem/types.d.ts +7 -0
  12. package/dist/styles.css +67 -12
  13. package/dist/ui/AmenitiesBlock.js +60 -66
  14. package/dist/ui/BottomAmenities/BottomAmenities.d.ts +26 -0
  15. package/dist/ui/BottomAmenities/BottomAmenities.js +22 -0
  16. package/dist/ui/DurationBlock.js +2 -2
  17. package/dist/ui/ExpendedDropDown/ExpandedDropdown.d.ts +19 -0
  18. package/dist/ui/ExpendedDropDown/ExpandedDropdown.js +27 -0
  19. package/dist/ui/FlexibleBlock.js +2 -4
  20. package/dist/ui/KuposButton/KuposButton.d.ts +12 -0
  21. package/dist/ui/KuposButton/KuposButton.js +12 -0
  22. package/dist/ui/PetBlock.js +1 -3
  23. package/dist/ui/RatingBlock.js +6 -2
  24. package/dist/ui/SeatSection/SeatSection.d.ts +17 -0
  25. package/dist/ui/SeatSection/SeatSection.js +92 -0
  26. package/dist/ui/TopAmenities/TopAmenities.d.ts +12 -0
  27. package/dist/ui/TopAmenities/TopAmenities.js +32 -0
  28. package/dist/ui/mobileweb/BottomAmenitiesMobile.d.ts +23 -0
  29. package/dist/ui/mobileweb/BottomAmenitiesMobile.js +37 -0
  30. package/dist/ui/mobileweb/DateTimeSectionMobile.d.ts +23 -0
  31. package/dist/ui/mobileweb/DateTimeSectionMobile.js +57 -0
  32. package/dist/ui/mobileweb/SeatSectionMobile.d.ts +17 -0
  33. package/dist/ui/mobileweb/SeatSectionMobile.js +100 -0
  34. package/dist/ui/mobileweb/TopAmenitieMobile.d.ts +10 -0
  35. package/dist/ui/mobileweb/TopAmenitieMobile.js +35 -0
  36. package/package.json +1 -1
  37. package/src/assets/images/anims/service_list/bomb.json +1 -0
  38. package/src/assets/images/anims/service_list/directo.json +1 -1
  39. package/src/assets/images/anims/service_list/priority_stage.json +1 -1
  40. package/src/components/ServiceItem/ServiceItemDesktop.tsx +222 -465
  41. package/src/components/ServiceItem/ServiceItemMobile.tsx +120 -501
  42. package/src/components/ServiceItem/mobileTypes.ts +3 -0
  43. package/src/components/ServiceItem/types.ts +7 -0
  44. package/src/ui/AmenitiesBlock.tsx +115 -97
  45. package/src/ui/BottomAmenities/BottomAmenities.tsx +109 -0
  46. package/src/ui/DurationBlock.tsx +2 -2
  47. package/src/ui/ExpendedDropDown/ExpandedDropdown.tsx +85 -0
  48. package/src/ui/FlexibleBlock.tsx +3 -3
  49. package/src/ui/KuposButton/KuposButton.tsx +48 -0
  50. package/src/ui/PetBlock.tsx +2 -2
  51. package/src/ui/RatingBlock.tsx +16 -4
  52. package/src/ui/SeatSection/SeatSection.tsx +187 -0
  53. package/src/ui/TopAmenities/TopAmenities.tsx +82 -0
  54. package/src/ui/mobileweb/BottomAmenitiesMobile.tsx +168 -0
  55. package/src/ui/mobileweb/DateTimeSectionMobile.tsx +192 -0
  56. package/src/ui/mobileweb/SeatSectionMobile.tsx +256 -0
  57. package/src/ui/mobileweb/TopAmenitieMobile.tsx +82 -0
@@ -113,6 +113,9 @@ export interface MobileServiceItemProps {
113
113
  seatFallBackIcon: string;
114
114
  headPhoneIcon?: string;
115
115
  allowCancellationIcon?: string;
116
+ bombAnim?: string;
117
+ whiteBoardingIcon?: string;
118
+ downArrow?: string;
116
119
  [key: string]: string | Record<string, string | undefined> | undefined;
117
120
  };
118
121
  useLottieFor?: string[];
@@ -117,6 +117,9 @@ export interface ServiceItemProps {
117
117
  seatFallBackIcon: string;
118
118
  headPhoneIcon?: string;
119
119
  allowCancellationIcon?: string;
120
+ whiteBoardingIcon?: string
121
+ bombJson?:string
122
+ downArrow?:string
120
123
 
121
124
  [key: string]: string | Record<string, string | undefined> | undefined;
122
125
  };
@@ -192,7 +195,11 @@ export interface ServiceItemProps {
192
195
  petFriendlyAnim?: string;
193
196
  priorityStageAnim?: string;
194
197
  promoAnim?: string;
198
+ bombAnimation?: string;
195
199
  isPeru?: boolean;
196
200
  siteType?: "kupos" | "pullman" | "opsites" | "linatal";
197
201
  isAllinBus?: boolean;
202
+ isExpand?: any;
203
+ setIsExpand?: (value: any) => void;
204
+ coachKey?: number
198
205
  }
@@ -1,6 +1,50 @@
1
1
  import React from "react";
2
2
  import LottiePlayer from "../assets/LottiePlayer";
3
3
 
4
+ const DEFAULT_PRIORITY_IDS = ["2", "3", "13"];
5
+
6
+ const TOOLTIP_CLASS =
7
+ "hidden group-hover:block absolute top-[30px] left-1/2 -translate-x-1/2 text-white rounded-[14px] whitespace-nowrap mt-2.5 text-center shadow-service text-[13.33px]";
8
+
9
+ const getAmenityBaseName = (amenityStr) => amenityStr?.split(".")[0] ?? "";
10
+
11
+ const isWater = (amenityStr) =>
12
+ getAmenityBaseName(amenityStr)?.toUpperCase() === "WATER";
13
+
14
+ const TooltipArrow = ({ color }) => (
15
+ <div
16
+ 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"
17
+ style={{ borderBottomColor: color }}
18
+ />
19
+ );
20
+
21
+ const getAmenitySplit = ({ isPeru, amenities, priorityIds }) => {
22
+ const priority = amenities.filter((id) => priorityIds.includes(id));
23
+ const nonPriority = amenities.filter((id) => !priorityIds.includes(id));
24
+ const hasPriority = priority.length > 0;
25
+
26
+ /* ============================
27
+ 🇵🇪 PERU LOGIC
28
+ ============================ */
29
+ if (isPeru) {
30
+ return hasPriority
31
+ ? { visible: priority, plus: nonPriority }
32
+ : { visible: [], plus: amenities };
33
+ }
34
+
35
+ /* ============================
36
+ 🌍 NON-PERU LOGIC
37
+ ============================ */
38
+ const sorted = [...amenities].sort(
39
+ (a, b) => Number(priorityIds.includes(b)) - Number(priorityIds.includes(a)),
40
+ );
41
+
42
+ return {
43
+ visible: sorted.slice(0, 3),
44
+ plus: sorted.slice(3),
45
+ };
46
+ };
47
+
4
48
  const AmenitiesBlock = ({
5
49
  serviceItem,
6
50
  metaData,
@@ -19,100 +63,77 @@ const AmenitiesBlock = ({
19
63
  return null;
20
64
  }
21
65
 
22
- const PRIORITY_IDS = ["2", "3", "13"];
66
+ const operatorPriorityIds = serviceItem?.operator_details?.[5];
67
+ const priorityIds =
68
+ operatorPriorityIds?.length > 0
69
+ ? operatorPriorityIds
70
+ : DEFAULT_PRIORITY_IDS;
23
71
 
24
72
  const amenities = [...serviceItem.operator_details[4]];
25
73
 
26
- const priorityAmenities = amenities.filter((id) => PRIORITY_IDS.includes(id));
27
-
28
- const nonPriorityAmenities = amenities.filter(
29
- (id) => !PRIORITY_IDS.includes(id),
30
- );
31
-
32
- const hasPriority = priorityAmenities.length > 0;
33
-
34
- /* ============================
35
- 🇵🇪 PERU LOGIC
36
- ============================ */
37
- let visibleAmenities = [];
38
- let shouldShowPlus = false;
39
- let plusAmenities = [];
40
-
41
- if (isPeru) {
42
- if (hasPriority) {
43
- visibleAmenities = priorityAmenities;
44
- shouldShowPlus = nonPriorityAmenities.length > 0;
45
- plusAmenities = nonPriorityAmenities;
46
- } else {
47
- visibleAmenities = [];
48
- shouldShowPlus = amenities.length > 0;
49
- plusAmenities = amenities;
50
- }
51
- }
74
+ const { visible: visibleAmenities, plus: plusAmenities } = getAmenitySplit({
75
+ isPeru,
76
+ amenities,
77
+ priorityIds,
78
+ });
52
79
 
53
- /* ============================
54
- 🌍 NON-PERU LOGIC
55
- ============================ */
56
- if (!isPeru) {
57
- const sortedAmenities = [...amenities].sort(
58
- (a, b) =>
59
- Number(PRIORITY_IDS.includes(b)) - Number(PRIORITY_IDS.includes(a)),
60
- );
61
-
62
- visibleAmenities = sortedAmenities.slice(0, 3);
63
- shouldShowPlus = sortedAmenities.length > 3;
64
- plusAmenities = sortedAmenities.slice(3);
65
- }
80
+ const shouldShowPlus = plusAmenities.length > 0;
81
+ const grayscaleClass = isSoldOut ? "grayscale" : "";
66
82
 
67
83
  return (
68
84
  <div className="flex items-center gap-[6px]">
69
- {/* GPS */}
70
- {serviceItem?.is_tracking_enabled && (
71
- <div className={isSoldOut ? "grayscale" : ""}>
72
- <LottiePlayer
73
- animationData={getAnimationIcon("locationAnim")}
74
- width="20px"
75
- height="20px"
76
- />
77
- </div>
78
- )}
79
-
80
85
  {/* AMENITIES */}
81
- {visibleAmenities.map((val, key) =>
82
- metaData.amenities[val]?.split(".")[0]?.toUpperCase() !== "WATER" ? (
86
+ {visibleAmenities.map((val, key) => {
87
+ const raw = metaData.amenities[val];
88
+ if (isWater(raw)) return null;
89
+ const baseName = getAmenityBaseName(raw);
90
+
91
+ return (
83
92
  <div key={key} className="relative group cursor-pointer">
84
- <div className={`${isSoldOut ? "grayscale" : ""}`}>
93
+ <div className={grayscaleClass}>
85
94
  <SvgAmenities
86
95
  moreAnemities={false}
87
- name={metaData.amenities[val]?.split(".")[0]?.toLowerCase()}
96
+ name={baseName.toLowerCase()}
88
97
  />
89
98
  </div>
90
99
 
91
- {/* Tooltip */}
100
+ {/* Tooltip – show ALL amenities */}
92
101
  <div
93
- className="hidden group-hover:block absolute top-[30px] left-1/2 -translate-x-1/2 text-white rounded-[14px] whitespace-nowrap mt-2.5 text-center shadow-service text-[13.33px]"
102
+ className={TOOLTIP_CLASS}
94
103
  style={{
95
104
  backgroundColor: colors.tooltipColor,
96
105
  zIndex: 21,
97
106
  padding: "12px",
98
107
  }}
99
108
  >
100
- <div
101
- 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"
102
- style={{
103
- borderBottomColor: colors.tooltipColor,
104
- }}
105
- />
106
- {getAmenityName(
107
- metaData.amenities[val]?.split(".")[0]?.split("_")?.join(" "),
108
- )}
109
+ <TooltipArrow color={colors.tooltipColor} />
110
+ <div className="flex flex-col gap-[10px]">
111
+ {amenities.map((id, i) => {
112
+ const rawItem = metaData.amenities[id];
113
+ if (isWater(rawItem)) return null;
114
+ const name = getAmenityBaseName(rawItem);
115
+ return (
116
+ <div
117
+ key={i}
118
+ className="flex items-center gap-[5px] text-xs whitespace-nowrap"
119
+ >
120
+ <SvgAmenities
121
+ moreAnemities={true}
122
+ name={name.toUpperCase()}
123
+ color="white"
124
+ />
125
+ {getAmenityName(name.split("_").join(" "))}
126
+ </div>
127
+ );
128
+ })}
129
+ </div>
109
130
  </div>
110
131
  </div>
111
- ) : null,
112
- )}
132
+ );
133
+ })}
113
134
 
114
135
  {/* PLUS ICON */}
115
- {shouldShowPlus && (
136
+ {/* {shouldShowPlus && (
116
137
  <div className="relative ml-1 cursor-pointer">
117
138
  <div className="group">
118
139
  <img
@@ -124,51 +145,48 @@ const AmenitiesBlock = ({
124
145
  alt="plus"
125
146
  />
126
147
 
127
- <div
128
- style={{ zIndex: 100 }}
129
- className="hidden group-hover:block absolute top-[30px] left-1/2 -translate-x-1/2 text-white rounded-[14px] whitespace-nowrap mt-2.5 text-center shadow-service text-[13.33px]"
130
- >
131
- <div
132
- 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"
133
- style={{
134
- borderBottomColor: colors.tooltipColor,
135
- }}
136
- ></div>
148
+ <div style={{ zIndex: 100 }} className={TOOLTIP_CLASS}>
149
+ <TooltipArrow color={colors.tooltipColor} />
137
150
 
138
151
  <div
139
152
  className="flex flex-col gap-[10px] p-3 rounded-[8px] shadow-md"
140
- style={{
141
- backgroundColor: colors.tooltipColor,
142
- }}
153
+ style={{ backgroundColor: colors.tooltipColor }}
143
154
  >
144
- {plusAmenities.map((val, key) =>
145
- metaData.amenities[val]?.split(".")[0]?.toUpperCase() !==
146
- "WATER" ? (
155
+ {plusAmenities.map((val, key) => {
156
+ const raw = metaData.amenities[val];
157
+ if (isWater(raw)) return null;
158
+ const baseName = getAmenityBaseName(raw);
159
+
160
+ return (
147
161
  <div
148
162
  key={key}
149
163
  className="flex items-center gap-[5px] text-xs whitespace-nowrap"
150
164
  >
151
165
  <SvgAmenities
152
166
  moreAnemities={true}
153
- name={metaData.amenities[val]
154
- ?.split(".")[0]
155
- ?.toUpperCase()}
167
+ name={baseName.toUpperCase()}
156
168
  color="white"
157
169
  />
158
- {getAmenityName(
159
- metaData.amenities[val]
160
- ?.split(".")[0]
161
- ?.split("_")
162
- ?.join(" "),
163
- )}
170
+ {getAmenityName(baseName.split("_").join(" "))}
164
171
  </div>
165
- ) : null,
166
- )}
172
+ );
173
+ })}
167
174
  </div>
168
175
  </div>
169
176
  </div>
170
177
  </div>
171
- )}
178
+ )} */}
179
+
180
+ {/* GPS */}
181
+ {/* {serviceItem?.is_tracking_enabled && (
182
+ <div className={grayscaleClass}>
183
+ <LottiePlayer
184
+ animationData={getAnimationIcon("locationAnim")}
185
+ width="20px"
186
+ height="20px"
187
+ />
188
+ </div>
189
+ )} */}
172
190
  </div>
173
191
  );
174
192
  };
@@ -0,0 +1,109 @@
1
+ import React from "react";
2
+ import LottiePlayer from "../../assets/LottiePlayer";
3
+ import FlexibleBlock from "../FlexibleBlock";
4
+ import PetBlock from "../PetBlock";
5
+
6
+ interface ItemEntry {
7
+ key: string;
8
+ render: React.ReactNode;
9
+ }
10
+
11
+ interface BottomAmenitiesProps {
12
+ otherItems: ItemEntry[];
13
+ serviceItem: {
14
+ id: string;
15
+ is_tracking_enabled?: boolean;
16
+ is_change_ticket?: boolean;
17
+ pet_seat_info?: Record<string, any>;
18
+ };
19
+ grayscaleClass: string;
20
+ isSoldOut: boolean;
21
+ isItemExpanded: boolean;
22
+ colors: Record<string, any>;
23
+ translation?: { [key: string]: string };
24
+ getAnimationIcon: (icon: string) => any;
25
+ downArrowIcon?: React.ReactNode;
26
+ onToggleExpand: () => void;
27
+ }
28
+
29
+ function BottomAmenities({
30
+ otherItems,
31
+ serviceItem,
32
+ grayscaleClass,
33
+ isSoldOut,
34
+ isItemExpanded,
35
+ colors,
36
+ translation,
37
+ getAnimationIcon,
38
+ downArrowIcon,
39
+ onToggleExpand,
40
+ }: BottomAmenitiesProps): React.ReactElement {
41
+ const hasPetInfo =
42
+ serviceItem.pet_seat_info &&
43
+ Object.keys(serviceItem.pet_seat_info).length > 0;
44
+
45
+ const showDownArrow =
46
+ (serviceItem?.is_change_ticket && serviceItem.pet_seat_info) ||
47
+ (serviceItem.pet_seat_info &&
48
+ Object.keys(serviceItem.pet_seat_info).length > 0);
49
+
50
+ return (
51
+ <div className="flex items-center mt-[15px] border-t border-[#eee] pt-[6px]">
52
+ {/* OTHER ITEMS (GRID) */}
53
+ <div
54
+ className="grid items-center gap-[2%] flex-1 "
55
+ style={{
56
+ gridTemplateColumns: "18% 18% 23% 23%",
57
+ }}
58
+ >
59
+ {otherItems.map((item) => (
60
+ <div key={item.key} className="flex items-center">
61
+ {item.render}
62
+ </div>
63
+ ))}
64
+ </div>
65
+
66
+ {/* PET + FLEXIBLE (always visible) */}
67
+ <div className="flex items-center justify-end shrink-0 ml-[5px] w-[150px]">
68
+ {serviceItem?.is_tracking_enabled && (
69
+ <div className={grayscaleClass + " mr-[10px]"}>
70
+ <LottiePlayer
71
+ animationData={getAnimationIcon("locationAnim")}
72
+ width="20px"
73
+ height="20px"
74
+ />
75
+ </div>
76
+ )}
77
+ {serviceItem.is_change_ticket && (
78
+ <FlexibleBlock
79
+ translation={translation}
80
+ getAnimationIcon={getAnimationIcon}
81
+ colors={colors}
82
+ serviceItem={serviceItem}
83
+ isSoldOut={isSoldOut}
84
+ />
85
+ )}
86
+ {hasPetInfo && (
87
+ <PetBlock
88
+ translation={translation}
89
+ getAnimationIcon={getAnimationIcon}
90
+ colors={colors}
91
+ isSoldOut={isSoldOut}
92
+ />
93
+ )}
94
+
95
+ {/* DOWN ARROW ICON */}
96
+ {showDownArrow ? (
97
+ <div
98
+ className="flex items-center cursor-pointer ml-[4px] transition-transform duration-300 w-[14px] h-[14px]"
99
+ onClick={onToggleExpand}
100
+ >
101
+ {downArrowIcon}
102
+ </div>
103
+ ) : null}
104
+ </div>
105
+ </div>
106
+ );
107
+ }
108
+
109
+ export default BottomAmenities;
@@ -7,12 +7,12 @@ const DurationBlock = ({
7
7
  isSoldOut,
8
8
  colors,
9
9
  }) => (
10
- <div className="flex items-baseline relative whitespace-nowrap">
10
+ <div className="flex items-baseline relative whitespace-nowrap ">
11
11
  <div className={`w-[18px] mr-[4px] ${isSoldOut ? "grayscale" : ""}`}>
12
12
  {renderIcon("hours", "14px")}
13
13
  </div>
14
14
 
15
- <div className="group text-[13.33px]">
15
+ <div className="group text-[13.33px] cursor-pointer">
16
16
  {serviceItem.duration} {translation.hours}
17
17
  <div
18
18
  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]"
@@ -0,0 +1,85 @@
1
+ import React from "react";
2
+ import LottiePlayer from "../../assets/LottiePlayer";
3
+
4
+ interface ExpandedDropdownProps {
5
+ serviceItem: {
6
+ pet_seat_info?: Record<string, any>;
7
+ is_change_ticket?: boolean;
8
+ is_tracking_enabled?: boolean;
9
+ };
10
+ showPromo: boolean;
11
+ colors: {
12
+ priceColor?: string;
13
+ };
14
+ grayscaleClass: string;
15
+ translation?: { [key: string]: string };
16
+ getAnimationIcon: (icon: string) => any;
17
+ }
18
+
19
+ function ExpandedDropdown({
20
+ serviceItem,
21
+ showPromo,
22
+ colors,
23
+ grayscaleClass,
24
+ translation,
25
+ getAnimationIcon,
26
+ }: ExpandedDropdownProps): React.ReactElement {
27
+ const hasPetInfo =
28
+ serviceItem.pet_seat_info &&
29
+ Object.keys(serviceItem.pet_seat_info).length > 0;
30
+
31
+ return (
32
+ <div
33
+ className="px-[15px] pt-[26px] pb-[14px] -mt-[16px] pt-[20px] relative -z-9"
34
+ style={{
35
+ backgroundColor: "#f5f5f5",
36
+ borderRadius: "0 0 10px 10px",
37
+ // border: showPromo ? `1px solid ${colors.priceColor}` : "1px solid #ccc",
38
+ border: `1px solid ${colors.priceColor}`,
39
+
40
+ borderTop: "none",
41
+ }}
42
+ >
43
+ <div className="flex flex-col gap-[12px] text-[13px] text-[#464647]">
44
+ {hasPetInfo && (
45
+ <div className="flex items-center gap-[10px]">
46
+ <LottiePlayer
47
+ animationData={getAnimationIcon("petFriendlyAnim")}
48
+ width="20px"
49
+ height="20px"
50
+ />
51
+ <div className="h-auto mr-[4px] text-[13px] text-[#464647] bold-text">
52
+ <span>{translation?.petFriendly}</span>
53
+ </div>
54
+ </div>
55
+ )}
56
+ {serviceItem.is_change_ticket && (
57
+ <div className="flex items-center gap-[10px]">
58
+ <LottiePlayer
59
+ animationData={getAnimationIcon("flexibleIcon")}
60
+ width="20px"
61
+ height="20px"
62
+ />
63
+ <div className="h-auto mr-[4px] text-[13px] text-[#464647] bold-text">
64
+ <span>{translation?.flexible}</span>
65
+ </div>
66
+ </div>
67
+ )}
68
+ {serviceItem?.is_tracking_enabled && (
69
+ <div className={`${grayscaleClass} flex items-center gap-[10px]`}>
70
+ <LottiePlayer
71
+ animationData={getAnimationIcon("locationAnim")}
72
+ width="20px"
73
+ height="20px"
74
+ />
75
+ <div className="h-auto mr-[4px] text-[13px] text-[#464647] bold-text">
76
+ <span>{"GPS Tracker"}</span>
77
+ </div>
78
+ </div>
79
+ )}
80
+ </div>
81
+ </div>
82
+ );
83
+ }
84
+
85
+ export default ExpandedDropdown;
@@ -9,7 +9,7 @@ const FlexibleBlock = ({
9
9
  isSoldOut,
10
10
  }) => (
11
11
  <div className="flex items-center">
12
- <div className="relative group cursor-default">
12
+ <div className="relative group cursor-pointer">
13
13
  <div className="flex items-center">
14
14
  <div className={`mr-[5px] ${isSoldOut ? "grayscale" : ""}`}>
15
15
  <LottiePlayer
@@ -19,9 +19,9 @@ const FlexibleBlock = ({
19
19
  height="20px"
20
20
  />
21
21
  </div>
22
- <div className="h-auto mr-[4px] text-[13px] text-[#464647]">
22
+ {/* <div className="h-auto mr-[4px] text-[13px] text-[#464647]">
23
23
  <span>{translation?.flexible}</span>
24
- </div>
24
+ </div> */}
25
25
  </div>
26
26
  <div
27
27
  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-[230px] text-center break-normal shadow-service text-[12px]"
@@ -0,0 +1,48 @@
1
+ import React from "react";
2
+
3
+ interface KuposButtonProps {
4
+ isSoldOut: boolean;
5
+ isLoading: boolean;
6
+ buttonColor?: string;
7
+ buyLabel?: string;
8
+ soldOutLabel?: string;
9
+ soldOutIcon?: React.ReactNode;
10
+ onClick: () => void;
11
+ }
12
+
13
+ function KuposButton({
14
+ isSoldOut,
15
+ isLoading,
16
+ buttonColor,
17
+ buyLabel,
18
+ soldOutLabel,
19
+ soldOutIcon,
20
+ onClick,
21
+ }: KuposButtonProps): React.ReactElement {
22
+ const isDisabled = isLoading || isSoldOut;
23
+
24
+ return (
25
+ <button
26
+ onClick={() => (!isSoldOut ? onClick() : null)}
27
+ disabled={isLoading}
28
+ className="w-full py-[12px] text-[12px] font-bold text-white rounded-[14px] border-none px-[20px] flex items-center justify-center"
29
+ style={{
30
+ backgroundColor: isDisabled ? "lightgray" : buttonColor,
31
+ cursor: isDisabled ? "not-allowed" : "pointer",
32
+ }}
33
+ >
34
+ <span className="min-w-[75px] flex justify-center items-center bold-text uppercase">
35
+ {isSoldOut ? soldOutIcon : null}
36
+ {isLoading ? (
37
+ <span className="loader-circle"></span>
38
+ ) : !isSoldOut ? (
39
+ buyLabel
40
+ ) : (
41
+ soldOutLabel
42
+ )}
43
+ </span>
44
+ </button>
45
+ );
46
+ }
47
+
48
+ export default KuposButton;
@@ -13,9 +13,9 @@ const PetBlock = ({ translation, getAnimationIcon, colors, isSoldOut }) => (
13
13
  height="20px"
14
14
  />
15
15
  </div>
16
- <div className="h-auto mr-[4px] text-[13px] text-[#464647]">
16
+ {/* <div className="h-auto mr-[4px] text-[13px] text-[#464647]">
17
17
  <span>{translation?.petFriendly}</span>
18
- </div>
18
+ </div> */}
19
19
  </div>
20
20
  <div
21
21
  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-[230px] text-center break-normal shadow-service"
@@ -20,15 +20,27 @@ const RatingBlock = ({
20
20
  />
21
21
  )}
22
22
 
23
- <span
24
- className="ml-[10px] text-[13.33px]"
23
+ <div
24
+ className="group relative ml-[10px] text-[13.33px]"
25
25
  style={{
26
26
  marginLeft: showRating ? "10px" : "0",
27
27
  color: isSoldOut ? "#c0c0c0" : "#464647",
28
28
  }}
29
29
  >
30
- {serviceItem.operator_details[2]}
31
- </span>
30
+ <span className="block max-w-[120px] overflow-hidden text-ellipsis whitespace-nowrap cursor-pointer">
31
+ {serviceItem.operator_details[2]}
32
+ </span>
33
+ <div
34
+ className="hidden group-hover:block absolute top-[24px] left-1/2 -translate-x-1/2 text-white p-3 rounded-[14px] whitespace-nowrap z-10 mt-2.5 w-max text-center shadow-service text-[12px]"
35
+ style={{ backgroundColor: colors.tooltipColor }}
36
+ >
37
+ <div
38
+ 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 "
39
+ style={{ borderBottomColor: colors.tooltipColor }}
40
+ ></div>
41
+ {serviceItem.operator_details[2]}
42
+ </div>
43
+ </div>
32
44
  </div>
33
45
  );
34
46