Merged in chore/cleanup-booking-flow (pull request #2824)
chore: Cleanup booking-flow after migration * Remove unused types * Clean up exports, types, unused files etc in booking-flow Approved-by: Joakim Jäderberg
This commit is contained in:
@@ -5,7 +5,17 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
|
|||||||
|
|
||||||
import styles from "./promo.module.css"
|
import styles from "./promo.module.css"
|
||||||
|
|
||||||
import type { PromoProps } from "@scandic-hotels/booking-flow/types/components/promo/promoProps"
|
type PromoProps = {
|
||||||
|
buttonText: string
|
||||||
|
href: string
|
||||||
|
text: string
|
||||||
|
title: string
|
||||||
|
image?: {
|
||||||
|
src: string
|
||||||
|
altText: string
|
||||||
|
altText_En: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default function Promo({
|
export default function Promo({
|
||||||
buttonText,
|
buttonText,
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
import { createContext } from "react"
|
|
||||||
|
|
||||||
import type { RatesStore } from "@/types/contexts/rates"
|
|
||||||
|
|
||||||
export const RatesContext = createContext<RatesStore | null>(null)
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { usePathname, useSearchParams } from "next/navigation"
|
|
||||||
import { useMemo } from "react"
|
|
||||||
import { useIntl } from "react-intl"
|
|
||||||
|
|
||||||
import { createRatesStore } from "@/stores/select-rate"
|
|
||||||
|
|
||||||
import { RatesContext } from "@/contexts/Rates"
|
|
||||||
|
|
||||||
import type { RatesProviderProps } from "@/types/providers/rates"
|
|
||||||
|
|
||||||
export default function RatesProvider({
|
|
||||||
booking,
|
|
||||||
children,
|
|
||||||
hotelType,
|
|
||||||
roomCategories,
|
|
||||||
roomsAvailability,
|
|
||||||
vat,
|
|
||||||
}: RatesProviderProps) {
|
|
||||||
const pathname = usePathname()
|
|
||||||
const searchParams = useSearchParams()
|
|
||||||
const intl = useIntl()
|
|
||||||
|
|
||||||
const modifyRateIndex = searchParams.has("activeRoomIndex")
|
|
||||||
? Number(searchParams.get("activeRoomIndex"))
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
const store = useMemo(() => {
|
|
||||||
return createRatesStore({
|
|
||||||
booking,
|
|
||||||
hotelType,
|
|
||||||
labels: {
|
|
||||||
accessibilityRoom: intl.formatMessage({
|
|
||||||
defaultMessage: "Accessible room",
|
|
||||||
}),
|
|
||||||
allergyRoom: intl.formatMessage({
|
|
||||||
defaultMessage: "Allergy-friendly room",
|
|
||||||
}),
|
|
||||||
petRoom: intl.formatMessage({
|
|
||||||
defaultMessage: "Pet-friendly room",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
pathname,
|
|
||||||
roomCategories,
|
|
||||||
roomsAvailability,
|
|
||||||
vat,
|
|
||||||
initialActiveRoom: modifyRateIndex,
|
|
||||||
})
|
|
||||||
}, [
|
|
||||||
booking,
|
|
||||||
hotelType,
|
|
||||||
intl,
|
|
||||||
pathname,
|
|
||||||
roomCategories,
|
|
||||||
roomsAvailability,
|
|
||||||
modifyRateIndex,
|
|
||||||
vat,
|
|
||||||
])
|
|
||||||
|
|
||||||
return <RatesContext.Provider value={store}>{children}</RatesContext.Provider>
|
|
||||||
}
|
|
||||||
@@ -1,537 +0,0 @@
|
|||||||
import { produce } from "immer"
|
|
||||||
import { useContext } from "react"
|
|
||||||
import { create, useStore } from "zustand"
|
|
||||||
|
|
||||||
import { BookingCodeFilterEnum } from "@scandic-hotels/booking-flow/stores/bookingCode-filter"
|
|
||||||
import { serializeBookingSearchParams } from "@scandic-hotels/booking-flow/utils/url"
|
|
||||||
import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
|
|
||||||
import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
|
|
||||||
import { AvailabilityEnum } from "@scandic-hotels/trpc/enums/selectHotel"
|
|
||||||
|
|
||||||
import { RatesContext } from "@/contexts/Rates"
|
|
||||||
|
|
||||||
import {
|
|
||||||
findDefaultCurrency,
|
|
||||||
findProductInRoom,
|
|
||||||
findSelectedRate,
|
|
||||||
} from "./helpers"
|
|
||||||
|
|
||||||
import type {
|
|
||||||
InitialState,
|
|
||||||
RatesState,
|
|
||||||
} from "@scandic-hotels/booking-flow/types/stores/rates"
|
|
||||||
import type { Package, Packages } from "@scandic-hotels/trpc/types/packages"
|
|
||||||
import type { PriceProduct } from "@scandic-hotels/trpc/types/roomAvailability"
|
|
||||||
|
|
||||||
export function createRatesStore({
|
|
||||||
booking,
|
|
||||||
hotelType,
|
|
||||||
labels,
|
|
||||||
pathname,
|
|
||||||
roomCategories,
|
|
||||||
roomsAvailability,
|
|
||||||
initialActiveRoom,
|
|
||||||
vat,
|
|
||||||
}: InitialState) {
|
|
||||||
function updateUrl(booking: RatesState["booking"], activeRoom: number = -1) {
|
|
||||||
const searchParams = serializeBookingSearchParams(booking, {
|
|
||||||
initialSearchParams: new URLSearchParams(window.location.search),
|
|
||||||
})
|
|
||||||
if (activeRoom >= 0) {
|
|
||||||
searchParams.set("modifyRateIndex", activeRoom.toString())
|
|
||||||
} else {
|
|
||||||
searchParams.delete("modifyRateIndex")
|
|
||||||
}
|
|
||||||
window.history.replaceState({}, "", `${pathname}?${searchParams}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const packageOptions = [
|
|
||||||
{
|
|
||||||
code: RoomPackageCodeEnum.ACCESSIBILITY_ROOM,
|
|
||||||
description: labels.accessibilityRoom,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: RoomPackageCodeEnum.ALLERGY_ROOM,
|
|
||||||
description: labels.allergyRoom,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: RoomPackageCodeEnum.PET_ROOM,
|
|
||||||
description: labels.petRoom,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const roomsPackages: NonNullable<Packages>[] = []
|
|
||||||
const roomConfigurations: RatesState["roomConfigurations"] = []
|
|
||||||
if (roomsAvailability) {
|
|
||||||
for (const availability of roomsAvailability) {
|
|
||||||
if ("error" in availability) {
|
|
||||||
// Availability request failed, default to empty array
|
|
||||||
roomConfigurations.push([])
|
|
||||||
roomsPackages.push([])
|
|
||||||
} else {
|
|
||||||
roomConfigurations.push(availability.roomConfigurations)
|
|
||||||
roomsPackages.push(availability.packages)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const rateSummary: RatesState["rateSummary"] = []
|
|
||||||
for (const [idx, room] of booking.rooms.entries()) {
|
|
||||||
if (room.rateCode && room.roomTypeCode) {
|
|
||||||
const roomConfiguration = roomConfigurations?.[idx]
|
|
||||||
|
|
||||||
const selectedRoom = findSelectedRate(
|
|
||||||
room.rateCode,
|
|
||||||
room.counterRateCode,
|
|
||||||
room.roomTypeCode,
|
|
||||||
roomConfiguration
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!selectedRoom) {
|
|
||||||
booking.rooms[idx] = roomWithoutSelection(room)
|
|
||||||
updateUrl(booking)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const product = findProductInRoom(
|
|
||||||
room.rateCode,
|
|
||||||
selectedRoom,
|
|
||||||
room.counterRateCode
|
|
||||||
)
|
|
||||||
if (product) {
|
|
||||||
const roomPackages = roomsPackages[idx].filter((pkg) =>
|
|
||||||
room.packages?.includes(pkg.code)
|
|
||||||
)
|
|
||||||
|
|
||||||
rateSummary[idx] = {
|
|
||||||
features: selectedRoom.features,
|
|
||||||
product,
|
|
||||||
packages: roomPackages,
|
|
||||||
rate: product.rate,
|
|
||||||
roomType: selectedRoom.roomType,
|
|
||||||
roomTypeCode: selectedRoom.roomTypeCode,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rateSummary[idx] = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let activeRoom = rateSummary.length
|
|
||||||
if (initialActiveRoom !== undefined && initialActiveRoom >= 0) {
|
|
||||||
activeRoom = initialActiveRoom
|
|
||||||
} else if (rateSummary.length === booking.rooms.length) {
|
|
||||||
// Finds the first unselected room and sets that to active
|
|
||||||
// if no unselected rooms it will return -1 and close all rooms
|
|
||||||
const unselectedRoomIndex = rateSummary.findIndex((rate) => !rate)
|
|
||||||
activeRoom = unselectedRoomIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
const isRedemptionBooking = booking.searchType === SEARCH_TYPE_REDEMPTION
|
|
||||||
|
|
||||||
const defaultCurrency = findDefaultCurrency(roomsAvailability)
|
|
||||||
|
|
||||||
return create<RatesState>()((set) => {
|
|
||||||
return {
|
|
||||||
activeRoom,
|
|
||||||
booking,
|
|
||||||
packageOptions,
|
|
||||||
hotelType,
|
|
||||||
isRedemptionBooking,
|
|
||||||
rateSummary,
|
|
||||||
roomConfigurations,
|
|
||||||
roomCategories,
|
|
||||||
roomsPackages,
|
|
||||||
roomsAvailability,
|
|
||||||
vat,
|
|
||||||
defaultCurrency,
|
|
||||||
rooms: booking.rooms.map((room, idx) => {
|
|
||||||
const roomConfiguration = roomConfigurations[idx]
|
|
||||||
const roomPackages = roomsPackages[idx]
|
|
||||||
const selectedPackages =
|
|
||||||
room.packages
|
|
||||||
?.map((code) => roomPackages.find((pkg) => pkg.code === code))
|
|
||||||
.filter((pkg): pkg is Package => Boolean(pkg)) ?? []
|
|
||||||
|
|
||||||
const selectedRate =
|
|
||||||
findSelectedRate(
|
|
||||||
room.rateCode,
|
|
||||||
room.counterRateCode,
|
|
||||||
room.roomTypeCode,
|
|
||||||
roomConfiguration
|
|
||||||
) ?? null
|
|
||||||
|
|
||||||
let product = null
|
|
||||||
if (selectedRate) {
|
|
||||||
product = findProductInRoom(
|
|
||||||
room.rateCode,
|
|
||||||
selectedRate,
|
|
||||||
room.counterRateCode
|
|
||||||
)
|
|
||||||
}
|
|
||||||
const bookingCode = room.rateCode
|
|
||||||
? room.bookingCode
|
|
||||||
: booking.bookingCode
|
|
||||||
const selectedFilter =
|
|
||||||
bookingCode && !isRedemptionBooking
|
|
||||||
? BookingCodeFilterEnum.Discounted
|
|
||||||
: BookingCodeFilterEnum.All
|
|
||||||
|
|
||||||
return {
|
|
||||||
actions: {
|
|
||||||
appendRegularRates(roomConfigurations) {
|
|
||||||
return set(
|
|
||||||
produce((state: RatesState) => {
|
|
||||||
state.rooms[idx].isFetchingAdditionalRate = false
|
|
||||||
if (roomConfigurations) {
|
|
||||||
const rooms = state.rooms[idx].rooms
|
|
||||||
const updatedRooms = rooms.map((currentRoom) => {
|
|
||||||
const incomingRoom = roomConfigurations.find(
|
|
||||||
(room) =>
|
|
||||||
room.roomType === currentRoom.roomType &&
|
|
||||||
room.roomTypeCode === currentRoom.roomTypeCode
|
|
||||||
)
|
|
||||||
|
|
||||||
if (incomingRoom) {
|
|
||||||
let campaign = currentRoom.campaign
|
|
||||||
if (incomingRoom.campaign.length) {
|
|
||||||
const newCampaign = [
|
|
||||||
...campaign,
|
|
||||||
...incomingRoom.campaign,
|
|
||||||
].reduce((cpns, cpn) => {
|
|
||||||
if (cpns.has(cpn.rateDefinition.rateCode)) {
|
|
||||||
return cpns
|
|
||||||
}
|
|
||||||
cpns.set(cpn.rateDefinition.rateCode, cpn)
|
|
||||||
return cpns
|
|
||||||
}, new Map<string, PriceProduct>())
|
|
||||||
campaign = Array.from(newCampaign.values())
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentRoomAvailable =
|
|
||||||
currentRoom.status === AvailabilityEnum.Available
|
|
||||||
const incomingRoomAvailable =
|
|
||||||
incomingRoom.status === AvailabilityEnum.Available
|
|
||||||
let status = AvailabilityEnum.NotAvailable
|
|
||||||
if (currentRoomAvailable || incomingRoomAvailable) {
|
|
||||||
status = AvailabilityEnum.Available
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...currentRoom,
|
|
||||||
campaign,
|
|
||||||
products: [
|
|
||||||
...currentRoom.products,
|
|
||||||
...incomingRoom.products,
|
|
||||||
],
|
|
||||||
regular: incomingRoom.regular,
|
|
||||||
status,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentRoom
|
|
||||||
})
|
|
||||||
|
|
||||||
state.rooms[idx].rooms = updatedRooms
|
|
||||||
} else {
|
|
||||||
state.rooms[idx].rooms = []
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
},
|
|
||||||
closeSection() {
|
|
||||||
return set(
|
|
||||||
produce((state: RatesState) => {
|
|
||||||
if (state.rateSummary.length === state.booking.rooms.length) {
|
|
||||||
state.activeRoom = -1
|
|
||||||
} else {
|
|
||||||
state.activeRoom = idx + 1
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifyRate() {
|
|
||||||
return set(
|
|
||||||
produce((state: RatesState) => {
|
|
||||||
state.activeRoom = idx
|
|
||||||
})
|
|
||||||
)
|
|
||||||
},
|
|
||||||
removeSelectedPackage(code) {
|
|
||||||
return set(
|
|
||||||
produce((state: RatesState) => {
|
|
||||||
state.rooms[idx].isFetchingPackages = true
|
|
||||||
const filteredSelectedPackages = state.rooms[
|
|
||||||
idx
|
|
||||||
].selectedPackages.filter((c) => c.code !== code)
|
|
||||||
state.rooms[idx].selectedPackages = filteredSelectedPackages
|
|
||||||
|
|
||||||
if (
|
|
||||||
state.rooms[idx].selectedRate?.product.bookingCode ||
|
|
||||||
state.booking.bookingCode
|
|
||||||
) {
|
|
||||||
state.rooms[idx].selectedFilter =
|
|
||||||
BookingCodeFilterEnum.Discounted
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filteredSelectedPackages.length) {
|
|
||||||
state.booking.rooms[idx].packages =
|
|
||||||
filteredSelectedPackages.map((pkg) => pkg.code)
|
|
||||||
} else {
|
|
||||||
state.booking.rooms[idx].packages = null
|
|
||||||
}
|
|
||||||
|
|
||||||
updateUrl(state.booking, state.activeRoom)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
},
|
|
||||||
removeSelectedPackages() {
|
|
||||||
return set(
|
|
||||||
produce((state: RatesState) => {
|
|
||||||
state.rooms[idx].isFetchingPackages = true
|
|
||||||
state.rooms[idx].selectedPackages = []
|
|
||||||
|
|
||||||
if (
|
|
||||||
state.rooms[idx].selectedRate?.product.bookingCode ||
|
|
||||||
state.booking.bookingCode
|
|
||||||
) {
|
|
||||||
state.rooms[idx].selectedFilter =
|
|
||||||
BookingCodeFilterEnum.Discounted
|
|
||||||
}
|
|
||||||
|
|
||||||
state.booking.rooms[idx].packages = null
|
|
||||||
updateUrl(state.booking, state.activeRoom)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
},
|
|
||||||
selectFilter(filter) {
|
|
||||||
return set(
|
|
||||||
produce((state: RatesState) => {
|
|
||||||
state.rooms[idx].selectedFilter = filter
|
|
||||||
state.rooms[idx].isFetchingAdditionalRate =
|
|
||||||
filter === BookingCodeFilterEnum.All
|
|
||||||
})
|
|
||||||
)
|
|
||||||
},
|
|
||||||
selectRate(selectedRate, isUserLoggedIn) {
|
|
||||||
return set(
|
|
||||||
produce((state: RatesState) => {
|
|
||||||
if (!selectedRate.product) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
state.rooms[idx].selectedRate = selectedRate
|
|
||||||
state.rateSummary[idx] = {
|
|
||||||
features: selectedRate.features,
|
|
||||||
packages: state.rooms[idx].selectedPackages,
|
|
||||||
product: selectedRate.product,
|
|
||||||
rate: selectedRate.product.rate,
|
|
||||||
roomType: selectedRate.roomType,
|
|
||||||
roomTypeCode: selectedRate.roomTypeCode,
|
|
||||||
}
|
|
||||||
|
|
||||||
const roomNr = idx + 1
|
|
||||||
const isMainRoom = roomNr === 1
|
|
||||||
|
|
||||||
let productRateCode = ""
|
|
||||||
if ("corporateCheque" in selectedRate.product) {
|
|
||||||
productRateCode =
|
|
||||||
selectedRate.product.corporateCheque.rateCode
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("redemption" in selectedRate.product) {
|
|
||||||
productRateCode = selectedRate.product.redemption.rateCode
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("voucher" in selectedRate.product) {
|
|
||||||
productRateCode = selectedRate.product.voucher.rateCode
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
"public" in selectedRate.product &&
|
|
||||||
selectedRate.product.public
|
|
||||||
) {
|
|
||||||
productRateCode = selectedRate.product.public.rateCode
|
|
||||||
}
|
|
||||||
|
|
||||||
let hasMemberRate = false
|
|
||||||
let memberRateCode = ""
|
|
||||||
if (
|
|
||||||
"member" in selectedRate.product &&
|
|
||||||
selectedRate.product.member
|
|
||||||
) {
|
|
||||||
hasMemberRate = true
|
|
||||||
memberRateCode = selectedRate.product.member.rateCode
|
|
||||||
}
|
|
||||||
|
|
||||||
const isMemberRate =
|
|
||||||
isUserLoggedIn && isMainRoom && hasMemberRate
|
|
||||||
|
|
||||||
state.rooms[idx].bookingRoom.rateCode = isMemberRate
|
|
||||||
? memberRateCode
|
|
||||||
: productRateCode
|
|
||||||
if (!isMemberRate && hasMemberRate) {
|
|
||||||
state.rooms[idx].bookingRoom.counterRateCode =
|
|
||||||
memberRateCode
|
|
||||||
}
|
|
||||||
state.rooms[idx].bookingRoom.roomTypeCode =
|
|
||||||
selectedRate.roomTypeCode
|
|
||||||
state.rooms[idx].bookingRoom.bookingCode =
|
|
||||||
selectedRate.product.bookingCode
|
|
||||||
|
|
||||||
const counterratecode = isMemberRate
|
|
||||||
? productRateCode
|
|
||||||
: memberRateCode
|
|
||||||
if (counterratecode) {
|
|
||||||
state.booking.rooms[idx].counterRateCode = counterratecode
|
|
||||||
} else {
|
|
||||||
state.booking.rooms[idx].counterRateCode = null
|
|
||||||
}
|
|
||||||
|
|
||||||
const rateCode = isMemberRate
|
|
||||||
? memberRateCode
|
|
||||||
: productRateCode
|
|
||||||
if (rateCode) {
|
|
||||||
state.booking.rooms[idx].rateCode = rateCode
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedRate.product.bookingCode) {
|
|
||||||
state.booking.rooms[idx].bookingCode =
|
|
||||||
selectedRate.product.bookingCode
|
|
||||||
} else {
|
|
||||||
if (state.booking.rooms[idx].bookingCode) {
|
|
||||||
state.booking.rooms[idx].bookingCode = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state.booking.rooms[idx].roomTypeCode =
|
|
||||||
selectedRate.roomTypeCode
|
|
||||||
|
|
||||||
if (state.rateSummary.length === state.booking.rooms.length) {
|
|
||||||
state.activeRoom = -1
|
|
||||||
} else {
|
|
||||||
state.activeRoom = idx + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
updateUrl(state.booking)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
},
|
|
||||||
selectPackages(selectedPackages) {
|
|
||||||
return set(
|
|
||||||
produce((state: RatesState) => {
|
|
||||||
state.rooms[idx].isFetchingPackages = true
|
|
||||||
const pkgs = state.roomsPackages[idx].filter((pkg) =>
|
|
||||||
selectedPackages.includes(pkg.code)
|
|
||||||
)
|
|
||||||
state.rooms[idx].selectedPackages = pkgs
|
|
||||||
|
|
||||||
if (
|
|
||||||
state.rooms[idx].selectedRate?.product.bookingCode ||
|
|
||||||
state.booking.bookingCode
|
|
||||||
) {
|
|
||||||
state.rooms[idx].selectedFilter =
|
|
||||||
BookingCodeFilterEnum.Discounted
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedPackages.length) {
|
|
||||||
state.booking.rooms[idx].packages = selectedPackages
|
|
||||||
} else {
|
|
||||||
state.booking.rooms[idx].packages = null
|
|
||||||
}
|
|
||||||
|
|
||||||
updateUrl(state.booking, state.activeRoom)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
},
|
|
||||||
updateRooms(rooms) {
|
|
||||||
return set(
|
|
||||||
produce((state: RatesState) => {
|
|
||||||
state.rooms[idx].isFetchingPackages = false
|
|
||||||
if (rooms) {
|
|
||||||
state.rooms[idx].rooms = rooms
|
|
||||||
const rateSummaryRoom = state.rateSummary[idx]
|
|
||||||
if (rateSummaryRoom) {
|
|
||||||
const room = state.rooms[idx].bookingRoom
|
|
||||||
const selectedRoom = findSelectedRate(
|
|
||||||
room.rateCode,
|
|
||||||
room.counterRateCode,
|
|
||||||
room.roomTypeCode,
|
|
||||||
rooms
|
|
||||||
)
|
|
||||||
|
|
||||||
if (selectedRoom) {
|
|
||||||
rateSummaryRoom.packages =
|
|
||||||
state.rooms[idx].selectedPackages
|
|
||||||
} else {
|
|
||||||
state.booking.rooms[idx] = roomWithoutSelection(
|
|
||||||
state.booking.rooms[idx]
|
|
||||||
)
|
|
||||||
|
|
||||||
state.rateSummary[idx] = null
|
|
||||||
state.rooms[idx].selectedRate = null
|
|
||||||
|
|
||||||
updateUrl(state.booking)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
state.rooms[idx].rooms = []
|
|
||||||
if (state.rateSummary[idx]) {
|
|
||||||
state.booking.rooms[idx] = roomWithoutSelection(
|
|
||||||
state.booking.rooms[idx]
|
|
||||||
)
|
|
||||||
|
|
||||||
state.rateSummary[idx] = null
|
|
||||||
state.rooms[idx].selectedRate = null
|
|
||||||
|
|
||||||
updateUrl(state.booking)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
bookingRoom: room,
|
|
||||||
isFetchingAdditionalRate: false,
|
|
||||||
isFetchingPackages: false,
|
|
||||||
rooms: roomConfiguration,
|
|
||||||
selectedFilter,
|
|
||||||
selectedPackages,
|
|
||||||
selectedRate:
|
|
||||||
selectedRate && product
|
|
||||||
? {
|
|
||||||
features: selectedRate.features,
|
|
||||||
packages: selectedPackages,
|
|
||||||
product,
|
|
||||||
roomType: selectedRate.roomType,
|
|
||||||
roomTypeCode: selectedRate.roomTypeCode,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useRatesStore<T>(selector: (store: RatesState) => T) {
|
|
||||||
const store = useContext(RatesContext)
|
|
||||||
|
|
||||||
if (!store) {
|
|
||||||
throw new Error("useRatesStore must be used within RatesProvider")
|
|
||||||
}
|
|
||||||
|
|
||||||
return useStore(store, selector)
|
|
||||||
}
|
|
||||||
|
|
||||||
function roomWithoutSelection(
|
|
||||||
room: RatesState["booking"]["rooms"][number]
|
|
||||||
): RatesState["booking"]["rooms"][number] {
|
|
||||||
return {
|
|
||||||
...room,
|
|
||||||
rateCode: null,
|
|
||||||
counterRateCode: null,
|
|
||||||
roomTypeCode: null,
|
|
||||||
bookingCode: null,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
import type { BookingSearchType } from "@scandic-hotels/booking-flow/searchType"
|
|
||||||
import type { Child } from "@scandic-hotels/trpc/types/child"
|
|
||||||
import type { PackageEnum } from "@scandic-hotels/trpc/types/packages"
|
|
||||||
import type { Product } from "@scandic-hotels/trpc/types/roomAvailability"
|
import type { Product } from "@scandic-hotels/trpc/types/roomAvailability"
|
||||||
|
|
||||||
import type { Price } from "../price"
|
import type { Price } from "../price"
|
||||||
@@ -11,21 +8,3 @@ export interface RoomPrice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type RoomRate = Product
|
export type RoomRate = Product
|
||||||
|
|
||||||
export type DetailsBooking = {
|
|
||||||
hotelId: string
|
|
||||||
fromDate: string
|
|
||||||
toDate: string
|
|
||||||
city?: string
|
|
||||||
bookingCode?: string
|
|
||||||
searchType?: BookingSearchType
|
|
||||||
rooms: {
|
|
||||||
adults: number
|
|
||||||
rateCode: string
|
|
||||||
roomTypeCode: string
|
|
||||||
bookingCode?: string
|
|
||||||
childrenInRoom?: Child[]
|
|
||||||
counterRateCode?: string
|
|
||||||
packages?: PackageEnum[]
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
import type { createRatesStore } from "@/stores/select-rate"
|
|
||||||
|
|
||||||
export type RatesStore = ReturnType<typeof createRatesStore>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
|
||||||
import type { BreakfastPackages } from "@scandic-hotels/trpc/routers/hotels/output"
|
|
||||||
import type { RoomCategories } from "@scandic-hotels/trpc/types/hotel"
|
|
||||||
import type { Room } from "@scandic-hotels/trpc/types/room"
|
|
||||||
|
|
||||||
import type { SafeUser } from "@/types/user"
|
|
||||||
import type { DetailsBooking } from "../components/hotelReservation/enterDetails/details"
|
|
||||||
@@ -17,7 +17,7 @@ import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConf
|
|||||||
import type { EventAttributes } from "ics"
|
import type { EventAttributes } from "ics"
|
||||||
import type { MutableRefObject } from "react"
|
import type { MutableRefObject } from "react"
|
||||||
|
|
||||||
export interface BookingConfirmationHeaderProps
|
interface BookingConfirmationHeaderProps
|
||||||
extends Pick<BookingConfirmation, "booking" | "hotel"> {
|
extends Pick<BookingConfirmation, "booking" | "hotel"> {
|
||||||
mainRef: MutableRefObject<HTMLElement | null>
|
mainRef: MutableRefObject<HTMLElement | null>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,17 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
|
|||||||
|
|
||||||
import styles from "./promo.module.css"
|
import styles from "./promo.module.css"
|
||||||
|
|
||||||
import type { PromoProps } from "../../../../types/components/promo/promoProps"
|
type PromoProps = {
|
||||||
|
buttonText: string
|
||||||
|
href: string
|
||||||
|
text: string
|
||||||
|
title: string
|
||||||
|
image?: {
|
||||||
|
src: string
|
||||||
|
altText: string
|
||||||
|
altText_En: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function Promo({ buttonText, href, text, title }: PromoProps) {
|
export function Promo({ buttonText, href, text, title }: PromoProps) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConf
|
|||||||
|
|
||||||
import type { AdditionalInfoCookieValue } from "../../../types/components/findMyBooking/additionalInfoCookieValue"
|
import type { AdditionalInfoCookieValue } from "../../../types/components/findMyBooking/additionalInfoCookieValue"
|
||||||
|
|
||||||
export type PromosProps = Pick<BookingConfirmation, "booking">
|
type PromosProps = Pick<BookingConfirmation, "booking">
|
||||||
|
|
||||||
export function Promos({ booking }: PromosProps) {
|
export function Promos({ booking }: PromosProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
|
|||||||
|
|
||||||
import styles from "./retry.module.css"
|
import styles from "./retry.module.css"
|
||||||
|
|
||||||
export interface RetryProps {
|
interface RetryProps {
|
||||||
handleRefetch: () => void
|
handleRefetch: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { Room } from "../Room"
|
|||||||
import { LinkedReservationCardSkeleton } from "./LinkedReservationCardSkeleton"
|
import { LinkedReservationCardSkeleton } from "./LinkedReservationCardSkeleton"
|
||||||
import Retry from "./Retry"
|
import Retry from "./Retry"
|
||||||
|
|
||||||
export interface LinkedReservationProps {
|
interface LinkedReservationProps {
|
||||||
checkInTime: string
|
checkInTime: string
|
||||||
checkOutTime: string
|
checkOutTime: string
|
||||||
refId: string
|
refId: string
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import styles from "./room.module.css"
|
|||||||
|
|
||||||
import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConfirmation"
|
import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConfirmation"
|
||||||
|
|
||||||
export interface RoomProps {
|
interface RoomProps {
|
||||||
booking: BookingConfirmation["booking"]
|
booking: BookingConfirmation["booking"]
|
||||||
checkInTime: string
|
checkInTime: string
|
||||||
checkOutTime: string
|
checkOutTime: string
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import styles from "./rooms.module.css"
|
|||||||
import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConfirmation"
|
import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConfirmation"
|
||||||
import type { Room as RoomProp } from "@scandic-hotels/trpc/types/hotel"
|
import type { Room as RoomProp } from "@scandic-hotels/trpc/types/hotel"
|
||||||
|
|
||||||
export interface BookingConfirmationRoomsProps
|
interface BookingConfirmationRoomsProps
|
||||||
extends Pick<BookingConfirmation, "booking"> {
|
extends Pick<BookingConfirmation, "booking"> {
|
||||||
mainRoom: RoomProp & {
|
mainRoom: RoomProp & {
|
||||||
bedType: RoomProp["roomTypes"][number]
|
bedType: RoomProp["roomTypes"][number]
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const bookingWidgetErrors = {
|
|||||||
"CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE",
|
"CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE",
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export const guestRoomSchema = z
|
const guestRoomSchema = z
|
||||||
.object({
|
.object({
|
||||||
adults: z.number().default(1),
|
adults: z.number().default(1),
|
||||||
childrenInRoom: z
|
childrenInRoom: z
|
||||||
@@ -45,7 +45,7 @@ export const guestRoomSchema = z
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const guestRoomsSchema = z.array(guestRoomSchema)
|
const guestRoomsSchema = z.array(guestRoomSchema)
|
||||||
|
|
||||||
export const bookingCodeSchema = z
|
export const bookingCodeSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import useLang from "../../../../../hooks/useLang"
|
|||||||
|
|
||||||
import styles from "./joinScandicFriendsCard.module.css"
|
import styles from "./joinScandicFriendsCard.module.css"
|
||||||
|
|
||||||
export type JoinScandicFriendsCardProps = {
|
type JoinScandicFriendsCardProps = {
|
||||||
name?: string
|
name?: string
|
||||||
}
|
}
|
||||||
export default function JoinScandicFriendsCard({
|
export default function JoinScandicFriendsCard({
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const stringMatcher =
|
|||||||
|
|
||||||
const isValidString = (key: string) => stringMatcher.test(key)
|
const isValidString = (key: string) => stringMatcher.test(key)
|
||||||
|
|
||||||
export const baseDetailsSchema = z.object({
|
const baseDetailsSchema = z.object({
|
||||||
countryCode: z.string().min(1, roomOneErrors.COUNTRY_REQUIRED),
|
countryCode: z.string().min(1, roomOneErrors.COUNTRY_REQUIRED),
|
||||||
email: z.string().email(roomOneErrors.EMAIL_REQUIRED),
|
email: z.string().email(roomOneErrors.EMAIL_REQUIRED),
|
||||||
firstName: z
|
firstName: z
|
||||||
@@ -31,7 +31,7 @@ export const baseDetailsSchema = z.object({
|
|||||||
specialRequest: specialRequestSchema,
|
specialRequest: specialRequestSchema,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notJoinDetailsSchema = baseDetailsSchema.merge(
|
const notJoinDetailsSchema = baseDetailsSchema.merge(
|
||||||
z.object({
|
z.object({
|
||||||
join: z.literal<boolean>(false),
|
join: z.literal<boolean>(false),
|
||||||
zipCode: z.string().optional(),
|
zipCode: z.string().optional(),
|
||||||
@@ -54,7 +54,7 @@ export const notJoinDetailsSchema = baseDetailsSchema.merge(
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
export const joinDetailsSchema = baseDetailsSchema.merge(
|
const joinDetailsSchema = baseDetailsSchema.merge(
|
||||||
z.object({
|
z.object({
|
||||||
join: z.literal<boolean>(true),
|
join: z.literal<boolean>(true),
|
||||||
zipCode: z
|
zipCode: z
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
export enum FloorPreference {
|
enum FloorPreference {
|
||||||
LOW = "Low floor",
|
LOW = "Low floor",
|
||||||
HIGH = "High floor",
|
HIGH = "High floor",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ElevatorPreference {
|
enum ElevatorPreference {
|
||||||
AWAY_FROM_ELEVATOR = "Away from elevator",
|
AWAY_FROM_ELEVATOR = "Away from elevator",
|
||||||
NEAR_ELEVATOR = "Near elevator",
|
NEAR_ELEVATOR = "Near elevator",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import styles from "./header.module.css"
|
|||||||
|
|
||||||
import type { HotelData } from "@scandic-hotels/trpc/types/hotel"
|
import type { HotelData } from "@scandic-hotels/trpc/types/hotel"
|
||||||
|
|
||||||
export type HotelHeaderProps = {
|
type HotelHeaderProps = {
|
||||||
hotelData: HotelData & { url: string | null }
|
hotelData: HotelData & { url: string | null }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ import type { PriceChangeData } from "../PriceChangeData"
|
|||||||
const maxRetries = 15
|
const maxRetries = 15
|
||||||
const retryInterval = 2000
|
const retryInterval = 2000
|
||||||
|
|
||||||
export type PaymentClientProps = {
|
type PaymentClientProps = {
|
||||||
otherPaymentOptions: PaymentMethodEnum[]
|
otherPaymentOptions: PaymentMethodEnum[]
|
||||||
savedCreditCards: CreditCard[] | null
|
savedCreditCards: CreditCard[] | null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { EnterDetailsStepEnum } from "../../../stores/enter-details/enterDetails
|
|||||||
|
|
||||||
import styles from "./section.module.css"
|
import styles from "./section.module.css"
|
||||||
|
|
||||||
export type SectionProps = {
|
type SectionProps = {
|
||||||
header: string
|
header: string
|
||||||
label: string
|
label: string
|
||||||
additionalInfo?: string | null
|
additionalInfo?: string | null
|
||||||
|
|||||||
@@ -11,15 +11,3 @@ export function getMemberPrice(roomRate: Product) {
|
|||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPublicPrice(roomRate: Product) {
|
|
||||||
if ("public" in roomRate && roomRate.public) {
|
|
||||||
return {
|
|
||||||
amount: roomRate.public.localPrice.pricePerStay,
|
|
||||||
currency: roomRate.public.localPrice.currency,
|
|
||||||
pricePerNight: roomRate.public.localPrice.pricePerNight,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ type RoomPrice =
|
|||||||
| RedemptionPriceType
|
| RedemptionPriceType
|
||||||
| VoucherPriceType
|
| VoucherPriceType
|
||||||
|
|
||||||
export interface Room {
|
interface Room {
|
||||||
adults: number
|
adults: number
|
||||||
bedType:
|
bedType:
|
||||||
| {
|
| {
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
export { default as FilterAndSortModal } from "./FilterAndSortModal"
|
|
||||||
export { default as HotelFilter } from "./HotelFilter"
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { HotelPin } from "../../../HotelCardDialogListing/utils"
|
import type { HotelPin } from "../../../HotelCardDialogListing/utils"
|
||||||
import type { HotelResponse } from "../../helpers"
|
import type { HotelResponse } from "../../helpers"
|
||||||
|
|
||||||
export function getVisibleHotelPins(
|
function getVisibleHotelPins(
|
||||||
map: google.maps.Map | null,
|
map: google.maps.Map | null,
|
||||||
filteredHotelPins: HotelPin[]
|
filteredHotelPins: HotelPin[]
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import styles from "./summaryContent.module.css"
|
|||||||
|
|
||||||
import type { Price } from "../../../../../../types/price"
|
import type { Price } from "../../../../../../types/price"
|
||||||
|
|
||||||
export type SelectRateSummaryProps = {
|
type SelectRateSummaryProps = {
|
||||||
isUserLoggedIn: boolean
|
isUserLoggedIn: boolean
|
||||||
bookingCode?: string
|
bookingCode?: string
|
||||||
toggleSummaryOpen: () => void
|
toggleSummaryOpen: () => void
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
|
||||||
|
|
||||||
import type { Packages } from "@scandic-hotels/trpc/types/packages"
|
|
||||||
|
|
||||||
import type {
|
|
||||||
Rate,
|
|
||||||
Room,
|
|
||||||
} from "../../../../../types/components/selectRate/selectRate"
|
|
||||||
import type { Price } from "../../../../../types/price"
|
|
||||||
|
|
||||||
export function mapRate(
|
|
||||||
room: Rate,
|
|
||||||
index: number,
|
|
||||||
bookingRooms: Room[],
|
|
||||||
packages: NonNullable<Packages>
|
|
||||||
) {
|
|
||||||
const rate = {
|
|
||||||
adults: bookingRooms[index].adults,
|
|
||||||
cancellationText: room.product.rateDefinition?.cancellationText ?? "",
|
|
||||||
childrenInRoom: bookingRooms[index].childrenInRoom ?? undefined,
|
|
||||||
rateDetails: room.product.rateDefinition?.generalTerms,
|
|
||||||
roomPrice: {
|
|
||||||
currency: CurrencyEnum.Unknown,
|
|
||||||
perNight: <Price>{
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.Unknown,
|
|
||||||
price: 0,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
},
|
|
||||||
perStay: <Price>{
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.Unknown,
|
|
||||||
price: 0,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
roomRate: room.product,
|
|
||||||
roomType: room.roomType,
|
|
||||||
packages,
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("corporateCheque" in room.product) {
|
|
||||||
rate.roomPrice.currency = CurrencyEnum.CC
|
|
||||||
rate.roomPrice.perNight.local = {
|
|
||||||
currency: CurrencyEnum.CC,
|
|
||||||
price: room.product.corporateCheque.localPrice.numberOfCheques,
|
|
||||||
additionalPrice:
|
|
||||||
room.product.corporateCheque.localPrice.additionalPricePerStay,
|
|
||||||
additionalPriceCurrency:
|
|
||||||
room.product.corporateCheque.localPrice.currency ??
|
|
||||||
CurrencyEnum.Unknown,
|
|
||||||
}
|
|
||||||
rate.roomPrice.perStay.local = {
|
|
||||||
currency: CurrencyEnum.CC,
|
|
||||||
price: room.product.corporateCheque.localPrice.numberOfCheques,
|
|
||||||
additionalPrice:
|
|
||||||
room.product.corporateCheque.localPrice.additionalPricePerStay,
|
|
||||||
additionalPriceCurrency:
|
|
||||||
room.product.corporateCheque.localPrice.currency ??
|
|
||||||
CurrencyEnum.Unknown,
|
|
||||||
}
|
|
||||||
} else if ("redemption" in room.product) {
|
|
||||||
rate.roomPrice.currency = CurrencyEnum.POINTS
|
|
||||||
rate.roomPrice.perNight.local = {
|
|
||||||
currency: CurrencyEnum.POINTS,
|
|
||||||
price: room.product.redemption.localPrice.pointsPerNight,
|
|
||||||
additionalPrice:
|
|
||||||
room.product.redemption.localPrice.additionalPricePerStay,
|
|
||||||
additionalPriceCurrency:
|
|
||||||
room.product.redemption.localPrice.currency ?? CurrencyEnum.Unknown,
|
|
||||||
}
|
|
||||||
rate.roomPrice.perStay.local = {
|
|
||||||
currency: CurrencyEnum.POINTS,
|
|
||||||
price: room.product.redemption.localPrice.pointsPerStay,
|
|
||||||
additionalPrice:
|
|
||||||
room.product.redemption.localPrice.additionalPricePerStay,
|
|
||||||
additionalPriceCurrency:
|
|
||||||
room.product.redemption.localPrice.currency ?? CurrencyEnum.Unknown,
|
|
||||||
}
|
|
||||||
} else if ("voucher" in room.product) {
|
|
||||||
rate.roomPrice.currency = CurrencyEnum.Voucher
|
|
||||||
rate.roomPrice.perNight.local = {
|
|
||||||
currency: CurrencyEnum.Voucher,
|
|
||||||
price: room.product.voucher.numberOfVouchers,
|
|
||||||
}
|
|
||||||
rate.roomPrice.perStay.local = {
|
|
||||||
currency: CurrencyEnum.Voucher,
|
|
||||||
price: room.product.voucher.numberOfVouchers,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const currency =
|
|
||||||
room.product.public?.localPrice.currency ||
|
|
||||||
room.product.member?.localPrice.currency ||
|
|
||||||
CurrencyEnum.Unknown
|
|
||||||
rate.roomPrice.currency = currency
|
|
||||||
rate.roomPrice.perNight.local = {
|
|
||||||
currency,
|
|
||||||
price:
|
|
||||||
room.product.public?.localPrice.pricePerNight ||
|
|
||||||
room.product.member?.localPrice.pricePerNight ||
|
|
||||||
0,
|
|
||||||
}
|
|
||||||
rate.roomPrice.perStay.local = {
|
|
||||||
currency,
|
|
||||||
price:
|
|
||||||
room.product.public?.localPrice.pricePerStay ||
|
|
||||||
room.product.member?.localPrice.pricePerStay ||
|
|
||||||
0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rate
|
|
||||||
}
|
|
||||||
@@ -1,243 +1,6 @@
|
|||||||
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
|
||||||
import { RateTypeEnum } from "@scandic-hotels/common/constants/rateType"
|
import { RateTypeEnum } from "@scandic-hotels/common/constants/rateType"
|
||||||
|
|
||||||
import { sumPackages } from "../../../../utils/SelectRate"
|
import type { Product } from "@scandic-hotels/trpc/types/roomAvailability"
|
||||||
|
|
||||||
import type { Packages } from "@scandic-hotels/trpc/types/packages"
|
|
||||||
import type {
|
|
||||||
Product,
|
|
||||||
RedemptionProduct,
|
|
||||||
} from "@scandic-hotels/trpc/types/roomAvailability"
|
|
||||||
|
|
||||||
import type { Rate } from "../../../../types/components/selectRate/selectRate"
|
|
||||||
import type { Price } from "../../../../types/price"
|
|
||||||
|
|
||||||
export function calculateTotalPrice(
|
|
||||||
selectedRateSummary: Rate[],
|
|
||||||
isUserLoggedIn: boolean
|
|
||||||
) {
|
|
||||||
return selectedRateSummary.reduce<Price>(
|
|
||||||
(total, room, idx) => {
|
|
||||||
if (!("member" in room.product) || !("public" in room.product)) {
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
|
|
||||||
const roomNr = idx + 1
|
|
||||||
const isMainRoom = roomNr === 1
|
|
||||||
let rate
|
|
||||||
if (isUserLoggedIn && isMainRoom && room.product.member) {
|
|
||||||
rate = room.product.member
|
|
||||||
} else if (room.product.public) {
|
|
||||||
rate = room.product.public
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rate) {
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
|
|
||||||
const packagesPrice = room.packages.reduce(
|
|
||||||
(total, pkg) => {
|
|
||||||
total.local = total.local + pkg.localPrice.totalPrice
|
|
||||||
if (pkg.requestedPrice.totalPrice) {
|
|
||||||
total.requested = total.requested + pkg.requestedPrice.totalPrice
|
|
||||||
}
|
|
||||||
return total
|
|
||||||
},
|
|
||||||
{ local: 0, requested: 0 }
|
|
||||||
)
|
|
||||||
|
|
||||||
total.local.currency = rate.localPrice.currency
|
|
||||||
total.local.price =
|
|
||||||
total.local.price + rate.localPrice.pricePerStay + packagesPrice.local
|
|
||||||
|
|
||||||
if (rate.localPrice.regularPricePerStay) {
|
|
||||||
total.local.regularPrice =
|
|
||||||
(total.local.regularPrice || 0) +
|
|
||||||
rate.localPrice.regularPricePerStay +
|
|
||||||
packagesPrice.local
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rate.requestedPrice) {
|
|
||||||
if (!total.requested) {
|
|
||||||
total.requested = {
|
|
||||||
currency: rate.requestedPrice.currency,
|
|
||||||
price: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!total.requested.currency) {
|
|
||||||
total.requested.currency = rate.requestedPrice.currency
|
|
||||||
}
|
|
||||||
|
|
||||||
total.requested.price =
|
|
||||||
total.requested.price +
|
|
||||||
rate.requestedPrice.pricePerStay +
|
|
||||||
packagesPrice.requested
|
|
||||||
|
|
||||||
if (rate.requestedPrice.regularPricePerStay) {
|
|
||||||
total.requested.regularPrice =
|
|
||||||
(total.requested.regularPrice || 0) +
|
|
||||||
rate.requestedPrice.regularPricePerStay +
|
|
||||||
packagesPrice.requested
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return total
|
|
||||||
},
|
|
||||||
{
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.Unknown,
|
|
||||||
price: 0,
|
|
||||||
regularPrice: undefined,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function calculateRedemptionTotalPrice(
|
|
||||||
redemption: RedemptionProduct["redemption"],
|
|
||||||
packages: Packages | null
|
|
||||||
) {
|
|
||||||
const pkgsSum = sumPackages(packages)
|
|
||||||
let additionalPrice
|
|
||||||
if (redemption.localPrice.additionalPricePerStay) {
|
|
||||||
additionalPrice =
|
|
||||||
redemption.localPrice.additionalPricePerStay + pkgsSum.price
|
|
||||||
} else if (pkgsSum.price) {
|
|
||||||
additionalPrice = pkgsSum.price
|
|
||||||
}
|
|
||||||
|
|
||||||
let additionalPriceCurrency
|
|
||||||
if (redemption.localPrice.currency) {
|
|
||||||
additionalPriceCurrency = redemption.localPrice.currency
|
|
||||||
} else if (pkgsSum.currency) {
|
|
||||||
additionalPriceCurrency = pkgsSum.currency
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
local: {
|
|
||||||
additionalPrice,
|
|
||||||
additionalPriceCurrency,
|
|
||||||
currency: CurrencyEnum.POINTS,
|
|
||||||
price: redemption.localPrice.pointsPerStay,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function calculateVoucherPrice(selectedRateSummary: Rate[]) {
|
|
||||||
return selectedRateSummary.reduce<Price>(
|
|
||||||
(total, room) => {
|
|
||||||
if (!("voucher" in room.product)) {
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
const rate = room.product.voucher
|
|
||||||
|
|
||||||
total.local.price = total.local.price + rate.numberOfVouchers
|
|
||||||
|
|
||||||
const pkgsSum = sumPackages(room.packages)
|
|
||||||
if (pkgsSum.price && pkgsSum.currency) {
|
|
||||||
total.local.additionalPrice =
|
|
||||||
(total.local.additionalPrice || 0) + pkgsSum.price
|
|
||||||
total.local.additionalPriceCurrency = pkgsSum.currency
|
|
||||||
}
|
|
||||||
|
|
||||||
return total
|
|
||||||
},
|
|
||||||
{
|
|
||||||
local: {
|
|
||||||
currency: CurrencyEnum.Voucher,
|
|
||||||
price: 0,
|
|
||||||
},
|
|
||||||
requested: undefined,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function calculateCorporateChequePrice(selectedRateSummary: Rate[]) {
|
|
||||||
return selectedRateSummary.reduce<Price>(
|
|
||||||
(total, room) => {
|
|
||||||
if (!("corporateCheque" in room.product)) {
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
const rate = room.product.corporateCheque
|
|
||||||
const pkgsSum = sumPackages(room.packages)
|
|
||||||
|
|
||||||
total.local.price = total.local.price + rate.localPrice.numberOfCheques
|
|
||||||
if (rate.localPrice.additionalPricePerStay) {
|
|
||||||
total.local.additionalPrice =
|
|
||||||
(total.local.additionalPrice || 0) +
|
|
||||||
rate.localPrice.additionalPricePerStay +
|
|
||||||
pkgsSum.price
|
|
||||||
} else if (pkgsSum.price) {
|
|
||||||
total.local.additionalPrice =
|
|
||||||
(total.local.additionalPrice || 0) + pkgsSum.price
|
|
||||||
}
|
|
||||||
if (rate.localPrice.currency) {
|
|
||||||
total.local.additionalPriceCurrency = rate.localPrice.currency
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rate.requestedPrice) {
|
|
||||||
if (!total.requested) {
|
|
||||||
total.requested = {
|
|
||||||
currency: CurrencyEnum.CC,
|
|
||||||
price: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
total.requested.price =
|
|
||||||
total.requested.price + rate.requestedPrice.numberOfCheques
|
|
||||||
|
|
||||||
if (rate.requestedPrice.additionalPricePerStay) {
|
|
||||||
total.requested.additionalPrice =
|
|
||||||
(total.requested.additionalPrice || 0) +
|
|
||||||
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 getTotalPrice(
|
|
||||||
mainRoomProduct: Rate | null,
|
|
||||||
rateSummary: Array<Rate | null>,
|
|
||||||
isUserLoggedIn: boolean
|
|
||||||
): Price | null {
|
|
||||||
const summaryArray = rateSummary.filter((rate): rate is Rate => rate !== null)
|
|
||||||
|
|
||||||
if (summaryArray.some((rate) => "corporateCheque" in rate.product)) {
|
|
||||||
return calculateCorporateChequePrice(summaryArray)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mainRoomProduct) {
|
|
||||||
return calculateTotalPrice(summaryArray, isUserLoggedIn)
|
|
||||||
}
|
|
||||||
|
|
||||||
const { packages, product } = mainRoomProduct
|
|
||||||
|
|
||||||
// In case of reward night (redemption) or voucher only single room booking is supported by business rules
|
|
||||||
if ("redemption" in product) {
|
|
||||||
return calculateRedemptionTotalPrice(product.redemption, packages)
|
|
||||||
}
|
|
||||||
if ("voucher" in product) {
|
|
||||||
const voucherPrice = calculateVoucherPrice(summaryArray)
|
|
||||||
return voucherPrice
|
|
||||||
}
|
|
||||||
|
|
||||||
return calculateTotalPrice(summaryArray, isUserLoggedIn)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isBookingCodeRate(product: Product | undefined | null) {
|
export function isBookingCodeRate(product: Product | undefined | null) {
|
||||||
if (!product) return false
|
if (!product) return false
|
||||||
|
|||||||
@@ -1,124 +0,0 @@
|
|||||||
.bookingCodeFilter {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog {
|
|
||||||
border-radius: var(--Corner-radius-md);
|
|
||||||
background-color: var(--Surface-Primary-Default);
|
|
||||||
box-shadow: var(--popup-box-shadow);
|
|
||||||
max-width: 340px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radioGroup {
|
|
||||||
display: grid;
|
|
||||||
gap: var(--Space-x1);
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio {
|
|
||||||
padding: var(--Space-x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio[data-hovered] {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.radio[data-focus-visible]::before {
|
|
||||||
outline: 1px auto var(--Border-Interactive-Focus);
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio::before {
|
|
||||||
flex-shrink: 0;
|
|
||||||
content: "";
|
|
||||||
margin-right: var(--Space-x15);
|
|
||||||
background-color: var(--Surface-UI-Fill-Default);
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border-radius: 50%;
|
|
||||||
box-shadow: inset 0 0 0 2px var(--Base-Border-Normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio[data-selected]::before {
|
|
||||||
box-shadow: inset 0 0 0 8px var(--Surface-UI-Fill-Active);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalOverlay {
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
background-color: var(--Overlay-40);
|
|
||||||
|
|
||||||
&[data-entering] {
|
|
||||||
animation: overlay-fade 200ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-exiting] {
|
|
||||||
animation: overlay-fade 150ms reverse ease-in;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
padding: var(--Space-x2) var(--Space-x05);
|
|
||||||
border-radius: var(--Corner-radius-md) var(--Corner-radius-md) 0 0;
|
|
||||||
background-color: var(--Surface-Primary-Default);
|
|
||||||
box-shadow: 0px 0px 14px 6px rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
&[data-entering] {
|
|
||||||
animation: modal-anim 200ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-exiting] {
|
|
||||||
animation: modal-anim 150ms reverse ease-in;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalDialog {
|
|
||||||
display: grid;
|
|
||||||
gap: var(--Space-x2);
|
|
||||||
padding: 0 var(--Space-x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 var(--Space-x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
|
||||||
.radioGroup {
|
|
||||||
padding: var(--Space-x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalOverlay {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes overlay-fade {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes modal-anim {
|
|
||||||
from {
|
|
||||||
transform: translateY(100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { useState } from "react"
|
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogTrigger,
|
|
||||||
Modal,
|
|
||||||
ModalOverlay,
|
|
||||||
Popover,
|
|
||||||
Radio,
|
|
||||||
RadioGroup,
|
|
||||||
} from "react-aria-components"
|
|
||||||
import { useIntl } from "react-intl"
|
|
||||||
|
|
||||||
import { RateTypeEnum } from "@scandic-hotels/common/constants/rateType"
|
|
||||||
import { ChipButton } from "@scandic-hotels/design-system/ChipButton"
|
|
||||||
import { IconButton } from "@scandic-hotels/design-system/IconButton"
|
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
|
||||||
|
|
||||||
import { useSelectRateContext } from "../../../../../../contexts/SelectRate/SelectRateContext"
|
|
||||||
import { useBreakpoint } from "../../../../../../hooks/useBreakpoint"
|
|
||||||
import { BookingCodeFilterEnum } from "../../../../../../stores/bookingCode-filter"
|
|
||||||
|
|
||||||
import styles from "./bookingCodeFilter.module.css"
|
|
||||||
|
|
||||||
export function BookingCodeFilter({ roomIndex }: { roomIndex: number }) {
|
|
||||||
const intl = useIntl()
|
|
||||||
const [isOpen, setIsOpen] = useState(false)
|
|
||||||
const displayAsModal = useBreakpoint("mobile")
|
|
||||||
|
|
||||||
const {
|
|
||||||
input,
|
|
||||||
getAvailabilityForRoom,
|
|
||||||
bookingCodeFilter,
|
|
||||||
actions: { selectBookingCodeFilter },
|
|
||||||
} = useSelectRateContext()
|
|
||||||
const roomAvailability = getAvailabilityForRoom(roomIndex)
|
|
||||||
|
|
||||||
const bookingCodeFilterItems = [
|
|
||||||
{
|
|
||||||
label: intl.formatMessage({
|
|
||||||
defaultMessage: "Booking code rates",
|
|
||||||
}),
|
|
||||||
value: BookingCodeFilterEnum.Discounted,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: intl.formatMessage({
|
|
||||||
defaultMessage: "All rates",
|
|
||||||
}),
|
|
||||||
value: BookingCodeFilterEnum.All,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
async function updateFilterValue(selectedFilter: string) {
|
|
||||||
selectBookingCodeFilter(selectedFilter as BookingCodeFilterEnum)
|
|
||||||
}
|
|
||||||
|
|
||||||
const hideFilter = (roomAvailability ?? []).some((room) => {
|
|
||||||
room.products.some((product) => {
|
|
||||||
const isRedemption = Array.isArray(product)
|
|
||||||
if (isRedemption) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (product.rateDefinition.rateType) {
|
|
||||||
case RateTypeEnum.Arb:
|
|
||||||
case RateTypeEnum.CorporateCheque:
|
|
||||||
case RateTypeEnum.Voucher:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if (hideFilter || !input?.bookingCode) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={styles.bookingCodeFilter}>
|
|
||||||
<DialogTrigger isOpen={isOpen} onOpenChange={setIsOpen}>
|
|
||||||
<ChipButton variant="Outlined">
|
|
||||||
{
|
|
||||||
bookingCodeFilterItems.find(
|
|
||||||
(item) => item.value === bookingCodeFilter
|
|
||||||
)?.label
|
|
||||||
}
|
|
||||||
<MaterialIcon
|
|
||||||
icon="keyboard_arrow_down"
|
|
||||||
size={20}
|
|
||||||
color="CurrentColor"
|
|
||||||
/>
|
|
||||||
</ChipButton>
|
|
||||||
{!displayAsModal ? (
|
|
||||||
<Popover placement="bottom end" isNonModal>
|
|
||||||
<Dialog className={styles.dialog}>
|
|
||||||
{({ close }) => {
|
|
||||||
function handleChangeFilterValue(value: string) {
|
|
||||||
updateFilterValue(value)
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Typography variant="Body/Paragraph/mdRegular">
|
|
||||||
<RadioGroup
|
|
||||||
aria-label={intl.formatMessage({
|
|
||||||
defaultMessage: "Booking Code Filter",
|
|
||||||
})}
|
|
||||||
onChange={handleChangeFilterValue}
|
|
||||||
name="bookingCodeFilter"
|
|
||||||
value={bookingCodeFilter}
|
|
||||||
className={styles.radioGroup}
|
|
||||||
>
|
|
||||||
{bookingCodeFilterItems.map((item) => (
|
|
||||||
<Radio
|
|
||||||
aria-label={item.label}
|
|
||||||
key={item.value}
|
|
||||||
value={item.value}
|
|
||||||
className={styles.radio}
|
|
||||||
autoFocus={bookingCodeFilter === item.value}
|
|
||||||
>
|
|
||||||
{item.label}
|
|
||||||
</Radio>
|
|
||||||
))}
|
|
||||||
</RadioGroup>
|
|
||||||
</Typography>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</Dialog>
|
|
||||||
</Popover>
|
|
||||||
) : (
|
|
||||||
<ModalOverlay className={styles.modalOverlay} isDismissable>
|
|
||||||
<Modal className={styles.modal}>
|
|
||||||
<Dialog className={styles.modalDialog}>
|
|
||||||
{({ close }) => {
|
|
||||||
function handleChangeFilterValue(value: string) {
|
|
||||||
updateFilterValue(value)
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={styles.header}>
|
|
||||||
<Typography variant="Title/Subtitle/md">
|
|
||||||
<h3>
|
|
||||||
{intl.formatMessage({
|
|
||||||
defaultMessage: "Room rates",
|
|
||||||
})}
|
|
||||||
</h3>
|
|
||||||
</Typography>
|
|
||||||
<IconButton
|
|
||||||
theme="Black"
|
|
||||||
style="Muted"
|
|
||||||
onPress={() => {
|
|
||||||
close()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MaterialIcon
|
|
||||||
icon="close"
|
|
||||||
size={24}
|
|
||||||
color="CurrentColor"
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
<Typography variant="Body/Paragraph/mdRegular">
|
|
||||||
<RadioGroup
|
|
||||||
aria-label={intl.formatMessage({
|
|
||||||
defaultMessage: "Booking Code Filter",
|
|
||||||
})}
|
|
||||||
onChange={handleChangeFilterValue}
|
|
||||||
name="bookingCodeFilter"
|
|
||||||
value={bookingCodeFilter}
|
|
||||||
className={styles.radioGroup}
|
|
||||||
>
|
|
||||||
{bookingCodeFilterItems.map((item) => (
|
|
||||||
<Radio
|
|
||||||
aria-label={item.label}
|
|
||||||
key={item.value}
|
|
||||||
value={item.value}
|
|
||||||
className={styles.radio}
|
|
||||||
>
|
|
||||||
{item.label}
|
|
||||||
</Radio>
|
|
||||||
))}
|
|
||||||
</RadioGroup>
|
|
||||||
</Typography>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</Dialog>
|
|
||||||
</Modal>
|
|
||||||
</ModalOverlay>
|
|
||||||
)}
|
|
||||||
</DialogTrigger>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -80,21 +80,21 @@ export function PackageCheckboxes({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function includesAllergyRoom(codes: PackageEnum[]) {
|
function includesAllergyRoom(codes: PackageEnum[]) {
|
||||||
return codes.includes(RoomPackageCodeEnum.ALLERGY_ROOM)
|
return codes.includes(RoomPackageCodeEnum.ALLERGY_ROOM)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function includesPetRoom(codes: PackageEnum[]) {
|
function includesPetRoom(codes: PackageEnum[]) {
|
||||||
return codes.includes(RoomPackageCodeEnum.PET_ROOM)
|
return codes.includes(RoomPackageCodeEnum.PET_ROOM)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkIsAllergyRoom(
|
function checkIsAllergyRoom(
|
||||||
code: PackageEnum
|
code: PackageEnum
|
||||||
): code is RoomPackageCodeEnum.ALLERGY_ROOM {
|
): code is RoomPackageCodeEnum.ALLERGY_ROOM {
|
||||||
return code === RoomPackageCodeEnum.ALLERGY_ROOM
|
return code === RoomPackageCodeEnum.ALLERGY_ROOM
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkIsPetRoom(
|
function checkIsPetRoom(
|
||||||
code: PackageEnum
|
code: PackageEnum
|
||||||
): code is RoomPackageCodeEnum.PET_ROOM {
|
): code is RoomPackageCodeEnum.PET_ROOM {
|
||||||
return code === RoomPackageCodeEnum.PET_ROOM
|
return code === RoomPackageCodeEnum.PET_ROOM
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import type { Package } from "@scandic-hotels/trpc/types/packages"
|
|||||||
|
|
||||||
import type { AvailabilityWithRoomInfo } from "../../../../../../../contexts/SelectRate/types"
|
import type { AvailabilityWithRoomInfo } from "../../../../../../../contexts/SelectRate/types"
|
||||||
|
|
||||||
export interface RatesProps {
|
interface RatesProps {
|
||||||
roomConfiguration: AvailabilityWithRoomInfo
|
roomConfiguration: AvailabilityWithRoomInfo
|
||||||
roomIndex: number
|
roomIndex: number
|
||||||
selectedPackages: Package[]
|
selectedPackages: Package[]
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
import type {
|
|
||||||
CorporateChequeProduct,
|
|
||||||
PriceProduct,
|
|
||||||
VoucherProduct,
|
|
||||||
} from "@scandic-hotels/trpc/types/roomAvailability"
|
|
||||||
|
|
||||||
import type { SelectedRate } from "../../../../../../../types/stores/rates"
|
|
||||||
|
|
||||||
export function isSelectedPriceProduct(
|
|
||||||
product: PriceProduct,
|
|
||||||
selectedRate: SelectedRate | null,
|
|
||||||
roomTypeCode: string
|
|
||||||
) {
|
|
||||||
if (!selectedRate || roomTypeCode !== selectedRate.roomTypeCode) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const { member, public: standard } = product
|
|
||||||
let isSelected = false
|
|
||||||
if (
|
|
||||||
"member" in selectedRate.product &&
|
|
||||||
selectedRate.product.member &&
|
|
||||||
member
|
|
||||||
) {
|
|
||||||
isSelected = selectedRate.product.member.rateCode === member.rateCode
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
"public" in selectedRate.product &&
|
|
||||||
selectedRate.product.public &&
|
|
||||||
standard
|
|
||||||
) {
|
|
||||||
isSelected = selectedRate.product.public.rateCode === standard.rateCode
|
|
||||||
}
|
|
||||||
|
|
||||||
return isSelected
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isSelectedCorporateCheque(
|
|
||||||
product: CorporateChequeProduct,
|
|
||||||
selectedRate: SelectedRate | null,
|
|
||||||
roomTypeCode: string
|
|
||||||
) {
|
|
||||||
if (!selectedRate || !("corporateCheque" in selectedRate.product)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const isSameRateCode =
|
|
||||||
product.corporateCheque.rateCode ===
|
|
||||||
selectedRate.product.corporateCheque.rateCode
|
|
||||||
const isSameRoomTypeCode = selectedRate.roomTypeCode === roomTypeCode
|
|
||||||
return isSameRateCode && isSameRoomTypeCode
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isSelectedVoucher(
|
|
||||||
product: VoucherProduct,
|
|
||||||
selectedRate: SelectedRate | null,
|
|
||||||
roomTypeCode: string
|
|
||||||
) {
|
|
||||||
if (!selectedRate || !("voucher" in selectedRate.product)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const isSameRateCode =
|
|
||||||
product.voucher.rateCode === selectedRate.product.voucher.rateCode
|
|
||||||
const isSameRoomTypeCode = selectedRate.roomTypeCode === roomTypeCode
|
|
||||||
return isSameRateCode && isSameRoomTypeCode
|
|
||||||
}
|
|
||||||
@@ -17,7 +17,7 @@ import type { ApiImage } from "@scandic-hotels/trpc/types/hotel"
|
|||||||
import type { PackageEnum } from "@scandic-hotels/trpc/types/packages"
|
import type { PackageEnum } from "@scandic-hotels/trpc/types/packages"
|
||||||
import type { RoomConfiguration } from "@scandic-hotels/trpc/types/roomAvailability"
|
import type { RoomConfiguration } from "@scandic-hotels/trpc/types/roomAvailability"
|
||||||
|
|
||||||
export type RoomListItemImageProps = Pick<
|
type RoomListItemImageProps = Pick<
|
||||||
RoomConfiguration,
|
RoomConfiguration,
|
||||||
"roomType" | "roomTypeCode" | "roomsLeft"
|
"roomType" | "roomTypeCode" | "roomsLeft"
|
||||||
> & {
|
> & {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import type { Package } from "@scandic-hotels/trpc/types/packages"
|
|||||||
|
|
||||||
import type { AvailabilityWithRoomInfo } from "../../../../../../contexts/SelectRate/types"
|
import type { AvailabilityWithRoomInfo } from "../../../../../../contexts/SelectRate/types"
|
||||||
|
|
||||||
export type RoomListItemProps = {
|
type RoomListItemProps = {
|
||||||
room: AvailabilityWithRoomInfo
|
room: AvailabilityWithRoomInfo
|
||||||
selectedPackages: Package[]
|
selectedPackages: Package[]
|
||||||
roomIndex: number
|
roomIndex: number
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import type { DetailsBooking } from "../../utils/url"
|
|||||||
|
|
||||||
export const EnterDetailsContext = createContext<EnterDetailsStore | null>(null)
|
export const EnterDetailsContext = createContext<EnterDetailsStore | null>(null)
|
||||||
|
|
||||||
export type DetailsProviderProps = React.PropsWithChildren & {
|
type DetailsProviderProps = React.PropsWithChildren & {
|
||||||
booking: DetailsBooking
|
booking: DetailsBooking
|
||||||
breakfastPackages: BreakfastPackages
|
breakfastPackages: BreakfastPackages
|
||||||
lang: Lang
|
lang: Lang
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import type { Room } from "@scandic-hotels/trpc/types/room"
|
|||||||
|
|
||||||
import type { RoomState } from "../../stores/enter-details/types"
|
import type { RoomState } from "../../stores/enter-details/types"
|
||||||
|
|
||||||
export interface RoomContextValue {
|
interface RoomContextValue {
|
||||||
actions: RoomState["actions"]
|
actions: RoomState["actions"]
|
||||||
isComplete: RoomState["isComplete"]
|
isComplete: RoomState["isComplete"]
|
||||||
idx: number
|
idx: number
|
||||||
@@ -16,7 +16,7 @@ export interface RoomContextValue {
|
|||||||
steps: RoomState["steps"]
|
steps: RoomState["steps"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RoomContext = createContext<RoomContextValue | null>(null)
|
const RoomContext = createContext<RoomContextValue | null>(null)
|
||||||
|
|
||||||
export function useRoomContext() {
|
export function useRoomContext() {
|
||||||
const ctx = useContext(RoomContext)
|
const ctx = useContext(RoomContext)
|
||||||
@@ -26,7 +26,7 @@ export function useRoomContext() {
|
|||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RoomProviderProps = {
|
type RoomProviderProps = {
|
||||||
idx: number
|
idx: number
|
||||||
room: Room
|
room: Room
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
|
|||||||
@@ -481,7 +481,6 @@ export function SelectRateProvider({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useSelectRateContext = () => useContext(SelectRateContext)
|
export const useSelectRateContext = () => useContext(SelectRateContext)
|
||||||
export const SelectRateConsumer = SelectRateContext.Consumer
|
|
||||||
|
|
||||||
const getDefaultRoomPackages = (intl: IntlShape): DefaultRoomPackage[] =>
|
const getDefaultRoomPackages = (intl: IntlShape): DefaultRoomPackage[] =>
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ type OneLevelNonNullable<T> = {
|
|||||||
[K in keyof T]-?: NonNullable<T[K]>
|
[K in keyof T]-?: NonNullable<T[K]>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateCorporateChequePrice(
|
function calculateCorporateChequePrice(
|
||||||
selectedRates: OneLevelNonNullable<SelectedRate>[],
|
selectedRates: OneLevelNonNullable<SelectedRate>[],
|
||||||
addAdditionalCost?: boolean
|
addAdditionalCost?: boolean
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function extractGuestFromUser(user: User) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function add(...nums: (number | string | undefined)[]) {
|
function add(...nums: (number | string | undefined)[]) {
|
||||||
return nums.reduce((total: number, num) => {
|
return nums.reduce((total: number, num) => {
|
||||||
if (typeof num === "undefined") {
|
if (typeof num === "undefined") {
|
||||||
num = 0
|
num = 0
|
||||||
@@ -354,7 +354,7 @@ interface TRoomCorporateCheque extends TRoom {
|
|||||||
roomRate: CorporateChequeProduct
|
roomRate: CorporateChequeProduct
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCorporateChequePrice(rooms: TRoom[], nights: number) {
|
function getCorporateChequePrice(rooms: TRoom[], nights: number) {
|
||||||
return rooms
|
return rooms
|
||||||
.filter(
|
.filter(
|
||||||
(room): room is TRoomCorporateCheque => "corporateCheque" in room.roomRate
|
(room): room is TRoomCorporateCheque => "corporateCheque" in room.roomRate
|
||||||
@@ -407,7 +407,7 @@ interface TRoomVoucher extends TRoom {
|
|||||||
roomRate: VoucherProduct
|
roomRate: VoucherProduct
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getVoucherPrice(rooms: TRoom[], nights: number) {
|
function getVoucherPrice(rooms: TRoom[], nights: number) {
|
||||||
return rooms
|
return rooms
|
||||||
.filter((room): room is TRoomVoucher => "voucher" in room.roomRate)
|
.filter((room): room is TRoomVoucher => "voucher" in room.roomRate)
|
||||||
.reduce<Price>(
|
.reduce<Price>(
|
||||||
@@ -440,7 +440,7 @@ interface TRoomRedemption extends TRoom {
|
|||||||
roomRate: RedemptionProduct
|
roomRate: RedemptionProduct
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRedemptionPrice(rooms: TRoom[], nights: number) {
|
function getRedemptionPrice(rooms: TRoom[], nights: number) {
|
||||||
return rooms
|
return rooms
|
||||||
.filter((room): room is TRoomRedemption => "redemption" in room.roomRate)
|
.filter((room): room is TRoomRedemption => "redemption" in room.roomRate)
|
||||||
.reduce<Price>(
|
.reduce<Price>(
|
||||||
@@ -478,11 +478,7 @@ interface TRoomPriceProduct extends TRoom {
|
|||||||
roomRate: PriceProduct
|
roomRate: PriceProduct
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRegularPrice(
|
function getRegularPrice(rooms: TRoom[], isMember: boolean, nights: number) {
|
||||||
rooms: TRoom[],
|
|
||||||
isMember: boolean,
|
|
||||||
nights: number
|
|
||||||
) {
|
|
||||||
const totalPrice = rooms
|
const totalPrice = rooms
|
||||||
.filter(
|
.filter(
|
||||||
(room): room is TRoomPriceProduct =>
|
(room): room is TRoomPriceProduct =>
|
||||||
|
|||||||
@@ -5,14 +5,12 @@ import { serverClient } from "../trpc"
|
|||||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
import type { HotelInput } from "@scandic-hotels/trpc/types/hotel"
|
import type { HotelInput } from "@scandic-hotels/trpc/types/hotel"
|
||||||
|
|
||||||
export const getSiteConfig = cache(async function getMemoizedSiteConfig(
|
const getSiteConfig = cache(async function getMemoizedSiteConfig(lang: Lang) {
|
||||||
lang: Lang
|
|
||||||
) {
|
|
||||||
const caller = await serverClient()
|
const caller = await serverClient()
|
||||||
return caller.contentstack.base.siteConfig({ lang })
|
return caller.contentstack.base.siteConfig({ lang })
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getPageSettings = cache(async function getMemoizedPageSettings(
|
const getPageSettings = cache(async function getMemoizedPageSettings(
|
||||||
lang: Lang
|
lang: Lang
|
||||||
) {
|
) {
|
||||||
const caller = await serverClient()
|
const caller = await serverClient()
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
export type PromoProps = {
|
|
||||||
buttonText: string
|
|
||||||
href: string
|
|
||||||
text: string
|
|
||||||
title: string
|
|
||||||
image?: {
|
|
||||||
src: string
|
|
||||||
altText: string
|
|
||||||
altText_En: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -67,7 +67,7 @@ export function calculateRegularPrice({
|
|||||||
}
|
}
|
||||||
|
|
||||||
//copied from enter-details/helpers.ts
|
//copied from enter-details/helpers.ts
|
||||||
export function add(...nums: (number | string | undefined)[]) {
|
function add(...nums: (number | string | undefined)[]) {
|
||||||
return nums.reduce((total: number, num) => {
|
return nums.reduce((total: number, num) => {
|
||||||
if (typeof num === "undefined") {
|
if (typeof num === "undefined") {
|
||||||
num = 0
|
num = 0
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
"test:watch": "vitest"
|
"test:watch": "vitest"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
"./bedTypeIcons": "./lib/misc/bedTypeIcons.ts",
|
|
||||||
"./BookingCodeFilter": "./lib/components/BookingCodeFilter/index.tsx",
|
|
||||||
"./BookingFlowContextProvider": "./lib/components/BookingFlowContextProvider.tsx",
|
"./BookingFlowContextProvider": "./lib/components/BookingFlowContextProvider.tsx",
|
||||||
"./BookingFlowTrackingProvider": "./lib/components/BookingFlowTrackingProvider.tsx",
|
"./BookingFlowTrackingProvider": "./lib/components/BookingFlowTrackingProvider.tsx",
|
||||||
"./BookingWidget": "./lib/components/BookingWidget/index.tsx",
|
"./BookingWidget": "./lib/components/BookingWidget/index.tsx",
|
||||||
@@ -21,59 +19,31 @@
|
|||||||
"./BookingWidget/Skeleton": "./lib/components/BookingWidget/Skeleton.tsx",
|
"./BookingWidget/Skeleton": "./lib/components/BookingWidget/Skeleton.tsx",
|
||||||
"./components/AdditionalAmenities": "./lib/components/AdditionalAmenities/index.tsx",
|
"./components/AdditionalAmenities": "./lib/components/AdditionalAmenities/index.tsx",
|
||||||
"./components/AddToCalendar": "./lib/components/AddToCalendar/index.tsx",
|
"./components/AddToCalendar": "./lib/components/AddToCalendar/index.tsx",
|
||||||
"./components/BookingConfirmation/Confirmation": "./lib/components/BookingConfirmation/Confirmation/index.tsx",
|
|
||||||
"./components/BookingConfirmation/Header/Actions/downloadInvoice": "./lib/components/BookingConfirmation/Header/Actions/downloadInvoice.ts",
|
|
||||||
"./components/BookingConfirmation/Header/Actions/helpers": "./lib/components/BookingConfirmation/Header/Actions/helpers.ts",
|
"./components/BookingConfirmation/Header/Actions/helpers": "./lib/components/BookingConfirmation/Header/Actions/helpers.ts",
|
||||||
"./components/Contact": "./lib/components/Contact/index.tsx",
|
|
||||||
"./components/EnterDetails/enterDetailsErrors": "./lib/components/EnterDetails/enterDetailsErrors.ts",
|
"./components/EnterDetails/enterDetailsErrors": "./lib/components/EnterDetails/enterDetailsErrors.ts",
|
||||||
"./components/EnterDetails/Payment/helpers": "./lib/components/EnterDetails/Payment/helpers.ts",
|
"./components/EnterDetails/Payment/helpers": "./lib/components/EnterDetails/Payment/helpers.ts",
|
||||||
"./components/EnterDetails/Payment/PaymentCallback/HandleErrorCallback": "./lib/components/EnterDetails/Payment/PaymentCallback/HandleErrorCallback.tsx",
|
"./components/EnterDetails/Payment/PaymentCallback/HandleErrorCallback": "./lib/components/EnterDetails/Payment/PaymentCallback/HandleErrorCallback.tsx",
|
||||||
"./components/EnterDetails/Payment/PaymentCallback/HandleSuccessCallback": "./lib/components/EnterDetails/Payment/PaymentCallback/HandleSuccessCallback.tsx",
|
"./components/EnterDetails/Payment/PaymentCallback/HandleSuccessCallback": "./lib/components/EnterDetails/Payment/PaymentCallback/HandleSuccessCallback.tsx",
|
||||||
"./components/EnterDetails/Payment/PaymentCallback/helpers": "./lib/components/EnterDetails/Payment/PaymentCallback/helpers.ts",
|
"./components/EnterDetails/Payment/PaymentCallback/helpers": "./lib/components/EnterDetails/Payment/PaymentCallback/helpers.ts",
|
||||||
"./components/EnterDetails/StorageCleaner": "./lib/components/EnterDetails/StorageCleaner.tsx",
|
"./components/EnterDetails/StorageCleaner": "./lib/components/EnterDetails/StorageCleaner.tsx",
|
||||||
"./components/FnFNotAllowedAlert": "./lib/components/FnFNotAllowedAlert/index.tsx",
|
|
||||||
"./components/HotelDetailsSidePeek": "./lib/components/HotelDetailsSidePeek/index.tsx",
|
|
||||||
"./components/HotelReservationSidePeek": "./lib/components/HotelReservationSidePeek/index.tsx",
|
|
||||||
"./components/OpenSidePeekButton": "./lib/components/OpenSidePeekButton/index.tsx",
|
|
||||||
"./components/PriceDetailsModal": "./lib/components/PriceDetailsModal/index.tsx",
|
"./components/PriceDetailsModal": "./lib/components/PriceDetailsModal/index.tsx",
|
||||||
"./components/RoomCardSkeleton": "./lib/components/RoomCardSkeleton/RoomCardSkeleton.tsx",
|
|
||||||
"./components/RoomDetailsSidePeek": "./lib/components/RoomDetailsSidePeek/index.tsx",
|
|
||||||
"./components/RoomSidePeekContent": "./lib/components/RoomSidePeek/RoomSidePeekContent/index.tsx",
|
|
||||||
"./components/SelectHotel": "./lib/components/SelectHotel/index.tsx",
|
"./components/SelectHotel": "./lib/components/SelectHotel/index.tsx",
|
||||||
"./components/SelectHotelMap": "./lib/components/SelectHotel/SelectHotelMap/index.tsx",
|
|
||||||
"./components/SelectRate": "./lib/components/SelectRate/index.tsx",
|
"./components/SelectRate": "./lib/components/SelectRate/index.tsx",
|
||||||
"./components/SelectRate/RoomsContainer/RateSummary/utils": "./lib/components/SelectRate/RoomsContainer/RateSummary/utils.ts",
|
|
||||||
"./components/SidePanel": "./lib/components/SidePanel/index.tsx",
|
|
||||||
"./components/SidePeekAccordions/BreakfastAccordionItem": "./lib/components/SidePeekAccordions/BreakfastAccordionItem.tsx",
|
"./components/SidePeekAccordions/BreakfastAccordionItem": "./lib/components/SidePeekAccordions/BreakfastAccordionItem.tsx",
|
||||||
"./components/SidePeekAccordions/CheckInCheckOutAccordionItem": "./lib/components/SidePeekAccordions/CheckInCheckOutAccordionItem.tsx",
|
"./components/SidePeekAccordions/CheckInCheckOutAccordionItem": "./lib/components/SidePeekAccordions/CheckInCheckOutAccordionItem.tsx",
|
||||||
"./components/SidePeekAccordions/ParkingAccordionItem": "./lib/components/SidePeekAccordions/ParkingAccordionItem.tsx",
|
"./components/SidePeekAccordions/ParkingAccordionItem": "./lib/components/SidePeekAccordions/ParkingAccordionItem.tsx",
|
||||||
"./components/SignupPromoDesktop": "./lib/components/SignupPromo/Desktop.tsx",
|
|
||||||
"./components/SignupPromoMobile": "./lib/components/SignupPromo/Mobile.tsx",
|
|
||||||
"./components/TripAdvisorChip": "./lib/components/TripAdvisorChip/index.tsx",
|
|
||||||
"./contexts/EnterDetails/RoomContext": "./lib/contexts/EnterDetails/RoomContext.tsx",
|
|
||||||
"./contexts/SelectRate/getTotalPrice": "./lib/contexts/SelectRate/getTotalPrice.ts",
|
|
||||||
"./contexts/SelectRate/Room": "./lib/contexts/SelectRate/Room.ts",
|
|
||||||
"./contexts/SelectRate/SelectRateContext": "./lib/contexts/SelectRate/SelectRateContext.tsx",
|
|
||||||
"./contexts/SelectRate/types": "./lib/contexts/SelectRate/types.ts",
|
|
||||||
"./global.d.ts": "./global.d.ts",
|
"./global.d.ts": "./global.d.ts",
|
||||||
"./hooks/useHandleBookingStatus": "./lib/hooks/useHandleBookingStatus.ts",
|
"./hooks/useHandleBookingStatus": "./lib/hooks/useHandleBookingStatus.ts",
|
||||||
"./hooks/useSearchHistory": "./lib/hooks/useSearchHistory.ts",
|
"./hooks/useSearchHistory": "./lib/hooks/useSearchHistory.ts",
|
||||||
"./pages/*": "./lib/pages/*.tsx",
|
"./pages/*": "./lib/pages/*.tsx",
|
||||||
"./providers/BookingConfirmationProvider": "./lib/providers/BookingConfirmationProvider.tsx",
|
|
||||||
"./searchType": "./lib/misc/searchType.ts",
|
"./searchType": "./lib/misc/searchType.ts",
|
||||||
"./stores/bookingCode-filter": "./lib/stores/bookingCode-filter.ts",
|
|
||||||
"./stores/enter-details": "./lib/stores/enter-details/index.ts",
|
|
||||||
"./stores/enter-details/types": "./lib/stores/enter-details/types.ts",
|
"./stores/enter-details/types": "./lib/stores/enter-details/types.ts",
|
||||||
"./stores/hotels-map": "./lib/stores/hotels-map.ts",
|
"./stores/hotels-map": "./lib/stores/hotels-map.ts",
|
||||||
"./stores/booking-confirmation": "./lib/stores/booking-confirmation/index.ts",
|
"./stores/booking-confirmation": "./lib/stores/booking-confirmation/index.ts",
|
||||||
"./types/components/bookingConfirmation/bookingConfirmation": "./lib/types/components/bookingConfirmation/bookingConfirmation.ts",
|
|
||||||
"./types/components/findMyBooking/additionalInfoCookieValue": "./lib/types/components/findMyBooking/additionalInfoCookieValue.ts",
|
"./types/components/findMyBooking/additionalInfoCookieValue": "./lib/types/components/findMyBooking/additionalInfoCookieValue.ts",
|
||||||
"./types/components/promo/promoProps": "./lib/types/components/promo/promoProps.ts",
|
|
||||||
"./types/components/selectRate/selectRate": "./lib/types/components/selectRate/selectRate.ts",
|
"./types/components/selectRate/selectRate": "./lib/types/components/selectRate/selectRate.ts",
|
||||||
"./types/membershipFailedError": "./lib/types/membershipFailedError.ts",
|
|
||||||
"./types/stores/booking-confirmation": "./lib/types/stores/booking-confirmation.ts",
|
"./types/stores/booking-confirmation": "./lib/types/stores/booking-confirmation.ts",
|
||||||
"./types/stores/rates": "./lib/types/stores/rates.ts",
|
"./types/stores/rates": "./lib/types/stores/rates.ts",
|
||||||
"./utils/calculateRegularPrice": "./lib/utils/calculateRegularPrice.ts",
|
|
||||||
"./utils/getRoomFeatureDescription": "./lib/utils/getRoomFeatureDescription.ts",
|
"./utils/getRoomFeatureDescription": "./lib/utils/getRoomFeatureDescription.ts",
|
||||||
"./utils/isSameBooking": "./lib/utils/isSameBooking.ts",
|
"./utils/isSameBooking": "./lib/utils/isSameBooking.ts",
|
||||||
"./utils/nuqs": "./lib/utils/nuqs.ts",
|
"./utils/nuqs": "./lib/utils/nuqs.ts",
|
||||||
|
|||||||
Reference in New Issue
Block a user