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:
Anton Gunnarsson
2025-09-18 07:28:05 +00:00
parent 9620bfe76d
commit b0f3e4afbd
44 changed files with 63 additions and 1483 deletions

View File

@@ -17,7 +17,7 @@ import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConf
import type { EventAttributes } from "ics"
import type { MutableRefObject } from "react"
export interface BookingConfirmationHeaderProps
interface BookingConfirmationHeaderProps
extends Pick<BookingConfirmation, "booking" | "hotel"> {
mainRef: MutableRefObject<HTMLElement | null>
}

View File

@@ -4,7 +4,17 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
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) {
return (

View File

@@ -13,7 +13,7 @@ import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConf
import type { AdditionalInfoCookieValue } from "../../../types/components/findMyBooking/additionalInfoCookieValue"
export type PromosProps = Pick<BookingConfirmation, "booking">
type PromosProps = Pick<BookingConfirmation, "booking">
export function Promos({ booking }: PromosProps) {
const intl = useIntl()

View File

@@ -7,7 +7,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
import styles from "./retry.module.css"
export interface RetryProps {
interface RetryProps {
handleRefetch: () => void
}

View File

@@ -14,7 +14,7 @@ import { Room } from "../Room"
import { LinkedReservationCardSkeleton } from "./LinkedReservationCardSkeleton"
import Retry from "./Retry"
export interface LinkedReservationProps {
interface LinkedReservationProps {
checkInTime: string
checkOutTime: string
refId: string

View File

@@ -22,7 +22,7 @@ import styles from "./room.module.css"
import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConfirmation"
export interface RoomProps {
interface RoomProps {
booking: BookingConfirmation["booking"]
checkInTime: string
checkOutTime: string

View File

@@ -12,7 +12,7 @@ import styles from "./rooms.module.css"
import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConfirmation"
import type { Room as RoomProp } from "@scandic-hotels/trpc/types/hotel"
export interface BookingConfirmationRoomsProps
interface BookingConfirmationRoomsProps
extends Pick<BookingConfirmation, "booking"> {
mainRoom: RoomProp & {
bedType: RoomProp["roomTypes"][number]

View File

@@ -16,7 +16,7 @@ export const bookingWidgetErrors = {
"CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE",
} as const
export const guestRoomSchema = z
const guestRoomSchema = z
.object({
adults: z.number().default(1),
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
.object({

View File

@@ -15,7 +15,7 @@ import useLang from "../../../../../hooks/useLang"
import styles from "./joinScandicFriendsCard.module.css"
export type JoinScandicFriendsCardProps = {
type JoinScandicFriendsCardProps = {
name?: string
}
export default function JoinScandicFriendsCard({

View File

@@ -12,7 +12,7 @@ const stringMatcher =
const isValidString = (key: string) => stringMatcher.test(key)
export const baseDetailsSchema = z.object({
const baseDetailsSchema = z.object({
countryCode: z.string().min(1, roomOneErrors.COUNTRY_REQUIRED),
email: z.string().email(roomOneErrors.EMAIL_REQUIRED),
firstName: z
@@ -31,7 +31,7 @@ export const baseDetailsSchema = z.object({
specialRequest: specialRequestSchema,
})
export const notJoinDetailsSchema = baseDetailsSchema.merge(
const notJoinDetailsSchema = baseDetailsSchema.merge(
z.object({
join: z.literal<boolean>(false),
zipCode: z.string().optional(),
@@ -54,7 +54,7 @@ export const notJoinDetailsSchema = baseDetailsSchema.merge(
})
)
export const joinDetailsSchema = baseDetailsSchema.merge(
const joinDetailsSchema = baseDetailsSchema.merge(
z.object({
join: z.literal<boolean>(true),
zipCode: z

View File

@@ -1,11 +1,11 @@
import { z } from "zod"
export enum FloorPreference {
enum FloorPreference {
LOW = "Low floor",
HIGH = "High floor",
}
export enum ElevatorPreference {
enum ElevatorPreference {
AWAY_FROM_ELEVATOR = "Away from elevator",
NEAR_ELEVATOR = "Near elevator",
}

View File

@@ -12,7 +12,7 @@ import styles from "./header.module.css"
import type { HotelData } from "@scandic-hotels/trpc/types/hotel"
export type HotelHeaderProps = {
type HotelHeaderProps = {
hotelData: HotelData & { url: string | null }
}

View File

@@ -63,7 +63,7 @@ import type { PriceChangeData } from "../PriceChangeData"
const maxRetries = 15
const retryInterval = 2000
export type PaymentClientProps = {
type PaymentClientProps = {
otherPaymentOptions: PaymentMethodEnum[]
savedCreditCards: CreditCard[] | null
}

View File

@@ -9,7 +9,7 @@ import { EnterDetailsStepEnum } from "../../../stores/enter-details/enterDetails
import styles from "./section.module.css"
export type SectionProps = {
type SectionProps = {
header: string
label: string
additionalInfo?: string | null

View File

@@ -11,15 +11,3 @@ export function getMemberPrice(roomRate: Product) {
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
}

View File

@@ -38,7 +38,7 @@ type RoomPrice =
| RedemptionPriceType
| VoucherPriceType
export interface Room {
interface Room {
adults: number
bedType:
| {

View File

@@ -1,2 +0,0 @@
export { default as FilterAndSortModal } from "./FilterAndSortModal"
export { default as HotelFilter } from "./HotelFilter"

View File

@@ -1,7 +1,7 @@
import type { HotelPin } from "../../../HotelCardDialogListing/utils"
import type { HotelResponse } from "../../helpers"
export function getVisibleHotelPins(
function getVisibleHotelPins(
map: google.maps.Map | null,
filteredHotelPins: HotelPin[]
) {

View File

@@ -23,7 +23,7 @@ import styles from "./summaryContent.module.css"
import type { Price } from "../../../../../../types/price"
export type SelectRateSummaryProps = {
type SelectRateSummaryProps = {
isUserLoggedIn: boolean
bookingCode?: string
toggleSummaryOpen: () => void

View File

@@ -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
}

View File

@@ -1,243 +1,6 @@
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { RateTypeEnum } from "@scandic-hotels/common/constants/rateType"
import { sumPackages } from "../../../../utils/SelectRate"
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)
}
import type { Product } from "@scandic-hotels/trpc/types/roomAvailability"
export function isBookingCodeRate(product: Product | undefined | null) {
if (!product) return false

View File

@@ -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);
}
}

View File

@@ -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>
</>
)
}

View File

@@ -80,21 +80,21 @@ export function PackageCheckboxes({
)
}
export function includesAllergyRoom(codes: PackageEnum[]) {
function includesAllergyRoom(codes: PackageEnum[]) {
return codes.includes(RoomPackageCodeEnum.ALLERGY_ROOM)
}
export function includesPetRoom(codes: PackageEnum[]) {
function includesPetRoom(codes: PackageEnum[]) {
return codes.includes(RoomPackageCodeEnum.PET_ROOM)
}
export function checkIsAllergyRoom(
function checkIsAllergyRoom(
code: PackageEnum
): code is RoomPackageCodeEnum.ALLERGY_ROOM {
return code === RoomPackageCodeEnum.ALLERGY_ROOM
}
export function checkIsPetRoom(
function checkIsPetRoom(
code: PackageEnum
): code is RoomPackageCodeEnum.PET_ROOM {
return code === RoomPackageCodeEnum.PET_ROOM

View File

@@ -14,7 +14,7 @@ import type { Package } from "@scandic-hotels/trpc/types/packages"
import type { AvailabilityWithRoomInfo } from "../../../../../../../contexts/SelectRate/types"
export interface RatesProps {
interface RatesProps {
roomConfiguration: AvailabilityWithRoomInfo
roomIndex: number
selectedPackages: Package[]

View File

@@ -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
}

View File

@@ -17,7 +17,7 @@ import type { ApiImage } from "@scandic-hotels/trpc/types/hotel"
import type { PackageEnum } from "@scandic-hotels/trpc/types/packages"
import type { RoomConfiguration } from "@scandic-hotels/trpc/types/roomAvailability"
export type RoomListItemImageProps = Pick<
type RoomListItemImageProps = Pick<
RoomConfiguration,
"roomType" | "roomTypeCode" | "roomsLeft"
> & {

View File

@@ -12,7 +12,7 @@ import type { Package } from "@scandic-hotels/trpc/types/packages"
import type { AvailabilityWithRoomInfo } from "../../../../../../contexts/SelectRate/types"
export type RoomListItemProps = {
type RoomListItemProps = {
room: AvailabilityWithRoomInfo
selectedPackages: Package[]
roomIndex: number

View File

@@ -32,7 +32,7 @@ import type { DetailsBooking } from "../../utils/url"
export const EnterDetailsContext = createContext<EnterDetailsStore | null>(null)
export type DetailsProviderProps = React.PropsWithChildren & {
type DetailsProviderProps = React.PropsWithChildren & {
booking: DetailsBooking
breakfastPackages: BreakfastPackages
lang: Lang

View File

@@ -7,7 +7,7 @@ import type { Room } from "@scandic-hotels/trpc/types/room"
import type { RoomState } from "../../stores/enter-details/types"
export interface RoomContextValue {
interface RoomContextValue {
actions: RoomState["actions"]
isComplete: RoomState["isComplete"]
idx: number
@@ -16,7 +16,7 @@ export interface RoomContextValue {
steps: RoomState["steps"]
}
export const RoomContext = createContext<RoomContextValue | null>(null)
const RoomContext = createContext<RoomContextValue | null>(null)
export function useRoomContext() {
const ctx = useContext(RoomContext)
@@ -26,7 +26,7 @@ export function useRoomContext() {
return ctx
}
export type RoomProviderProps = {
type RoomProviderProps = {
idx: number
room: Room
children: React.ReactNode

View File

@@ -481,7 +481,6 @@ export function SelectRateProvider({
}
export const useSelectRateContext = () => useContext(SelectRateContext)
export const SelectRateConsumer = SelectRateContext.Consumer
const getDefaultRoomPackages = (intl: IntlShape): DefaultRoomPackage[] =>
[

View File

@@ -224,7 +224,7 @@ type OneLevelNonNullable<T> = {
[K in keyof T]-?: NonNullable<T[K]>
}
export function calculateCorporateChequePrice(
function calculateCorporateChequePrice(
selectedRates: OneLevelNonNullable<SelectedRate>[],
addAdditionalCost?: boolean
) {

View File

@@ -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) => {
if (typeof num === "undefined") {
num = 0
@@ -354,7 +354,7 @@ interface TRoomCorporateCheque extends TRoom {
roomRate: CorporateChequeProduct
}
export function getCorporateChequePrice(rooms: TRoom[], nights: number) {
function getCorporateChequePrice(rooms: TRoom[], nights: number) {
return rooms
.filter(
(room): room is TRoomCorporateCheque => "corporateCheque" in room.roomRate
@@ -407,7 +407,7 @@ interface TRoomVoucher extends TRoom {
roomRate: VoucherProduct
}
export function getVoucherPrice(rooms: TRoom[], nights: number) {
function getVoucherPrice(rooms: TRoom[], nights: number) {
return rooms
.filter((room): room is TRoomVoucher => "voucher" in room.roomRate)
.reduce<Price>(
@@ -440,7 +440,7 @@ interface TRoomRedemption extends TRoom {
roomRate: RedemptionProduct
}
export function getRedemptionPrice(rooms: TRoom[], nights: number) {
function getRedemptionPrice(rooms: TRoom[], nights: number) {
return rooms
.filter((room): room is TRoomRedemption => "redemption" in room.roomRate)
.reduce<Price>(
@@ -478,11 +478,7 @@ interface TRoomPriceProduct extends TRoom {
roomRate: PriceProduct
}
export function getRegularPrice(
rooms: TRoom[],
isMember: boolean,
nights: number
) {
function getRegularPrice(rooms: TRoom[], isMember: boolean, nights: number) {
const totalPrice = rooms
.filter(
(room): room is TRoomPriceProduct =>

View File

@@ -5,14 +5,12 @@ import { serverClient } from "../trpc"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { HotelInput } from "@scandic-hotels/trpc/types/hotel"
export const getSiteConfig = cache(async function getMemoizedSiteConfig(
lang: Lang
) {
const getSiteConfig = cache(async function getMemoizedSiteConfig(lang: Lang) {
const caller = await serverClient()
return caller.contentstack.base.siteConfig({ lang })
})
export const getPageSettings = cache(async function getMemoizedPageSettings(
const getPageSettings = cache(async function getMemoizedPageSettings(
lang: Lang
) {
const caller = await serverClient()

View File

@@ -1,11 +0,0 @@
export type PromoProps = {
buttonText: string
href: string
text: string
title: string
image?: {
src: string
altText: string
altText_En: string
}
}

View File

@@ -67,7 +67,7 @@ export function calculateRegularPrice({
}
//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) => {
if (typeof num === "undefined") {
num = 0

View File

@@ -11,8 +11,6 @@
"test:watch": "vitest"
},
"exports": {
"./bedTypeIcons": "./lib/misc/bedTypeIcons.ts",
"./BookingCodeFilter": "./lib/components/BookingCodeFilter/index.tsx",
"./BookingFlowContextProvider": "./lib/components/BookingFlowContextProvider.tsx",
"./BookingFlowTrackingProvider": "./lib/components/BookingFlowTrackingProvider.tsx",
"./BookingWidget": "./lib/components/BookingWidget/index.tsx",
@@ -21,59 +19,31 @@
"./BookingWidget/Skeleton": "./lib/components/BookingWidget/Skeleton.tsx",
"./components/AdditionalAmenities": "./lib/components/AdditionalAmenities/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/Contact": "./lib/components/Contact/index.tsx",
"./components/EnterDetails/enterDetailsErrors": "./lib/components/EnterDetails/enterDetailsErrors.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/HandleSuccessCallback": "./lib/components/EnterDetails/Payment/PaymentCallback/HandleSuccessCallback.tsx",
"./components/EnterDetails/Payment/PaymentCallback/helpers": "./lib/components/EnterDetails/Payment/PaymentCallback/helpers.ts",
"./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/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/SelectHotelMap": "./lib/components/SelectHotel/SelectHotelMap/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/CheckInCheckOutAccordionItem": "./lib/components/SidePeekAccordions/CheckInCheckOutAccordionItem.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",
"./hooks/useHandleBookingStatus": "./lib/hooks/useHandleBookingStatus.ts",
"./hooks/useSearchHistory": "./lib/hooks/useSearchHistory.ts",
"./pages/*": "./lib/pages/*.tsx",
"./providers/BookingConfirmationProvider": "./lib/providers/BookingConfirmationProvider.tsx",
"./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/hotels-map": "./lib/stores/hotels-map.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/promo/promoProps": "./lib/types/components/promo/promoProps.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/rates": "./lib/types/stores/rates.ts",
"./utils/calculateRegularPrice": "./lib/utils/calculateRegularPrice.ts",
"./utils/getRoomFeatureDescription": "./lib/utils/getRoomFeatureDescription.ts",
"./utils/isSameBooking": "./lib/utils/isSameBooking.ts",
"./utils/nuqs": "./lib/utils/nuqs.ts",