Files
web/stores/enter-details/helpers.ts
2025-01-14 11:09:42 +01:00

314 lines
8.6 KiB
TypeScript

import deepmerge from "deepmerge"
import isEqual from "fast-deep-equal"
import { Lang } from "@/constants/languages"
import { getLang } from "@/i18n/serverContext"
import { arrayMerge } from "@/utils/merge"
import { detailsStorageName } from "."
import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
import { CurrencyEnum } from "@/types/enums/currency"
import type { StepEnum } from "@/types/enums/step"
import type {
DetailsState,
PersistedState,
PersistedStatePart,
RoomRate,
} from "@/types/stores/enter-details"
import type { SafeUser } from "@/types/user"
export function langToCurrency() {
const lang = getLang()
switch (lang) {
case Lang.da:
return CurrencyEnum.DKK
case Lang.de:
case Lang.en:
case Lang.fi:
return CurrencyEnum.EUR
case Lang.no:
return CurrencyEnum.NOK
case Lang.sv:
return CurrencyEnum.SEK
default:
throw new Error(`Unexpected lang: ${lang}`)
}
}
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 navigate(step: StepEnum, searchParams: string) {
window.history.pushState({ step }, "", `${step}?${searchParams}`)
}
export function checkIsSameRoom(
prev: SelectRateSearchParams,
next: SelectRateSearchParams
) {
const { rooms: prevRooms, ...prevBooking } = prev
const prevRoomsWithoutRateCodes = prevRooms.map(
({ rateCode, counterRateCode, ...room }) => room
)
const { rooms: nextRooms, ...nextBooking } = next
const nextRoomsWithoutRateCodes = nextRooms.map(
({ rateCode, counterRateCode, ...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 subtract(...nums: (number | string | undefined)[]) {
return nums.reduce((total: number, num, idx) => {
if (typeof num === "undefined") {
num = 0
}
if (idx === 0) {
return parseInt(`${num}`)
}
total = total - parseInt(`${num}`)
if (total < 0) {
return 0
}
return total
}, 0)
}
export function getInitialRoomPrice(roomRate: RoomRate, isMember: boolean) {
if (isMember && roomRate.memberRate) {
return {
perNight: {
requested: roomRate.memberRate.requestedPrice && {
currency: roomRate.memberRate.requestedPrice.currency,
price: roomRate.memberRate.requestedPrice.pricePerNight,
},
local: {
currency: roomRate.memberRate.localPrice.currency,
price: roomRate.memberRate.localPrice.pricePerNight,
},
},
perStay: {
requested: roomRate.memberRate.requestedPrice && {
currency: roomRate.memberRate.requestedPrice.currency,
price: roomRate.memberRate.requestedPrice.pricePerStay,
},
local: {
currency: roomRate.memberRate.localPrice.currency,
price: roomRate.memberRate.localPrice.pricePerStay,
},
},
}
}
return {
perNight: {
requested: roomRate.publicRate.requestedPrice && {
currency: roomRate.publicRate.requestedPrice.currency,
price: roomRate.publicRate.requestedPrice.pricePerNight,
},
local: {
currency: roomRate.publicRate.localPrice.currency,
price: roomRate.publicRate.localPrice.pricePerNight,
},
},
perStay: {
requested: roomRate.publicRate.requestedPrice && {
currency: roomRate.publicRate.requestedPrice.currency,
price: roomRate.publicRate.requestedPrice.pricePerStay,
},
local: {
currency: roomRate.publicRate.localPrice.currency,
price: roomRate.publicRate.localPrice.pricePerStay,
},
},
}
}
export function getInitialTotalPrice(roomRate: RoomRate, isMember: boolean) {
if (isMember && roomRate.memberRate) {
return {
requested: roomRate.memberRate.requestedPrice && {
currency: roomRate.memberRate.requestedPrice.currency,
price: roomRate.memberRate.requestedPrice.pricePerStay,
},
local: {
currency: roomRate.memberRate.localPrice.currency,
price: roomRate.memberRate.localPrice.pricePerStay,
},
}
}
return {
requested: roomRate.publicRate.requestedPrice && {
currency: roomRate.publicRate.requestedPrice.currency,
price: roomRate.publicRate.requestedPrice.pricePerStay,
},
local: {
currency: roomRate.publicRate.localPrice.currency,
price: roomRate.publicRate.localPrice.pricePerStay,
},
}
}
export function calcTotalMemberPrice(state: DetailsState) {
if (!state.roomRate.memberRate) {
return {
roomPrice: state.roomPrice,
totalPrice: state.totalPrice,
}
}
return calcTotalPrice({
breakfast: state.breakfast,
packages: state.packages,
roomPrice: state.roomPrice,
totalPrice: state.totalPrice,
...state.roomRate.memberRate,
})
}
export function calcTotalPublicPrice(state: DetailsState) {
return calcTotalPrice({
breakfast: state.breakfast,
packages: state.packages,
roomPrice: state.roomPrice,
totalPrice: state.totalPrice,
...state.roomRate.publicRate,
})
}
export function calcTotalPrice(
state: Pick<
DetailsState,
"breakfast" | "packages" | "roomPrice" | "totalPrice"
> &
DetailsState["roomRate"]["publicRate"]
) {
// state is sometimes read-only, thus we
// need to create a deep copy of the values
const roomAndTotalPrice = {
roomPrice: {
perNight: {
local: { ...state.roomPrice.perNight.local },
requested: state.roomPrice.perNight.requested
? { ...state.roomPrice.perNight.requested }
: state.roomPrice.perNight.requested,
},
perStay: {
local: { ...state.roomPrice.perStay.local },
requested: state.roomPrice.perStay.requested
? { ...state.roomPrice.perStay.requested }
: state.roomPrice.perStay.requested,
},
},
totalPrice: {
local: { ...state.totalPrice.local },
requested: state.totalPrice.requested
? { ...state.totalPrice.requested }
: state.totalPrice.requested,
},
}
if (state.requestedPrice?.pricePerStay) {
roomAndTotalPrice.roomPrice.perStay.requested = {
currency: state.requestedPrice.currency,
price: state.requestedPrice.pricePerStay,
}
let totalPriceRequested = state.requestedPrice.pricePerStay
if (state.breakfast) {
totalPriceRequested = add(
totalPriceRequested,
state.breakfast.requestedPrice.totalPrice
)
}
if (state.packages) {
totalPriceRequested = state.packages.reduce((total, pkg) => {
if (pkg.requestedPrice.totalPrice) {
total = add(total, pkg.requestedPrice.totalPrice)
}
return total
}, totalPriceRequested)
}
roomAndTotalPrice.totalPrice.requested = {
currency: state.requestedPrice.currency,
price: totalPriceRequested,
}
}
const roomPriceLocal = state.localPrice
roomAndTotalPrice.roomPrice.perStay.local = {
currency: roomPriceLocal.currency,
price: roomPriceLocal.pricePerStay,
}
let totalPriceLocal = roomPriceLocal.pricePerStay
if (state.breakfast) {
totalPriceLocal = add(
totalPriceLocal,
state.breakfast.localPrice.totalPrice
)
}
if (state.packages) {
totalPriceLocal = state.packages.reduce((total, pkg) => {
if (pkg.localPrice.totalPrice) {
total = add(total, pkg.localPrice.totalPrice)
}
return total
}, totalPriceLocal)
}
roomAndTotalPrice.totalPrice.local = {
currency: roomPriceLocal.currency,
price: totalPriceLocal,
}
return roomAndTotalPrice
}
export function writeToSessionStorage(part: PersistedStatePart) {
const unparsedData = sessionStorage.getItem(detailsStorageName)
if (unparsedData) {
const data: PersistedState = JSON.parse(unparsedData)
// @ts-expect-error - deepmerge is not to happy with
// the part type
const updated = deepmerge(data, part, { arrayMerge })
sessionStorage.setItem(detailsStorageName, JSON.stringify(updated))
} else {
sessionStorage.setItem(detailsStorageName, JSON.stringify(part))
}
}