Files
web/apps/scandic-web/stores/enter-details/helpers.ts
Anton Gunnarsson 7e97b74c18 Merged in chore/remove-unused-code (pull request #2229)
Remove unused code

* Remove unused scandic-web files

* Remove unused exports


Approved-by: Joakim Jäderberg
2025-05-30 12:41:18 +00:00

596 lines
17 KiB
TypeScript

import isEqual from "fast-deep-equal"
import {
sumPackages,
sumPackagesRequestedPrice,
} from "@/components/HotelReservation/utils"
import { detailsStorageName } from "."
import { type RoomRate } from "@/types/components/hotelReservation/enterDetails/details"
import type { Price } from "@/types/components/hotelReservation/price"
import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
import { CurrencyEnum } from "@/types/enums/currency"
import type { Package } from "@/types/requests/packages"
import type { PersistedState, RoomState } from "@/types/stores/enter-details"
import type { SafeUser } from "@/types/user"
export function extractGuestFromUser(user: NonNullable<SafeUser>) {
return {
countryCode: user.address.countryCode?.toString(),
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
join: false,
membershipNo: user.membership?.membershipNumber,
phoneNumber: user.phoneNumber ?? "",
}
}
export function checkIsSameBooking(
prev: SelectRateSearchParams & { errorCode?: string },
next: SelectRateSearchParams & { errorCode?: string }
) {
const { rooms: prevRooms, errorCode: prevErrorCode, ...prevBooking } = prev
const prevRoomsWithoutRateCodes = prevRooms?.map(
({ rateCode, counterRateCode, roomTypeCode, bookingCode, ...room }) => room
)
const { rooms: nextRooms, errorCode: nextErrorCode, ...nextBooking } = next
const nextRoomsWithoutRateCodes = nextRooms?.map(
({ rateCode, counterRateCode, roomTypeCode, bookingCode, ...room }) => room
)
return isEqual(
{
...prevBooking,
rooms: prevRoomsWithoutRateCodes,
},
{
...nextBooking,
rooms: nextRoomsWithoutRateCodes,
}
)
}
export function add(...nums: (number | string | undefined)[]) {
return nums.reduce((total: number, num) => {
if (typeof num === "undefined") {
num = 0
}
total = total + parseInt(`${num}`)
return total
}, 0)
}
export function getRoomPrice(roomRate: RoomRate, isMember: boolean) {
if (isMember && "member" in roomRate && roomRate.member) {
return {
perNight: {
requested: roomRate.member.requestedPrice
? {
currency: roomRate.member.requestedPrice.currency,
price: roomRate.member.requestedPrice.pricePerNight,
}
: undefined,
local: {
currency: roomRate.member.localPrice.currency,
price: roomRate.member.localPrice.pricePerNight,
},
},
perStay: {
requested: roomRate.member.requestedPrice
? {
currency: roomRate.member.requestedPrice.currency,
price: roomRate.member.requestedPrice.pricePerStay,
}
: undefined,
local: {
currency: roomRate.member.localPrice.currency,
price: roomRate.member.localPrice.pricePerStay,
},
},
}
}
if ("public" in roomRate && roomRate.public) {
return {
perNight: {
requested: roomRate.public.requestedPrice
? {
currency: roomRate.public.requestedPrice.currency,
price: roomRate.public.requestedPrice.pricePerNight,
}
: undefined,
local: {
currency: roomRate.public.localPrice.currency,
price: roomRate.public.localPrice.pricePerNight,
regularPrice: roomRate.public.localPrice.regularPricePerNight,
},
},
perStay: {
requested: roomRate.public.requestedPrice
? {
currency: roomRate.public.requestedPrice.currency,
price: roomRate.public.requestedPrice.pricePerStay,
}
: undefined,
local: {
currency: roomRate.public.localPrice.currency,
price: roomRate.public.localPrice.pricePerStay,
regularPrice: roomRate.public.localPrice.regularPricePerStay,
},
},
}
}
if ("corporateCheque" in roomRate) {
return {
perNight: {
requested: roomRate.corporateCheque.requestedPrice
? {
currency: CurrencyEnum.CC,
price: roomRate.corporateCheque.requestedPrice.numberOfCheques,
additionalPrice:
roomRate.corporateCheque.requestedPrice.additionalPricePerStay,
additionalPriceCurrency:
roomRate.corporateCheque.requestedPrice.currency ?? undefined,
}
: undefined,
local: {
currency: CurrencyEnum.CC,
price: roomRate.corporateCheque.localPrice.numberOfCheques,
additionalPrice:
roomRate.corporateCheque.localPrice.additionalPricePerStay,
additionalPriceCurrency:
roomRate.corporateCheque.localPrice.currency ?? undefined,
},
},
perStay: {
requested: roomRate.corporateCheque.requestedPrice
? {
currency: CurrencyEnum.CC,
price: roomRate.corporateCheque.requestedPrice.numberOfCheques,
additionalPrice:
roomRate.corporateCheque.requestedPrice.additionalPricePerStay,
additionalPriceCurrency:
roomRate.corporateCheque.requestedPrice.currency ?? undefined,
}
: undefined,
local: {
currency: CurrencyEnum.CC,
price: roomRate.corporateCheque.localPrice.numberOfCheques,
additionalPrice:
roomRate.corporateCheque.localPrice.additionalPricePerStay,
additionalPriceCurrency:
roomRate.corporateCheque.localPrice.currency ?? undefined,
},
},
}
}
if ("voucher" in roomRate) {
return {
perNight: {
requested: undefined,
local: {
currency: CurrencyEnum.Voucher,
price: roomRate.voucher.numberOfVouchers,
},
},
perStay: {
requested: undefined,
local: {
currency: CurrencyEnum.Voucher,
price: roomRate.voucher.numberOfVouchers,
},
},
}
}
if ("redemption" in roomRate) {
return {
// ToDo Handle perNight as undefined
perNight: {
requested: undefined,
local: {
currency: CurrencyEnum.POINTS,
price: roomRate.redemption.localPrice.pointsPerStay,
additionalPrice:
roomRate.redemption.localPrice.additionalPricePerStay,
additionalPriceCurrency:
roomRate.redemption.localPrice.currency ?? undefined,
},
},
perStay: {
requested: undefined,
local: {
currency: CurrencyEnum.POINTS,
price: roomRate.redemption.localPrice.pointsPerStay,
additionalPrice:
roomRate.redemption.localPrice.additionalPricePerStay,
additionalPriceCurrency:
roomRate.redemption.localPrice.currency ?? undefined,
},
},
}
}
throw new Error(
`Unable to calculate RoomPrice since user is neither a member or memberRate is missing, or publicRate is missing`
)
}
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)
.every((step) => step.isValid)
}
export function readFromSessionStorage(): PersistedState | undefined {
if (typeof window === "undefined") {
return undefined
}
try {
const storedData = sessionStorage.getItem(detailsStorageName)
if (!storedData) {
return undefined
}
const parsedData = JSON.parse(storedData) as PersistedState
if (!parsedData.booking || !parsedData.rooms) {
return undefined
}
return parsedData
} catch (error) {
console.error("Error reading from session storage:", error)
return undefined
}
}
export function writeToSessionStorage(state: PersistedState) {
if (typeof window === "undefined") {
return
}
try {
sessionStorage.setItem(detailsStorageName, JSON.stringify(state))
} catch (error) {
console.error("Error writing to session storage:", error)
}
}
export function clearSessionStorage() {
if (typeof window === "undefined") {
return
}
sessionStorage.removeItem(detailsStorageName)
}