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:
@@ -1,6 +0,0 @@
|
||||
export enum SortOption {
|
||||
Recommended = "recommended",
|
||||
Distance = "distance",
|
||||
Name = "name",
|
||||
TripAdvisorRating = "tripadvisor",
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import type {
|
||||
CategorizedFilters,
|
||||
Filter,
|
||||
} from "../../../types/destinationFilterAndSort"
|
||||
import type { DestinationPagesHotelData } 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",
|
||||
]
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { SortOption } from "../../../enums/destinationFilterAndSort"
|
||||
import { ApiCountry } from "../../../types/country"
|
||||
import { HotelSortOption } from "../../../types/hotel"
|
||||
import { getFiltersFromHotels } from "../../../utils/getFiltersFromHotels"
|
||||
import { getSortedCities } from "../../../utils/getSortedCities"
|
||||
import {
|
||||
getCityByCityIdentifier,
|
||||
@@ -8,7 +9,6 @@ import {
|
||||
getHotelsByHotelIds,
|
||||
} from "../../hotels/utils"
|
||||
import { getCityPages } from "../destinationCountryPage/utils"
|
||||
import { getFiltersFromHotels } from "./helpers"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
|
||||
@@ -61,7 +61,7 @@ export async function getCityData(
|
||||
|
||||
let filterType
|
||||
if (filter) {
|
||||
const allFilters = getFiltersFromHotels(hotels)
|
||||
const allFilters = getFiltersFromHotels(hotels, lang)
|
||||
const facilityFilter = allFilters.facilityFilters.find(
|
||||
(f) => f.slug === filter
|
||||
)
|
||||
@@ -101,7 +101,7 @@ export async function getCountryData(
|
||||
let filterType
|
||||
|
||||
const cities = await getCityPages(lang, serviceToken, country)
|
||||
const sortedCities = getSortedCities(cities, SortOption.Recommended)
|
||||
const sortedCities = getSortedCities(cities, HotelSortOption.Recommended)
|
||||
const hotelIds = await getHotelIdsByCountry({
|
||||
country,
|
||||
serviceToken,
|
||||
@@ -110,7 +110,7 @@ export async function getCountryData(
|
||||
const hotels = await getHotelsByHotelIds({ hotelIds, lang, serviceToken })
|
||||
|
||||
if (filter) {
|
||||
const allFilters = getFiltersFromHotels(hotels)
|
||||
const allFilters = getFiltersFromHotels(hotels, lang)
|
||||
const facilityFilter = allFilters.facilityFilters.find(
|
||||
(f) => f.slug === filter
|
||||
)
|
||||
|
||||
@@ -239,9 +239,13 @@ export const getHotelsByCSFilterInput = z.object({
|
||||
})
|
||||
.nullish(),
|
||||
hotelsToInclude: z.array(z.string()),
|
||||
contentType: z
|
||||
.enum(["hotel", "restaurant", "meeting"])
|
||||
.optional()
|
||||
.default("hotel"),
|
||||
})
|
||||
export interface GetHotelsByCSFilterInput
|
||||
extends z.infer<typeof getHotelsByCSFilterInput> {}
|
||||
extends z.input<typeof getHotelsByCSFilterInput> {}
|
||||
|
||||
export const nearbyHotelIdsInput = z.object({
|
||||
hotelId: z.string(),
|
||||
|
||||
@@ -616,40 +616,24 @@ export const roomFeaturesSchema = z
|
||||
return data.data.attributes.roomFeatures
|
||||
})
|
||||
|
||||
export const destinationPagesHotelDataSchema = z
|
||||
.object({
|
||||
data: z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
location: locationSchema,
|
||||
cityIdentifier: z.string().optional(),
|
||||
tripadvisor: z.number().optional(),
|
||||
detailedFacilities: detailedFacilitiesSchema,
|
||||
galleryImages: z
|
||||
.array(imageSchema)
|
||||
.nullish()
|
||||
.transform((arr) => (arr ? arr.filter(Boolean) : [])),
|
||||
address: addressSchema,
|
||||
hotelType: z.string(),
|
||||
type: z.literal("hotels"), // No enum here but the standard return appears to be "hotels".
|
||||
url: z.string().optional(),
|
||||
hotelContent: z
|
||||
.object({
|
||||
texts: z.object({
|
||||
descriptions: z.object({
|
||||
short: z.string().optional(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
})
|
||||
.transform(({ data: { hotelContent, ...data } }) => {
|
||||
return {
|
||||
hotel: {
|
||||
...data,
|
||||
hotelDescription: hotelContent?.texts.descriptions?.short,
|
||||
},
|
||||
url: data.url ?? "",
|
||||
}
|
||||
})
|
||||
export const hotelListingHotelDataSchema = z.object({
|
||||
hotel: z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
countryCode: z.string(),
|
||||
location: locationSchema,
|
||||
cityIdentifier: z.string().nullable(),
|
||||
tripadvisor: z.number().nullable(),
|
||||
detailedFacilities: detailedFacilitiesSchema,
|
||||
galleryImages: z
|
||||
.array(imageSchema)
|
||||
.nullish()
|
||||
.transform((arr) => (arr ? arr.filter(Boolean) : [])),
|
||||
address: addressSchema,
|
||||
hotelType: z.string(),
|
||||
type: z.literal("hotels"), // No enum here but the standard return appears to be "hotels".
|
||||
description: z.string().nullable(),
|
||||
}),
|
||||
url: z.string().nullable(),
|
||||
meetingUrl: z.string().nullable(),
|
||||
})
|
||||
|
||||
@@ -53,19 +53,17 @@ import { getVerifiedUser } from "../user/utils"
|
||||
import { additionalDataSchema } from "./schemas/hotel/include/additionalData"
|
||||
import { meetingRoomsSchema } from "./schemas/meetingRoom"
|
||||
import {
|
||||
getBedTypes,
|
||||
getCitiesByCountry,
|
||||
getCountries,
|
||||
getHotel,
|
||||
getHotelIdsByCityId,
|
||||
getHotelIdsByCityIdentifier,
|
||||
getHotelIdsByCountry,
|
||||
getHotelsByHotelIds,
|
||||
getLocations,
|
||||
} from "./utils"
|
||||
import {
|
||||
getBedTypes,
|
||||
getHotelsAvailabilityByCity,
|
||||
getHotelsAvailabilityByHotelIds,
|
||||
getHotelsByHotelIds,
|
||||
getLocations,
|
||||
getPackages,
|
||||
getRoomsAvailability,
|
||||
getSelectedRoomAvailability,
|
||||
@@ -73,10 +71,7 @@ import {
|
||||
selectRateRedirectURL,
|
||||
} from "./utils"
|
||||
|
||||
import type {
|
||||
DestinationPagesHotelData,
|
||||
HotelDataWithUrl,
|
||||
} from "../../types/hotel"
|
||||
import type { HotelListingHotelData } from "../../types/hotel"
|
||||
import type { CityLocation } from "../../types/locations"
|
||||
import type { Room } from "../../types/room"
|
||||
|
||||
@@ -570,7 +565,7 @@ export const hotelQueryRouter = router({
|
||||
get: contentStackBaseWithServiceProcedure
|
||||
.input(getHotelsByCSFilterInput)
|
||||
.query(async function ({ ctx, input }) {
|
||||
const { locationFilter, hotelsToInclude } = input
|
||||
const { locationFilter, hotelsToInclude, contentType } = input
|
||||
|
||||
const language = ctx.lang
|
||||
let hotelsToFetch: string[] = []
|
||||
@@ -669,29 +664,16 @@ export const hotelQueryRouter = router({
|
||||
|
||||
return []
|
||||
}
|
||||
const hotelPages = await getHotelPageUrls(language)
|
||||
const hotels = await Promise.all(
|
||||
hotelsToFetch.map(async (hotelId) => {
|
||||
const hotelData = await getHotel(
|
||||
{ hotelId, isCardOnlyPayment: false, language },
|
||||
ctx.serviceToken
|
||||
)
|
||||
const hotelPage = hotelPages.find(
|
||||
(page) => page.hotelId === hotelId
|
||||
)
|
||||
|
||||
return hotelData
|
||||
? {
|
||||
...hotelData,
|
||||
url: hotelPage?.url ?? null,
|
||||
}
|
||||
: null
|
||||
})
|
||||
)
|
||||
const hotels = await getHotelsByHotelIds({
|
||||
hotelIds: hotelsToFetch,
|
||||
lang: language,
|
||||
serviceToken: ctx.serviceToken,
|
||||
contentType,
|
||||
})
|
||||
|
||||
metricsGetHotelsByCSFilter.success()
|
||||
|
||||
return hotels.filter((hotel): hotel is HotelDataWithUrl => !!hotel)
|
||||
return hotels
|
||||
}),
|
||||
}),
|
||||
getDestinationsMapData: serviceProcedure
|
||||
@@ -713,7 +695,7 @@ export const hotelQueryRouter = router({
|
||||
}
|
||||
|
||||
const countryNames = countries.data.map((country) => country.name)
|
||||
const hotelData: DestinationPagesHotelData[] = (
|
||||
const hotelData: HotelListingHotelData[] = (
|
||||
await Promise.all(
|
||||
countryNames.map(async (country) => {
|
||||
const hotelIds = await getHotelIdsByCountry({
|
||||
|
||||
@@ -48,8 +48,11 @@ import type {
|
||||
RoomsAvailabilityOutputSchema,
|
||||
} from "../../types/availability"
|
||||
import type { BedTypeSelection } from "../../types/bedTypeSelection"
|
||||
import type { Room as RoomCategory } from "../../types/hotel"
|
||||
import type { DestinationPagesHotelData, HotelInput } from "../../types/hotel"
|
||||
import type {
|
||||
HotelInput,
|
||||
HotelListingHotelData,
|
||||
Room as RoomCategory,
|
||||
} from "../../types/hotel"
|
||||
import type {
|
||||
CitiesGroupedByCountry,
|
||||
CityLocation,
|
||||
@@ -348,13 +351,15 @@ export async function getHotelsByHotelIds({
|
||||
hotelIds,
|
||||
lang,
|
||||
serviceToken,
|
||||
contentType = "hotel",
|
||||
}: {
|
||||
hotelIds: string[]
|
||||
lang: Lang
|
||||
serviceToken: string
|
||||
contentType?: "hotel" | "restaurant" | "meeting"
|
||||
}) {
|
||||
const cacheClient = await getCacheClient()
|
||||
const cacheKey = `${lang}:getHotelsByHotelIds:hotels:${hotelIds.sort().join(",")}`
|
||||
const cacheKey = `${lang}:getHotelsByHotelIds:hotels:${contentType}:${hotelIds.sort().join(",")}`
|
||||
|
||||
return await cacheClient.cacheOrGet(
|
||||
cacheKey,
|
||||
@@ -362,7 +367,7 @@ export async function getHotelsByHotelIds({
|
||||
const hotelPages = await getHotelPageUrls(lang)
|
||||
const chunkedHotelIds = chunk(hotelIds, 10)
|
||||
|
||||
const hotels: DestinationPagesHotelData[] = []
|
||||
const hotels: HotelListingHotelData[] = []
|
||||
for (const hotelIdChunk of chunkedHotelIds) {
|
||||
const chunkedHotels = await Promise.all(
|
||||
hotelIdChunk.map(async (hotelId) => {
|
||||
@@ -378,22 +383,59 @@ export async function getHotelsByHotelIds({
|
||||
const hotelPage = hotelPages.find(
|
||||
(page) => page.hotelId === hotelId
|
||||
)
|
||||
const { hotel, cities } = hotelResponse
|
||||
const data: DestinationPagesHotelData = {
|
||||
const { hotel, cities, additionalData } = hotelResponse
|
||||
|
||||
const content = {
|
||||
description: hotel.hotelContent?.texts.descriptions?.short,
|
||||
galleryImages: hotel.galleryImages,
|
||||
url: hotelPage?.url ?? "",
|
||||
openInNewTab: false,
|
||||
}
|
||||
|
||||
if (contentType === "restaurant") {
|
||||
const restaurantDescription =
|
||||
additionalData?.restaurantsOverviewPage
|
||||
.restaurantsContentDescriptionShort
|
||||
const restaurantImages =
|
||||
additionalData.restaurantImages?.heroImages
|
||||
if (restaurantDescription) {
|
||||
content.description = restaurantDescription
|
||||
}
|
||||
if (restaurantImages && restaurantImages.length > 0) {
|
||||
content.galleryImages = restaurantImages
|
||||
}
|
||||
} else if (contentType === "meeting") {
|
||||
const meetingDescription =
|
||||
hotel.hotelContent.texts.meetingDescription?.short
|
||||
const meetingImages =
|
||||
additionalData?.conferencesAndMeetings?.heroImages
|
||||
if (meetingDescription) {
|
||||
content.description = meetingDescription
|
||||
}
|
||||
if (meetingImages && meetingImages.length > 0) {
|
||||
content.galleryImages = meetingImages
|
||||
}
|
||||
}
|
||||
|
||||
const data: HotelListingHotelData = {
|
||||
hotel: {
|
||||
id: hotel.id,
|
||||
galleryImages: hotel.galleryImages,
|
||||
countryCode: hotel.countryCode,
|
||||
galleryImages: content.galleryImages,
|
||||
name: hotel.name,
|
||||
tripadvisor: hotel.ratings?.tripAdvisor?.rating,
|
||||
detailedFacilities: hotel.detailedFacilities || [],
|
||||
tripadvisor: hotel.ratings?.tripAdvisor?.rating || null,
|
||||
detailedFacilities: hotel.detailedFacilities.sort(
|
||||
(a, b) => b.sortOrder - a.sortOrder
|
||||
),
|
||||
location: hotel.location,
|
||||
hotelType: hotel.hotelType,
|
||||
type: hotel.type,
|
||||
address: hotel.address,
|
||||
cityIdentifier: cities?.[0]?.cityIdentifier,
|
||||
hotelDescription: hotel.hotelContent?.texts.descriptions?.short,
|
||||
cityIdentifier: cities[0]?.cityIdentifier || null,
|
||||
description: content.description || null,
|
||||
},
|
||||
url: hotelPage?.url ?? "",
|
||||
url: content.url,
|
||||
meetingUrl: additionalData.meetingRooms.meetingOnlineLink || null,
|
||||
}
|
||||
|
||||
return data
|
||||
@@ -402,9 +444,7 @@ export async function getHotelsByHotelIds({
|
||||
|
||||
hotels.push(...chunkedHotels)
|
||||
}
|
||||
return hotels.filter(
|
||||
(hotel): hotel is DestinationPagesHotelData => !!hotel
|
||||
)
|
||||
return hotels.filter((hotel): hotel is HotelListingHotelData => !!hotel)
|
||||
},
|
||||
"1d"
|
||||
)
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
export interface Filter {
|
||||
name: string
|
||||
slug: string
|
||||
filterType: string
|
||||
sortOrder: number
|
||||
}
|
||||
|
||||
export interface CategorizedFilters {
|
||||
facilityFilters: Filter[]
|
||||
surroundingsFilters: Filter[]
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import type {
|
||||
hotelInputSchema,
|
||||
} from "../routers/hotels/input"
|
||||
import type {
|
||||
destinationPagesHotelDataSchema,
|
||||
hotelListingHotelDataSchema,
|
||||
hotelSchema,
|
||||
} from "../routers/hotels/output"
|
||||
import type { citySchema } from "../routers/hotels/schemas/city"
|
||||
@@ -79,11 +79,35 @@ export type ExtraPageSchema = z.output<typeof extraPageSchema>
|
||||
|
||||
export type HotelDataWithUrl = HotelData & { url: string }
|
||||
|
||||
export type DestinationPagesHotelData = z.output<
|
||||
typeof destinationPagesHotelDataSchema
|
||||
>
|
||||
export type HotelListingHotelData = z.output<typeof hotelListingHotelDataSchema>
|
||||
|
||||
export type CityCoordinatesInput = z.input<typeof cityCoordinatesInputSchema>
|
||||
export type HotelInput = z.input<typeof hotelInputSchema>
|
||||
|
||||
export type RoomType = Pick<Room, "roomTypes" | "name">
|
||||
|
||||
export interface HotelFilter {
|
||||
name: string
|
||||
slug: string
|
||||
filterType: string
|
||||
sortOrder: number
|
||||
}
|
||||
|
||||
export interface CategorizedHotelFilters {
|
||||
facilityFilters: HotelFilter[]
|
||||
surroundingsFilters: HotelFilter[]
|
||||
countryFilters: HotelFilter[]
|
||||
}
|
||||
|
||||
export enum HotelSortOption {
|
||||
Recommended = "recommended",
|
||||
Distance = "distance",
|
||||
Name = "name",
|
||||
TripAdvisorRating = "tripadvisor",
|
||||
}
|
||||
|
||||
export interface HotelSortItem {
|
||||
label: string
|
||||
value: HotelSortOption
|
||||
isDefault?: boolean
|
||||
}
|
||||
|
||||
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