Feat/SW-2271 hotel list filtering
* feat(SW-2271): Changes to hotel data types in preperation for filtering * feat(SW-2271): Added filter and sort functionality Approved-by: Matilda Landström
This commit is contained in:
110
packages/trpc/lib/utils/getFiltersFromHotels.ts
Normal file
110
packages/trpc/lib/utils/getFiltersFromHotels.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import type {
|
||||
CategorizedHotelFilters,
|
||||
HotelFilter,
|
||||
HotelListingHotelData,
|
||||
} from "../types/hotel"
|
||||
|
||||
const HOTEL_SURROUNDINGS_FILTER_TYPE_NAMES = [
|
||||
"Hotel surroundings",
|
||||
"Hotel omgivelser",
|
||||
"Hotelumgebung",
|
||||
"Hotellia lähellä",
|
||||
"Hotellomgivelser",
|
||||
"Omgivningar",
|
||||
]
|
||||
|
||||
const HOTEL_FACILITIES_FILTER_TYPE_NAMES = [
|
||||
"Hotel facilities",
|
||||
"Hotellfaciliteter",
|
||||
"Hotelfaciliteter",
|
||||
"Hotel faciliteter",
|
||||
"Hotel-Infos",
|
||||
"Hotellin palvelut",
|
||||
]
|
||||
|
||||
function sortFilters(filters: HotelFilter[]): HotelFilter[] {
|
||||
return [...filters].sort((a, b) => {
|
||||
// First sort by sortOrder
|
||||
const orderDiff = a.sortOrder - b.sortOrder
|
||||
// If sortOrder is the same, sort by name as secondary criterion
|
||||
return orderDiff === 0 ? a.name.localeCompare(b.name) : orderDiff
|
||||
})
|
||||
}
|
||||
|
||||
export function getFiltersFromHotels(
|
||||
hotels: HotelListingHotelData[],
|
||||
lang: Lang
|
||||
): CategorizedHotelFilters {
|
||||
if (hotels.length === 0) {
|
||||
return { facilityFilters: [], surroundingsFilters: [], countryFilters: [] }
|
||||
}
|
||||
|
||||
const uniqueCountries = new Set(
|
||||
hotels.flatMap(({ hotel }) => hotel.countryCode)
|
||||
)
|
||||
const countryFilters = [...uniqueCountries]
|
||||
.map((countryCode) => {
|
||||
const localizedCountry = getLocalizedCountryByCountryCode(
|
||||
countryCode,
|
||||
lang
|
||||
)
|
||||
return localizedCountry
|
||||
? {
|
||||
name: localizedCountry,
|
||||
slug: countryCode.toLowerCase(),
|
||||
filterType: "Country",
|
||||
sortOrder: 0,
|
||||
}
|
||||
: null
|
||||
})
|
||||
.filter((filter): filter is HotelFilter => !!filter)
|
||||
const flattenedFacilityFilters = hotels.flatMap(
|
||||
({ hotel }) => hotel.detailedFacilities
|
||||
)
|
||||
const uniqueFacilityFilterNames = [
|
||||
...new Set(flattenedFacilityFilters.map((filter) => filter.name)),
|
||||
]
|
||||
const facilityFilterList = uniqueFacilityFilterNames
|
||||
.map((filterName) => {
|
||||
const filter = flattenedFacilityFilters.find(
|
||||
(filter) => filter.name === filterName
|
||||
)
|
||||
return filter
|
||||
? {
|
||||
name: filter.name,
|
||||
slug: filter.slug,
|
||||
filterType: filter.filter,
|
||||
sortOrder: filter.sortOrder,
|
||||
}
|
||||
: null
|
||||
})
|
||||
.filter((filter): filter is HotelFilter => !!filter)
|
||||
|
||||
const facilityFilters = facilityFilterList.filter((filter) =>
|
||||
HOTEL_FACILITIES_FILTER_TYPE_NAMES.includes(filter.filterType)
|
||||
)
|
||||
const surroundingsFilters = facilityFilterList.filter((filter) =>
|
||||
HOTEL_SURROUNDINGS_FILTER_TYPE_NAMES.includes(filter.filterType)
|
||||
)
|
||||
return {
|
||||
facilityFilters: sortFilters(facilityFilters),
|
||||
surroundingsFilters: sortFilters(surroundingsFilters),
|
||||
countryFilters: sortFilters(countryFilters),
|
||||
}
|
||||
}
|
||||
|
||||
function getLocalizedCountryByCountryCode(
|
||||
countryCode: string,
|
||||
lang: Lang
|
||||
): string | null {
|
||||
const country = new Intl.DisplayNames([lang], { type: "region" })
|
||||
const localizedCountry = country.of(countryCode)
|
||||
if (!localizedCountry) {
|
||||
console.error(`Could not map ${countryCode} to localized country.`)
|
||||
return null
|
||||
}
|
||||
|
||||
return localizedCountry
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
import { SortOption } from "../enums/destinationFilterAndSort"
|
||||
import { HotelSortOption } from "../types/hotel"
|
||||
|
||||
import type { DestinationCityListItem } from "../types/destinationCityPage"
|
||||
|
||||
const CITY_SORTING_STRATEGIES: Partial<
|
||||
Record<
|
||||
SortOption,
|
||||
HotelSortOption,
|
||||
(a: DestinationCityListItem, b: DestinationCityListItem) => number
|
||||
>
|
||||
> = {
|
||||
[SortOption.Name]: function (a, b) {
|
||||
[HotelSortOption.Name]: function (a, b) {
|
||||
return a.cityName.localeCompare(b.cityName)
|
||||
},
|
||||
[SortOption.Recommended]: function (a, b) {
|
||||
[HotelSortOption.Recommended]: function (a, b) {
|
||||
if (a.sort_order === null && b.sort_order === null) {
|
||||
return a.cityName.localeCompare(b.cityName)
|
||||
}
|
||||
@@ -27,7 +27,7 @@ const CITY_SORTING_STRATEGIES: Partial<
|
||||
|
||||
export function getSortedCities(
|
||||
cities: DestinationCityListItem[],
|
||||
sortOption: SortOption
|
||||
sortOption: HotelSortOption
|
||||
) {
|
||||
const sortFn = CITY_SORTING_STRATEGIES[sortOption]
|
||||
return sortFn ? cities.sort(sortFn) : cities
|
||||
|
||||
Reference in New Issue
Block a user