From f34e88db7c99739a645f9a34d0ef827fc1ab0bb2 Mon Sep 17 00:00:00 2001 From: Christel Westerberg Date: Mon, 24 Nov 2025 09:51:16 +0000 Subject: [PATCH] Merged in fix/STAY-124-change-dates (pull request #3199) Fix/STAY-124 change dates * fix: handle change dates for different rate types * fix: update wrong spelling in cancellation rules * fix: add hover state on links * fix: handle multiroom scenario Approved-by: Erik Tiekstra --- .../Actions/CancelStay/Steps/index.tsx | 2 - .../CannotChange/cannotChange.module.css | 3 + .../ChangeDates/Alerts/CannotChange/index.tsx | 54 +++++++++++++ .../ChangeDates/Alerts/CannotChangeDate.tsx | 45 ----------- .../customerSupport.module.css | 28 +++++++ .../Alerts/CustomerSupport/index.tsx | 78 +++++++++++++++++++ .../ChangeDates/Alerts/MultiRoomBooking.tsx | 45 ----------- .../Actions/ChangeDates/Alerts/index.tsx | 48 +++++++++--- .../ChangeDates/Steps/Form/NewDates/index.tsx | 2 +- .../Steps/Form/NewDates/newDates.module.css | 4 + .../ChangeDates/changeDates.module.css | 3 + .../ManageStay/Actions/ChangeDates/index.tsx | 37 ++++----- .../MyStay/utils/mapRoomDetails.ts | 2 +- .../BookingConfirmation/Tracking/tracking.ts | 6 +- packages/common/constants/booking.ts | 2 +- packages/trpc/lib/routers/hotels/output.ts | 7 +- 16 files changed, 235 insertions(+), 131 deletions(-) create mode 100644 apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChange/cannotChange.module.css create mode 100644 apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChange/index.tsx delete mode 100644 apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChangeDate.tsx create mode 100644 apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CustomerSupport/customerSupport.module.css create mode 100644 apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CustomerSupport/index.tsx delete mode 100644 apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/MultiRoomBooking.tsx create mode 100644 apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/changeDates.module.css diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/CancelStay/Steps/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/CancelStay/Steps/index.tsx index 5d9d944ec..859ceaad9 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/CancelStay/Steps/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/CancelStay/Steps/index.tsx @@ -46,14 +46,12 @@ export default function Steps({ closeModal }: StepsProps) { const stepTwo = confirm return ( - {/* Step 1 */} {stepOne ? ( ) : null} - {/* Step 2 */} {stepTwo ? : null} ) diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChange/cannotChange.module.css b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChange/cannotChange.module.css new file mode 100644 index 000000000..f782f5c6d --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChange/cannotChange.module.css @@ -0,0 +1,3 @@ +.textDefault { + color: var(--Text-Default); +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChange/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChange/index.tsx new file mode 100644 index 000000000..09d7f31dd --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChange/index.tsx @@ -0,0 +1,54 @@ +"use client" +import { useIntl } from "react-intl" + +import { Typography } from "@scandic-hotels/design-system/Typography" + +import { useMyStayStore } from "@/stores/my-stay" + +import Modal from "@/components/HotelReservation/MyStay/Modal" + +import styles from "./cannotChange.module.css" + +export default function CannotChangeDate({ + closeModal, +}: { + closeModal: () => void +}) { + const intl = useIntl() + const cancellationText = useMyStayStore( + (state) => state.bookedRoom.rateDefinition.cancellationText + ) + + const title = intl.formatMessage({ + id: "myStay.referenceCard.actions.changeDates", + defaultMessage: "Change dates", + }) + + const notChangeableText = intl.formatMessage( + { + id: "myStay.referenceCard.actions.changeDates.cannotChangeDatesInfo", + defaultMessage: + "Your stay has been booked with {cancellationText} terms which unfortunately doesn’t allow for date changes.", + }, + { + cancellationText, + strong: (str) => {str}, + } + ) + + return ( + + + + +

{notChangeableText}

+
+
+ + + {intl.formatMessage({ defaultMessage: "Back", id: "common.back" })} + + +
+ ) +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChangeDate.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChangeDate.tsx deleted file mode 100644 index 5fde48863..000000000 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CannotChangeDate.tsx +++ /dev/null @@ -1,45 +0,0 @@ -"use client" -import { useIntl } from "react-intl" - -import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert" -import { Alert } from "@scandic-hotels/design-system/Alert" - -import Modal from "@/components/HotelReservation/MyStay/Modal" - -export default function CannotChangeDate({ - closeModal, -}: { - closeModal: () => void -}) { - const intl = useIntl() - return ( - - - - - - - - {intl.formatMessage({ defaultMessage: "Back", id: "common.back" })} - - - - ) -} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CustomerSupport/customerSupport.module.css b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CustomerSupport/customerSupport.module.css new file mode 100644 index 000000000..091f9af45 --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CustomerSupport/customerSupport.module.css @@ -0,0 +1,28 @@ +.links { + display: grid; + gap: var(--Space-x05); +} + +.link { + display: flex; + flex: 1; + color: var(--Text-Interactive-Default); + align-items: center; + background-color: var(--Surface-Feedback-Information-light); + border: 1px solid rgba(0, 0, 0, 0.05); + border-radius: var(--Corner-radius-md); + flex-direction: column; + gap: var(--Space-x1); + padding: var(--Space-x3); + + &:hover { + color: var(--Text-Interactive-Hover); + } +} + +@media screen and (min-width: 768px) { + .links { + gap: var(--Space-x3); + grid-template-columns: 1fr 1fr; + } +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CustomerSupport/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CustomerSupport/index.tsx new file mode 100644 index 000000000..fe8346860 --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/CustomerSupport/index.tsx @@ -0,0 +1,78 @@ +"use client" +import Link from "next/link" +import { useIntl } from "react-intl" + +import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" +import { Typography } from "@scandic-hotels/design-system/Typography" + +import { useMyStayStore } from "@/stores/my-stay" + +import Modal from "@/components/HotelReservation/MyStay/Modal" + +import styles from "./customerSupport.module.css" + +export default function CustomerSupport({ + closeModal, +}: { + closeModal: () => void +}) { + const intl = useIntl() + const { email, phone } = useMyStayStore((state) => ({ + email: state.hotel.contactInformation.email, + phone: state.hotel.contactInformation.phoneNumber, + })) + + const title = intl.formatMessage({ + id: "common.customerService", + defaultMessage: "Customer service", + }) + const contact = intl.formatMessage( + { + id: "myStay.referenceCard.actions.changeDates.contactCustomerSupport", + defaultMessage: + "Please call {phone} or email us at {email} to modify your booking dates.", + }, + { email, phone } + ) + + return ( + + + +

{contact}

+
+
+ +
+ + + + + {intl.formatMessage({ + id: "myStay.referenceCard.actions.customerSupport.makeCall", + defaultMessage: "Make a call", + })} + + + + + + + + {intl.formatMessage({ + id: "myStay.referenceCard.actions.customerSupport.sendEmail", + defaultMessage: "Send an email", + })} + + + +
+
+ + + {intl.formatMessage({ defaultMessage: "Back", id: "common.back" })} + + +
+ ) +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/MultiRoomBooking.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/MultiRoomBooking.tsx deleted file mode 100644 index 47d073c80..000000000 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/MultiRoomBooking.tsx +++ /dev/null @@ -1,45 +0,0 @@ -"use client" -import { useIntl } from "react-intl" - -import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert" -import { Alert } from "@scandic-hotels/design-system/Alert" - -import Modal from "@/components/HotelReservation/MyStay/Modal" - -export default function MultiRoomBooking({ - closeModal, -}: { - closeModal: () => void -}) { - const intl = useIntl() - return ( - - - - - - - - {intl.formatMessage({ defaultMessage: "Back", id: "common.back" })} - - - - ) -} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/index.tsx index 10d552583..f80ed796c 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Alerts/index.tsx @@ -1,29 +1,53 @@ "use client" +import { CancellationRuleEnum } from "@scandic-hotels/common/constants/booking" + import { useMyStayStore } from "@/stores/my-stay" -import CannotChangeDate from "./CannotChangeDate" -import MultiRoomBooking from "./MultiRoomBooking" +import CannotChangeDate from "./CannotChange" +import CustomerSupport from "./CustomerSupport" import NotMainRoom from "./NotMainRoom" export default function Alerts({ children, closeModal, }: React.PropsWithChildren<{ closeModal: () => void }>) { - const { canChangeDate, mainRoom, multiRoom } = useMyStayStore((state) => ({ - canChangeDate: state.bookedRoom.canChangeDate, - mainRoom: state.bookedRoom.mainRoom, - multiRoom: state.bookedRoom.multiRoom, - })) - - if (multiRoom) { - return - } + const { cancellationRule, isModifiable, mainRoom, rooms, multiRoom } = + useMyStayStore((state) => ({ + cancellationRule: state.bookedRoom.rateDefinition.cancellationRule, + cancellationText: state.bookedRoom.rateDefinition.cancellationText, + isModifiable: state.bookedRoom.isModifiable, + mainRoom: state.bookedRoom.mainRoom, + rooms: state.rooms, + multiRoom: state.bookedRoom.multiRoom, + })) if (!mainRoom) { return } - if (!canChangeDate) { + // Multiroom: If any room has rate that allows changing dates needs to contact customer support to change it + // Single room: CHANGEABLE bookings needs to contact customer support to change dates + const isChangeable = multiRoom + ? rooms.some( + (room) => + room.rateDefinition.cancellationRule === + CancellationRuleEnum.Changeable || + room.rateDefinition.cancellationRule === + CancellationRuleEnum.CancellableBefore6PM + ) + : cancellationRule === CancellationRuleEnum.Changeable + + if (!isModifiable && isChangeable) { + return + } + + const isAllNotCancellable = rooms.every( + (room) => + room.rateDefinition.cancellationRule === + CancellationRuleEnum.NotCancellable + ) + // For SAVE bookings we show info that they cannot change dates + if (!isModifiable && isAllNotCancellable) { return } diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Steps/Form/NewDates/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Steps/Form/NewDates/index.tsx index 2f6a80ff1..b218ceb7a 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Steps/Form/NewDates/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/ChangeDates/Steps/Form/NewDates/index.tsx @@ -93,7 +93,7 @@ export default function NewDates({ checkInDate, checkOutDate }: NewDatesProps) { - + {({ close }) => ( <> ({ - canChangeDate: state.bookedRoom.canChangeDate, - checkInDate: state.bookedRoom.checkInDate, - checkInTime: state.hotel.hotelFacts.checkin.checkInTime, - isCancelled: state.bookedRoom.isCancelled, - priceType: state.bookedRoom.priceType, - })) - - const isRewardNight = priceType === "points" - const isDisabled = - canChangeDate && - !isCancelled && - !isRewardNight && - dateHasPassed(checkInDate, checkInTime) + const { isModifiable, cancellationRule } = useMyStayStore((state) => ({ + isModifiable: state.bookedRoom.isModifiable, + cancellationRule: state.bookedRoom.rateDefinition.cancellationRule, + })) function trackChangeDates() { trackMyStayPageLink("modify dates") @@ -39,16 +31,25 @@ export default function ChangeDates() { defaultMessage: "Change dates", id: "myStay.referenceCard.actions.changeDates", }) + + const notMofifiableFlex = + !isModifiable && + cancellationRule === CancellationRuleEnum.CancellableBefore6PM + + // For a FLEX booking that for some reason is not modifiable anymore, we do not show the change dates option + // Could be that the booking is too close to the check-in time + if (notMofifiableFlex) { + return null + } return ( - + {({ close }) => ( diff --git a/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts b/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts index ce0f3e158..5b432dab1 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts +++ b/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts @@ -106,7 +106,7 @@ export function mapRoomDetails({ case CancellationRuleEnum.Changeable: rate = rates.change break - case CancellationRuleEnum.NonCancellable: + case CancellationRuleEnum.NotCancellable: rate = rates.save break } diff --git a/packages/booking-flow/lib/components/BookingConfirmation/Tracking/tracking.ts b/packages/booking-flow/lib/components/BookingConfirmation/Tracking/tracking.ts index 14d0b381a..26b1496a6 100644 --- a/packages/booking-flow/lib/components/BookingConfirmation/Tracking/tracking.ts +++ b/packages/booking-flow/lib/components/BookingConfirmation/Tracking/tracking.ts @@ -27,11 +27,11 @@ import type { Room } from "../../../types/stores/booking-confirmation" function getRate(cancellationRule: RateDefinition["cancellationRule"] | null) { switch (cancellationRule) { - case "CancellableBefore6PM": + case CancellationRuleEnum.CancellableBefore6PM: return RateEnum.flex - case "Changeable": + case CancellationRuleEnum.Changeable: return RateEnum.change - case "NotCancellable": + case CancellationRuleEnum.NotCancellable: return RateEnum.save default: return "" diff --git a/packages/common/constants/booking.ts b/packages/common/constants/booking.ts index 57175318a..8717ae88e 100644 --- a/packages/common/constants/booking.ts +++ b/packages/common/constants/booking.ts @@ -2,6 +2,6 @@ export const SEARCHTYPE = "searchtype" export enum CancellationRuleEnum { CancellableBefore6PM = "CancellableBefore6PM", - NonCancellable = "NonCancellable", + NotCancellable = "NotCancellable", Changeable = "Changeable", } diff --git a/packages/trpc/lib/routers/hotels/output.ts b/packages/trpc/lib/routers/hotels/output.ts index 756c307ce..b5674cafc 100644 --- a/packages/trpc/lib/routers/hotels/output.ts +++ b/packages/trpc/lib/routers/hotels/output.ts @@ -1,5 +1,6 @@ import { z } from "zod" +import { CancellationRuleEnum } from "@scandic-hotels/common/constants/booking" import { RateEnum } from "@scandic-hotels/common/constants/rate" import { RateTypeEnum } from "@scandic-hotels/common/constants/rateType" import { logger } from "@scandic-hotels/common/logger" @@ -109,11 +110,11 @@ export const hotelsAvailabilitySchema = z.object({ function getRate(rate: RateDefinition) { switch (rate.cancellationRule) { - case "CancellableBefore6PM": + case CancellationRuleEnum.CancellableBefore6PM: return RateEnum.flex - case "Changeable": + case CancellationRuleEnum.Changeable: return RateEnum.change - case "NotCancellable": + case CancellationRuleEnum.NotCancellable: return RateEnum.save default: logger.warn(