feat: add support for bought children breakfast package
This commit is contained in:
committed by
Simon.Emanuelsson
parent
aceb88cb1a
commit
b7c78a53b5
@@ -77,7 +77,7 @@ export default function PriceDetails({
|
||||
title: `${selectedAncillary.title} / ${intl.formatMessage({
|
||||
defaultMessage: "Adult",
|
||||
})}`,
|
||||
totalPrice: breakfastData.priceAdult * breakfastData.nrOfAdults,
|
||||
totalPrice: breakfastData.priceAdult,
|
||||
currency: breakfastData.currency,
|
||||
quantityWithCard: breakfastData.nrOfAdults * breakfastData.nrOfNights,
|
||||
},
|
||||
@@ -88,7 +88,7 @@ export default function PriceDetails({
|
||||
title: `${selectedAncillary.title} / ${intl.formatMessage({
|
||||
defaultMessage: "Children",
|
||||
})} 4-12`,
|
||||
totalPrice: breakfastData.priceChild * breakfastData.nrOfPayingChildren,
|
||||
totalPrice: breakfastData.priceChild,
|
||||
currency: breakfastData.currency,
|
||||
quantityWithCard:
|
||||
breakfastData.nrOfPayingChildren * breakfastData.nrOfNights,
|
||||
|
||||
@@ -511,20 +511,28 @@ function calculateBreakfastData(
|
||||
return null
|
||||
}
|
||||
|
||||
const [nrOfPayingChildren, nrOfFreeChildren] = childrenAges.reduce(
|
||||
(acc, curr) => (curr >= 4 ? [acc[0] + 1, acc[1]] : [acc[0], acc[1] + 1]),
|
||||
[0, 0]
|
||||
const { nrOfPayingChildren, nrOfFreeChildren } = childrenAges.reduce(
|
||||
(total, childAge) => {
|
||||
if (childAge >= 4) {
|
||||
total.nrOfPayingChildren = total.nrOfPayingChildren + 1
|
||||
} else {
|
||||
total.nrOfFreeChildren = total.nrOfFreeChildren + 1
|
||||
}
|
||||
return total
|
||||
},
|
||||
{ nrOfPayingChildren: 0, nrOfFreeChildren: 0 }
|
||||
)
|
||||
|
||||
const priceAdult = packages?.find(
|
||||
const adultPackage = packages?.find(
|
||||
(p) => p.code === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST
|
||||
)?.localPrice.price
|
||||
const priceChild = packages?.find(
|
||||
)
|
||||
const childPackage = packages?.find(
|
||||
(p) => p.code === BreakfastPackageEnum.ANCILLARY_CHILD_PAYING_BREAKFAST
|
||||
)?.localPrice.price
|
||||
const currency = packages?.find(
|
||||
(p) => p.code === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST
|
||||
)?.localPrice.currency
|
||||
)
|
||||
const priceAdult = adultPackage?.localPrice.price
|
||||
const priceChild = childPackage?.localPrice.price
|
||||
const currency =
|
||||
adultPackage?.localPrice.currency ?? childPackage?.localPrice.currency
|
||||
|
||||
if (
|
||||
typeof priceAdult !== "number" ||
|
||||
|
||||
@@ -107,33 +107,34 @@ export function Ancillaries({
|
||||
return undefined
|
||||
}
|
||||
|
||||
const breakfastPackage = packages?.find(
|
||||
const breakfastPackageAdults = packages?.find(
|
||||
(p) => p.code === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST
|
||||
)
|
||||
|
||||
const breakfastAncillary: SelectedAncillary | undefined = breakfastPackage
|
||||
? {
|
||||
description: intl.formatMessage({
|
||||
defaultMessage: "Buffet",
|
||||
}),
|
||||
id: breakfastPackage.code,
|
||||
title: intl.formatMessage({
|
||||
defaultMessage: "Breakfast",
|
||||
}),
|
||||
price: {
|
||||
currency: breakfastPackage.localPrice.currency,
|
||||
total: breakfastPackage.localPrice.totalPrice,
|
||||
},
|
||||
// TODO: Change this to the correct URL, whatever that is
|
||||
imageUrl:
|
||||
"https://images.scandichotels.com/publishedmedia/inyre69evkpzgtygjnvp/Breakfast_-_Scandic_Sweden_-_Free_to_use.jpg",
|
||||
requiresDeliveryTime: false,
|
||||
loyaltyCode: undefined,
|
||||
points: undefined,
|
||||
hotelId: Number(booking.hotelId),
|
||||
categoryName: "Food",
|
||||
}
|
||||
: undefined
|
||||
const breakfastAncillary: SelectedAncillary | undefined =
|
||||
breakfastPackageAdults
|
||||
? {
|
||||
description: intl.formatMessage({
|
||||
defaultMessage: "Buffet",
|
||||
}),
|
||||
id: breakfastPackageAdults.code,
|
||||
title: intl.formatMessage({
|
||||
defaultMessage: "Breakfast",
|
||||
}),
|
||||
price: {
|
||||
currency: breakfastPackageAdults.localPrice.currency,
|
||||
total: breakfastPackageAdults.localPrice.totalPrice,
|
||||
},
|
||||
// TODO: Change this to the correct URL, whatever that is
|
||||
imageUrl:
|
||||
"https://images.scandichotels.com/publishedmedia/inyre69evkpzgtygjnvp/Breakfast_-_Scandic_Sweden_-_Free_to_use.jpg",
|
||||
requiresDeliveryTime: false,
|
||||
loyaltyCode: undefined,
|
||||
points: undefined,
|
||||
hotelId: Number(booking.hotelId),
|
||||
categoryName: "Food",
|
||||
}
|
||||
: undefined
|
||||
|
||||
return breakfastAncillary
|
||||
}, [
|
||||
|
||||
@@ -10,10 +10,13 @@ import Row from "./Row"
|
||||
export default function Breakfast() {
|
||||
const intl = useIntl()
|
||||
|
||||
const { breakfast, rateDefinition } = useMyStayStore((state) => ({
|
||||
breakfast: state.bookedRoom.breakfast,
|
||||
rateDefinition: state.bookedRoom.rateDefinition,
|
||||
}))
|
||||
const { breakfast, breakfastChildren, rateDefinition } = useMyStayStore(
|
||||
(state) => ({
|
||||
breakfast: state.bookedRoom.breakfast,
|
||||
breakfastChildren: state.bookedRoom.breakfastChildren,
|
||||
rateDefinition: state.bookedRoom.rateDefinition,
|
||||
})
|
||||
)
|
||||
|
||||
let breakfastPrice = intl.formatMessage({
|
||||
defaultMessage: "No breakfast",
|
||||
@@ -23,9 +26,10 @@ export default function Breakfast() {
|
||||
defaultMessage: "Included",
|
||||
})
|
||||
} else if (breakfast) {
|
||||
const childPrice = breakfastChildren?.localPrice.totalPrice || 0
|
||||
breakfastPrice = formatPrice(
|
||||
intl,
|
||||
breakfast.localPrice.totalPrice,
|
||||
breakfast.localPrice.totalPrice + childPrice,
|
||||
breakfast.localPrice.currency
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,30 +31,50 @@ export function mapRoomDetails({
|
||||
.startOf("day")
|
||||
.diff(dt(booking.checkInDate).startOf("day"), "days")
|
||||
|
||||
const validBreakfastPackages: string[] = [
|
||||
const validBreakfastPackagesAdults: string[] = [
|
||||
BreakfastPackageEnum.REGULAR_BREAKFAST,
|
||||
BreakfastPackageEnum.ANCILLARY_CHILD_PAYING_BREAKFAST,
|
||||
BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST,
|
||||
]
|
||||
const breakfastPackage = booking.packages.find((pkg) =>
|
||||
validBreakfastPackages.includes(pkg.code)
|
||||
const breakfastPackageAdults = booking.packages.find((pkg) =>
|
||||
validBreakfastPackagesAdults.includes(pkg.code)
|
||||
)
|
||||
|
||||
// We don't get `requestedPrice` in packages
|
||||
const breakfast: Omit<BreakfastPackage, "requestedPrice"> | null =
|
||||
breakfastPackage
|
||||
breakfastPackageAdults
|
||||
? {
|
||||
code: breakfastPackage.code,
|
||||
description: breakfastPackage.description,
|
||||
code: breakfastPackageAdults.code,
|
||||
description: breakfastPackageAdults.description,
|
||||
localPrice: {
|
||||
currency: breakfastPackage.currency,
|
||||
price: breakfastPackage.unitPrice,
|
||||
totalPrice: breakfastPackage.totalPrice,
|
||||
currency: breakfastPackageAdults.currency,
|
||||
price: breakfastPackageAdults.unitPrice,
|
||||
totalPrice: breakfastPackageAdults.totalPrice,
|
||||
},
|
||||
packageType: PackageTypeEnum.BreakfastAdult,
|
||||
}
|
||||
: null
|
||||
|
||||
const validBreakfastPackagesChildren: string[] = [
|
||||
BreakfastPackageEnum.ANCILLARY_CHILD_PAYING_BREAKFAST,
|
||||
]
|
||||
const breakfastPackageChildren = booking.packages.find((pkg) =>
|
||||
validBreakfastPackagesChildren.includes(pkg.code)
|
||||
)
|
||||
// We don't get `requestedPrice` in packages
|
||||
const breakfastChildren: Omit<BreakfastPackage, "requestedPrice"> | null =
|
||||
breakfastPackageChildren
|
||||
? {
|
||||
code: breakfastPackageChildren.code,
|
||||
description: breakfastPackageChildren.description,
|
||||
localPrice: {
|
||||
currency: breakfastPackageChildren.currency,
|
||||
price: breakfastPackageChildren.unitPrice,
|
||||
totalPrice: breakfastPackageChildren.totalPrice,
|
||||
},
|
||||
packageType: PackageTypeEnum.BreakfastChildren,
|
||||
}
|
||||
: null
|
||||
|
||||
const isCancelled = booking.reservationStatus === BookingStatusEnum.Cancelled
|
||||
|
||||
const childrenAsString = formatChildBedPreferences({
|
||||
@@ -120,6 +140,7 @@ export function mapRoomDetails({
|
||||
},
|
||||
bookingCode: booking.bookingCode,
|
||||
breakfast,
|
||||
breakfastChildren,
|
||||
canChangeDate: booking.canChangeDate,
|
||||
cancellationNumber: booking.cancellationNumber,
|
||||
checkInDate: booking.checkInDate,
|
||||
|
||||
@@ -13,6 +13,7 @@ import type { Child } from "@/types/components/hotelReservation/selectRate/selec
|
||||
interface BreakfastProps {
|
||||
adults: number
|
||||
breakfast: Omit<BreakfastPackage, "requestedPrice"> | false | undefined | null
|
||||
breakfastChildren: Omit<BreakfastPackage, "requestedPrice"> | null | undefined
|
||||
breakfastIncluded: boolean
|
||||
childrenInRoom: Child[] | undefined
|
||||
currency: string
|
||||
@@ -22,8 +23,9 @@ interface BreakfastProps {
|
||||
export default function Breakfast({
|
||||
adults,
|
||||
breakfast,
|
||||
breakfastChildren,
|
||||
breakfastIncluded,
|
||||
childrenInRoom,
|
||||
childrenInRoom = [],
|
||||
currency,
|
||||
nights,
|
||||
}: BreakfastProps) {
|
||||
@@ -70,17 +72,56 @@ export default function Breakfast({
|
||||
return null
|
||||
}
|
||||
|
||||
const adultPricePerNight = breakfast.localPrice.price * adults
|
||||
const breakfastAdultsPricePerNight = formatPrice(
|
||||
intl,
|
||||
breakfast.localPrice.price * adults,
|
||||
adultPricePerNight,
|
||||
breakfast.localPrice.currency
|
||||
)
|
||||
const breakfastAdultsTotalPrice = formatPrice(
|
||||
|
||||
const { payingChildren, freeChildren } = childrenInRoom.reduce(
|
||||
(total, child) => {
|
||||
if (child.age >= 4) {
|
||||
total.payingChildren = total.payingChildren + 1
|
||||
} else {
|
||||
total.freeChildren = total.freeChildren + 1
|
||||
}
|
||||
return total
|
||||
},
|
||||
{ payingChildren: 0, freeChildren: 0 }
|
||||
)
|
||||
|
||||
const childrenPrice = breakfastChildren?.localPrice.price || 0
|
||||
const childrenPricePerNight = childrenPrice * payingChildren
|
||||
|
||||
const childCurrency =
|
||||
breakfastChildren?.localPrice.currency ?? breakfast.localPrice.currency
|
||||
|
||||
const breakfastChildrenPricePerNight = formatPrice(
|
||||
intl,
|
||||
breakfast.localPrice.price * adults * nights,
|
||||
childrenPricePerNight,
|
||||
childCurrency
|
||||
)
|
||||
|
||||
const totalAdultsPrice = adultPricePerNight * nights
|
||||
const totalChildrenPrice = childrenPricePerNight * nights
|
||||
const breakfastTotalPrice = formatPrice(
|
||||
intl,
|
||||
totalAdultsPrice + totalChildrenPrice,
|
||||
breakfast.localPrice.currency
|
||||
)
|
||||
|
||||
const freeChildrenMsg = intl.formatMessage(
|
||||
{
|
||||
defaultMessage:
|
||||
"Breakfast ({totalChildren, plural, one {# child} other {# children}}) x {totalBreakfasts}",
|
||||
},
|
||||
{
|
||||
totalChildren: freeChildren,
|
||||
totalBreakfasts: nights,
|
||||
}
|
||||
)
|
||||
|
||||
return (
|
||||
<Tbody border>
|
||||
<RegularRow
|
||||
@@ -93,7 +134,28 @@ export default function Breakfast({
|
||||
)}
|
||||
value={breakfastAdultsPricePerNight}
|
||||
/>
|
||||
{childrenInRoom?.length ? (
|
||||
{breakfastChildren ? (
|
||||
<RegularRow
|
||||
label={intl.formatMessage(
|
||||
{
|
||||
defaultMessage:
|
||||
"Breakfast ({totalChildren, plural, one {# child} other {# children}}) x {totalBreakfasts}",
|
||||
},
|
||||
{
|
||||
totalChildren: payingChildren,
|
||||
totalBreakfasts: nights,
|
||||
}
|
||||
)}
|
||||
value={breakfastChildrenPricePerNight}
|
||||
/>
|
||||
) : null}
|
||||
{breakfastChildren && freeChildren ? (
|
||||
<RegularRow
|
||||
label={`${freeChildrenMsg} (0-3)`}
|
||||
value={formatPrice(intl, 0, breakfast.localPrice.currency)}
|
||||
/>
|
||||
) : null}
|
||||
{childrenInRoom?.length && !breakfastChildren ? (
|
||||
<RegularRow
|
||||
label={intl.formatMessage(
|
||||
{
|
||||
@@ -110,7 +172,7 @@ export default function Breakfast({
|
||||
) : null}
|
||||
<BoldRow
|
||||
label={intl.formatMessage({ defaultMessage: "Breakfast charge" })}
|
||||
value={breakfastAdultsTotalPrice}
|
||||
value={breakfastTotalPrice}
|
||||
/>
|
||||
</Tbody>
|
||||
)
|
||||
|
||||
@@ -43,6 +43,7 @@ export interface Room {
|
||||
adults: number
|
||||
bedType: BedTypeSchema | undefined
|
||||
breakfast: Omit<BreakfastPackage, "requestedPrice"> | false | undefined | null
|
||||
breakfastChildren?: Omit<BreakfastPackage, "requestedPrice"> | null
|
||||
breakfastIncluded: boolean
|
||||
childrenInRoom: Child[] | undefined
|
||||
packages: Packages | null
|
||||
@@ -182,6 +183,7 @@ export default function PriceDetailsTable({
|
||||
<Breakfast
|
||||
adults={room.adults}
|
||||
breakfast={room.breakfast}
|
||||
breakfastChildren={room.breakfastChildren}
|
||||
breakfastIncluded={room.breakfastIncluded}
|
||||
childrenInRoom={room.childrenInRoom}
|
||||
currency={currency}
|
||||
|
||||
@@ -2,19 +2,81 @@ import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums"
|
||||
import type { Child } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
||||
|
||||
const bedTypeToMapEnum: Record<string, ChildBedMapEnum> = {
|
||||
Crib: ChildBedMapEnum.IN_CRIB,
|
||||
ExtraBed: ChildBedMapEnum.IN_EXTRA_BED,
|
||||
ParentsBed: ChildBedMapEnum.IN_ADULTS_BED,
|
||||
Unknown: ChildBedMapEnum.UNKNOWN,
|
||||
}
|
||||
|
||||
export function convertToChildType(
|
||||
childrenAges: number[],
|
||||
childBedPreferences: BookingConfirmation["booking"]["childBedPreferences"]
|
||||
): Child[] {
|
||||
return childBedPreferences.map((preference, index) => ({
|
||||
age: childrenAges[index],
|
||||
bed: bedTypeToMapEnum[preference.bedType] ?? ChildBedMapEnum.UNKNOWN,
|
||||
}))
|
||||
const lookup = childBedPreferences.reduce(
|
||||
(preferences, preference) => {
|
||||
preferences[preference.bedType] = preference.quantity
|
||||
return preferences
|
||||
},
|
||||
{
|
||||
Crib: 0,
|
||||
ExtraBed: 0,
|
||||
ParentsBed: 0,
|
||||
Unknown: 0,
|
||||
}
|
||||
)
|
||||
|
||||
const adultsAndOrCribKids = childrenAges.filter((childAge) => childAge <= 2)
|
||||
const adultsAndOrExtraBedKids = childrenAges.filter(
|
||||
(childAge) => childAge >= 3 && childAge <= 5
|
||||
)
|
||||
const extraBedKids = childrenAges.filter((childAge) => childAge >= 6)
|
||||
|
||||
const cribKids = adultsAndOrCribKids.map((age) => {
|
||||
if (lookup.Crib) {
|
||||
lookup.Crib = lookup.Crib - 1
|
||||
return {
|
||||
age,
|
||||
bed: ChildBedMapEnum.IN_CRIB,
|
||||
}
|
||||
}
|
||||
|
||||
lookup.ParentsBed = lookup.ParentsBed - 1
|
||||
return {
|
||||
age,
|
||||
bed: ChildBedMapEnum.IN_ADULTS_BED,
|
||||
}
|
||||
})
|
||||
|
||||
const adultOrExtraKids = adultsAndOrExtraBedKids.map((age) => {
|
||||
if (lookup.ParentsBed) {
|
||||
lookup.ParentsBed = lookup.ParentsBed - 1
|
||||
return {
|
||||
age,
|
||||
bed: ChildBedMapEnum.IN_ADULTS_BED,
|
||||
}
|
||||
}
|
||||
|
||||
if (lookup.ExtraBed) {
|
||||
lookup.ExtraBed = lookup.ExtraBed - 1
|
||||
return {
|
||||
age,
|
||||
bed: ChildBedMapEnum.IN_EXTRA_BED,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
age,
|
||||
bed: ChildBedMapEnum.UNKNOWN,
|
||||
}
|
||||
})
|
||||
|
||||
const extraKids = extraBedKids.map((age) => {
|
||||
if (lookup.ExtraBed) {
|
||||
lookup.ExtraBed = lookup.ExtraBed - 1
|
||||
return {
|
||||
age,
|
||||
bed: ChildBedMapEnum.IN_EXTRA_BED,
|
||||
}
|
||||
}
|
||||
return {
|
||||
age,
|
||||
bed: ChildBedMapEnum.UNKNOWN,
|
||||
}
|
||||
})
|
||||
|
||||
return [...cribKids, ...adultOrExtraKids, ...extraKids]
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ export type Room = Pick<
|
||||
> & {
|
||||
bedType: BedTypeSchema
|
||||
breakfast: Omit<BreakfastPackage, "requestedPrice"> | null
|
||||
breakfastChildren: Omit<BreakfastPackage, "requestedPrice"> | null
|
||||
childrenAsString: string
|
||||
childrenInRoom: Child[]
|
||||
isCancelled: boolean
|
||||
|
||||
Reference in New Issue
Block a user