Merged in feat/BOOK-747-alert-extra-cost (pull request #3455)

feat(BOOK-747): show extra cost alert if reward night or voucher

* feat(BOOK-747): show extra cost alert if reward night or voucher

* feat(BOOK-747): use enum

* feat(BOOK-747): refactor

* feat(BOOK-747): add underline to trigger text


Approved-by: Anton Gunnarsson
This commit is contained in:
Bianca Widstam
2026-01-20 11:51:24 +00:00
parent 5af64ef896
commit 2dd08bb5d0
13 changed files with 224 additions and 184 deletions

View File

@@ -0,0 +1,5 @@
.alert {
max-width: var(--max-width-page);
margin: 0 auto;
padding: var(--Space-x5) 0 0;
}

View File

@@ -0,0 +1,92 @@
"use client"
import { useIntl } from "react-intl"
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import { RateEnum } from "@scandic-hotels/common/constants/rate"
import { Alert } from "@scandic-hotels/design-system/Alert"
import TermModal from "@scandic-hotels/design-system/TermModal"
import { useSelectRateContext } from "../../../../contexts/SelectRate/SelectRateContext"
import { useRateTitles } from "../Rooms/RoomsList/RoomListItem/Rates/useRateTitles"
import styles from "./extraCostAlert.module.css"
import type { RouterOutput } from "@scandic-hotels/trpc/client"
type RoomAvailability = Extract<
RouterOutput["hotel"]["availability"]["selectRate"]["rooms"][0],
{ roomConfigurations: unknown }
>
export default function ExtraCostAlert() {
const intl = useIntl()
const { availability, input: rooms } = useSelectRateContext()
const rateTitles = useRateTitles()
if (!availability.data) {
return null
}
const availableRooms = availability.data.filter(
(room): room is RoomAvailability => !("error" in room)
)
if (availableRooms.length === 0) {
return null
}
const hasMoreThanTwoAdults = rooms.data?.booking.rooms.some(
(room) => room.adults > 2
)
const isRewardNightOrVoucher = availableRooms.some((room) => {
return room.roomConfigurations.some((config) =>
config.products?.some((product) =>
Array.isArray(product)
? product.some((p) => "redemption" in p)
: "voucher" in product
)
)
})
const rateDefinition = availableRooms.find(
(room) => room.rateDefinitions.length
)?.rateDefinitions[0]
const rateTermDetails = [
{
title: rateDefinition?.title ?? "",
terms: rateDefinition?.generalTerms ?? [],
},
]
if (!(isRewardNightOrVoucher && hasMoreThanTwoAdults && rateDefinition)) {
return null
}
return (
<div className={styles.alert}>
<Alert
type={AlertTypeEnum.Info}
heading={intl.formatMessage({
id: "booking.alert.extraguests",
defaultMessage: "Extra guest(s)",
})}
text={intl.formatMessage({
id: "booking.alert.extraBeds.text",
defaultMessage:
"When booking for more than 2 guests, an additional fee will apply per person, see link for details.",
})}
slot={
<TermModal
rateTitle={rateTitles[RateEnum.flex].title}
paymentTerm={rateTitles[RateEnum.flex].paymentTerm}
rateTermDetails={rateTermDetails}
variant="text"
/>
}
/>
</div>
)
}

View File

@@ -14,6 +14,7 @@ import { useSelectRateContext } from "../../../contexts/SelectRate/SelectRateCon
import useLang from "../../../hooks/useLang"
import { mapPackageToLabel } from "../../../utils/getRoomFeatureDescription"
import { trackLowestRoomPrice, trackRoomsLoaded } from "../Tracking/tracking"
import ExtraCostAlert from "./ExtraCostAlert"
import { RateSummary } from "./RateSummary"
import Rooms from "./Rooms"
import { RoomsContainerSkeleton } from "./RoomsContainerSkeleton"
@@ -23,7 +24,8 @@ import styles from "./index.module.css"
import type { HotelData } from "@scandic-hotels/trpc/types/hotel"
interface RoomsContainerProps
extends Pick<HotelData, "roomCategories">,
extends
Pick<HotelData, "roomCategories">,
Pick<HotelData["hotel"], "hotelType" | "vat"> {}
export function RoomsContainer({}: RoomsContainerProps) {
@@ -139,6 +141,7 @@ export function RoomsContainer({}: RoomsContainerProps) {
return (
<>
<ExtraCostAlert />
<Rooms />
<RateSummary />
</>