import type { CategorizedFilters, Filter, SortItem, } from "@/types/components/destinationFilterAndSort" import { SortOption } from "@/types/enums/destinationFilterAndSort" import type { DestinationPagesHotelData } from "@/types/hotel" import type { DestinationCityListItem } from "@/types/trpc/routers/contentstack/destinationCityPage" const HOTEL_SORTING_STRATEGIES: Partial< Record< SortOption, (a: DestinationPagesHotelData, b: DestinationPagesHotelData) => number > > = { [SortOption.Name]: function (a, b) { return a.hotel.name.localeCompare(b.hotel.name) }, [SortOption.TripAdvisorRating]: function (a, b) { return (b.hotel.tripadvisor ?? 0) - (a.hotel.tripadvisor ?? 0) }, [SortOption.Distance]: function (a, b) { return a.hotel.location.distanceToCentre - b.hotel.location.distanceToCentre }, } const CITY_SORTING_STRATEGIES: Partial< Record< SortOption, (a: DestinationCityListItem, b: DestinationCityListItem) => number > > = { [SortOption.Name]: function (a, b) { return a.cityName.localeCompare(b.cityName) }, [SortOption.Recommended]: function (a, b) { if (a.sort_order === null && b.sort_order === null) { return a.cityName.localeCompare(b.cityName) } if (a.sort_order === null) { return 1 } if (b.sort_order === null) { return -1 } return b.sort_order - a.sort_order }, } function sortFilters(filters: Filter[]): Filter[] { 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 getFilteredHotels( hotels: DestinationPagesHotelData[], filters: string[] ) { if (filters.length) { return hotels.filter(({ hotel }) => filters.every((filter) => hotel.detailedFacilities.some((facility) => facility.slug === filter) ) ) } return hotels } export function getFilteredCities( filteredHotels: DestinationPagesHotelData[], 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 getSortedCities( cities: DestinationCityListItem[], sortOption: SortOption ) { const sortFn = CITY_SORTING_STRATEGIES[sortOption] return sortFn ? cities.sort(sortFn) : cities } export function getSortedHotels( hotels: DestinationPagesHotelData[], sortOption: SortOption ) { const sortFn = HOTEL_SORTING_STRATEGIES[sortOption] return sortFn ? hotels.sort(sortFn) : hotels } export function isValidSortOption( value: string, sortItems: SortItem[] ): value is SortOption { return sortItems.map((item) => item.value).includes(value as SortOption) } 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", ] export function getFiltersFromHotels( hotels: DestinationPagesHotelData[] ): CategorizedFilters { if (hotels.length === 0) { return { facilityFilters: [], surroundingsFilters: [] } } const filters = hotels.flatMap(({ hotel }) => hotel.detailedFacilities) const uniqueFilterNames = [...new Set(filters.map((filter) => filter.name))] const filterList = uniqueFilterNames .map((filterName) => { const filter = filters.find((filter) => filter.name === filterName) return filter ? { name: filter.name, slug: filter.slug, filterType: filter.filter, sortOrder: filter.sortOrder, } : null }) .filter((filter): filter is Filter => !!filter) const facilityFilters = filterList.filter((filter) => HOTEL_FACILITIES_FILTER_TYPE_NAMES.includes(filter.filterType) ) const surroundingsFilters = filterList.filter((filter) => HOTEL_SURROUNDINGS_FILTER_TYPE_NAMES.includes(filter.filterType) ) return { facilityFilters: sortFilters(facilityFilters), surroundingsFilters: sortFilters(surroundingsFilters), } } export function getBasePathNameWithoutFilters( pathname: string, filterSlugs: string[] ) { const pathSegments = pathname.split("/") const filteredSegments = pathSegments.filter( (segment) => !filterSlugs.includes(segment) ) return filteredSegments.join("/") }