Feat/LOY-430 reward nights * chore(LOY-430): add reward nights request and dynamic content * chore(LOY-430): fix Reward Night component * Refactor: use existing endpoint and add rewardNight data to that response instead Approved-by: Linus Flood
114 lines
3.9 KiB
TypeScript
114 lines
3.9 KiB
TypeScript
import { getCacheClient } from "@scandic-hotels/common/dataCache"
|
|
import { chunk } from "@scandic-hotels/common/utils/chunk"
|
|
|
|
import { getHotelPageUrls } from "../../contentstack/hotelPage/utils"
|
|
import { getHotel } from "./getHotel"
|
|
|
|
import type { Lang } from "@scandic-hotels/common/constants/language"
|
|
|
|
import type { HotelListingHotelData } from "../../../types/hotel"
|
|
|
|
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:${contentType}:${[...hotelIds].sort().join(",")}`
|
|
|
|
return await cacheClient.cacheOrGet(
|
|
cacheKey,
|
|
async () => {
|
|
const hotelPages = await getHotelPageUrls(lang)
|
|
const chunkedHotelIds = chunk(hotelIds, 10)
|
|
|
|
const hotels: HotelListingHotelData[] = []
|
|
for (const hotelIdChunk of chunkedHotelIds) {
|
|
const chunkedHotels = await Promise.all(
|
|
hotelIdChunk.map(async (hotelId) => {
|
|
const hotelResponse = await getHotel(
|
|
{ hotelId, language: lang, isCardOnlyPayment: false },
|
|
serviceToken
|
|
)
|
|
|
|
if (!hotelResponse) {
|
|
throw new Error(`Hotel not found: ${hotelId}`)
|
|
}
|
|
|
|
const hotelPage = hotelPages.find(
|
|
(page) => page.hotelId === hotelId
|
|
)
|
|
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,
|
|
countryCode: hotel.countryCode,
|
|
galleryImages: content.galleryImages,
|
|
name: hotel.name,
|
|
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 || null,
|
|
description: content.description || null,
|
|
rewardNight: hotel.rewardNight,
|
|
},
|
|
url: content.url,
|
|
meetingUrl: additionalData.meetingRooms.meetingOnlineLink || null,
|
|
}
|
|
|
|
return data
|
|
})
|
|
)
|
|
|
|
hotels.push(...chunkedHotels)
|
|
}
|
|
return hotels.filter((hotel): hotel is HotelListingHotelData => !!hotel)
|
|
},
|
|
"1d"
|
|
)
|
|
}
|