Merged in feat/SW-1719-strikethrough-rates (pull request #2266)
Feat/SW-1719 strikethrough rates * feat(SW-1719): Strikethrough rate if logged in on regular rate cards * feat(SW-1719): Strikethrough rate if logged in on rate summary * feat(SW-1719): Strikethrough rate if logged in on mobile rate summary * feat(SW-1719): Strikethrough rate if logged in on enter details * feat(SW-1719): Strikethrough rate support for multiple rooms * feat(SW-1719): booking receipt fixes on confirmation page * feat(SW-1719): improve initial total price calculation * feat: harmonize enter details total price to use one and the same function Approved-by: Michael Zetterberg
This commit is contained in:
committed by
Michael Zetterberg
parent
e1ede52014
commit
85acd3453d
@@ -8,12 +8,20 @@ import {
|
||||
|
||||
import { detailsStorageName } from "."
|
||||
|
||||
import type { BreakfastPackage } from "@/types/components/hotelReservation/breakfast"
|
||||
import { type RoomRate } from "@/types/components/hotelReservation/enterDetails/details"
|
||||
import type { Price } from "@/types/components/hotelReservation/price"
|
||||
import type { SelectRateBooking } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||
import { CurrencyEnum } from "@/types/enums/currency"
|
||||
import type { Package } from "@/types/requests/packages"
|
||||
import { RateTypeEnum } from "@/types/enums/rateType"
|
||||
import type { Packages } from "@/types/requests/packages"
|
||||
import type { PersistedState, RoomState } from "@/types/stores/enter-details"
|
||||
import type {
|
||||
CorporateChequeProduct,
|
||||
PriceProduct,
|
||||
RedemptionProduct,
|
||||
VoucherProduct,
|
||||
} from "@/types/trpc/routers/hotel/roomAvailability"
|
||||
import type { SafeUser } from "@/types/user"
|
||||
|
||||
export function extractGuestFromUser(user: NonNullable<SafeUser>) {
|
||||
@@ -75,6 +83,13 @@ export function add(...nums: (number | string | undefined)[]) {
|
||||
|
||||
export function getRoomPrice(roomRate: RoomRate, isMember: boolean) {
|
||||
if (isMember && "member" in roomRate && roomRate.member) {
|
||||
let publicRate
|
||||
if (
|
||||
"public" in roomRate &&
|
||||
roomRate.public?.rateType === RateTypeEnum.Regular
|
||||
) {
|
||||
publicRate = roomRate.public
|
||||
}
|
||||
return {
|
||||
perNight: {
|
||||
requested: roomRate.member.requestedPrice
|
||||
@@ -86,6 +101,9 @@ export function getRoomPrice(roomRate: RoomRate, isMember: boolean) {
|
||||
local: {
|
||||
currency: roomRate.member.localPrice.currency,
|
||||
price: roomRate.member.localPrice.pricePerNight,
|
||||
regularPrice:
|
||||
publicRate?.localPrice.pricePerStay ||
|
||||
roomRate.member.localPrice.regularPricePerNight,
|
||||
},
|
||||
},
|
||||
perStay: {
|
||||
@@ -98,6 +116,9 @@ export function getRoomPrice(roomRate: RoomRate, isMember: boolean) {
|
||||
local: {
|
||||
currency: roomRate.member.localPrice.currency,
|
||||
price: roomRate.member.localPrice.pricePerStay,
|
||||
regularPrice:
|
||||
publicRate?.localPrice.pricePerStay ||
|
||||
roomRate.member.localPrice.regularPricePerStay,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -231,329 +252,6 @@ export function getRoomPrice(roomRate: RoomRate, isMember: boolean) {
|
||||
)
|
||||
}
|
||||
|
||||
export function getTotalPrice(roomRates: RoomRate[], isMember: boolean) {
|
||||
const totalPrice = roomRates.reduce<Price>(
|
||||
(total, roomRate, idx) => {
|
||||
const isMainRoom = idx === 0
|
||||
let rate
|
||||
if (isMainRoom && isMember && "member" in roomRate && roomRate.member) {
|
||||
rate = roomRate.member
|
||||
} else if ("public" in roomRate && roomRate.public) {
|
||||
rate = roomRate.public
|
||||
}
|
||||
// TODO: Handle other products?
|
||||
if (!rate) {
|
||||
return total
|
||||
}
|
||||
|
||||
total.local.currency = rate.localPrice.currency
|
||||
total.local.price = add(total.local.price, rate.localPrice.pricePerStay)
|
||||
if (rate.localPrice.regularPricePerStay) {
|
||||
total.local.regularPrice = add(
|
||||
total.local.regularPrice,
|
||||
rate.localPrice.regularPricePerStay
|
||||
)
|
||||
}
|
||||
|
||||
if (rate.requestedPrice) {
|
||||
if (total.requested) {
|
||||
total.requested.price = add(
|
||||
total.requested.price,
|
||||
rate.requestedPrice.pricePerStay
|
||||
)
|
||||
} else {
|
||||
total.requested = {
|
||||
currency: rate.requestedPrice.currency,
|
||||
price: rate.requestedPrice.pricePerStay,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total
|
||||
},
|
||||
{
|
||||
local: {
|
||||
currency: CurrencyEnum.Unknown,
|
||||
price: 0,
|
||||
},
|
||||
requested: undefined,
|
||||
}
|
||||
)
|
||||
|
||||
if (totalPrice.local.regularPrice) {
|
||||
const totalPriceWithRegularPrice = roomRates.reduce(
|
||||
(total, roomRate, idx) => {
|
||||
const isMainRoom = idx === 0
|
||||
let rate
|
||||
if (isMainRoom && isMember && "member" in roomRate && roomRate.member) {
|
||||
rate = roomRate.member
|
||||
} else if ("public" in roomRate && roomRate.public) {
|
||||
rate = roomRate.public
|
||||
}
|
||||
|
||||
if (!rate) {
|
||||
return total
|
||||
}
|
||||
|
||||
if (rate.localPrice.regularPricePerStay) {
|
||||
total.local.regularPrice =
|
||||
total.local.regularPrice + rate.localPrice.regularPricePerStay
|
||||
} else {
|
||||
total.local.regularPrice =
|
||||
total.local.regularPrice + rate.localPrice.pricePerStay
|
||||
}
|
||||
|
||||
return total
|
||||
},
|
||||
{
|
||||
...totalPrice,
|
||||
local: {
|
||||
...totalPrice.local,
|
||||
regularPrice: 0,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (
|
||||
totalPriceWithRegularPrice.local.price ===
|
||||
totalPriceWithRegularPrice.local.regularPrice
|
||||
) {
|
||||
totalPriceWithRegularPrice.local.regularPrice = 0
|
||||
}
|
||||
|
||||
return totalPriceWithRegularPrice
|
||||
}
|
||||
|
||||
return totalPrice
|
||||
}
|
||||
|
||||
export function calculateVoucherPrice(
|
||||
roomRates: RoomRate[],
|
||||
packages: Package[]
|
||||
) {
|
||||
return roomRates.reduce<Price>(
|
||||
(total, room) => {
|
||||
if (!("voucher" in room)) {
|
||||
return total
|
||||
}
|
||||
|
||||
const pkgsSum = sumPackages(packages)
|
||||
|
||||
return {
|
||||
local: {
|
||||
additionalPrice: pkgsSum.price,
|
||||
additionalPriceCurrency: pkgsSum.currency,
|
||||
currency: total.local.currency,
|
||||
price: total.local.price + room.voucher.numberOfVouchers,
|
||||
},
|
||||
requested: undefined,
|
||||
}
|
||||
},
|
||||
{
|
||||
local: {
|
||||
currency: CurrencyEnum.Voucher,
|
||||
price: 0,
|
||||
},
|
||||
requested: undefined,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export function calculateCorporateChequePrice(roomRates: RoomRate[]) {
|
||||
return roomRates.reduce<Price>(
|
||||
(total, room) => {
|
||||
if (!("corporateCheque" in room)) {
|
||||
return total
|
||||
}
|
||||
|
||||
const rate = room.corporateCheque
|
||||
|
||||
total.local.price = add(
|
||||
total.local.price,
|
||||
rate.localPrice.numberOfCheques
|
||||
)
|
||||
|
||||
if (rate.localPrice.additionalPricePerStay) {
|
||||
total.local.additionalPrice = add(
|
||||
total.local.additionalPrice,
|
||||
rate.localPrice.additionalPricePerStay
|
||||
)
|
||||
}
|
||||
if (rate.localPrice.currency) {
|
||||
total.local.additionalPriceCurrency = rate.localPrice.currency
|
||||
}
|
||||
|
||||
if (rate.requestedPrice) {
|
||||
if (total.requested) {
|
||||
total.requested.price = add(
|
||||
total.requested.price,
|
||||
rate.requestedPrice.numberOfCheques
|
||||
)
|
||||
} else {
|
||||
total.requested = {
|
||||
currency: CurrencyEnum.CC,
|
||||
price: rate.requestedPrice.numberOfCheques,
|
||||
}
|
||||
}
|
||||
|
||||
if (rate.requestedPrice.additionalPricePerStay) {
|
||||
total.requested.additionalPrice = add(
|
||||
total.requested.additionalPrice,
|
||||
rate.requestedPrice.additionalPricePerStay
|
||||
)
|
||||
}
|
||||
|
||||
if (rate.requestedPrice.currency) {
|
||||
total.requested.additionalPriceCurrency = rate.requestedPrice.currency
|
||||
}
|
||||
}
|
||||
|
||||
return total
|
||||
},
|
||||
{
|
||||
local: {
|
||||
currency: CurrencyEnum.CC,
|
||||
price: 0,
|
||||
},
|
||||
requested: undefined,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export function calcTotalPrice(
|
||||
rooms: RoomState[],
|
||||
currency: Price["local"]["currency"],
|
||||
isMember: boolean,
|
||||
nights: number
|
||||
) {
|
||||
return rooms.reduce<Price>(
|
||||
(acc, { room }, index) => {
|
||||
const isFirstRoomAndMember = index === 0 && isMember
|
||||
const join = Boolean(room.guest.join || room.guest.membershipNo)
|
||||
|
||||
const roomPrice = getRoomPrice(
|
||||
room.roomRate,
|
||||
isFirstRoomAndMember || join
|
||||
)
|
||||
|
||||
if (!roomPrice) {
|
||||
return acc
|
||||
}
|
||||
|
||||
const isSpecialRate =
|
||||
"corporateCheque" in room.roomRate ||
|
||||
"redemption" in room.roomRate ||
|
||||
"voucher" in room.roomRate
|
||||
|
||||
const breakfastRequestedPrice = room.breakfast
|
||||
? (room.breakfast.requestedPrice?.price ?? 0)
|
||||
: 0
|
||||
const breakfastLocalPrice = room.breakfast
|
||||
? (room.breakfast.localPrice?.price ?? 0)
|
||||
: 0
|
||||
|
||||
const pkgsSum = sumPackages(room.roomFeatures)
|
||||
const pkgsSumRequested = sumPackagesRequestedPrice(room.roomFeatures)
|
||||
|
||||
const breakfastRequestedTotalPrice =
|
||||
breakfastRequestedPrice * room.adults * nights
|
||||
if (roomPrice.perStay.requested) {
|
||||
if (!acc.requested) {
|
||||
acc.requested = {
|
||||
currency: roomPrice.perStay.requested.currency,
|
||||
price: 0,
|
||||
}
|
||||
}
|
||||
|
||||
if (isSpecialRate) {
|
||||
acc.requested.price = add(
|
||||
acc.requested.price,
|
||||
roomPrice.perStay.requested.price
|
||||
)
|
||||
|
||||
acc.requested.additionalPrice = add(
|
||||
breakfastRequestedTotalPrice,
|
||||
pkgsSumRequested.price
|
||||
)
|
||||
|
||||
if (!acc.requested.additionalPriceCurrency) {
|
||||
if (roomPrice.perStay.requested.additionalPriceCurrency) {
|
||||
acc.requested.additionalPriceCurrency =
|
||||
roomPrice.perStay.requested.additionalPriceCurrency
|
||||
} else if (room.breakfast) {
|
||||
acc.requested.additionalPriceCurrency =
|
||||
room.breakfast.localPrice.currency
|
||||
} else if (pkgsSumRequested.currency) {
|
||||
acc.requested.additionalPriceCurrency = pkgsSumRequested.currency
|
||||
}
|
||||
}
|
||||
} else {
|
||||
acc.requested.price = add(
|
||||
acc.requested.price,
|
||||
roomPrice.perStay.requested.price,
|
||||
breakfastRequestedTotalPrice,
|
||||
pkgsSumRequested.price
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const breakfastLocalTotalPrice =
|
||||
breakfastLocalPrice * room.adults * nights
|
||||
|
||||
if (isSpecialRate) {
|
||||
acc.local.price = add(acc.local.price, roomPrice.perStay.local.price)
|
||||
|
||||
if (
|
||||
roomPrice.perStay.local.additionalPrice ||
|
||||
breakfastLocalTotalPrice ||
|
||||
pkgsSum.price
|
||||
) {
|
||||
acc.local.additionalPrice = add(
|
||||
acc.local.additionalPrice,
|
||||
roomPrice.perStay.local.additionalPrice,
|
||||
breakfastLocalTotalPrice,
|
||||
pkgsSum.price
|
||||
)
|
||||
}
|
||||
|
||||
if (!acc.local.additionalPriceCurrency) {
|
||||
if (roomPrice.perStay.local.additionalPriceCurrency) {
|
||||
acc.local.additionalPriceCurrency =
|
||||
roomPrice.perStay.local.additionalPriceCurrency
|
||||
} else if (room.breakfast) {
|
||||
acc.local.additionalPriceCurrency =
|
||||
room.breakfast.localPrice.currency
|
||||
} else if (pkgsSum.currency) {
|
||||
acc.local.additionalPriceCurrency = pkgsSum.currency
|
||||
}
|
||||
}
|
||||
} else {
|
||||
acc.local.price = add(
|
||||
acc.local.price,
|
||||
roomPrice.perStay.local.price,
|
||||
breakfastLocalTotalPrice,
|
||||
pkgsSum.price
|
||||
)
|
||||
|
||||
if (roomPrice.perStay.local.regularPrice) {
|
||||
acc.local.regularPrice = add(
|
||||
acc.local.regularPrice,
|
||||
roomPrice.perStay.local.regularPrice,
|
||||
breakfastLocalTotalPrice,
|
||||
pkgsSum.price
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return acc
|
||||
},
|
||||
{
|
||||
requested: undefined,
|
||||
local: { currency, price: 0 },
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const checkRoomProgress = (steps: RoomState["steps"]) => {
|
||||
return Object.values(steps)
|
||||
.filter(Boolean)
|
||||
@@ -602,3 +300,373 @@ export function clearSessionStorage() {
|
||||
}
|
||||
sessionStorage.removeItem(detailsStorageName)
|
||||
}
|
||||
|
||||
function getAdditionalPrice(
|
||||
total: Price,
|
||||
adults: number,
|
||||
breakfast: BreakfastPackage | false | undefined,
|
||||
nights: number,
|
||||
packages: Packages | null,
|
||||
additionalPrice = 0,
|
||||
additionalPriceCurrency?: CurrencyEnum | null | undefined
|
||||
) {
|
||||
const breakfastLocalPrice =
|
||||
(breakfast ? breakfast.localPrice.price : 0) * nights * adults
|
||||
const pkgsSum = sumPackages(packages)
|
||||
|
||||
total.local.additionalPrice = add(
|
||||
total.local.additionalPrice,
|
||||
additionalPrice,
|
||||
breakfastLocalPrice,
|
||||
pkgsSum.price
|
||||
)
|
||||
|
||||
if (!total.local.additionalPriceCurrency) {
|
||||
if (additionalPriceCurrency) {
|
||||
total.local.additionalPriceCurrency = additionalPriceCurrency
|
||||
} else if (breakfast && breakfast.localPrice.currency) {
|
||||
total.local.additionalPriceCurrency = breakfast.localPrice.currency
|
||||
} else if (pkgsSum.currency) {
|
||||
total.local.additionalPriceCurrency = pkgsSum.currency
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getRequestedAdditionalPrice(
|
||||
total: Price,
|
||||
adults: number,
|
||||
breakfast: BreakfastPackage | false | undefined,
|
||||
nights: number,
|
||||
packages: Packages | null,
|
||||
additionalPrice = 0,
|
||||
additionalPriceCurrency: CurrencyEnum | null | undefined
|
||||
) {
|
||||
if (!total.requested) {
|
||||
total.requested = {
|
||||
currency: CurrencyEnum.CC,
|
||||
price: 0,
|
||||
}
|
||||
}
|
||||
|
||||
const breakfastRequestedPrice =
|
||||
(breakfast ? breakfast.requestedPrice?.price || 0 : 0) * nights * adults
|
||||
const pkgsSumRequested = sumPackagesRequestedPrice(packages)
|
||||
|
||||
total.requested.additionalPrice = add(
|
||||
total.requested.additionalPrice,
|
||||
additionalPrice,
|
||||
breakfastRequestedPrice,
|
||||
pkgsSumRequested.price
|
||||
)
|
||||
|
||||
if (!total.requested.additionalPriceCurrency) {
|
||||
if (additionalPriceCurrency) {
|
||||
total.requested.additionalPriceCurrency = additionalPriceCurrency
|
||||
} else if (pkgsSumRequested.currency) {
|
||||
total.requested.additionalPriceCurrency = pkgsSumRequested.currency
|
||||
} else if (breakfast && breakfast.requestedPrice) {
|
||||
total.requested.additionalPriceCurrency =
|
||||
breakfast.requestedPrice.currency
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface TRoom
|
||||
extends Pick<
|
||||
RoomState["room"],
|
||||
"adults" | "breakfast" | "guest" | "roomFeatures" | "roomRate"
|
||||
> {}
|
||||
|
||||
interface TRoomCorporateCheque extends TRoom {
|
||||
roomRate: CorporateChequeProduct
|
||||
}
|
||||
|
||||
export function getCorporateChequePrice(rooms: TRoom[], nights: number) {
|
||||
return rooms
|
||||
.filter(
|
||||
(room): room is TRoomCorporateCheque => "corporateCheque" in room.roomRate
|
||||
)
|
||||
.reduce<Price>(
|
||||
(total, room) => {
|
||||
const corporateCheque = room.roomRate.corporateCheque
|
||||
|
||||
total.local.price = add(
|
||||
total.local.price,
|
||||
corporateCheque.localPrice.numberOfCheques
|
||||
)
|
||||
|
||||
getAdditionalPrice(
|
||||
total,
|
||||
room.adults,
|
||||
room.breakfast,
|
||||
nights,
|
||||
room.roomFeatures,
|
||||
corporateCheque.localPrice.additionalPricePerStay,
|
||||
corporateCheque.localPrice.currency
|
||||
)
|
||||
|
||||
if (corporateCheque.requestedPrice) {
|
||||
getRequestedAdditionalPrice(
|
||||
total,
|
||||
room.adults,
|
||||
room.breakfast,
|
||||
nights,
|
||||
room.roomFeatures,
|
||||
corporateCheque.requestedPrice?.additionalPricePerStay,
|
||||
corporateCheque.requestedPrice?.currency
|
||||
)
|
||||
}
|
||||
|
||||
return total
|
||||
},
|
||||
{
|
||||
local: {
|
||||
currency: CurrencyEnum.CC,
|
||||
price: 0,
|
||||
},
|
||||
requested: undefined,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
interface TRoomVoucher extends TRoom {
|
||||
roomRate: VoucherProduct
|
||||
}
|
||||
|
||||
export function getVoucherPrice(rooms: TRoom[], nights: number) {
|
||||
return rooms
|
||||
.filter((room): room is TRoomVoucher => "voucher" in room.roomRate)
|
||||
.reduce<Price>(
|
||||
(total, room) => {
|
||||
const voucher = room.roomRate.voucher
|
||||
|
||||
total.local.price = add(total.local.price, voucher.numberOfVouchers)
|
||||
|
||||
getAdditionalPrice(
|
||||
total,
|
||||
room.adults,
|
||||
room.breakfast,
|
||||
nights,
|
||||
room.roomFeatures
|
||||
)
|
||||
|
||||
return total
|
||||
},
|
||||
{
|
||||
local: {
|
||||
currency: CurrencyEnum.Voucher,
|
||||
price: 0,
|
||||
},
|
||||
requested: undefined,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
interface TRoomRedemption extends TRoom {
|
||||
roomRate: RedemptionProduct
|
||||
}
|
||||
|
||||
export function getRedemptionPrice(rooms: TRoom[], nights: number) {
|
||||
return rooms
|
||||
.filter((room): room is TRoomRedemption => "redemption" in room.roomRate)
|
||||
.reduce<Price>(
|
||||
(total, room) => {
|
||||
const redemption = room.roomRate.redemption
|
||||
|
||||
total.local.price = add(
|
||||
total.local.price,
|
||||
redemption.localPrice.pointsPerStay
|
||||
)
|
||||
|
||||
getAdditionalPrice(
|
||||
total,
|
||||
room.adults,
|
||||
room.breakfast,
|
||||
nights,
|
||||
room.roomFeatures,
|
||||
redemption.localPrice.additionalPricePerStay,
|
||||
redemption.localPrice.currency
|
||||
)
|
||||
|
||||
return total
|
||||
},
|
||||
{
|
||||
local: {
|
||||
currency: CurrencyEnum.POINTS,
|
||||
price: 0,
|
||||
},
|
||||
requested: undefined,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
interface TRoomPriceProduct extends TRoom {
|
||||
roomRate: PriceProduct
|
||||
}
|
||||
|
||||
export function getRegularPrice(
|
||||
rooms: TRoom[],
|
||||
isMember: boolean,
|
||||
nights: number
|
||||
) {
|
||||
const totalPrice = rooms
|
||||
.filter(
|
||||
(room): room is TRoomPriceProduct =>
|
||||
"member" in room.roomRate || "public" in room.roomRate
|
||||
)
|
||||
.reduce<Price>(
|
||||
(total, room, idx) => {
|
||||
const isMainRoomAndMember = idx === 0 && isMember
|
||||
const join = Boolean(room.guest.join || room.guest.membershipNo)
|
||||
const getMemberRate = isMainRoomAndMember || join
|
||||
|
||||
const memberRate = "member" in room.roomRate && room.roomRate.member
|
||||
const publicRate = "public" in room.roomRate && room.roomRate.public
|
||||
|
||||
let rate
|
||||
if (getMemberRate && memberRate) {
|
||||
rate = memberRate
|
||||
} else if (publicRate) {
|
||||
rate = publicRate
|
||||
}
|
||||
|
||||
if (!rate) {
|
||||
return total
|
||||
}
|
||||
|
||||
const breakfastLocalPrice =
|
||||
(room.breakfast ? room.breakfast.localPrice.price || 0 : 0) *
|
||||
nights *
|
||||
room.adults
|
||||
const pkgsSum = sumPackages(room.roomFeatures)
|
||||
const additionalCost = breakfastLocalPrice + pkgsSum.price
|
||||
|
||||
total.local.currency = rate.localPrice.currency
|
||||
total.local.price = add(
|
||||
total.local.price,
|
||||
rate.localPrice.pricePerStay,
|
||||
additionalCost
|
||||
)
|
||||
|
||||
if (rate.requestedPrice) {
|
||||
if (!total.requested) {
|
||||
total.requested = {
|
||||
currency: rate.requestedPrice.currency,
|
||||
price: 0,
|
||||
}
|
||||
}
|
||||
|
||||
const breakfastRequestedPrice =
|
||||
(room.breakfast ? (room.breakfast.requestedPrice?.price ?? 0) : 0) *
|
||||
nights *
|
||||
room.adults
|
||||
const pkgsSumRequested = sumPackagesRequestedPrice(room.roomFeatures)
|
||||
|
||||
total.requested.price = add(
|
||||
total.requested.price,
|
||||
rate.requestedPrice.pricePerStay,
|
||||
breakfastRequestedPrice,
|
||||
pkgsSumRequested.price
|
||||
)
|
||||
}
|
||||
|
||||
// Legend:
|
||||
// - total.local.price = Total Price = Black price, what the user pays
|
||||
// - total.local.regularPrice = Regular Price = Strikethrough price (could potentially be none)
|
||||
// - total.requested.price = Requested Price = EUR approx price
|
||||
|
||||
// We sometimes don't get all the required data to calculate the correct strikethrough total.
|
||||
// Therefore we try these different approach to get a number that is close
|
||||
// enough to the real number if all data would've been present.
|
||||
if (getMemberRate && memberRate) {
|
||||
if (publicRate) {
|
||||
// #1 Member price uses public price as strikethrough
|
||||
total.local.regularPrice = add(
|
||||
total.local.regularPrice,
|
||||
publicRate.localPrice.pricePerStay,
|
||||
additionalCost
|
||||
)
|
||||
} else if (memberRate.localPrice.regularPricePerStay) {
|
||||
// #2 Member price uses member regular price as strikethrough
|
||||
total.local.regularPrice = add(
|
||||
total.local.regularPrice,
|
||||
memberRate.localPrice.regularPricePerStay,
|
||||
additionalCost
|
||||
)
|
||||
} else {
|
||||
// #3 Member price uses member price as strikethrough
|
||||
// NOTE: If all rooms end up using this, no strikethrough price is shown.
|
||||
total.local.regularPrice = add(
|
||||
total.local.regularPrice,
|
||||
memberRate.localPrice.pricePerStay,
|
||||
additionalCost
|
||||
)
|
||||
}
|
||||
} else if (publicRate) {
|
||||
if (publicRate.localPrice.regularPricePerStay) {
|
||||
// #1 Public price uses public regular price as strikethrough
|
||||
total.local.regularPrice = add(
|
||||
total.local.regularPrice,
|
||||
publicRate.localPrice.regularPricePerStay,
|
||||
additionalCost
|
||||
)
|
||||
} else {
|
||||
// #2 Public price uses public price as strikethrough
|
||||
// NOTE: If all rooms end up using this, no strikethrough price is shown.
|
||||
total.local.regularPrice = add(
|
||||
total.local.regularPrice,
|
||||
publicRate.localPrice.pricePerStay,
|
||||
additionalCost
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// We cannot do anything, too much data is missing.
|
||||
return total
|
||||
}
|
||||
|
||||
return total
|
||||
},
|
||||
{
|
||||
local: {
|
||||
currency: CurrencyEnum.Unknown,
|
||||
price: 0,
|
||||
regularPrice: 0,
|
||||
},
|
||||
requested: undefined,
|
||||
}
|
||||
)
|
||||
|
||||
if (
|
||||
totalPrice.local.regularPrice &&
|
||||
totalPrice.local.price >= totalPrice.local.regularPrice
|
||||
) {
|
||||
totalPrice.local.regularPrice = 0
|
||||
}
|
||||
|
||||
return totalPrice
|
||||
}
|
||||
|
||||
export function getTotalPrice(
|
||||
rooms: TRoom[],
|
||||
isMember: boolean,
|
||||
nights: number
|
||||
) {
|
||||
const hasCorpChqRates = rooms.some(
|
||||
(room) => "corporateCheque" in room.roomRate
|
||||
)
|
||||
if (hasCorpChqRates) {
|
||||
return getCorporateChequePrice(rooms, nights)
|
||||
}
|
||||
|
||||
const hasRedemptionRates = rooms.some((room) => "redemption" in room.roomRate)
|
||||
if (hasRedemptionRates) {
|
||||
return getRedemptionPrice(rooms, nights)
|
||||
}
|
||||
|
||||
const hasVoucherRates = rooms.some((room) => "voucher" in room.roomRate)
|
||||
if (hasVoucherRates) {
|
||||
return getVoucherPrice(rooms, nights)
|
||||
}
|
||||
|
||||
return getRegularPrice(rooms, isMember, nights)
|
||||
}
|
||||
|
||||
@@ -3,21 +3,12 @@ import { produce } from "immer"
|
||||
import { useContext } from "react"
|
||||
import { create, useStore } from "zustand"
|
||||
|
||||
import { REDEMPTION } from "@/constants/booking"
|
||||
import { getDefaultCountryFromLang } from "@/constants/languages"
|
||||
import { dt } from "@/lib/dt"
|
||||
|
||||
import {
|
||||
sumPackages,
|
||||
sumPackagesRequestedPrice,
|
||||
} from "@/components/HotelReservation/utils"
|
||||
import { DetailsContext } from "@/contexts/Details"
|
||||
|
||||
import {
|
||||
add,
|
||||
calcTotalPrice,
|
||||
calculateCorporateChequePrice,
|
||||
calculateVoucherPrice,
|
||||
checkRoomProgress,
|
||||
extractGuestFromUser,
|
||||
getRoomPrice,
|
||||
@@ -27,7 +18,6 @@ import {
|
||||
|
||||
import type { BreakfastPackages } from "@/types/components/hotelReservation/breakfast"
|
||||
import type { Price } from "@/types/components/hotelReservation/price"
|
||||
import { CurrencyEnum } from "@/types/enums/currency"
|
||||
import { StepEnum } from "@/types/enums/step"
|
||||
import type {
|
||||
DetailsState,
|
||||
@@ -60,89 +50,37 @@ export function createDetailsStore(
|
||||
lang: Lang
|
||||
) {
|
||||
const isMember = !!user
|
||||
const isRedemption =
|
||||
new URLSearchParams(searchParams).get("searchtype") === REDEMPTION
|
||||
|
||||
const isVoucher = initialState.rooms.some(
|
||||
(room) => "voucher" in room.roomRate
|
||||
)
|
||||
const isCorpChq = initialState.rooms.some(
|
||||
(room) => "corporateCheque" in room.roomRate
|
||||
const nights = dt(initialState.booking.toDate).diff(
|
||||
initialState.booking.fromDate,
|
||||
"days"
|
||||
)
|
||||
|
||||
let initialTotalPrice: Price
|
||||
const roomOneRoomRate = initialState.rooms[0].roomRate
|
||||
const initialRoomRates = initialState.rooms.map((r) => r.roomRate)
|
||||
if (isRedemption && "redemption" in roomOneRoomRate) {
|
||||
initialTotalPrice = {
|
||||
local: {
|
||||
currency: CurrencyEnum.POINTS,
|
||||
price: roomOneRoomRate.redemption.localPrice.pointsPerStay,
|
||||
const initialRooms = initialState.rooms.map((room, idx) => {
|
||||
return {
|
||||
...room,
|
||||
adults: initialState.booking.rooms[idx].adults,
|
||||
childrenInRoom: initialState.booking.rooms[idx].childrenInRoom,
|
||||
bedType: room.bedType,
|
||||
breakfast:
|
||||
!breakfastPackages.length || room.breakfastIncluded
|
||||
? (false as const)
|
||||
: undefined,
|
||||
guest:
|
||||
isMember && idx === 0
|
||||
? deepmerge(defaultGuestState, extractGuestFromUser(user))
|
||||
: {
|
||||
...defaultGuestState,
|
||||
phoneNumberCC: getDefaultCountryFromLang(lang),
|
||||
},
|
||||
roomPrice: getRoomPrice(room.roomRate, isMember && idx === 0),
|
||||
specialRequest: {
|
||||
comment: "",
|
||||
},
|
||||
}
|
||||
if (roomOneRoomRate.redemption.localPrice.currency) {
|
||||
initialTotalPrice.local.additionalPriceCurrency =
|
||||
roomOneRoomRate.redemption.localPrice.currency
|
||||
}
|
||||
if (roomOneRoomRate.redemption.localPrice.additionalPricePerStay) {
|
||||
initialTotalPrice.local.additionalPrice =
|
||||
roomOneRoomRate.redemption.localPrice.additionalPricePerStay
|
||||
}
|
||||
} else if (isVoucher) {
|
||||
const pkgs = initialState.rooms.flatMap((room) => room.roomFeatures || [])
|
||||
initialTotalPrice = calculateVoucherPrice(initialRoomRates, pkgs)
|
||||
} else if (isCorpChq) {
|
||||
initialTotalPrice = calculateCorporateChequePrice(initialRoomRates)
|
||||
} else {
|
||||
initialTotalPrice = getTotalPrice(initialRoomRates, isMember)
|
||||
}
|
||||
|
||||
initialState.rooms.forEach((room) => {
|
||||
if (room.roomFeatures) {
|
||||
const pkgsSum = sumPackages(room.roomFeatures)
|
||||
const pkgsSumRequested = sumPackagesRequestedPrice(room.roomFeatures)
|
||||
|
||||
if ("corporateCheque" in room.roomRate || "redemption" in room.roomRate) {
|
||||
initialTotalPrice.local.additionalPrice = add(
|
||||
initialTotalPrice.local.additionalPrice,
|
||||
pkgsSum.price
|
||||
)
|
||||
if (
|
||||
!initialTotalPrice.local.additionalPriceCurrency &&
|
||||
pkgsSum.currency
|
||||
) {
|
||||
initialTotalPrice.local.additionalPriceCurrency = pkgsSum.currency
|
||||
}
|
||||
|
||||
if (initialTotalPrice.requested) {
|
||||
initialTotalPrice.requested.additionalPrice = add(
|
||||
initialTotalPrice.requested.additionalPrice,
|
||||
pkgsSumRequested.price
|
||||
)
|
||||
if (
|
||||
!initialTotalPrice.requested.additionalPriceCurrency &&
|
||||
pkgsSumRequested.currency
|
||||
) {
|
||||
initialTotalPrice.requested.additionalPriceCurrency =
|
||||
pkgsSumRequested.currency
|
||||
}
|
||||
}
|
||||
} else if ("public" in room.roomRate) {
|
||||
if (initialTotalPrice.requested) {
|
||||
initialTotalPrice.requested.price = add(
|
||||
initialTotalPrice.requested.price,
|
||||
pkgsSumRequested.price
|
||||
)
|
||||
}
|
||||
|
||||
initialTotalPrice.local.price = add(
|
||||
initialTotalPrice.local.price,
|
||||
pkgsSum.price
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const initialTotalPrice: Price = getTotalPrice(initialRooms, isMember, nights)
|
||||
|
||||
const availableBeds = initialState.rooms.reduce<
|
||||
DetailsState["availableBeds"]
|
||||
>((total, room) => {
|
||||
@@ -162,7 +100,7 @@ export function createDetailsStore(
|
||||
isSubmitting: false,
|
||||
isSummaryOpen: false,
|
||||
lastRoom: initialState.booking.rooms.length - 1,
|
||||
rooms: initialState.rooms.map((room, idx) => {
|
||||
rooms: initialRooms.map((room, idx) => {
|
||||
const steps: RoomState["steps"] = {
|
||||
[StepEnum.selectBed]: {
|
||||
step: StepEnum.selectBed,
|
||||
@@ -235,9 +173,8 @@ export function createDetailsStore(
|
||||
"days"
|
||||
)
|
||||
|
||||
state.totalPrice = calcTotalPrice(
|
||||
state.rooms,
|
||||
currentRoom.room.roomPrice.perStay.local.currency,
|
||||
state.totalPrice = getTotalPrice(
|
||||
state.rooms.map((r) => r.room),
|
||||
isMember,
|
||||
nights
|
||||
)
|
||||
@@ -275,9 +212,8 @@ export function createDetailsStore(
|
||||
"days"
|
||||
)
|
||||
|
||||
state.totalPrice = calcTotalPrice(
|
||||
state.rooms,
|
||||
state.totalPrice.local.currency,
|
||||
state.totalPrice = getTotalPrice(
|
||||
state.rooms.map((r) => r.room),
|
||||
isMember,
|
||||
nights
|
||||
)
|
||||
@@ -307,9 +243,8 @@ export function createDetailsStore(
|
||||
"days"
|
||||
)
|
||||
|
||||
state.totalPrice = calcTotalPrice(
|
||||
state.rooms,
|
||||
state.totalPrice.local.currency,
|
||||
state.totalPrice = getTotalPrice(
|
||||
state.rooms.map((r) => r.room),
|
||||
isMember,
|
||||
nights
|
||||
)
|
||||
@@ -368,9 +303,8 @@ export function createDetailsStore(
|
||||
"days"
|
||||
)
|
||||
|
||||
state.totalPrice = calcTotalPrice(
|
||||
state.rooms,
|
||||
state.totalPrice.local.currency,
|
||||
state.totalPrice = getTotalPrice(
|
||||
state.rooms.map((r) => r.room),
|
||||
isMember,
|
||||
nights
|
||||
)
|
||||
@@ -390,27 +324,7 @@ export function createDetailsStore(
|
||||
)
|
||||
},
|
||||
},
|
||||
room: {
|
||||
...room,
|
||||
adults: initialState.booking.rooms[idx].adults,
|
||||
childrenInRoom: initialState.booking.rooms[idx].childrenInRoom,
|
||||
bedType: room.bedType,
|
||||
breakfast:
|
||||
!breakfastPackages.length || room.breakfastIncluded
|
||||
? false
|
||||
: undefined,
|
||||
guest:
|
||||
isMember && idx === 0
|
||||
? deepmerge(defaultGuestState, extractGuestFromUser(user))
|
||||
: {
|
||||
...defaultGuestState,
|
||||
phoneNumberCC: getDefaultCountryFromLang(lang),
|
||||
},
|
||||
roomPrice: getRoomPrice(room.roomRate, isMember && idx === 0),
|
||||
specialRequest: {
|
||||
comment: "",
|
||||
},
|
||||
},
|
||||
room,
|
||||
isComplete: false,
|
||||
steps,
|
||||
}
|
||||
@@ -429,14 +343,6 @@ export function createDetailsStore(
|
||||
})
|
||||
)
|
||||
},
|
||||
setTotalPrice(totalPrice) {
|
||||
return set(
|
||||
produce((state: DetailsState) => {
|
||||
state.totalPrice.requested = totalPrice.requested
|
||||
state.totalPrice.local = totalPrice.local
|
||||
})
|
||||
)
|
||||
},
|
||||
toggleSummaryOpen() {
|
||||
return set(
|
||||
produce((state: DetailsState) => {
|
||||
|
||||
Reference in New Issue
Block a user