UNPKG

@qite/tide-booking-component

Version:

React Booking wizard & Booking product component for Tide

119 lines (99 loc) 4.76 kB
import { createSelector } from '@reduxjs/toolkit'; import { RootState } from '../../store'; import { selectRequestRooms } from '../booking/selectors'; import { isEmpty, sum } from 'lodash'; import { PriceDetailsPerPaxType, PricePerPaxType } from '../../types'; import { BookingPackageRequestRoom, BookingPriceDetail } from '@qite/tide-client'; export const selectPriceDetails = (state: RootState) => state.priceDetails.priceDetails; export const selectPackagePriceDetails = createSelector(selectPriceDetails, (priceDetails) => priceDetails.filter((priceDetail) => priceDetail.isInPackage)); export const selectSeparatePackagePriceDetails = createSelector(selectPackagePriceDetails, (pricedetails) => { const result: BookingPriceDetail[] = []; const filteredPriceDetails = pricedetails.filter((priceDetail) => priceDetail.isSeparate); filteredPriceDetails.forEach((priceDetail) => { const priceDetailToMerge = result.find( (x) => x.productCode === priceDetail.productCode && x.accommodationCode === priceDetail.accommodationCode && x.productType === priceDetail.productType ); if (priceDetailToMerge) { priceDetailToMerge.total += priceDetail.total; priceDetailToMerge.price += priceDetail.price; } else { result.push(Object.assign({}, priceDetail)); } }); return result; }); export const selectBasePrice = createSelector(selectPackagePriceDetails, (priceDetails) => sum(priceDetails.map((priceDetail) => priceDetail.price * priceDetail.amount)) ); export const selectSeparateExtraPriceDetails = createSelector(selectPriceDetails, (priceDetails) => priceDetails.filter((priceDetail) => !priceDetail.isInPackage && priceDetail.isSeparate) ); export const selectTotalPrice = createSelector(selectBasePrice, selectSeparateExtraPriceDetails, (basePrice, separatePriceDetails) => sum([basePrice, ...separatePriceDetails.map((priceDetail) => priceDetail.price * priceDetail.amount)]) ); // Shared function to aggregate price and details per paxType const aggregatePricePerPaxType = (priceDetails: BookingPriceDetail[], requestRooms: BookingPackageRequestRoom[] | undefined): PricePerPaxType[] => { if (!requestRooms || isEmpty(requestRooms)) return []; if (!priceDetails || isEmpty(priceDetails)) return []; // Compute paxType by age: >=2 INFANT, >=11 CHILD, else ADULT const paxTypeToPaxIds: Record<string, Set<number>> = {}; requestRooms.forEach((room) => { room.pax.forEach((pax) => { let paxType = 'ADULT'; if (typeof pax.age === 'number') { if (pax.age <= 11 && pax.age > 2) { paxType = 'CHILD'; } else if (pax.age <= 2) { paxType = 'INFANT'; } } if (!paxTypeToPaxIds[paxType]) paxTypeToPaxIds[paxType] = new Set(); paxTypeToPaxIds[paxType].add(pax.id); }); }); const result: PricePerPaxType[] = []; Object.keys(paxTypeToPaxIds).forEach((paxType) => { const paxIds = Array.from(paxTypeToPaxIds[paxType]); let pricePerPaxType = 0; const detailsMap: Record<string, PriceDetailsPerPaxType> = {}; priceDetails.forEach((detail) => { if (!detail.showPrice || !detail.pricePerPax) return; detail.pricePerPax.forEach((ppp) => { if (paxIds.includes(ppp.paxId)) { pricePerPaxType += ppp.price; const descKey = detail.priceDescription || ''; if (!detailsMap[descKey]) { detailsMap[descKey] = { numberOfPax: 1, description: detail.priceDescription || '', price: ppp.price, paxIds: [ppp.paxId] } as PriceDetailsPerPaxType; } else { detailsMap[descKey].price += ppp.price; if (!detailsMap[descKey].paxIds.includes(ppp.paxId)) { detailsMap[descKey].paxIds.push(ppp.paxId); detailsMap[descKey].numberOfPax += 1; } } } }); }); result.push({ paxType, pricePerPaxType, numberOfPax: paxIds.length, details: Object.values(detailsMap) }); }); return result; }; export const selectBasePricePerPaxType = createSelector(selectPackagePriceDetails, selectRequestRooms, (priceDetails, requestRooms) => aggregatePricePerPaxType(priceDetails, requestRooms) ); export const selectSeparateExtraPriceDetailsPerPaxType = createSelector(selectSeparateExtraPriceDetails, selectRequestRooms, (priceDetails, requestRooms) => aggregatePricePerPaxType(priceDetails, requestRooms) ); export const selectDeposit = (state: RootState) => state.priceDetails.deposit; export const selectCommission = (state: RootState) => state.priceDetails.commission; export const selectIsFetchingPriceDetails = (state: RootState) => state.priceDetails.isBusy;