import { selectRate } from "@scandic-hotels/common/constants/routes/hotelReservation" import { BookingErrorCodeEnum } from "../../enums/bookingErrorCode" import { AvailabilityEnum } from "../../enums/selectHotel" import { sortRoomConfigs } from "../../utils/sortRoomConfigs" import type { BedTypeSelection } from "../../types/bedTypeSelection" import type { Room as RoomCategory } from "../../types/hotel" import type { Product, Products, RateDefinition, RedemptionsProduct, RoomConfiguration, } from "../../types/roomAvailability" import type { RoomsAvailabilityExtendedInputSchema } from "./availability/enterDetails" export const locationsAffix = "locations" export const TWENTYFOUR_HOURS = 60 * 60 * 24 function findProduct(product: Products, rateDefinition: RateDefinition) { if ("corporateCheque" in product) { return product.corporateCheque.rateCode === rateDefinition.rateCode } if (("member" in product && product.member) || "public" in product) { let isMemberRate = false if (product.member) { isMemberRate = product.member.rateCode === rateDefinition.rateCode } let isPublicRate = false if (product.public) { isPublicRate = product.public.rateCode === rateDefinition.rateCode } return isMemberRate || isPublicRate } if ("voucher" in product) { return product.voucher.rateCode === rateDefinition.rateCode } if (Array.isArray(product)) { return product.find( (r) => r.redemption.rateCode === rateDefinition.rateCode ) } } export function getSelectedRoomAvailability( rateCode: string, rateDefinitions: RateDefinition[], roomConfigurations: RoomConfiguration[], roomTypeCode: string, userPoints: number | undefined ) { const rateDefinition = rateDefinitions.find((rd) => rd.rateCode === rateCode) if (!rateDefinition) { return null } const selectedRoom = roomConfigurations.find( (room) => room.roomTypeCode === roomTypeCode && room.products.find((product) => findProduct(product, rateDefinition)) ) if (!selectedRoom) { return null } let product: Product | RedemptionsProduct | undefined = selectedRoom.products.find((product) => findProduct(product, rateDefinition) ) if (!product) { return null } if (Array.isArray(product)) { const redemptionProduct = userPoints ? product.find( (r) => r.redemption.rateCode === rateDefinition.rateCode && r.redemption.localPrice.pointsPerStay <= userPoints ) : undefined if (!redemptionProduct) { return null } product = redemptionProduct } return { rateDefinition, rateDefinitions, rooms: roomConfigurations, product, selectedRoom, } } export function getBedTypes( rooms: RoomConfiguration[], roomType: string, roomCategories?: RoomCategory[] ) { if (!roomCategories) { return [] } return rooms .filter( (room) => room.status === AvailabilityEnum.Available || room.roomsLeft > 0 ) .filter((room) => room.roomType === roomType) .map((availRoom) => { const matchingRoom = roomCategories ?.find((room) => room.roomTypes .map((roomType) => roomType.code) .includes(availRoom.roomTypeCode) ) ?.roomTypes.find((roomType) => roomType.code === availRoom.roomTypeCode) if (matchingRoom) { return { description: matchingRoom.description, size: matchingRoom.mainBed.widthRange, value: matchingRoom.code, type: matchingRoom.mainBed.type, roomsLeft: availRoom.roomsLeft, extraBed: matchingRoom.fixedExtraBed ? { type: matchingRoom.fixedExtraBed.type, description: matchingRoom.fixedExtraBed.description, } : undefined, } } }) .filter((bed): bed is BedTypeSelection => Boolean(bed)) } export function mergeRoomTypes(roomConfigurations: RoomConfiguration[]) { // Initial sort to guarantee if one bed is NotAvailable and whereas // the other is Available to make sure data is added to the correct // roomConfig roomConfigurations.sort(sortRoomConfigs) const roomConfigs = new Map() for (const roomConfig of roomConfigurations) { if (roomConfigs.has(roomConfig.roomType)) { const currentRoomConf = roomConfigs.get(roomConfig.roomType) if (currentRoomConf) { currentRoomConf.features = roomConfig.features.reduce( (feats, feature) => { const currentFeatureIndex = feats.findIndex( (f) => f.code === feature.code ) if (currentFeatureIndex !== -1) { feats[currentFeatureIndex].inventory = feats[currentFeatureIndex].inventory + feature.inventory } else { feats.push(feature) } return feats }, currentRoomConf.features ) currentRoomConf.roomsLeft = currentRoomConf.roomsLeft + roomConfig.roomsLeft roomConfigs.set(currentRoomConf.roomType, currentRoomConf) } } else { roomConfigs.set(roomConfig.roomType, roomConfig) } } return Array.from(roomConfigs.values()) } export function selectRateRedirectURL( input: RoomsAvailabilityExtendedInputSchema, selectedRooms: boolean[] ) { const searchParams = new URLSearchParams({ errorCode: BookingErrorCodeEnum.AvailabilityError, fromdate: input.booking.fromDate, hotel: input.booking.hotelId, todate: input.booking.toDate, }) if (input.booking.searchType) { searchParams.set("searchtype", input.booking.searchType) } for (const [idx, room] of input.booking.rooms.entries()) { searchParams.set(`room[${idx}].adults`, room.adults.toString()) if (selectedRooms[idx]) { if (room.counterRateCode) { searchParams.set(`room[${idx}].counterratecode`, room.counterRateCode) } searchParams.set(`room[${idx}].ratecode`, room.rateCode) searchParams.set(`room[${idx}].roomtype`, room.roomTypeCode) } else { if (!searchParams.has("activeRoomIndex")) { searchParams.set("activeRoomIndex", idx.toString()) } } if (room.bookingCode) { searchParams.set(`room[${idx}].bookingCode`, room.bookingCode) } if (room.packages) { searchParams.set(`room[${idx}].packages`, room.packages.join(",")) } if (room.childrenInRoom?.length) { for (const [i, kid] of room.childrenInRoom.entries()) { searchParams.set(`room[${idx}].child[${i}].age`, kid.age.toString()) searchParams.set(`room[${idx}].child[${i}].bed`, kid.bed.toString()) } } } return `${selectRate(input.lang)}?${searchParams.toString()}` }