import { type HotelListingHotelData, type HotelSortItem, HotelSortOption, } from "@scandic-hotels/trpc/types/hotel" import type { HotelFilter, HotelFilters, } from "@scandic-hotels/trpc/routers/hotels/filters/output" import type { DestinationCityListItem } from "@scandic-hotels/trpc/types/destinationCityPage" import type { DestinationFilter } from "@scandic-hotels/trpc/types/destinationsData" const HOTEL_SORTING_STRATEGIES: Partial< Record< HotelSortOption, (a: HotelListingHotelData, b: HotelListingHotelData) => number > > = { [HotelSortOption.Name]: function (a, b) { return a.hotel.name.localeCompare(b.hotel.name) }, [HotelSortOption.TripAdvisorRating]: function (a, b) { return (b.hotel.tripadvisor ?? 0) - (a.hotel.tripadvisor ?? 0) }, [HotelSortOption.Distance]: function (a, b) { return a.hotel.location.distanceToCentre - b.hotel.location.distanceToCentre }, } export function getFilteredHotels( hotels: HotelListingHotelData[], filters: HotelFilter[] ) { if (filters.length) { return hotels.filter(({ hotel }) => filters.every((filter) => hotel.detailedFacilities.some( (facility) => facility.id === Number(filter.id) ) ) ) } return hotels } export function getFilteredCities( filteredHotels: HotelListingHotelData[], cities: DestinationCityListItem[] ) { const filteredCityIdentifiers = filteredHotels.map( (hotel) => hotel.hotel.cityIdentifier ) return cities.filter( (city) => city.destination_settings.city && filteredCityIdentifiers.includes(city.destination_settings.city) ) } export function getSortedHotels( hotels: HotelListingHotelData[], sortOption: HotelSortOption ) { const sortFn = HOTEL_SORTING_STRATEGIES[sortOption] return sortFn ? [...hotels].sort(sortFn) : hotels } export function isValidSortOption( value: string, sortItems: HotelSortItem[] ): value is HotelSortOption { return sortItems.map((item) => item.value).includes(value as HotelSortOption) } export function getBasePathNameWithoutFilters( pathname: string, filterSlugs: string[] ) { if (!filterSlugs.length) { return pathname } const lastSlashIndex = pathname.lastIndexOf("/") const lastSegment = pathname.slice(lastSlashIndex + 1) if (filterSlugs.includes(lastSegment)) { return pathname.slice(0, lastSlashIndex) || "/" } return pathname } export function getActiveDestinationFilter( filterFromUrl: HotelFilter | null, allSeoFilters: DestinationFilter[] ) { if (!filterFromUrl) { return null } return allSeoFilters.find((f) => f.filter.id === filterFromUrl.id) || null } export function getFiltersWithHotelAndCityCount( hotelFilters: HotelFilters, hotels: HotelListingHotelData[], cities: DestinationCityListItem[] ): HotelFilters { const flattenedFilters = Object.values(hotelFilters).flat() const filterHotelCounts: Record = {} const filterCityIdentifiers: Record> = {} hotels.forEach(({ hotel }) => { hotel.detailedFacilities.forEach((facility) => { filterHotelCounts[facility.id] = (filterHotelCounts[facility.id] || 0) + 1 if (!filterCityIdentifiers[facility.id]) { filterCityIdentifiers[facility.id] = new Set() } if (hotel.cityIdentifier) { filterCityIdentifiers[facility.id].add(hotel.cityIdentifier) } }) if (hotel.countryCode) { filterHotelCounts[hotel.countryCode] = (filterHotelCounts[hotel.countryCode] || 0) + 1 if (!filterCityIdentifiers[hotel.countryCode]) { filterCityIdentifiers[hotel.countryCode] = new Set() } if (hotel.cityIdentifier) { filterCityIdentifiers[hotel.countryCode].add(hotel.cityIdentifier) } } }) // Count cities that match the cityIdentifiers for each filter const filterCityCounts: Record = {} Object.entries(filterCityIdentifiers).forEach( ([filterId, cityIdentifiers]) => { filterCityCounts[filterId] = cities.filter( (city) => city.destination_settings.city && cityIdentifiers.has(city.destination_settings.city) ).length } ) return flattenedFilters.reduce( (acc, filter) => { if (filter.filterType === "facility") { acc.facilityFilters.push({ ...filter, hotelCount: filterHotelCounts[filter.id] ?? 0, cityCount: filterCityCounts[filter.id] ?? 0, }) } else if (filter.filterType === "surroundings") { acc.surroundingsFilters.push({ ...filter, hotelCount: filterHotelCounts[filter.id] ?? 0, cityCount: filterCityCounts[filter.id] ?? 0, }) } else if (filter.filterType === "country") { acc.countryFilters.push({ ...filter, filterType: "country", hotelCount: filterHotelCounts[filter.id] ?? 0, cityCount: filterCityCounts[filter.id] ?? 0, }) } return acc }, { facilityFilters: [], surroundingsFilters: [], countryFilters: [], } as HotelFilters ) }