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:
Erik Tiekstra
2026-01-12 12:02:25 +00:00
parent b2ca2c2612
commit 0c6a4cf186
40 changed files with 732 additions and 399 deletions

View File

@@ -12,7 +12,10 @@ import FilterCheckbox from "./FilterCheckbox"
import styles from "./filterContent.module.css"
import type { CategorizedHotelFilters, HotelFilter } from "../../../../types"
import type {
CategorizedHotelFilters,
SelectHotelFilter,
} from "../../../../types"
interface FilterContentProps {
filters: CategorizedHotelFilters
@@ -75,7 +78,7 @@ export default function FilterContent({
return null
}
function filterOutput(filters: HotelFilter[]) {
function filterOutput(filters: SelectHotelFilter[]) {
return filters.map((filter) => {
const relevantIds = showOnlyBookingCodeRates
? filter.bookingCodeFilteredIds

View File

@@ -1,5 +1,6 @@
import { dt } from "@scandic-hotels/common/dt"
import { AvailabilityEnum } from "@scandic-hotels/trpc/enums/selectHotel"
import { getHotelFilters } from "@scandic-hotels/trpc/routers/hotels/filters/utils"
import { generateChildrenString } from "@scandic-hotels/trpc/routers/hotels/helpers"
import { serverClient } from "../../trpc"
@@ -18,7 +19,7 @@ import type {
Location,
} from "@scandic-hotels/trpc/types/locations"
import type { CategorizedHotelFilters, HotelFilter } from "../../types"
import type { CategorizedHotelFilters, SelectHotelFilter } from "../../types"
type AvailabilityInput = {
cityId: string
@@ -273,50 +274,38 @@ export async function getHotels({
return hotels
}
const hotelSurroundingsFilterNames = [
"Hotel surroundings",
"Hotel omgivelser",
"Hotelumgebung",
"Hotellia lähellä",
"Hotellomgivelser",
"Omgivningar",
]
const hotelFacilitiesFilterNames = [
"Hotel facilities",
"Hotellfaciliteter",
"Hotelfaciliteter",
"Hotel faciliteter",
"Hotel-Infos",
"Hotellin palvelut",
]
export function getFiltersFromHotels(
export async function fetchHotelFiltersAndMapToCategorizedFilters(
hotels: HotelResponse[],
showBookingCodeFilter: boolean
): CategorizedHotelFilters {
showBookingCodeFilter: boolean,
lang: Lang
): Promise<CategorizedHotelFilters> {
const defaultFilters = { facilityFilters: [], surroundingsFilters: [] }
if (!hotels.length) {
return defaultFilters
}
const { countryFilters, ...hotelFilters } = await getHotelFilters(lang)
const allFlattenedFilters = Object.values(hotelFilters).flat()
const filters = hotels.flatMap(({ hotel, availability }) => {
const hotelFilterData = allFlattenedFilters.map((filter) => {
const hotelHasFilter = hotel.detailedFacilities.some(
(facility) => facility.id.toString() === filter.id
)
return {
...filter,
hotelId: hotelHasFilter ? hotel.operaId : null,
hotelIds: hotelHasFilter ? [hotel.operaId] : [],
bookingCodeFilteredIds:
(availability.bookingCode || !showBookingCodeFilter) && hotelHasFilter
? [hotel.operaId]
: [],
}
})
const filters = hotels.flatMap(({ hotel, availability }) =>
hotel.detailedFacilities.map(
(facility) =>
<HotelFilter>{
...facility,
hotelId: hotel.operaId,
hotelIds: [hotel.operaId],
bookingCodeFilteredIds:
availability.bookingCode || !showBookingCodeFilter
? [hotel.operaId]
: [],
}
)
)
return hotelFilterData
})
const uniqueFilterIds = [...new Set(filters.map((filter) => filter.id))]
const filterList: HotelFilter[] = uniqueFilterIds
const filterList: SelectHotelFilter[] = uniqueFilterIds
.map((filterId) => {
const filter = filters.find((f) => f.id === filterId)
@@ -324,7 +313,9 @@ export function getFiltersFromHotels(
if (filter) {
const matchingFilters = filters.filter((f) => f.id === filterId)
filter.hotelIds = matchingFilters.map((f) => f.hotelId)
filter.hotelIds = matchingFilters
.map((f) => f.hotelId)
.filter((id) => id !== null)
filter.bookingCodeFilteredIds = [
...new Set(
matchingFilters.flatMap((f) => f.bookingCodeFilteredIds ?? [])
@@ -333,18 +324,17 @@ export function getFiltersFromHotels(
}
return filter
})
.filter((filter): filter is HotelFilter => filter !== undefined)
.filter((filter): filter is SelectHotelFilter => filter !== undefined)
.sort((a, b) => b.sortOrder - a.sortOrder)
return filterList.reduce<CategorizedHotelFilters>((filters, filter) => {
if (filter.filter && hotelSurroundingsFilterNames.includes(filter.filter)) {
filters.surroundingsFilters.push(filter)
}
if (filter.filter && hotelFacilitiesFilterNames.includes(filter.filter)) {
filters.facilityFilters.push(filter)
}
return filters
}, defaultFilters)
const facilityFilters = filterList.filter(
(filter) => filter.filterType === "facility"
)
const surroundingsFilters = filterList.filter(
(filter) => filter.filterType === "surroundings"
)
return {
facilityFilters,
surroundingsFilters,
}
}

View File

@@ -9,7 +9,10 @@ import BookingCodeFilter from "../BookingCodeFilter"
import HotelCardListing from "../HotelCardListing"
import { StaticMap } from "../StaticMap"
import HotelFilter from "./Filters/HotelFilter"
import { getFiltersFromHotels, type HotelResponse } from "./helpers"
import {
fetchHotelFiltersAndMapToCategorizedFilters,
type HotelResponse,
} from "./helpers"
import HotelCount from "./HotelCount"
import HotelSorter from "./HotelSorter"
import { MapWithButtonWrapper } from "./MapWithButtonWrapper"
@@ -35,7 +38,7 @@ interface SelectHotelProps {
topSlot?: ReactNode
}
export function SelectHotel({
export async function SelectHotel({
bookingCode,
city,
hotels,
@@ -61,7 +64,11 @@ export function SelectHotel({
const showBookingCodeFilter = isBookingCodeRateAvailable && !isSpecialRate
const filterList = getFiltersFromHotels(hotels, showBookingCodeFilter)
const filterList = await fetchHotelFiltersAndMapToCategorizedFilters(
hotels,
showBookingCodeFilter,
lang
)
return (
<>