From 2dd08bb5d045e73c0a87c7b652d2a31f11f215f7 Mon Sep 17 00:00:00 2001 From: Bianca Widstam Date: Tue, 20 Jan 2026 11:51:24 +0000 Subject: [PATCH] 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 --- .../ExtraCostAlert/extraCostAlert.module.css | 5 + .../RoomsContainer/ExtraCostAlert/index.tsx | 92 +++++++++++++++++++ .../SelectRate/RoomsContainer/index.tsx | 5 +- .../lib/components/Alert/alert.ts | 3 +- .../lib/components/Alert/index.tsx | 2 + .../components/RateCard/Campaign/index.tsx | 48 ++-------- .../lib/components/RateCard/Code/index.tsx | 48 ++-------- .../lib/components/RateCard/Points/index.tsx | 48 ++-------- .../lib/components/RateCard/Regular/index.tsx | 49 ++-------- .../components/RateCard/TermModal/index.tsx | 73 +++++++++++++++ .../RateCard/TermModal/termModal.module.css | 19 ++++ .../components/RateCard/rate-card.module.css | 15 --- packages/design-system/package.json | 1 + 13 files changed, 224 insertions(+), 184 deletions(-) create mode 100644 packages/booking-flow/lib/components/SelectRate/RoomsContainer/ExtraCostAlert/extraCostAlert.module.css create mode 100644 packages/booking-flow/lib/components/SelectRate/RoomsContainer/ExtraCostAlert/index.tsx create mode 100644 packages/design-system/lib/components/RateCard/TermModal/index.tsx create mode 100644 packages/design-system/lib/components/RateCard/TermModal/termModal.module.css diff --git a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/ExtraCostAlert/extraCostAlert.module.css b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/ExtraCostAlert/extraCostAlert.module.css new file mode 100644 index 000000000..6bd395666 --- /dev/null +++ b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/ExtraCostAlert/extraCostAlert.module.css @@ -0,0 +1,5 @@ +.alert { + max-width: var(--max-width-page); + margin: 0 auto; + padding: var(--Space-x5) 0 0; +} diff --git a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/ExtraCostAlert/index.tsx b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/ExtraCostAlert/index.tsx new file mode 100644 index 000000000..2955268fe --- /dev/null +++ b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/ExtraCostAlert/index.tsx @@ -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 ( +
+ + } + /> +
+ ) +} diff --git a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/index.tsx b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/index.tsx index 505d6d5fc..2e9a9ab0e 100644 --- a/packages/booking-flow/lib/components/SelectRate/RoomsContainer/index.tsx +++ b/packages/booking-flow/lib/components/SelectRate/RoomsContainer/index.tsx @@ -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, + extends + Pick, Pick {} export function RoomsContainer({}: RoomsContainerProps) { @@ -139,6 +141,7 @@ export function RoomsContainer({}: RoomsContainerProps) { return ( <> + diff --git a/packages/design-system/lib/components/Alert/alert.ts b/packages/design-system/lib/components/Alert/alert.ts index 81080f615..0d2257744 100644 --- a/packages/design-system/lib/components/Alert/alert.ts +++ b/packages/design-system/lib/components/Alert/alert.ts @@ -3,7 +3,7 @@ import type { SidepeekContent, } from "@scandic-hotels/common/constants/alert" import type { VariantProps } from "class-variance-authority" -import type { AriaRole } from "react" +import type { AriaRole, ReactNode } from "react" import type { alertVariants } from "./variants" @@ -27,4 +27,5 @@ export interface AlertProps extends VariantProps { close?: () => void ariaRole?: AriaRole ariaLive?: "off" | "assertive" | "polite" + slot?: ReactNode } diff --git a/packages/design-system/lib/components/Alert/index.tsx b/packages/design-system/lib/components/Alert/index.tsx index 81886f52e..f69840616 100644 --- a/packages/design-system/lib/components/Alert/index.tsx +++ b/packages/design-system/lib/components/Alert/index.tsx @@ -26,6 +26,7 @@ export function Alert({ sidepeekContent, ariaLive, ariaRole, + slot, }: AlertProps) { const classNames = alertVariants({ className, @@ -93,6 +94,7 @@ export function Alert({ sidePeekContent={sidepeekContent} /> ) : null} + {slot} {close ? ( + ) : ( + + ) + } + > + {rateTermDetails.map((termGroup) => ( +
+ +

{termGroup.title}

+
+ {termGroup.terms.map((term) => ( + +

+ + {term} +

+
+ ))} +
+ ))} + + ) +} diff --git a/packages/design-system/lib/components/RateCard/TermModal/termModal.module.css b/packages/design-system/lib/components/RateCard/TermModal/termModal.module.css new file mode 100644 index 000000000..f1377ef6b --- /dev/null +++ b/packages/design-system/lib/components/RateCard/TermModal/termModal.module.css @@ -0,0 +1,19 @@ +.terms { + display: flex; + flex-direction: column; + gap: var(--Space-x1); +} + +.term { + display: flex; + gap: var(--Space-x1); +} + +.triggerButton { + cursor: pointer; + z-index: 2; +} + +.triggerText { + text-decoration: underline; +} diff --git a/packages/design-system/lib/components/RateCard/rate-card.module.css b/packages/design-system/lib/components/RateCard/rate-card.module.css index 9d74524dc..c9726545e 100644 --- a/packages/design-system/lib/components/RateCard/rate-card.module.css +++ b/packages/design-system/lib/components/RateCard/rate-card.module.css @@ -65,10 +65,6 @@ position: relative; } -.triggerButton { - cursor: pointer; - z-index: 2; -} .container > * { padding-bottom: var(--Space-x1); border-bottom: 2px solid var(--Neutral-Opacity-Black-5); @@ -147,17 +143,6 @@ gap: var(--Space-x05); } -.terms { - display: flex; - flex-direction: column; - gap: var(--Space-x1); -} - -.term { - display: flex; - gap: var(--Space-x1); -} - .variant-campaign .banner { background-color: var(--Surface-Feedback-Succes); display: flex; diff --git a/packages/design-system/package.json b/packages/design-system/package.json index 2df56f6ca..8d053fe04 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -176,6 +176,7 @@ "./Stepper": "./lib/components/Stepper/index.tsx", "./Switch": "./lib/components/Switch/index.tsx", "./Table": "./lib/components/Table/index.tsx", + "./TermModal": "./lib/components/RateCard/TermModal/index.tsx", "./TextArea": "./lib/components/TextArea/index.tsx", "./TextLink": "./lib/components/TextLink/index.tsx", "./TextLinkButton": "./lib/components/TextLinkButton/index.tsx",