kupos-ui-components-lib 10.4.58 → 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.
- package/dist/components/FilterBar/FilterBarDesktop.d.ts +1 -1
- package/dist/components/FilterBar/FilterBarDesktop.js +2 -2
- package/dist/components/FilterBar/ServiceFilter.js +8 -1
- package/dist/components/FilterBar/ServiceFilterProps.d.ts +1 -0
- package/dist/components/FilterBar/tyoes.d.ts +6 -0
- package/dist/components/FilterSortBar/FilterSortBarMobile.d.ts +1 -1
- package/dist/components/FilterSortBar/FilterSortBarMobile.js +2 -2
- package/dist/components/FilterSortBar/FiltersMasterSheet.d.ts +2 -1
- package/dist/components/FilterSortBar/FiltersMasterSheet.js +2 -2
- package/dist/components/FilterSortBar/OptionCheckboxList.d.ts +3 -1
- package/dist/components/FilterSortBar/OptionCheckboxList.js +6 -2
- package/dist/components/FilterSortBar/types.d.ts +7 -0
- package/dist/ui/SeatSection/PeruSeatSection.js +1 -1
- package/dist/ui/SeatSection/SeatSection.js +1 -1
- package/dist/ui/mobileweb/SeatSectionMobile.js +1 -1
- package/dist/utils/CommonService.d.ts +2 -0
- package/dist/utils/CommonService.js +9 -0
- package/package.json +1 -1
- package/src/components/FilterBar/FilterBarDesktop.tsx +2 -0
- package/src/components/FilterBar/ServiceFilter.tsx +18 -1
- package/src/components/FilterBar/ServiceFilterProps.ts +1 -0
- package/src/components/FilterBar/tyoes.ts +6 -0
- package/src/components/FilterSortBar/FilterSortBarMobile.tsx +2 -0
- package/src/components/FilterSortBar/FiltersMasterSheet.tsx +3 -0
- package/src/components/FilterSortBar/OptionCheckboxList.tsx +42 -20
- package/src/components/FilterSortBar/types.ts +7 -0
- package/src/ui/SeatSection/PeruSeatSection.tsx +1 -1
- package/src/ui/SeatSection/SeatSection.tsx +1 -1
- package/src/ui/mobileweb/SeatSectionMobile.tsx +1 -1
- package/src/utils/CommonService.ts +10 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { FilterBarProps } from "./tyoes";
|
|
3
|
-
declare const FilterBarDesktop: ({ t, serviceList, setServiceList, allSchedules, showReturnTripModal, filterArrData, isBlankTicket, operatorId, filtersArray, setFiltersArray, metaData, busTerminals, setTypes, colors, icons, translation, isTrain, isPeru, hideOperator, setCoachLoading, setCoachKey, isAllinBus, priority_stage_ids, }: FilterBarProps) => React.JSX.Element;
|
|
3
|
+
declare const FilterBarDesktop: ({ t, serviceList, setServiceList, allSchedules, showReturnTripModal, filterArrData, isBlankTicket, operatorId, filtersArray, setFiltersArray, metaData, busTerminals, setTypes, colors, icons, translation, isTrain, isPeru, hideOperator, isShowSeatDegree, setCoachLoading, setCoachKey, isAllinBus, priority_stage_ids, }: FilterBarProps) => React.JSX.Element;
|
|
4
4
|
export default FilterBarDesktop;
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import commonService from "../../utils/CommonService";
|
|
3
3
|
import ServiceFilter from "./ServiceFilter";
|
|
4
4
|
let cachedStageOptions = null;
|
|
5
|
-
const FilterBarDesktop = ({ t, serviceList, setServiceList, allSchedules, showReturnTripModal, filterArrData, isBlankTicket, operatorId, filtersArray, setFiltersArray, metaData, busTerminals, setTypes, colors, icons, translation, isTrain, isPeru, hideOperator, setCoachLoading, setCoachKey, isAllinBus, priority_stage_ids, }) => {
|
|
5
|
+
const FilterBarDesktop = ({ t, serviceList, setServiceList, allSchedules, showReturnTripModal, filterArrData, isBlankTicket, operatorId, filtersArray, setFiltersArray, metaData, busTerminals, setTypes, colors, icons, translation, isTrain, isPeru, hideOperator, isShowSeatDegree, setCoachLoading, setCoachKey, isAllinBus, priority_stage_ids, }) => {
|
|
6
6
|
// Same rule as showTopLabel in ServiceItemDesktop: a visible bus terminal
|
|
7
7
|
// label, restricted to priority_stage_ids when that list is non-empty.
|
|
8
8
|
const getTopLabel = (labelId) => {
|
|
@@ -267,6 +267,6 @@ const FilterBarDesktop = ({ t, serviceList, setServiceList, allSchedules, showRe
|
|
|
267
267
|
return (React.createElement(ServiceFilter, { filtersArray: enrichedFilters, onFilterSelected: onFilterSelected, onFilterClear: (val) => {
|
|
268
268
|
setFiltersArray(val);
|
|
269
269
|
filterBy(val);
|
|
270
|
-
}, showReturnTripModal: showReturnTripModal, initialOpenFilters: isBlankTicket ? ["operator"] : [], colors: colors, icons: icons, translation: translation, isTrain: isTrain, hideOperator: hideOperator, t: t }));
|
|
270
|
+
}, showReturnTripModal: showReturnTripModal, initialOpenFilters: isBlankTicket ? ["operator"] : [], colors: colors, icons: icons, translation: translation, isTrain: isTrain, hideOperator: hideOperator, isShowSeatDegree: isShowSeatDegree, t: t }));
|
|
271
271
|
};
|
|
272
272
|
export default FilterBarDesktop;
|
|
@@ -225,6 +225,9 @@ class ServiceFilter extends React.Component {
|
|
|
225
225
|
? val.spText
|
|
226
226
|
: val.label;
|
|
227
227
|
}
|
|
228
|
+
const seatDegreeIcon = option.type === "seat_types" && this.props.isShowSeatDegree
|
|
229
|
+
? commonService.getSeatDegreeIcon(label, this.props.icons)
|
|
230
|
+
: null;
|
|
228
231
|
return (React.createElement("div", { key: i, onClick: () => onClick(val.originalOptionIndex !== undefined
|
|
229
232
|
? val.originalOptionIndex
|
|
230
233
|
: i), style: {
|
|
@@ -240,11 +243,15 @@ class ServiceFilter extends React.Component {
|
|
|
240
243
|
? `text-[${this.props.colors.selectedTextColor}]`
|
|
241
244
|
: ""} ${val.active ? "bold-text" : ""}` },
|
|
242
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]" })),
|
|
243
247
|
React.createElement("span", { style: {
|
|
244
248
|
textTransform: option.type !== "time" ? "capitalize" : "none",
|
|
245
249
|
} }, option.type === "time"
|
|
246
250
|
? commonService.formatTimeLabel(label)
|
|
247
|
-
:
|
|
251
|
+
: option.type === "seat_types" &&
|
|
252
|
+
this.props.isShowSeatDegree
|
|
253
|
+
? commonService.addSeatDegree(commonService.formatDefaultLabel(label))
|
|
254
|
+
: commonService.formatDefaultLabel(label))));
|
|
248
255
|
}))));
|
|
249
256
|
}
|
|
250
257
|
render() {
|
|
@@ -14,6 +14,7 @@ export interface FilterBarProps {
|
|
|
14
14
|
busTerminals?: any;
|
|
15
15
|
setTypes?: any;
|
|
16
16
|
hideOperator?: boolean;
|
|
17
|
+
isShowSeatDegree?: boolean;
|
|
17
18
|
colors: {
|
|
18
19
|
selectedColor?: string;
|
|
19
20
|
selectedTextColor?: string;
|
|
@@ -27,6 +28,11 @@ export interface FilterBarProps {
|
|
|
27
28
|
iconSunsetOrange?: string;
|
|
28
29
|
iconNight?: string;
|
|
29
30
|
iconNightOrange?: string;
|
|
31
|
+
seat120?: string;
|
|
32
|
+
seat140?: string;
|
|
33
|
+
seat160?: string;
|
|
34
|
+
seat180?: string;
|
|
35
|
+
fallBackSeatIcon?: string;
|
|
30
36
|
};
|
|
31
37
|
translation?: {
|
|
32
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("
|
|
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
|
}
|
|
@@ -86,7 +86,7 @@ function getSeatLabelIcon(label, serviceItem) {
|
|
|
86
86
|
function addSeatDegree(label) {
|
|
87
87
|
if (!label)
|
|
88
88
|
return label;
|
|
89
|
-
return String(label).replace(/\b(140|160|180)\b(?!°)/g, "$1°");
|
|
89
|
+
return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
|
|
90
90
|
}
|
|
91
91
|
function PeruSeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, serviceItem, renderIcon, discountSeatPriceColor, isSeatIcon, isShowSeatIcon, }) {
|
|
92
92
|
var _a;
|
|
@@ -94,7 +94,7 @@ function getSeatLabelIcon(label, serviceItem) {
|
|
|
94
94
|
function addSeatDegree(label) {
|
|
95
95
|
if (!label)
|
|
96
96
|
return label;
|
|
97
|
-
return String(label).replace(/\b(140|160|180)\b(?!°)/g, "$1°");
|
|
97
|
+
return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
|
|
98
98
|
}
|
|
99
99
|
function SeatSection({ seatTypes, availableSeats, isSoldOut, priceColor, currencySign, removeDuplicateSeats, selectedSeatKey, onSeatSelect, isPeru, serviceItem, renderIcon, dpSeatColor, discountSeatPriceColor, isSeatIcon, isTrain, topLabelColor, tooltipColor, discountSeatCrossPriceColor, isShowSeatIcon }) {
|
|
100
100
|
var _a;
|
|
@@ -42,7 +42,7 @@ function getSeatLabelIcon(label, serviceItem) {
|
|
|
42
42
|
function addSeatDegree(label) {
|
|
43
43
|
if (!label)
|
|
44
44
|
return label;
|
|
45
|
-
return String(label).replace(/\b(140|160|180)\b(?!°)/g, "$1°");
|
|
45
|
+
return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
|
|
46
46
|
}
|
|
47
47
|
function hasInclinationSeatTypes(seatTypes) {
|
|
48
48
|
return (seatTypes !== null && seatTypes !== void 0 ? seatTypes : []).some((seat) => { var _a; return String((_a = seat === null || seat === void 0 ? void 0 : seat.label) !== null && _a !== void 0 ? _a : "").includes("°"); });
|
|
@@ -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
|
@@ -25,6 +25,7 @@ const FilterBarDesktop = ({
|
|
|
25
25
|
isTrain,
|
|
26
26
|
isPeru,
|
|
27
27
|
hideOperator,
|
|
28
|
+
isShowSeatDegree,
|
|
28
29
|
setCoachLoading,
|
|
29
30
|
setCoachKey,
|
|
30
31
|
isAllinBus,
|
|
@@ -329,6 +330,7 @@ const FilterBarDesktop = ({
|
|
|
329
330
|
translation={translation}
|
|
330
331
|
isTrain={isTrain}
|
|
331
332
|
hideOperator={hideOperator}
|
|
333
|
+
isShowSeatDegree={isShowSeatDegree}
|
|
332
334
|
t={t}
|
|
333
335
|
/>
|
|
334
336
|
);
|
|
@@ -302,6 +302,11 @@ class ServiceFilter extends React.Component<
|
|
|
302
302
|
: val.label;
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
+
const seatDegreeIcon =
|
|
306
|
+
option.type === "seat_types" && this.props.isShowSeatDegree
|
|
307
|
+
? commonService.getSeatDegreeIcon(label, this.props.icons)
|
|
308
|
+
: null;
|
|
309
|
+
|
|
305
310
|
return (
|
|
306
311
|
<div
|
|
307
312
|
key={i}
|
|
@@ -337,6 +342,13 @@ class ServiceFilter extends React.Component<
|
|
|
337
342
|
className="w-[20px] h-[20px] mr-[10px] "
|
|
338
343
|
/>
|
|
339
344
|
)}
|
|
345
|
+
{seatDegreeIcon && (
|
|
346
|
+
<img
|
|
347
|
+
src={seatDegreeIcon}
|
|
348
|
+
alt="seattype"
|
|
349
|
+
className="w-[20px] h-[20px] mr-[10px]"
|
|
350
|
+
/>
|
|
351
|
+
)}
|
|
340
352
|
<span
|
|
341
353
|
style={{
|
|
342
354
|
textTransform:
|
|
@@ -345,7 +357,12 @@ class ServiceFilter extends React.Component<
|
|
|
345
357
|
>
|
|
346
358
|
{option.type === "time"
|
|
347
359
|
? commonService.formatTimeLabel(label)
|
|
348
|
-
:
|
|
360
|
+
: option.type === "seat_types" &&
|
|
361
|
+
this.props.isShowSeatDegree
|
|
362
|
+
? commonService.addSeatDegree(
|
|
363
|
+
commonService.formatDefaultLabel(label),
|
|
364
|
+
)
|
|
365
|
+
: commonService.formatDefaultLabel(label)}
|
|
349
366
|
</span>
|
|
350
367
|
</div>
|
|
351
368
|
);
|
|
@@ -14,6 +14,7 @@ export interface FilterBarProps {
|
|
|
14
14
|
busTerminals?: any;
|
|
15
15
|
setTypes?: any;
|
|
16
16
|
hideOperator?: boolean;
|
|
17
|
+
isShowSeatDegree?: boolean;
|
|
17
18
|
colors: {
|
|
18
19
|
selectedColor?: string;
|
|
19
20
|
selectedTextColor?: string;
|
|
@@ -28,6 +29,11 @@ export interface FilterBarProps {
|
|
|
28
29
|
iconSunsetOrange?: string;
|
|
29
30
|
iconNight?: string;
|
|
30
31
|
iconNightOrange?: string;
|
|
32
|
+
seat120?: string;
|
|
33
|
+
seat140?: string;
|
|
34
|
+
seat160?: string;
|
|
35
|
+
seat180?: string;
|
|
36
|
+
fallBackSeatIcon?: string;
|
|
31
37
|
};
|
|
32
38
|
translation?: { [key: string]: string };
|
|
33
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 = ({
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
}
|
|
@@ -120,7 +120,7 @@ function getSeatLabelIcon(label: string, serviceItem: any) {
|
|
|
120
120
|
|
|
121
121
|
function addSeatDegree(label: string) {
|
|
122
122
|
if (!label) return label;
|
|
123
|
-
return String(label).replace(/\b(140|160|180)\b(?!°)/g, "$1°");
|
|
123
|
+
return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
function PeruSeatSection({
|
|
@@ -140,7 +140,7 @@ function getSeatLabelIcon(label: string, serviceItem: any) {
|
|
|
140
140
|
|
|
141
141
|
function addSeatDegree(label: string) {
|
|
142
142
|
if (!label) return label;
|
|
143
|
-
return String(label).replace(/\b(140|160|180)\b(?!°)/g, "$1°");
|
|
143
|
+
return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
function SeatSection({
|
|
@@ -106,7 +106,7 @@ function getSeatLabelIcon(label: string, serviceItem: any) {
|
|
|
106
106
|
|
|
107
107
|
function addSeatDegree(label: string | null) {
|
|
108
108
|
if (!label) return label;
|
|
109
|
-
return String(label).replace(/\b(140|160|180)\b(?!°)/g, "$1°");
|
|
109
|
+
return String(label).replace(/\b(120|140|160|180)\b(?!°)/g, "$1°");
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
function hasInclinationSeatTypes(seatTypes: SeatType[]): boolean {
|
|
@@ -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?: {
|