kupos-ui-components-lib 10.4.59 → 10.4.60

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.
@@ -10,11 +10,6 @@ let SEAT_ORDER = [
10
10
  "Premium",
11
11
  "Premium (I)",
12
12
  ];
13
- function addSeatDegree(label) {
14
- if (!label)
15
- return label;
16
- return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
17
- }
18
13
  class ServiceFilter extends React.Component {
19
14
  constructor(props) {
20
15
  var _a, _b, _c, _d, _e, _f, _g;
@@ -230,6 +225,9 @@ class ServiceFilter extends React.Component {
230
225
  ? val.spText
231
226
  : val.label;
232
227
  }
228
+ const seatDegreeIcon = option.type === "seat_types" && this.props.isShowSeatDegree
229
+ ? commonService.getSeatDegreeIcon(label, this.props.icons)
230
+ : null;
233
231
  return (React.createElement("div", { key: i, onClick: () => onClick(val.originalOptionIndex !== undefined
234
232
  ? val.originalOptionIndex
235
233
  : i), style: {
@@ -245,13 +243,14 @@ class ServiceFilter extends React.Component {
245
243
  ? `text-[${this.props.colors.selectedTextColor}]`
246
244
  : ""} ${val.active ? "bold-text" : ""}` },
247
245
  val.icon && this.props.icons && (React.createElement("img", { src: iconKey, alt: val.icon, className: "w-[20px] h-[20px] mr-[10px] " })),
246
+ seatDegreeIcon && (React.createElement("img", { src: seatDegreeIcon, alt: "seattype", className: "w-[20px] h-[20px] mr-[10px]" })),
248
247
  React.createElement("span", { style: {
249
248
  textTransform: option.type !== "time" ? "capitalize" : "none",
250
249
  } }, option.type === "time"
251
250
  ? commonService.formatTimeLabel(label)
252
251
  : option.type === "seat_types" &&
253
252
  this.props.isShowSeatDegree
254
- ? addSeatDegree(commonService.formatDefaultLabel(label))
253
+ ? commonService.addSeatDegree(commonService.formatDefaultLabel(label))
255
254
  : commonService.formatDefaultLabel(label))));
256
255
  }))));
257
256
  }
@@ -28,6 +28,11 @@ export interface FilterBarProps {
28
28
  iconSunsetOrange?: string;
29
29
  iconNight?: string;
30
30
  iconNightOrange?: string;
31
+ seat120?: string;
32
+ seat140?: string;
33
+ seat160?: string;
34
+ seat180?: string;
35
+ fallBackSeatIcon?: string;
31
36
  };
32
37
  translation?: {
33
38
  [key: string]: string;
@@ -6,5 +6,5 @@ import { FilterSortBarMobileProps } from "./types";
6
6
  * consumer's list — sees a change until Aplicar commits the draft via
7
7
  * onApply. Closing the sheet without applying discards it.
8
8
  */
9
- declare const FilterSortBarMobile: ({ categories, onApply, onClearFilter, sortOptions, onSortChange, currencySign, colors, icons, }: FilterSortBarMobileProps) => React.JSX.Element;
9
+ declare const FilterSortBarMobile: ({ categories, onApply, onClearFilter, sortOptions, onSortChange, currencySign, colors, icons, isShowSeatDegree, }: FilterSortBarMobileProps) => React.JSX.Element;
10
10
  export default FilterSortBarMobile;
@@ -45,7 +45,7 @@ const isCategoryActive = (category) => getCategoryActiveCount(category) > 0;
45
45
  * consumer's list — sees a change until Aplicar commits the draft via
46
46
  * onApply. Closing the sheet without applying discards it.
47
47
  */
48
- const FilterSortBarMobile = ({ categories, onApply, onClearFilter, sortOptions, onSortChange, currencySign = "$", colors, icons, }) => {
48
+ const FilterSortBarMobile = ({ categories, onApply, onClearFilter, sortOptions, onSortChange, currencySign = "$", colors, icons, isShowSeatDegree = false, }) => {
49
49
  const [openSheet, setOpenSheet] = useState(null);
50
50
  const [isScrolled, setIsScrolled] = useState(false);
51
51
  const [draftCategories, setDraftCategories] = useState(categories);
@@ -164,6 +164,6 @@ const FilterSortBarMobile = ({ categories, onApply, onClearFilter, sortOptions,
164
164
  var _a;
165
165
  return (React.createElement(FilterChip, { key: `${category.key}:${option.id}`, label: option.label, active: option.selected, isOpen: false, onClick: () => handleInlineOptionToggle(category.key, option.id), iconSrc: option.icon ? (_a = resolvedIcons.timeOfDayIcons) === null || _a === void 0 ? void 0 : _a[option.icon] : undefined, colors: resolvedColors, icons: resolvedIcons }));
166
166
  })))),
167
- React.createElement(FiltersMasterSheet, { isOpen: isMasterOpen, initialCategoryKey: initialCategoryKey, categories: draftCategories, onClose: closeSheet, onToggleOption: handleDraftToggleOption, onPriceRangeChange: handleDraftPriceRangeChange, onClearAll: handleClearAll, onApplyAll: handleApplyAll, currencySign: currencySign, colors: resolvedColors, icons: resolvedIcons })));
167
+ React.createElement(FiltersMasterSheet, { isOpen: isMasterOpen, initialCategoryKey: initialCategoryKey, categories: draftCategories, onClose: closeSheet, onToggleOption: handleDraftToggleOption, onPriceRangeChange: handleDraftPriceRangeChange, onClearAll: handleClearAll, onApplyAll: handleApplyAll, currencySign: currencySign, colors: resolvedColors, icons: resolvedIcons, isShowSeatDegree: isShowSeatDegree })));
168
168
  };
169
169
  export default FilterSortBarMobile;
@@ -13,6 +13,7 @@ interface FiltersMasterSheetProps {
13
13
  currencySign: string;
14
14
  colors: Required<FilterSortBarColors>;
15
15
  icons?: FilterSortBarIcons;
16
+ isShowSeatDegree?: boolean;
16
17
  }
17
- declare const FiltersMasterSheet: ({ isOpen, initialCategoryKey, categories, onClose, onToggleOption, onPriceRangeChange, onClearAll, onApplyAll, currencySign, colors, icons, }: FiltersMasterSheetProps) => React.JSX.Element;
18
+ declare const FiltersMasterSheet: ({ isOpen, initialCategoryKey, categories, onClose, onToggleOption, onPriceRangeChange, onClearAll, onApplyAll, currencySign, colors, icons, isShowSeatDegree, }: FiltersMasterSheetProps) => React.JSX.Element;
18
19
  export default FiltersMasterSheet;
@@ -4,7 +4,7 @@ import { CloseIcon } from "./icons";
4
4
  import OptionCheckboxList from "./OptionCheckboxList";
5
5
  import PriceRangeSlider from "./PriceRangeSlider";
6
6
  import SheetFooter from "./SheetFooter";
7
- const FiltersMasterSheet = ({ isOpen, initialCategoryKey, categories, onClose, onToggleOption, onPriceRangeChange, onClearAll, onApplyAll, currencySign, colors, icons, }) => {
7
+ const FiltersMasterSheet = ({ isOpen, initialCategoryKey, categories, onClose, onToggleOption, onPriceRangeChange, onClearAll, onApplyAll, currencySign, colors, icons, isShowSeatDegree, }) => {
8
8
  var _a, _b;
9
9
  const [activeKey, setActiveKey] = useState((_b = initialCategoryKey !== null && initialCategoryKey !== void 0 ? initialCategoryKey : (_a = categories[0]) === null || _a === void 0 ? void 0 : _a.key) !== null && _b !== void 0 ? _b : "time");
10
10
  // Reset the pre-selected tab every time the sheet is (re)opened, whether
@@ -35,7 +35,7 @@ const FiltersMasterSheet = ({ isOpen, initialCategoryKey, categories, onClose, o
35
35
  })),
36
36
  React.createElement("div", { className: "flex-1 overflow-y-auto pl-[16px] pr-[20px] relative z-[1] bg-white" },
37
37
  activeCategory && (React.createElement("div", { className: "text-[11px] font-bold text-[#9B9B9B] uppercase tracking-[0.4px] mb-[5px] mt-[15px]" }, activeCategory.sectionLabel || activeCategory.label)),
38
- (activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.kind) === "price" && activeCategory.priceRange ? (React.createElement(PriceRangeSlider, { value: activeCategory.priceRange, onChange: (min, max) => onPriceRangeChange(activeCategory.key, min, max), currencySign: currencySign, primaryColor: colors.primaryColor, minLabel: "M\u00EDnimo", maxLabel: "M\u00E1ximo" })) : (React.createElement(OptionCheckboxList, { options: (activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.options) || [], kind: (activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.kind) || "checkbox", onToggle: (optionId) => onToggleOption(activeCategory.key, optionId), primaryColor: colors.primaryColor, starColor: colors.buttonColor || colors.primaryColor, icons: icons })))),
38
+ (activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.kind) === "price" && activeCategory.priceRange ? (React.createElement(PriceRangeSlider, { value: activeCategory.priceRange, onChange: (min, max) => onPriceRangeChange(activeCategory.key, min, max), currencySign: currencySign, primaryColor: colors.primaryColor, minLabel: "M\u00EDnimo", maxLabel: "M\u00E1ximo" })) : (React.createElement(OptionCheckboxList, { options: (activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.options) || [], kind: (activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.kind) || "checkbox", onToggle: (optionId) => onToggleOption(activeCategory.key, optionId), primaryColor: colors.primaryColor, starColor: colors.buttonColor || colors.primaryColor, icons: icons, showSeatDegree: !!isShowSeatDegree && (activeCategory === null || activeCategory === void 0 ? void 0 : activeCategory.key) === "seatType" })))),
39
39
  React.createElement("div", { className: "px-[20px]" },
40
40
  React.createElement(SheetFooter, { onClear: onClearAll, onApply: onApplyAll, colors: colors })))));
41
41
  };
@@ -8,6 +8,8 @@ interface OptionCheckboxListProps {
8
8
  /** Filled-star color for rating options — the app's button/CTA color, not the chip accent. */
9
9
  starColor: string;
10
10
  icons?: FilterSortBarIcons;
11
+ /** For options whose label contains 120/140/160/180: add "°" and show icons.seat120/140/160/180. */
12
+ showSeatDegree?: boolean;
11
13
  }
12
- declare const OptionCheckboxList: ({ options, kind, onToggle, primaryColor, starColor, icons }: OptionCheckboxListProps) => React.JSX.Element;
14
+ declare const OptionCheckboxList: ({ options, kind, onToggle, primaryColor, starColor, icons, showSeatDegree, }: OptionCheckboxListProps) => React.JSX.Element;
13
15
  export default OptionCheckboxList;
@@ -4,16 +4,20 @@ import CommonService from "../../utils/CommonService";
4
4
  const RatingLabel = ({ stars, label, starColor, icons, }) => (React.createElement("div", { className: "flex items-center gap-[1px] whitespace-nowrap" },
5
5
  Array.from({ length: 5 }, (_, i) => (React.createElement(StarIcon, { key: i, size: 10, filled: stars != null && i < stars, color: starColor, filledSrc: icons === null || icons === void 0 ? void 0 : icons.starFilledIcon, emptySrc: icons === null || icons === void 0 ? void 0 : icons.starEmptyIcon }))),
6
6
  React.createElement("span", { className: "ml-[6px]" }, label)));
7
- const OptionCheckboxList = ({ options, kind, onToggle, primaryColor, starColor, icons }) => {
7
+ const OptionCheckboxList = ({ options, kind, onToggle, primaryColor, starColor, icons, showSeatDegree, }) => {
8
8
  if (!(options === null || options === void 0 ? void 0 : options.length)) {
9
9
  return (React.createElement("div", { className: "py-[24px] text-center text-[#9B9B9B] text-[13px]" }, "No hay opciones disponibles"));
10
10
  }
11
11
  return (React.createElement("div", null, options.map((option) => {
12
12
  var _a;
13
+ const seatIcon = showSeatDegree ? CommonService.getSeatDegreeIcon(option.label, icons) : null;
14
+ const label = CommonService.capitalizeFirstLetter(showSeatDegree ? CommonService.addSeatDegree(option.label) : option.label);
13
15
  return (React.createElement("div", { key: option.id, onClick: () => onToggle(option.id), className: "flex items-center justify-between py-[12px] px-[2px] cursor-pointer text-[13px] text-[#464647] select-none [-webkit-tap-highlight-color:transparent]" },
14
16
  kind === "rating" ? (React.createElement(RatingLabel, { stars: option.stars, label: option.label, starColor: starColor, icons: icons })) : option.icon ? (React.createElement("div", { className: "flex items-center gap-[10px]" },
15
17
  React.createElement(TimeOfDayIcon, { variant: option.icon, size: 16, src: (_a = icons === null || icons === void 0 ? void 0 : icons.timeOfDayIcons) === null || _a === void 0 ? void 0 : _a[option.icon] }),
16
- React.createElement("span", null, option.label))) : (React.createElement("span", null, CommonService.capitalizeFirstLetter(option.label))),
18
+ React.createElement("span", null, option.label))) : seatIcon ? (React.createElement("div", { className: "flex items-center gap-[10px]" },
19
+ React.createElement("img", { src: seatIcon, alt: "seattype", className: "w-[16px] h-[16px]" }),
20
+ React.createElement("span", null, label))) : (React.createElement("span", null, label)),
17
21
  React.createElement(CheckboxIcon, { checked: option.selected, color: primaryColor, spriteSrc: icons === null || icons === void 0 ? void 0 : icons.checkBoxIcon })));
18
22
  })));
19
23
  };
@@ -77,6 +77,11 @@ export interface FilterSortBarIcons {
77
77
  timeOfDayIcons?: Partial<Record<TimeOfDayVariant, string>>;
78
78
  /** Icons for sort chips whose key doesn't already map to a category/time-of-day icon (e.g. "duration" for a Rápido chip). Keyed by SortOption.key. */
79
79
  sortIcons?: Partial<Record<string, string>>;
80
+ /** Seat-type icons shown next to "Tipo de asiento" options whose label contains 120/140/160/180, only when isShowSeatDegree is true. */
81
+ seat120?: string;
82
+ seat140?: string;
83
+ seat160?: string;
84
+ seat180?: string;
80
85
  }
81
86
  export interface FilterSortBarMobileProps {
82
87
  categories: FilterCategory[];
@@ -88,4 +93,6 @@ export interface FilterSortBarMobileProps {
88
93
  currencySign?: string;
89
94
  colors?: FilterSortBarColors;
90
95
  icons?: FilterSortBarIcons;
96
+ /** In the Filtros sheet's seat-type tab, adds "°" to 120/140/160/180 labels and shows icons.seat120/140/160/180 next to them. */
97
+ isShowSeatDegree?: boolean;
91
98
  }
@@ -14,6 +14,8 @@ declare const commonService: {
14
14
  capitalizeFirstLetter: (str: any) => string;
15
15
  formatTimeLabel: (label: string) => string;
16
16
  formatDefaultLabel: (label: string) => string;
17
+ addSeatDegree: (label: string) => string;
18
+ getSeatDegreeIcon: (label: string, icons: any) => string | null;
17
19
  calculateDiscountedPrice: (originalPrice: number | string, serviceItem?: {
18
20
  discount_type?: string;
19
21
  discount_value?: number;
@@ -323,6 +323,15 @@ const commonService = {
323
323
  return "";
324
324
  return label.toLowerCase();
325
325
  },
326
+ addSeatDegree: (label) => {
327
+ if (!label)
328
+ return label;
329
+ return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
330
+ },
331
+ getSeatDegreeIcon: (label, icons) => {
332
+ const match = String(label !== null && label !== void 0 ? label : "").match(/\b(120|140|160|180)\b/);
333
+ return match ? (icons === null || icons === void 0 ? void 0 : icons[`seat${match[1]}`]) || null : null;
334
+ },
326
335
  calculateDiscountedPrice: (originalPrice, serviceItem) => {
327
336
  var _a;
328
337
  const price = typeof originalPrice === "string"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kupos-ui-components-lib",
3
- "version": "10.4.59",
3
+ "version": "10.4.60",
4
4
  "description": "A reusable UI components package",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -14,11 +14,6 @@ let SEAT_ORDER = [
14
14
  "Premium (I)",
15
15
  ];
16
16
 
17
- function addSeatDegree(label: string) {
18
- if (!label) return label;
19
- return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
20
- }
21
-
22
17
  interface ServiceFilterBarDesktopState {
23
18
  showOperators: boolean;
24
19
  showTimeOptions: boolean;
@@ -307,6 +302,11 @@ class ServiceFilter extends React.Component<
307
302
  : val.label;
308
303
  }
309
304
 
305
+ const seatDegreeIcon =
306
+ option.type === "seat_types" && this.props.isShowSeatDegree
307
+ ? commonService.getSeatDegreeIcon(label, this.props.icons)
308
+ : null;
309
+
310
310
  return (
311
311
  <div
312
312
  key={i}
@@ -342,6 +342,13 @@ class ServiceFilter extends React.Component<
342
342
  className="w-[20px] h-[20px] mr-[10px] "
343
343
  />
344
344
  )}
345
+ {seatDegreeIcon && (
346
+ <img
347
+ src={seatDegreeIcon}
348
+ alt="seattype"
349
+ className="w-[20px] h-[20px] mr-[10px]"
350
+ />
351
+ )}
345
352
  <span
346
353
  style={{
347
354
  textTransform:
@@ -352,7 +359,9 @@ class ServiceFilter extends React.Component<
352
359
  ? commonService.formatTimeLabel(label)
353
360
  : option.type === "seat_types" &&
354
361
  this.props.isShowSeatDegree
355
- ? addSeatDegree(commonService.formatDefaultLabel(label))
362
+ ? commonService.addSeatDegree(
363
+ commonService.formatDefaultLabel(label),
364
+ )
356
365
  : commonService.formatDefaultLabel(label)}
357
366
  </span>
358
367
  </div>
@@ -29,6 +29,11 @@ export interface FilterBarProps {
29
29
  iconSunsetOrange?: string;
30
30
  iconNight?: string;
31
31
  iconNightOrange?: string;
32
+ seat120?: string;
33
+ seat140?: string;
34
+ seat160?: string;
35
+ seat180?: string;
36
+ fallBackSeatIcon?: string;
32
37
  };
33
38
  translation?: { [key: string]: string };
34
39
  isTrain?: boolean;
@@ -59,6 +59,7 @@ const FilterSortBarMobile = ({
59
59
  currencySign = "$",
60
60
  colors,
61
61
  icons,
62
+ isShowSeatDegree = false,
62
63
  }: FilterSortBarMobileProps) => {
63
64
  const [openSheet, setOpenSheet] = useState<FilterCategoryKey | "all" | null>(null);
64
65
  const [isScrolled, setIsScrolled] = useState(false);
@@ -284,6 +285,7 @@ const FilterSortBarMobile = ({
284
285
  currencySign={currencySign}
285
286
  colors={resolvedColors}
286
287
  icons={resolvedIcons}
288
+ isShowSeatDegree={isShowSeatDegree}
287
289
  />
288
290
  </div>
289
291
  );
@@ -19,6 +19,7 @@ interface FiltersMasterSheetProps {
19
19
  currencySign: string;
20
20
  colors: Required<FilterSortBarColors>;
21
21
  icons?: FilterSortBarIcons;
22
+ isShowSeatDegree?: boolean;
22
23
  }
23
24
 
24
25
  const FiltersMasterSheet = ({
@@ -33,6 +34,7 @@ const FiltersMasterSheet = ({
33
34
  currencySign,
34
35
  colors,
35
36
  icons,
37
+ isShowSeatDegree,
36
38
  }: FiltersMasterSheetProps) => {
37
39
  const [activeKey, setActiveKey] = useState<FilterCategoryKey>(initialCategoryKey ?? categories[0]?.key ?? "time");
38
40
 
@@ -108,6 +110,7 @@ const FiltersMasterSheet = ({
108
110
  primaryColor={colors.primaryColor}
109
111
  starColor={colors.buttonColor || colors.primaryColor}
110
112
  icons={icons}
113
+ showSeatDegree={!!isShowSeatDegree && activeCategory?.key === "seatType"}
111
114
  />
112
115
  )}
113
116
  </div>
@@ -11,6 +11,8 @@ interface OptionCheckboxListProps {
11
11
  /** Filled-star color for rating options — the app's button/CTA color, not the chip accent. */
12
12
  starColor: string;
13
13
  icons?: FilterSortBarIcons;
14
+ /** For options whose label contains 120/140/160/180: add "°" and show icons.seat120/140/160/180. */
15
+ showSeatDegree?: boolean;
14
16
  }
15
17
 
16
18
  const RatingLabel = ({
@@ -39,7 +41,15 @@ const RatingLabel = ({
39
41
  </div>
40
42
  );
41
43
 
42
- const OptionCheckboxList = ({ options, kind, onToggle, primaryColor, starColor, icons }: OptionCheckboxListProps) => {
44
+ const OptionCheckboxList = ({
45
+ options,
46
+ kind,
47
+ onToggle,
48
+ primaryColor,
49
+ starColor,
50
+ icons,
51
+ showSeatDegree,
52
+ }: OptionCheckboxListProps) => {
43
53
  if (!options?.length) {
44
54
  return (
45
55
  <div className="py-[24px] text-center text-[#9B9B9B] text-[13px]">
@@ -50,25 +60,37 @@ const OptionCheckboxList = ({ options, kind, onToggle, primaryColor, starColor,
50
60
 
51
61
  return (
52
62
  <div>
53
- {options.map((option) => (
54
- <div
55
- key={option.id}
56
- onClick={() => onToggle(option.id)}
57
- className="flex items-center justify-between py-[12px] px-[2px] cursor-pointer text-[13px] text-[#464647] select-none [-webkit-tap-highlight-color:transparent]"
58
- >
59
- {kind === "rating" ? (
60
- <RatingLabel stars={option.stars} label={option.label} starColor={starColor} icons={icons} />
61
- ) : option.icon ? (
62
- <div className="flex items-center gap-[10px]">
63
- <TimeOfDayIcon variant={option.icon} size={16} src={icons?.timeOfDayIcons?.[option.icon]} />
64
- <span>{option.label}</span>
65
- </div>
66
- ) : (
67
- <span>{CommonService.capitalizeFirstLetter(option.label)}</span>
68
- )}
69
- <CheckboxIcon checked={option.selected} color={primaryColor} spriteSrc={icons?.checkBoxIcon} />
70
- </div>
71
- ))}
63
+ {options.map((option) => {
64
+ const seatIcon = showSeatDegree ? CommonService.getSeatDegreeIcon(option.label, icons) : null;
65
+ const label = CommonService.capitalizeFirstLetter(
66
+ showSeatDegree ? CommonService.addSeatDegree(option.label) : option.label,
67
+ );
68
+
69
+ return (
70
+ <div
71
+ key={option.id}
72
+ onClick={() => onToggle(option.id)}
73
+ className="flex items-center justify-between py-[12px] px-[2px] cursor-pointer text-[13px] text-[#464647] select-none [-webkit-tap-highlight-color:transparent]"
74
+ >
75
+ {kind === "rating" ? (
76
+ <RatingLabel stars={option.stars} label={option.label} starColor={starColor} icons={icons} />
77
+ ) : option.icon ? (
78
+ <div className="flex items-center gap-[10px]">
79
+ <TimeOfDayIcon variant={option.icon} size={16} src={icons?.timeOfDayIcons?.[option.icon]} />
80
+ <span>{option.label}</span>
81
+ </div>
82
+ ) : seatIcon ? (
83
+ <div className="flex items-center gap-[10px]">
84
+ <img src={seatIcon} alt="seattype" className="w-[16px] h-[16px]" />
85
+ <span>{label}</span>
86
+ </div>
87
+ ) : (
88
+ <span>{label}</span>
89
+ )}
90
+ <CheckboxIcon checked={option.selected} color={primaryColor} spriteSrc={icons?.checkBoxIcon} />
91
+ </div>
92
+ );
93
+ })}
72
94
  </div>
73
95
  );
74
96
  };
@@ -100,6 +100,11 @@ export interface FilterSortBarIcons {
100
100
  timeOfDayIcons?: Partial<Record<TimeOfDayVariant, string>>;
101
101
  /** Icons for sort chips whose key doesn't already map to a category/time-of-day icon (e.g. "duration" for a Rápido chip). Keyed by SortOption.key. */
102
102
  sortIcons?: Partial<Record<string, string>>;
103
+ /** Seat-type icons shown next to "Tipo de asiento" options whose label contains 120/140/160/180, only when isShowSeatDegree is true. */
104
+ seat120?: string;
105
+ seat140?: string;
106
+ seat160?: string;
107
+ seat180?: string;
103
108
  }
104
109
 
105
110
  export interface FilterSortBarMobileProps {
@@ -112,4 +117,6 @@ export interface FilterSortBarMobileProps {
112
117
  currencySign?: string;
113
118
  colors?: FilterSortBarColors;
114
119
  icons?: FilterSortBarIcons;
120
+ /** In the Filtros sheet's seat-type tab, adds "°" to 120/140/160/180 labels and shows icons.seat120/140/160/180 next to them. */
121
+ isShowSeatDegree?: boolean;
115
122
  }
@@ -339,6 +339,16 @@ const commonService = {
339
339
  return label.toLowerCase();
340
340
  },
341
341
 
342
+ addSeatDegree: (label: string) => {
343
+ if (!label) return label;
344
+ return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
345
+ },
346
+
347
+ getSeatDegreeIcon: (label: string, icons: any): string | null => {
348
+ const match = String(label ?? "").match(/\b(120|140|160|180)\b/);
349
+ return match ? icons?.[`seat${match[1]}`] || null : null;
350
+ },
351
+
342
352
  calculateDiscountedPrice: (
343
353
  originalPrice: number | string,
344
354
  serviceItem?: {