feat(BOOK-463): Fetching hotel filters from CMS and using these inside the destination pages and select hotel page
* feat(BOOK-463): Fetching hotel filters from CMS and using these inside the destination pages * fix(BOOK-698): fetch hotel filters from CMS on select hotel page Approved-by: Bianca Widstam
This commit is contained in:
@@ -1,150 +0,0 @@
|
||||
import { logger } from "@scandic-hotels/common/logger"
|
||||
|
||||
import type { FacilityEnum } from "@scandic-hotels/common/constants/facilities"
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
import type { DestinationFilters } from "../types/destinationsData"
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
// Merges hotel and SEO filters, removing duplicates (by id).
|
||||
// In case of duplicates, the SEO filter takes precedence.
|
||||
function mergeAndDeduplicate(
|
||||
hotelFilters: HotelFilter[],
|
||||
seoFilters:
|
||||
| DestinationFilters["facilityFilters"]
|
||||
| DestinationFilters["surroundingsFilters"]
|
||||
): HotelFilter[] {
|
||||
const map = new Map<FacilityEnum, HotelFilter>()
|
||||
hotelFilters.forEach((filter) => map.set(filter.id, filter))
|
||||
seoFilters.forEach(({ filter }) => map.set(filter.id, filter))
|
||||
return Array.from(map.values())
|
||||
}
|
||||
|
||||
export function mergeHotelFiltersAndSeoFilters(
|
||||
hotelFilters: CategorizedHotelFilters,
|
||||
seoFilters: DestinationFilters
|
||||
): CategorizedHotelFilters {
|
||||
if (!seoFilters) {
|
||||
return hotelFilters
|
||||
}
|
||||
|
||||
return {
|
||||
...hotelFilters,
|
||||
facilityFilters: mergeAndDeduplicate(
|
||||
hotelFilters.facilityFilters,
|
||||
seoFilters.facilityFilters
|
||||
),
|
||||
surroundingsFilters: mergeAndDeduplicate(
|
||||
hotelFilters.surroundingsFilters,
|
||||
seoFilters.surroundingsFilters
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
? {
|
||||
id: filter.id,
|
||||
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) {
|
||||
logger.error(`Could not map ${countryCode} to localized country.`)
|
||||
return null
|
||||
}
|
||||
|
||||
return localizedCountry
|
||||
}
|
||||
43
packages/trpc/lib/utils/mergeHotelFiltersAndSeoFilters.ts
Normal file
43
packages/trpc/lib/utils/mergeHotelFiltersAndSeoFilters.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
// Merges hotel and SEO filters, removing duplicates (by id).
|
||||
|
||||
import type {
|
||||
HotelFilter,
|
||||
HotelFilters,
|
||||
} from "../routers/hotels/filters/output"
|
||||
import type {
|
||||
DestinationFilter,
|
||||
DestinationFilters,
|
||||
} from "../types/destinationsData"
|
||||
|
||||
// In case of duplicates, the SEO filter takes precedence.
|
||||
function mergeAndDeduplicate(
|
||||
hotelFilters: HotelFilter[],
|
||||
seoFilters: DestinationFilter[]
|
||||
): HotelFilters["facilityFilters"] | HotelFilters["surroundingsFilters"] {
|
||||
const map = new Map<string, HotelFilter>()
|
||||
hotelFilters.forEach((filter) => map.set(filter.id, filter))
|
||||
seoFilters.forEach(({ filter }) => map.set(filter.id, filter))
|
||||
return Array.from(map.values())
|
||||
}
|
||||
|
||||
export function mergeHotelFiltersAndSeoFilters(
|
||||
hotelFilters: HotelFilters,
|
||||
seoFilters: DestinationFilters
|
||||
): HotelFilters {
|
||||
if (!seoFilters) {
|
||||
return hotelFilters
|
||||
}
|
||||
|
||||
return {
|
||||
...hotelFilters,
|
||||
facilityFilters: mergeAndDeduplicate(
|
||||
hotelFilters.facilityFilters,
|
||||
seoFilters.facilityFilters
|
||||
),
|
||||
surroundingsFilters: mergeAndDeduplicate(
|
||||
hotelFilters.surroundingsFilters,
|
||||
seoFilters.surroundingsFilters
|
||||
),
|
||||
countryFilters: hotelFilters.countryFilters,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user