import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel" import { RoomPackageCodeEnum, type RoomPackages, } from "@/types/components/hotelReservation/selectRate/roomFilter" import type { Rate, RateCode, } from "@/types/components/hotelReservation/selectRate/selectRate" import type { RoomConfiguration } from "@/types/trpc/routers/hotel/roomAvailability" interface CalculateRoomSummaryParams { availablePackages: RoomPackages getFilteredRooms: (roomIndex: number) => RoomConfiguration[] roomCategories: Array<{ name: string; roomTypes: Array<{ code: string }> }> selectedPackagesByRoom: Record selectedRate: RateCode roomIndex: number } export function calculateRoomSummary({ selectedRate, roomIndex, getFilteredRooms, availablePackages, roomCategories, selectedPackagesByRoom, }: CalculateRoomSummaryParams): Rate | null { const filteredRooms = getFilteredRooms(roomIndex) const selectedPackages = selectedPackagesByRoom[roomIndex] || [] const room = filteredRooms.find( (room) => room.roomTypeCode === selectedRate.roomTypeCode ) if (!room) return null const product = room.products.find( (product) => product.productType.public.rateCode === selectedRate.publicRateCode ) if (!product) return null const petRoomPackage = selectedPackages.includes(RoomPackageCodeEnum.PET_ROOM) ? availablePackages.find((pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM) : undefined const features = filteredRooms.find((room) => room.features.some( (feature) => feature.code === RoomPackageCodeEnum.PET_ROOM ) )?.features const roomType = roomCategories.find((roomCategory) => roomCategory.roomTypes.some((type) => type.code === room.roomTypeCode) ) return { features: petRoomPackage && features ? features : [], priceName: selectedRate.name, priceTerm: selectedRate.paymentTerm, public: product.productType.public, member: product.productType.member, roomType: roomType?.name ?? room.roomType, roomTypeCode: room.roomTypeCode, } } /** * Get the lowest priced room for each room type that appears more than once. */ export function filterDuplicateRoomTypesByLowestPrice( roomConfigurations: RoomConfiguration[] ): RoomConfiguration[] { const roomTypeCount = roomConfigurations.reduce>( (roomTypeTally, currentRoom) => { const currentRoomType = currentRoom.roomType const currentCount = roomTypeTally[currentRoomType] || 0 return { ...roomTypeTally, [currentRoomType]: currentCount + 1, } }, {} ) const duplicateRoomTypes = new Set( Object.keys(roomTypeCount).filter((roomType) => roomTypeCount[roomType] > 1) ) const roomMap = new Map() roomConfigurations.forEach((room) => { const { roomType, products, status } = room if (!duplicateRoomTypes.has(roomType)) { roomMap.set(roomType, room) return } const previousRoom = roomMap.get(roomType) // Prioritize 'Available' status if ( status === AvailabilityEnum.Available && previousRoom?.status === AvailabilityEnum.NotAvailable ) { roomMap.set(roomType, room) return } if ( status === AvailabilityEnum.NotAvailable && previousRoom?.status === AvailabilityEnum.Available ) { return } if (previousRoom) { products.forEach((product) => { const { productType } = product const publicProduct = productType.public || { requestedPrice: null, localPrice: null, } const memberProduct = productType.member || { requestedPrice: null, localPrice: null, } const { requestedPrice: publicRequestedPrice, localPrice: publicLocalPrice, } = publicProduct const { requestedPrice: memberRequestedPrice, localPrice: memberLocalPrice, } = memberProduct const previousLowest = roomMap.get(roomType) const currentRequestedPrice = Math.min( Number(publicRequestedPrice?.pricePerNight) ?? Infinity, Number(memberRequestedPrice?.pricePerNight) ?? Infinity ) const currentLocalPrice = Math.min( Number(publicLocalPrice?.pricePerNight) ?? Infinity, Number(memberLocalPrice?.pricePerNight) ?? Infinity ) if ( !previousLowest || currentRequestedPrice < Math.min( Number( previousLowest.products[0].productType.public.requestedPrice ?.pricePerNight ) ?? Infinity, Number( previousLowest.products[0].productType.member?.requestedPrice ?.pricePerNight ) ?? Infinity ) || (currentRequestedPrice === Math.min( Number( previousLowest.products[0].productType.public.requestedPrice ?.pricePerNight ) ?? Infinity, Number( previousLowest.products[0].productType.member?.requestedPrice ?.pricePerNight ) ?? Infinity ) && currentLocalPrice < Math.min( Number( previousLowest.products[0].productType.public.localPrice ?.pricePerNight ) ?? Infinity, Number( previousLowest.products[0].productType.member?.localPrice ?.pricePerNight ) ?? Infinity )) ) { roomMap.set(roomType, room) } }) } else { roomMap.set(roomType, room) } }) return Array.from(roomMap.values()) }