Merged in feat/SW-1232-filter-improvements-select-hot (pull request #2168)

feat: SW-1232 Implemented disabling of filters and show hotel count

* feat: SW-1232 Implemented disabling of filters and show hotel count

* feat: SW-1232 Optimised code


Approved-by: Niclas Edenvin
This commit is contained in:
Hrishikesh Vaipurkar
2025-05-21 12:27:11 +00:00
parent 16be305ad3
commit b3d5326adb
7 changed files with 95 additions and 96 deletions

View File

@@ -33,3 +33,12 @@
forced-color-adjust: none;
background: var(--UI-Input-Controls-Surface-Normal);
}
.container[data-disabled] {
color: var(--Text-Interactive-Disabled);
cursor: not-allowed;
}
.container[data-disabled] .checkbox {
border-color: var(--Text-Interactive-Disabled);
background: var(--Surface-Primary-Disabled);
}

View File

@@ -13,6 +13,7 @@ export default function FilterCheckbox({
isSelected,
name,
id,
isDisabled,
onChange,
}: FilterCheckboxProps) {
return (
@@ -20,6 +21,7 @@ export default function FilterCheckbox({
className={styles.container}
isSelected={isSelected}
onChange={() => onChange(id)}
isDisabled={isDisabled}
>
{({ isSelected }) => (
<>

View File

@@ -14,7 +14,10 @@ import FilterCheckbox from "./FilterCheckbox"
import styles from "./hotelFilter.module.css"
import type { HotelFiltersProps } from "@/types/components/hotelReservation/selectHotel/hotelFilters"
import type {
HotelFilter,
HotelFiltersProps,
} from "@/types/components/hotelReservation/selectHotel/hotelFilters"
export default function HotelFilter({ className, filters }: HotelFiltersProps) {
const intl = useIntl()
@@ -49,6 +52,47 @@ export default function HotelFilter({ className, filters }: HotelFiltersProps) {
return null
}
let filteredHotelIds: string[] | undefined
if (activeFilters.length) {
const allFilters = [
...filters.facilityFilters,
...filters.surroundingsFilters,
]
filteredHotelIds = allFilters
.filter((f) => activeFilters.includes(f.id.toString()))
.map((f) => f.hotelIds)
.reduce((accumlatedHotelIds, currentHotelIds) =>
accumlatedHotelIds?.filter((hotelId) =>
currentHotelIds?.includes(hotelId)
)
)
}
function filterOutput(filters: HotelFilter[]) {
return filters.map((filter) => {
const isDisabled = filteredHotelIds?.length
? !filter.hotelIds?.some((hotelId) =>
filteredHotelIds.includes(hotelId)
)
: false
return (
<li key={`li-${filter.id}`} className={styles.filter}>
<FilterCheckbox
name={filter.name}
id={filter.id.toString()}
onChange={() => toggleFilter(filter.id.toString())}
isSelected={activeFilters.some((f) => f === filter.id.toString())}
isDisabled={isDisabled}
/>
{!isDisabled ? (
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
<span>{`(${filteredHotelIds?.filter((id) => filter.hotelIds.includes(id))?.length ?? filter.hotelIds.length})`}</span>
) : null}
</li>
)
})
}
return (
<aside className={`${styles.container} ${className}`}>
<form>
@@ -63,20 +107,7 @@ export default function HotelFilter({ className, filters }: HotelFiltersProps) {
defaultMessage: "Hotel facilities",
})}
</Subtitle>
<ul>
{filters.facilityFilters.map((filter) => (
<li key={`li-${filter.id}`} className={styles.filter}>
<FilterCheckbox
name={filter.name}
id={filter.id.toString()}
onChange={() => toggleFilter(filter.id.toString())}
isSelected={
!!activeFilters.find((f) => f === filter.id.toString())
}
/>
</li>
))}
</ul>
<ul>{filterOutput(filters.facilityFilters)}</ul>
</div>
<div className={styles.facilities}>
@@ -85,20 +116,7 @@ export default function HotelFilter({ className, filters }: HotelFiltersProps) {
defaultMessage: "Hotel surroundings",
})}
</Subtitle>
<ul>
{filters.surroundingsFilters.map((filter) => (
<li key={`li-${filter.id}`} className={styles.filter}>
<FilterCheckbox
name={filter.name}
id={filter.id.toString()}
onChange={() => toggleFilter(filter.id.toString())}
isSelected={
!!activeFilters.find((f) => f === filter.id.toString())
}
/>
</li>
))}
</ul>
<ul>{filterOutput(filters.surroundingsFilters)}</ul>
</div>
</form>
</aside>

View File

@@ -9,13 +9,16 @@ import type {
AlternativeHotelsAvailabilityInput,
AvailabilityInput,
} from "@/types/components/hotelReservation/selectHotel/availabilityInput"
import type { CategorizedFilters } from "@/types/components/hotelReservation/selectHotel/hotelFilters"
import type {
CategorizedFilters,
HotelFilter,
} from "@/types/components/hotelReservation/selectHotel/hotelFilters"
import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel"
import type {
AlternativeHotelsSearchParams,
SelectHotelSearchParams,
} from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
import type { AdditionalData, DetailedFacility, Hotel } from "@/types/hotel"
import type { AdditionalData, Hotel } from "@/types/hotel"
import type { HotelsAvailabilityItem } from "@/types/trpc/routers/hotel/availability"
import type {
HotelLocation,
@@ -253,12 +256,31 @@ export function getFiltersFromHotels(
return defaultFilters
}
const filters = hotels.flatMap(({ hotel }) => hotel.detailedFacilities)
const filters = hotels.flatMap(({ hotel }) =>
hotel.detailedFacilities.map(
(facility) =>
<HotelFilter>{
...facility,
hotelId: hotel.operaId,
hotelIds: [hotel.operaId],
}
)
)
const uniqueFilterIds = [...new Set(filters.map((filter) => filter.id))]
const filterList: DetailedFacility[] = uniqueFilterIds
.map((filterId) => filters.find((filter) => filter.id === filterId))
.filter((filter): filter is DetailedFacility => filter !== undefined)
const filterList: HotelFilter[] = uniqueFilterIds
.map((filterId) => {
const filter = filters.find((f) => f.id === filterId)
// List and include all hotel Ids having same filter / amenity
if (filter) {
filter.hotelIds = filters
.filter((f) => f.id === filterId)
.map((f) => f.hotelId)
}
return filter
})
.filter((filter): filter is HotelFilter => filter !== undefined)
.sort((a, b) => b.sortOrder - a.sortOrder)
return filterList.reduce<CategorizedFilters>((filters, filter) => {