Files
web/stores/select-rate/helper.ts
2025-02-14 14:20:54 +01:00

198 lines
5.7 KiB
TypeScript

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<number, RoomPackageCodeEnum[]>
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<Record<string, number>>(
(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())
}