diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate-old/loading.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate-old/loading.tsx
deleted file mode 100644
index 8bb921599..000000000
--- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate-old/loading.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { HotelInfoCardSkeleton } from "@/components/HotelReservation/SelectRate/HotelInfoCard"
-import { RoomsContainerSkeleton } from "@/components/HotelReservation/SelectRate/RoomsContainer/RoomsContainerSkeleton"
-
-// Select Rate loading doesn't need a layout and wrapper
-// to force loading.tsx to show again since refetch of
-// availability happens client-side and only the RoomCards
-// display a loading state since we already have the hotel
-// data
-export default function LoadingSelectRate() {
- return (
- <>
-
-
- >
- )
-}
diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate-old/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate-old/page.tsx
deleted file mode 100644
index 45d483e4b..000000000
--- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate-old/page.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import { notFound } from "next/navigation"
-
-import { parseSelectRateSearchParams } from "@scandic-hotels/booking-flow/utils/url"
-import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
-
-import { combineRegExps, rateTypeRegex } from "@/constants/booking"
-
-import SelectRate from "@/components/HotelReservation/SelectRate"
-
-import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
-
-const singleRoomRateTypes = combineRegExps(
- [rateTypeRegex.ARB, rateTypeRegex.VOUCHER],
- "i"
-)
-
-export default async function SelectRatePage(
- props: PageArgs
-) {
- const params = await props.params
- const searchParams = await props.searchParams
- const booking = parseSelectRateSearchParams(searchParams)
-
- if (!booking) return notFound()
-
- const isMultiRoom = booking.rooms.length > 1
- const isRedemption = booking.searchType === SEARCH_TYPE_REDEMPTION
- const isArbOrVoucher = booking.bookingCode
- ? singleRoomRateTypes.test(booking.bookingCode)
- : false
-
- if ((isMultiRoom && isRedemption) || (isMultiRoom && isArbOrVoucher)) {
- return notFound()
- }
-
- // If someone tries to update the url with
- // a bookingCode also, then we need to remove it
- if (isRedemption && searchParams.bookingCode) {
- delete searchParams.bookingCode
- }
-
- return
-}
diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/loading.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/loading.tsx
index 8bb921599..2c48fbec1 100644
--- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/loading.tsx
+++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/loading.tsx
@@ -1,11 +1,6 @@
import { HotelInfoCardSkeleton } from "@/components/HotelReservation/SelectRate/HotelInfoCard"
import { RoomsContainerSkeleton } from "@/components/HotelReservation/SelectRate/RoomsContainer/RoomsContainerSkeleton"
-// Select Rate loading doesn't need a layout and wrapper
-// to force loading.tsx to show again since refetch of
-// availability happens client-side and only the RoomCards
-// display a loading state since we already have the hotel
-// data
export default function LoadingSelectRate() {
return (
<>
diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx
index c4be283b8..020a26595 100644
--- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx
+++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx
@@ -7,7 +7,7 @@ import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
import { combineRegExps, rateTypeRegex } from "@/constants/booking"
import { getHotel } from "@/lib/trpc/memoizedRequests"
-import SelectRate from "@/components/HotelReservation/SelectRate2"
+import SelectRate from "@/components/HotelReservation/SelectRate"
import { SelectRateProvider } from "@/contexts/SelectRate/SelectRateContext"
import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/Mobile/BottomSheet/index.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/Mobile/BottomSheet/index.tsx
index 20e5712b2..c3e871858 100644
--- a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/Mobile/BottomSheet/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/Mobile/BottomSheet/index.tsx
@@ -14,7 +14,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
import { useEnterDetailsStore } from "@/stores/enter-details"
import { formId } from "@/components/HotelReservation/EnterDetails/Payment/PaymentClient"
-import { isBookingCodeRate } from "@/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/utils"
+import { isBookingCodeRate } from "@/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/utils"
import styles from "./bottomSheet.module.css"
diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx
index d4850dcc9..2d376b59a 100644
--- a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx
@@ -16,7 +16,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
import BookingCodeChip from "@/components/BookingCodeChip"
import PriceDetailsModal from "@/components/HotelReservation/PriceDetailsModal"
-import { isBookingCodeRate } from "@/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/utils"
+import { isBookingCodeRate } from "@/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/utils"
import SignupPromoDesktop from "@/components/HotelReservation/SignupPromo/Desktop"
import useLang from "@/hooks/useLang"
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/HotelDescription/hotelDescription.module.css b/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/HotelDescription/hotelDescription.module.css
index a6f1bff19..b8dd42ba5 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/HotelDescription/hotelDescription.module.css
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/HotelDescription/hotelDescription.module.css
@@ -1,12 +1,11 @@
.hotelDescription {
overflow: hidden;
- text-align: left;
}
.descriptionWrapper {
display: flex;
flex-direction: column;
- gap: var(--Space-x2);
+ align-items: center;
}
.collapsed {
@@ -25,6 +24,7 @@
display: flex;
flex-direction: column;
align-items: center;
+ margin-top: var(--Space-x2);
}
.description {
@@ -34,6 +34,7 @@
.showMoreButton {
display: flex;
+ align-items: flex-end;
background-color: transparent;
border-width: 0;
padding: 0;
@@ -49,13 +50,16 @@
display: flex;
flex-direction: column;
gap: var(--Space-x15);
+ align-items: center;
}
.facilityList {
display: flex;
+ align-items: flex-start;
justify-content: center;
flex-wrap: wrap;
gap: var(--Space-x15);
+ padding-bottom: var(--Space-x2);
}
.facilitiesItem {
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/HotelDescription/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/HotelDescription/index.tsx
index 7c5334a7d..30a3fdcb4 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/HotelDescription/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/HotelDescription/index.tsx
@@ -53,21 +53,22 @@ export default function HotelDescription({
))}
-
-
-
- {description}
-
-
-
-
- {expanded ? textShowLess : textShowMore}
-
-
+
+
+ {description}
+
+
+
+
+ {expanded ? textShowLess : textShowMore}
+
+
+
+ {expanded && (
+ {hotel.specialAlerts.map((alert) => (
+
+ ))}
-
-
- {hotel.specialAlerts.map((alert) => (
-
- ))}
+ )}
)
}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx
index ddd7fd0b8..a80d1d3b2 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx
@@ -17,13 +17,17 @@ import HotelDescription from "./HotelDescription"
import styles from "./hotelInfoCard.module.css"
-import type { HotelInfoCardProps } from "@/types/components/hotelReservation/selectRate/hotelInfoCard"
+import type { Hotel } from "@scandic-hotels/trpc/types/hotel"
+
+import type { SelectRateBooking } from "@/types/components/hotelReservation/selectRate/selectRate"
import { SidePeekEnum } from "@/types/components/hotelReservation/sidePeek"
-export default async function HotelInfoCard({
- booking,
- hotel,
-}: HotelInfoCardProps) {
+export type HotelInfoCardProps = {
+ booking: SelectRateBooking
+ hotel: Hotel
+}
+
+export async function HotelInfoCard({ booking, hotel }: HotelInfoCardProps) {
const intl = await getIntl()
const sortedFacilities = hotel.detailedFacilities
@@ -34,7 +38,6 @@ export default async function HotelInfoCard({
const bookingFromDate = dt(booking.fromDate)
const bookingToDate = dt(booking.toDate)
-
const specialAlerts = getHotelAlertsForBookingDates(
hotel.specialAlerts,
bookingFromDate,
@@ -109,22 +112,26 @@ export default async function HotelInfoCard({
- {specialAlerts.map((alert) => {
- return (
-
- )
- })}
+ {specialAlerts.map((alert) => (
+
+ ))}
)
}
+function SpecialAlert({ alert }: { alert: Hotel["specialAlerts"][number] }) {
+ return (
+
+ )
+}
+
export function HotelInfoCardSkeleton() {
return (
@@ -157,7 +164,7 @@ export function HotelInfoCardSkeleton() {
>
- {[1, 2, 3, 4, 5].map((id) => {
+ {[1, 2, 3, 4, 5]?.map((id) => {
return (
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate2/RoomsContainer/RateSummary/DesktopSummary.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/DesktopSummary.tsx
similarity index 100%
rename from apps/scandic-web/components/HotelReservation/SelectRate2/RoomsContainer/RateSummary/DesktopSummary.tsx
rename to apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/DesktopSummary.tsx
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Content/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Content/index.tsx
index 785f84aa8..6ff39693b 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Content/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Content/index.tsx
@@ -2,6 +2,7 @@
import { cx } from "class-variance-authority"
import { useIntl } from "react-intl"
+import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { longDateFormat } from "@scandic-hotels/common/constants/dateFormats"
import { dt } from "@scandic-hotels/common/dt"
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
@@ -10,59 +11,64 @@ 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 { useRatesStore } from "@/stores/select-rate"
-
import PriceDetailsModal from "@/components/HotelReservation/PriceDetailsModal"
import SignupPromoDesktop from "@/components/HotelReservation/SignupPromo/Desktop"
+import { useSelectRateContext } from "@/contexts/SelectRate/SelectRateContext"
+import useRateTitles from "@/hooks/booking/useRateTitles"
import useLang from "@/hooks/useLang"
-import { mapToPrice } from "../mapToPrice"
+import { isBookingCodeRate } from "../../utils"
import Room from "../Room"
-import { getMemberPrice, isBookingCodeRate } from "../utils"
import styles from "./summaryContent.module.css"
-import type { SelectRateSummaryProps } from "@/types/components/hotelReservation/summary"
+import type { Price } from "@/contexts/SelectRate/getTotalPrice"
+
+export type SelectRateSummaryProps = {
+ isMember: boolean
+ bookingCode?: string
+ toggleSummaryOpen: () => void
+}
export default function SummaryContent({
- booking,
- rooms,
- totalPrice,
isMember,
- vat,
toggleSummaryOpen,
}: SelectRateSummaryProps) {
- const { rateSummary, defaultCurrency } = useRatesStore((state) => ({
- rateSummary: state.rateSummary,
- defaultCurrency: state.defaultCurrency,
- }))
+ const { selectedRates, input } = useSelectRateContext()
+
const intl = useIntl()
const lang = useLang()
+ const rateTitles = useRateTitles()
- const diff = dt(booking.toDate).diff(booking.fromDate, "days")
-
- const nights = intl.formatMessage(
+ const nightsLabel = intl.formatMessage(
{
defaultMessage: "{totalNights, plural, one {# night} other {# nights}}",
},
- { totalNights: diff }
+ { totalNights: input.nights }
)
- const filteredRooms = rooms.filter(
- (room): room is NonNullable => !!room
- )
const memberPrice =
- rooms.length === 1 && rooms[0] ? getMemberPrice(rooms[0].roomRate) : null
- const containsBookingCodeRate = rooms.find(
- (r) => r && isBookingCodeRate(r.roomRate)
+ selectedRates.rates.length === 1 &&
+ selectedRates.rates[0] &&
+ "member" in selectedRates.rates[0]
+ ? selectedRates.rates[0].member
+ : null
+
+ const containsBookingCodeRate = selectedRates.rates.find(
+ (r) => r && isBookingCodeRate(r)
)
+
+ if (!selectedRates?.totalPrice) {
+ return null
+ }
+
const showDiscounted = containsBookingCodeRate || isMember
- const totalRegularPrice = totalPrice.local?.regularPrice
- ? totalPrice.local.regularPrice
+ const totalRegularPrice = selectedRates?.totalPrice?.local?.regularPrice
+ ? selectedRates.totalPrice.local.regularPrice
: 0
- const showStrikeThroughPrice = totalRegularPrice > totalPrice.local.price
- const priceDetailsRooms = mapToPrice(rateSummary, booking.rooms, isMember)
+ const showStrikeThroughPrice =
+ totalRegularPrice > selectedRates?.totalPrice?.local?.price
return (
@@ -90,26 +96,44 @@ export default function SummaryContent({
- {dt(booking.fromDate).locale(lang).format(longDateFormat[lang])}
+ {dt(input.data?.booking.fromDate)
+ .locale(lang)
+ .format(longDateFormat[lang])}
{/* eslint-disable formatjs/no-literal-string-in-jsx */}
- {dt(booking.toDate).locale(lang).format(longDateFormat[lang])} (
- {nights}){/* eslint-enable formatjs/no-literal-string-in-jsx */}
+ {dt(input.data?.booking.toDate)
+ .locale(lang)
+ .format(longDateFormat[lang])}{" "}
+ ({nightsLabel})
+ {/* eslint-enable formatjs/no-literal-string-in-jsx */}
- {filteredRooms.map((room, idx) => (
-
- ))}
+ {selectedRates.rates.map((room, idx) => {
+ if (!room) {
+ return null
+ }
+
+ return (
+
+ )
+ })}
@@ -130,7 +154,7 @@ export default function SummaryContent({
)}
- {totalPrice.requested ? (
+ {selectedRates.totalPrice.requested ? (
{intl.formatMessage(
@@ -140,10 +164,11 @@ export default function SummaryContent({
{
value: formatPrice(
intl,
- totalPrice.requested.price,
- totalPrice.requested.currency,
- totalPrice.requested.additionalPrice,
- totalPrice.requested.additionalPriceCurrency
+ selectedRates.totalPrice.requested.price,
+ selectedRates.totalPrice.requested.currency,
+ selectedRates.totalPrice.requested.additionalPrice,
+ selectedRates.totalPrice.requested
+ .additionalPriceCurrency
),
}
)}
@@ -161,22 +186,22 @@ export default function SummaryContent({
>
{formatPrice(
intl,
- totalPrice.local.price,
- totalPrice.local.currency,
- totalPrice.local.additionalPrice,
- totalPrice.local.additionalPriceCurrency
+ selectedRates.totalPrice.local.price,
+ selectedRates.totalPrice.local.currency,
+ selectedRates.totalPrice.local.additionalPrice,
+ selectedRates.totalPrice.local.additionalPriceCurrency
)}
{showDiscounted &&
showStrikeThroughPrice &&
- totalPrice.local.regularPrice ? (
+ selectedRates.totalPrice.local.regularPrice ? (
{formatPrice(
intl,
- totalPrice.local.regularPrice,
- totalPrice.local.currency
+ selectedRates.totalPrice.local.regularPrice,
+ selectedRates.totalPrice.local.currency
)}
@@ -185,18 +210,140 @@ export default function SummaryContent({
{
+ if (!room) {
+ return null
+ }
+
+ const mapped = mapToRoom({
+ isMember,
+ rate: room,
+ input,
+ idx,
+ getPriceForRoom: selectedRates.getPriceForRoom,
+ rateTitles,
+ })
+
+ function getPrice(
+ room: NonNullable<(typeof selectedRates.rates)[number]>,
+ isMember: boolean
+ ) {
+ switch (room.type) {
+ case "regular":
+ return {
+ regular: isMember
+ ? (room.member?.localPrice ?? room.public?.localPrice)
+ : room.public?.localPrice,
+ }
+ case "campaign":
+ return {
+ campaign: isMember
+ ? (room.member ?? room.public)
+ : room.public,
+ }
+ case "redemption":
+ return {
+ redemption: room.redemption,
+ }
+ case "code": {
+ if ("corporateCheque" in room) {
+ return {
+ corporateCheque: room.corporateCheque,
+ }
+ }
+
+ if ("voucher" in room) {
+ return {
+ voucher: room.voucher,
+ }
+ }
+ if ("public" in room) {
+ return {
+ regular: isMember
+ ? (room.member?.localPrice ?? room.public?.localPrice)
+ : room.public?.localPrice,
+ }
+ }
+ }
+ default:
+ throw new Error("Unknown price type")
+ }
+ }
+
+ const p = getPrice(room!, isMember)
+
+ return {
+ ...mapped,
+ idx,
+ getPriceForRoom: selectedRates.getPriceForRoom,
+ rateTitles,
+ price: p,
+ bedType: undefined,
+ breakfast: undefined,
+ breakfastIncluded:
+ room?.rateDefinition.breakfastIncluded ?? false,
+ rateDefinition: room.rateDefinition,
+ }
+ })
+ .filter((x) => !!x)}
+ fromDate={input.data?.booking.fromDate ?? ""}
+ toDate={input.data?.booking.toDate ?? ""}
+ totalPrice={selectedRates.totalPrice}
+ vat={selectedRates.vat}
/>
{!isMember && memberPrice ? (
-
+
) : null}
)
}
+
+function mapToRoom({
+ isMember,
+ rate,
+ input,
+ idx,
+ getPriceForRoom,
+ rateTitles,
+}: {
+ isMember: boolean
+ rate: NonNullable<
+ ReturnType["selectedRates"]["rates"][number]
+ >
+ input: ReturnType["input"]
+ idx: number
+ getPriceForRoom: (roomIndex: number) => Price | null
+ rateTitles: ReturnType
+}) {
+ return {
+ adults: input.data?.booking.rooms[idx].adults || 0,
+ childrenInRoom: input.data?.booking.rooms[idx].childrenInRoom,
+ roomType: rate.roomInfo.roomType,
+ roomRate: rate,
+ cancellationText: rateTitles[rate.rate].title,
+ roomPrice: {
+ perNight: { local: { price: -1, currency: CurrencyEnum.SEK } },
+ perStay: getPriceForRoom(idx) ?? {
+ local: { price: -1, currency: CurrencyEnum.Unknown },
+ },
+ },
+ rateDetails: isMember
+ ? (rate.rateDefinitionMember?.generalTerms ??
+ rate.rateDefinition.generalTerms)
+ : rate.rateDefinition.generalTerms,
+ packages: rate.roomInfo.selectedPackages,
+ }
+}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Content/summaryContent.module.css b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Content/summaryContent.module.css
index a7f7834f6..bbc85e092 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Content/summaryContent.module.css
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Content/summaryContent.module.css
@@ -49,7 +49,7 @@
}
}
-.prices .strikeThroughRate {
+.strikeThroughRate {
text-decoration: line-through;
color: var(--Text-Secondary);
}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Room/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Room/index.tsx
index df3000bd9..7287f4fc8 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Room/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Room/index.tsx
@@ -8,11 +8,10 @@ import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { ChildBedMapEnum } from "@scandic-hotels/trpc/enums/childBedMapEnum"
-import { getRoomPrice } from "@/stores/enter-details/helpers"
-
import Modal from "@/components/Modal"
-import { getMemberPrice, isBookingCodeRate } from "../utils"
+import { isBookingCodeRate } from "../../utils"
+import { getMemberPrice } from "../utils"
import styles from "./room.module.css"
@@ -72,7 +71,6 @@ export default function Room({
const memberPrice = getMemberPrice(room.roomRate)
const showMemberPrice = !!(isMember && memberPrice && roomNumber === 1)
const showDiscounted = isBookingCodeRate(room.roomRate) || showMemberPrice
- const regularRate = getRoomPrice(room.roomRate, showMemberPrice)
const adultsMsg = intl.formatMessage(
{
@@ -146,13 +144,12 @@ export default function Room({
room.roomPrice.perStay.local.additionalPriceCurrency
)}
- {/* Show the price on which discount applies as Striked when discounted price is available */}
- {showDiscounted && regularRate.perStay.local.regularPrice ? (
+ {showDiscounted && room.roomPrice.perStay.local.price ? (
{formatPrice(
intl,
- regularRate.perStay.local.regularPrice,
- regularRate.perStay.local.currency
+ room.roomPrice.perStay.local.price,
+ room.roomPrice.perStay.local.currency
)}
) : null}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Room/room.module.css b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Room/room.module.css
index 28db86422..085bec231 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Room/room.module.css
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Room/room.module.css
@@ -18,6 +18,7 @@
.termsText:nth-child(n) {
display: flex;
+ align-items: center;
margin-bottom: var(--Space-x1);
}
@@ -46,7 +47,7 @@
}
}
-.prices .strikeThroughRate {
+.strikeThroughRate {
text-decoration: line-through;
color: var(--Text-Secondary);
}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Summary.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Summary.tsx
deleted file mode 100644
index ed9701d0f..000000000
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Summary.tsx
+++ /dev/null
@@ -1,370 +0,0 @@
-"use client"
-import { Fragment } from "react"
-import { Button as ButtonRAC } from "react-aria-components"
-import { useIntl } from "react-intl"
-
-import { longDateFormat } from "@scandic-hotels/common/constants/dateFormats"
-import { dt } from "@scandic-hotels/common/dt"
-import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
-import Body from "@scandic-hotels/design-system/Body"
-import { Button } from "@scandic-hotels/design-system/Button"
-import Caption from "@scandic-hotels/design-system/Caption"
-import { Divider } from "@scandic-hotels/design-system/Divider"
-import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
-import Subtitle from "@scandic-hotels/design-system/Subtitle"
-import { ChildBedMapEnum } from "@scandic-hotels/trpc/enums/childBedMapEnum"
-
-import { useRatesStore } from "@/stores/select-rate"
-
-import PriceDetailsModal from "@/components/HotelReservation/PriceDetailsModal"
-import SignupPromoDesktop from "@/components/HotelReservation/SignupPromo/Desktop"
-import Modal from "@/components/Modal"
-import useLang from "@/hooks/useLang"
-
-import { mapToPrice } from "./mapToPrice"
-import { isBookingCodeRate } from "./utils"
-
-import styles from "./summary.module.css"
-
-import type { RoomRate } from "@/types/components/hotelReservation/enterDetails/details"
-import type { SelectRateSummaryProps } from "@/types/components/hotelReservation/summary"
-
-export default function Summary({
- booking,
- rooms,
- totalPrice,
- isMember,
- vat,
- toggleSummaryOpen,
-}: SelectRateSummaryProps) {
- const { rateSummary, defaultCurrency } = useRatesStore((state) => ({
- rateSummary: state.rateSummary,
- defaultCurrency: state.defaultCurrency,
- }))
- const intl = useIntl()
- const lang = useLang()
-
- const diff = dt(booking.toDate).diff(booking.fromDate, "days")
-
- const nights = intl.formatMessage(
- {
- defaultMessage: "{totalNights, plural, one {# night} other {# nights}}",
- },
- { totalNights: diff }
- )
-
- function getMemberPrice(roomRate: RoomRate) {
- if ("member" in roomRate && roomRate.member) {
- return {
- amount: roomRate.member.localPrice.pricePerStay,
- currency: roomRate.member.localPrice.currency,
- pricePerNight: roomRate.member.localPrice.pricePerNight,
- }
- }
-
- return null
- }
-
- const memberPrice =
- rooms.length === 1 && rooms[0] ? getMemberPrice(rooms[0].roomRate) : null
-
- const containsBookingCodeRate = rooms.find(
- (r) => r && isBookingCodeRate(r.roomRate)
- )
- const showDiscounted = containsBookingCodeRate || isMember
-
- const priceDetailsRooms = mapToPrice(rateSummary, booking.rooms, isMember)
-
- return (
-
-
-
-
- {intl.formatMessage({
- defaultMessage: "Booking summary",
- })}
-
-
- {dt(booking.fromDate).locale(lang).format(longDateFormat[lang])}
-
- {/* eslint-disable formatjs/no-literal-string-in-jsx */}
- {dt(booking.toDate).locale(lang).format(longDateFormat[lang])} (
- {nights}){/* eslint-enable formatjs/no-literal-string-in-jsx */}
-
-
-
-
-
- {rooms.map((room, idx) => {
- if (!room) {
- return null
- }
-
- const roomNumber = idx + 1
- const adults = room.adults
- const childrenInRoom = room.childrenInRoom
-
- const childrenBeds = childrenInRoom?.reduce(
- (acc, value) => {
- const bedType = Number(value.bed)
- if (bedType === ChildBedMapEnum.IN_ADULTS_BED) {
- return acc
- }
- const count = acc.get(bedType) ?? 0
- acc.set(bedType, count + 1)
- return acc
- },
- new Map([
- [ChildBedMapEnum.IN_CRIB, 0],
- [ChildBedMapEnum.IN_EXTRA_BED, 0],
- ])
- )
-
- const childBedCrib = childrenBeds?.get(ChildBedMapEnum.IN_CRIB)
- const childBedExtraBed = childrenBeds?.get(ChildBedMapEnum.IN_EXTRA_BED)
-
- const memberPrice = getMemberPrice(room.roomRate)
- const showMemberPrice = !!(isMember && memberPrice && roomNumber === 1)
- const showDiscounted =
- isBookingCodeRate(room.roomRate) || showMemberPrice
-
- const adultsMsg = intl.formatMessage(
- {
- defaultMessage:
- "{totalAdults, plural, one {# adult} other {# adults}}",
- },
- { totalAdults: adults }
- )
-
- const guestsParts = [adultsMsg]
- if (childrenInRoom?.length) {
- const childrenMsg = intl.formatMessage(
- {
- defaultMessage:
- "{totalChildren, plural, one {# child} other {# children}}",
- },
- { totalChildren: childrenInRoom.length }
- )
- guestsParts.push(childrenMsg)
- }
-
- const roomPackages = room.packages
- const zeroPrice = formatPrice(intl, 0, defaultCurrency)
-
- return (
-
-
-
- {rooms.length > 1 ? (
-
- {intl.formatMessage(
- {
- defaultMessage: "Room {roomIndex}",
- },
- {
- roomIndex: roomNumber,
- }
- )}
-
- ) : null}
-
- {room.roomType}
-
- {formatPrice(
- intl,
- room.roomPrice.perStay.local.price,
- room.roomPrice.perStay.local.currency,
- room.roomPrice.perStay.local.additionalPrice,
- room.roomPrice.perStay.local.additionalPriceCurrency
- )}
-
-
-
- {guestsParts.join(", ")}
-
-
- {room.cancellationText}
-
-
- {intl.formatMessage({
- defaultMessage: "Rate details",
- })}
-
-
- }
- title={room.cancellationText}
- >
-
- {room.rateDetails?.map((info) => (
-
-
- {info}
-
- ))}
-
-
-
-
- {childBedCrib ? (
-
-
-
- {intl.formatMessage(
- {
- defaultMessage: "Crib (child) × {count}",
- },
- { count: childBedCrib }
- )}
-
-
- {intl.formatMessage({
- defaultMessage: "Subject to availability",
- })}
-
-
- {zeroPrice}
-
- ) : null}
- {childBedExtraBed ? (
-
-
-
- {intl.formatMessage(
- {
- defaultMessage: "Extra bed (child) × {count}",
- },
- {
- count: childBedExtraBed,
- }
- )}
-
-
- {zeroPrice}
-
- ) : null}
- {roomPackages?.map((pkg) => (
-
-
- {pkg.description}
-
-
-
- {formatPrice(
- intl,
- pkg.localPrice.price,
- pkg.localPrice.currency
- )}
-
-
- ))}
-
-
-
- )
- })}
-
-
-
-
- {intl.formatMessage(
- {
- defaultMessage: "
Total price (incl VAT)",
- },
- { b: (str) =>
{str} }
- )}
-
-
-
-
-
- {formatPrice(
- intl,
- totalPrice.local.price,
- totalPrice.local.currency,
- totalPrice.local.additionalPrice,
- totalPrice.local.additionalPriceCurrency
- )}
-
- {booking.bookingCode && totalPrice.local.regularPrice && (
-
- {formatPrice(
- intl,
- totalPrice.local.regularPrice,
- totalPrice.local.currency
- )}
-
- )}
- {totalPrice.requested && (
-
- {intl.formatMessage(
- {
- defaultMessage: "Approx. {value}",
- },
- {
- value: formatPrice(
- intl,
- totalPrice.requested.price,
- totalPrice.requested.currency,
- totalPrice.requested.additionalPrice,
- totalPrice.requested.additionalPriceCurrency
- ),
- }
- )}
-
- )}
-
-
-
-
- {!isMember && memberPrice ? (
-
- ) : null}
-
- )
-}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/index.tsx
index 4bfc3b243..d0ab3845c 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/index.tsx
@@ -9,35 +9,21 @@ import { Button } from "@scandic-hotels/design-system/Button"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
-import { useRatesStore } from "@/stores/select-rate"
+import { useSelectRateContext } from "@/contexts/SelectRate/SelectRateContext"
+import { useIsUserLoggedIn } from "@/hooks/useIsUserLoggedIn"
+import { isBookingCodeRate } from "../utils"
import SummaryContent from "./Content"
-import { mapRate } from "./mapRate"
-import { isBookingCodeRate } from "./utils"
import styles from "./mobileSummary.module.css"
-import type { RoomsAvailability } from "@scandic-hotels/trpc/types/roomAvailability"
-
-import type { MobileSummaryProps } from "@/types/components/hotelReservation/selectRate/rateSummary"
-
-export default function MobileSummary({
- isAllRoomsSelected,
- isUserLoggedIn,
- totalPriceToShow,
-}: MobileSummaryProps) {
+export function MobileSummary() {
const intl = useIntl()
const scrollY = useRef(0)
const [isSummaryOpen, setIsSummaryOpen] = useState(false)
+ const isUserLoggedIn = useIsUserLoggedIn()
- const { booking, bookingRooms, roomsAvailability, rateSummary, vat } =
- useRatesStore((state) => ({
- booking: state.booking,
- bookingRooms: state.booking.rooms,
- roomsAvailability: state.roomsAvailability,
- rateSummary: state.rateSummary,
- vat: state.vat,
- }))
+ const { selectedRates } = useSelectRateContext()
function toggleSummaryOpen() {
setIsSummaryOpen(!isSummaryOpen)
@@ -67,38 +53,28 @@ export default function MobileSummary({
}
}, [isSummaryOpen])
- const roomRateDefinitions = roomsAvailability?.find(
- (ra): ra is RoomsAvailability => "rateDefinitions" in ra
+ const containsBookingCodeRate = selectedRates.rates.find(
+ (r) => r && isBookingCodeRate(r)
)
- if (!roomRateDefinitions) {
+ const showDiscounted = containsBookingCodeRate || isUserLoggedIn
+
+ if (!selectedRates.totalPrice) {
return null
}
- const rooms = rateSummary.map((room, index) =>
- room ? mapRate(room, index, bookingRooms, room.packages) : null
- )
-
- const containsBookingCodeRate = rateSummary.find(
- (r) => r && isBookingCodeRate(r.product)
- )
- const showDiscounted = containsBookingCodeRate || isUserLoggedIn
- const totalRegularPrice = totalPriceToShow.local?.regularPrice
- ? totalPriceToShow.local.regularPrice
+ const totalRegularPrice = selectedRates.totalPrice.local?.regularPrice
+ ? selectedRates.totalPrice.local.regularPrice
: 0
const showStrikeThroughPrice =
- totalRegularPrice > totalPriceToShow.local.price
+ totalRegularPrice > selectedRates.totalPrice.local?.price
return (
@@ -124,22 +100,22 @@ export default function MobileSummary({
>
{formatPrice(
intl,
- totalPriceToShow.local.price,
- totalPriceToShow.local.currency,
- totalPriceToShow.local.additionalPrice,
- totalPriceToShow.local.additionalPriceCurrency
+ selectedRates.totalPrice.local.price,
+ selectedRates.totalPrice.local.currency,
+ selectedRates.totalPrice.local.additionalPrice,
+ selectedRates.totalPrice.local.additionalPriceCurrency
)}
{showDiscounted &&
showStrikeThroughPrice &&
- totalPriceToShow.local.regularPrice ? (
+ selectedRates.totalPrice.local.regularPrice ? (
{formatPrice(
intl,
- totalPriceToShow.local.regularPrice,
- totalPriceToShow.local.currency
+ selectedRates.totalPrice.local.regularPrice,
+ selectedRates.totalPrice.local.currency
)}
@@ -166,7 +142,7 @@ export default function MobileSummary({
size="Large"
type="submit"
typography="Body/Paragraph/mdBold"
- isDisabled={!isAllRoomsSelected}
+ isDisabled={selectedRates.state !== "ALL_SELECTED"}
>
{intl.formatMessage({
defaultMessage: "Continue",
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/mobileSummary.module.css b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/mobileSummary.module.css
index fdd7f901f..0daf39bb1 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/mobileSummary.module.css
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/mobileSummary.module.css
@@ -88,7 +88,7 @@
}
}
-.priceDetailsButton .strikeThroughRate {
+.strikeThroughRate {
text-decoration: line-through;
color: var(--Text-Secondary);
}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/summary.module.css b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/summary.module.css
index 20d8d5415..0062f8dc8 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/summary.module.css
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/summary.module.css
@@ -2,8 +2,8 @@
border-radius: var(--Corner-radius-lg);
display: flex;
flex-direction: column;
- gap: var(--Space-x2);
- padding: var(--Space-x3);
+ gap: var(--Spacing-x2);
+ padding: var(--Spacing-x3);
height: 100%;
}
@@ -31,32 +31,32 @@
.date {
align-items: center;
display: flex;
- gap: var(--Space-x1);
+ gap: var(--Spacing-x1);
justify-content: flex-start;
grid-area: date;
}
.link {
- margin-top: var(--Space-x1);
+ margin-top: var(--Spacing-x1);
}
.addOns {
display: flex;
flex-direction: column;
- gap: var(--Space-x15);
+ gap: var(--Spacing-x-one-and-half);
overflow-y: auto;
}
.rateDetailsPopover {
display: flex;
flex-direction: column;
- gap: var(--Space-x05);
+ gap: var(--Spacing-x-half);
max-width: 360px;
}
.entry {
display: flex;
- gap: var(--Space-x05);
+ gap: var(--Spacing-x-half);
justify-content: space-between;
}
@@ -67,7 +67,7 @@
.total {
display: flex;
flex-direction: column;
- gap: var(--Space-x2);
+ gap: var(--Spacing-x2);
}
.bottomDivider {
@@ -79,15 +79,16 @@
}
.terms {
- margin-top: var(--Space-x3);
- margin-bottom: var(--Space-x3);
+ margin-top: var(--Spacing-x3);
+ margin-bottom: var(--Spacing-x3);
}
.termsText:nth-child(n) {
display: flex;
- margin-bottom: var(--Space-x1);
+ align-items: center;
+ margin-bottom: var(--Spacing-x1);
}
.terms .termsIcon {
- margin-right: var(--Space-x1);
+ margin-right: var(--Spacing-x1);
}
@media screen and (min-width: 1367px) {
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/utils.ts b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/utils.ts
index ee5f420f2..8863fd899 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/utils.ts
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/utils.ts
@@ -1,7 +1,3 @@
-import { RateTypeEnum } from "@scandic-hotels/trpc/enums/rateType"
-
-import type { Product } from "@scandic-hotels/trpc/types/roomAvailability"
-
import type { RoomRate } from "@/types/components/hotelReservation/enterDetails/details"
export function getMemberPrice(roomRate: RoomRate) {
@@ -15,21 +11,3 @@ export function getMemberPrice(roomRate: RoomRate) {
return null
}
-
-export function isBookingCodeRate(product: Product) {
- if (
- "corporateCheque" in product ||
- "redemption" in product ||
- "voucher" in product
- ) {
- return true
- } else {
- if (product.public) {
- return product.public.rateType !== RateTypeEnum.Regular
- }
- if (product.member) {
- return product.member.rateType !== RateTypeEnum.Regular
- }
- return false
- }
-}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/index.tsx
index 71416f35c..94854269f 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/index.tsx
@@ -1,138 +1,37 @@
"use client"
+
import { useRouter, useSearchParams } from "next/navigation"
-import { useSession } from "next-auth/react"
import { useState, useTransition } from "react"
-import { useIntl } from "react-intl"
-import { dt } from "@scandic-hotels/common/dt"
-import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
-import Body from "@scandic-hotels/design-system/Body"
-import Caption from "@scandic-hotels/design-system/Caption"
-import Footnote from "@scandic-hotels/design-system/Footnote"
-import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton"
-import Subtitle from "@scandic-hotels/design-system/Subtitle"
-import { RateEnum } from "@scandic-hotels/trpc/enums/rate"
-import { RateTypeEnum } from "@scandic-hotels/trpc/enums/rateType"
+import { ErrorBoundary } from "@/components/ErrorBoundary/ErrorBoundary"
+import { useSelectRateContext } from "@/contexts/SelectRate/SelectRateContext"
-import { useRatesStore } from "@/stores/select-rate"
-
-import SignupPromoDesktop from "@/components/HotelReservation/SignupPromo/Desktop"
-import { isValidClientSession } from "@/utils/clientSession"
-
-import MobileSummary from "./MobileSummary"
-import { getTotalPrice } from "./utils"
+import { DesktopSummary } from "./DesktopSummary"
+import { MobileSummary } from "./MobileSummary"
import styles from "./rateSummary.module.css"
-export default function RateSummary() {
- const {
- bookingCode,
- bookingRooms,
- dates,
- isFetchingPackages,
- rateSummary,
- roomsAvailability,
- } = useRatesStore((state) => ({
- bookingCode: state.booking.bookingCode,
- bookingRooms: state.booking.rooms,
- dates: {
- checkInDate: state.booking.fromDate,
- checkOutDate: state.booking.toDate,
- },
- isFetchingPackages: state.rooms.some((room) => room.isFetchingPackages),
- rateSummary: state.rateSummary,
- roomsAvailability: state.roomsAvailability,
- }))
- const { data: session } = useSession()
- const isUserLoggedIn = isValidClientSession(session)
+export function RateSummary() {
+ return (
+ // eslint-disable-next-line formatjs/no-literal-string-in-jsx
+
Unable to render summary }>
+
+
+ )
+}
+
+function InnerRateSummary() {
+ const { selectedRates, input } = useSelectRateContext()
const [isSubmitting, setIsSubmitting] = useState(false)
- const intl = useIntl()
const router = useRouter()
const params = useSearchParams()
const [_, startTransition] = useTransition()
- if (!roomsAvailability) {
+ if (selectedRates.state === "NONE_SELECTED") {
return null
}
- const checkInDate = new Date(dates.checkInDate)
- const checkOutDate = new Date(dates.checkOutDate)
- const nights = dt(checkOutDate).diff(dt(checkInDate), "days")
-
- const totalNights = intl.formatMessage(
- {
- defaultMessage: "{totalNights, plural, one {# night} other {# nights}}",
- },
- { totalNights: nights }
- )
- const totalAdults = intl.formatMessage(
- {
- defaultMessage: "{totalAdults, plural, one {# adult} other {# adults}}",
- },
- { totalAdults: bookingRooms.reduce((acc, room) => acc + room.adults, 0) }
- )
- const childrenInOneOrMoreRooms = bookingRooms.some(
- (room) => room.childrenInRoom?.length
- )
- const childrenInroom = intl.formatMessage(
- {
- defaultMessage:
- "{totalChildren, plural, one {# child} other {# children}}",
- },
- {
- totalChildren: bookingRooms.reduce(
- (acc, room) => acc + (room.childrenInRoom?.length ?? 0),
- 0
- ),
- }
- )
- const totalChildren = childrenInOneOrMoreRooms ? `, ${childrenInroom}` : ""
- const totalRooms = intl.formatMessage(
- {
- defaultMessage: "{totalRooms, plural, one {# room} other {# rooms}}",
- },
- { totalRooms: bookingRooms.length }
- )
-
- const summaryPriceText = `${totalNights}, ${totalAdults}${totalChildren}, ${totalRooms}`
-
- const totalRoomsRequired = bookingRooms.length
- const isAllRoomsSelected =
- rateSummary.filter((rate) => rate !== null).length === totalRoomsRequired
- const hasMemberRates = rateSummary.some(
- (room) => room && "member" in room.product && room.product.member
- )
- const showMemberDiscountBanner = hasMemberRates && !isUserLoggedIn
-
- const freeCancelation = intl.formatMessage({
- defaultMessage: "Free cancellation",
- })
- const nonRefundable = intl.formatMessage({
- defaultMessage: "Non-refundable",
- })
- const freeBooking = intl.formatMessage({
- defaultMessage: "Free rebooking",
- })
- const payLater = intl.formatMessage({
- defaultMessage: "Pay later",
- })
- const payNow = intl.formatMessage({
- defaultMessage: "Pay now",
- })
-
- function getRateDetails(rate: RateEnum) {
- switch (rate) {
- case RateEnum.change:
- return `${freeBooking}, ${payNow}`
- case RateEnum.flex:
- return `${freeCancelation}, ${payLater}`
- case RateEnum.save:
- default:
- return `${nonRefundable}, ${payNow}`
- }
- }
-
function handleSubmit(e: React.FormEvent) {
e.preventDefault()
setIsSubmitting(true)
@@ -141,62 +40,15 @@ export default function RateSummary() {
})
}
- if (!rateSummary.length || isFetchingPackages) {
- return null
- }
+ const totalPriceToShow = selectedRates.totalPrice
- const isBookingCodeRate = rateSummary.some(
- (rate) =>
- rate &&
- "public" in rate.product &&
- rate.product.public?.rateType !== RateTypeEnum.Regular
- )
- const isVoucherRate = rateSummary.some(
- (rate) => rate && "voucher" in rate.product
- )
- const isCorporateChequeRate = rateSummary.some(
- (rate) => rate && "corporateCheque" in rate.product
- )
- const showDiscounted =
- isUserLoggedIn ||
- isBookingCodeRate ||
- isVoucherRate ||
- isCorporateChequeRate
-
- const mainRoomProduct = rateSummary[0]
- const totalPriceToShow = getTotalPrice(
- mainRoomProduct,
- rateSummary,
- isUserLoggedIn,
- intl
- )
-
- const rateProduct = rateSummary.find((rate) => rate?.product)?.product
-
- if (!totalPriceToShow || !rateProduct) {
- return null
- }
-
- let mainRoomCurrency = ""
- if ("member" in rateProduct && rateProduct.member?.localPrice) {
- mainRoomCurrency = rateProduct.member.localPrice.currency
- }
if (
- !mainRoomCurrency &&
- "public" in rateProduct &&
- rateProduct.public?.localPrice
+ !totalPriceToShow ||
+ !selectedRates.rates.some((room) => room?.isSelected ?? false)
) {
- mainRoomCurrency = rateProduct.public.localPrice.currency
+ return null
}
- const totalRegularPrice = totalPriceToShow.local?.regularPrice
- ? totalPriceToShow.local.regularPrice
- : 0
- const isTotalRegularPriceGreaterThanPrice =
- totalRegularPrice > totalPriceToShow.local.price
- const showStrikedThroughPrice =
- (!!bookingCode || isUserLoggedIn) && isTotalRegularPriceGreaterThanPrice
-
// attribute data-footer-spacing used to add spacing
// beneath footer to be able to show entire footer upon
// scrolling down to the bottom of the page
@@ -209,218 +61,21 @@ export default function RateSummary() {
>
-
- {rateSummary.map((room, index) => {
- if (!room) {
- return (
-
-
- {intl.formatMessage(
- {
- defaultMessage: "Room {roomIndex}",
- },
- { roomIndex: index + 1 }
- )}
-
-
- {intl.formatMessage({
- defaultMessage: "Select room",
- })}
-
-
- )
- }
-
- return (
-
- {rateSummary.length > 1 ? (
- <>
-
- {intl.formatMessage(
- {
- defaultMessage: "Room {roomIndex}",
- },
- { roomIndex: index + 1 }
- )}
-
- {room.roomType}
-
- {getRateDetails(room.rate)}
-
- >
- ) : (
- <>
-
- {room.roomType}
-
-
- {getRateDetails(room.rate)}
-
- >
- )}
-
- )
- })}
- {/* Render unselected rooms */}
- {Array.from({
- length: totalRoomsRequired - rateSummary.length,
- }).map((_, index) => (
-
-
- {intl.formatMessage(
- {
- defaultMessage: "Room {roomIndex}",
- },
- { roomIndex: rateSummary.length + index + 1 }
- )}
-
-
- {intl.formatMessage({
- defaultMessage: "Select room",
- })}
-
-
- ))}
-
-
- {showMemberDiscountBanner && (
-
- {
- if (!rate) {
- return total
- }
-
- const { packages: roomPackages, product } = rate
-
- const memberExists = "member" in product && product.member
- const publicExists = "public" in product && product.public
- if (!memberExists) {
- if (!publicExists) {
- return total
- }
- }
-
- const price =
- product.member?.localPrice.pricePerStay ||
- product.public?.localPrice.pricePerStay
-
- if (!price) {
- return total
- }
-
- const selectedPackagesPrice = roomPackages.reduce(
- (acc, pkg) => acc + pkg.localPrice.totalPrice,
- 0
- )
-
- return total + price + selectedPackagesPrice
- }, 0),
- currency: mainRoomCurrency,
- }}
- />
-
- )}
-
-
- {intl.formatMessage(
- {
- defaultMessage: "Total price (incl VAT)",
- },
- { b: (str) => {str} }
- )}
-
-
{summaryPriceText}
-
-
-
-
- {formatPrice(
- intl,
- totalPriceToShow.local.price,
- totalPriceToShow.local.currency,
- totalPriceToShow.local.additionalPrice,
- totalPriceToShow.local.additionalPriceCurrency
- )}
-
- {showStrikedThroughPrice &&
- totalPriceToShow.local.regularPrice ? (
-
- {formatPrice(
- intl,
- totalPriceToShow.local.regularPrice,
- totalPriceToShow.local.currency
- )}
-
- ) : null}
- {totalPriceToShow.requested ? (
-
- {intl.formatMessage(
- {
- defaultMessage: "Approx. {value}",
- },
- {
- value: formatPrice(
- intl,
- totalPriceToShow.requested.price,
- totalPriceToShow.requested.currency,
- totalPriceToShow.requested.additionalPrice,
- totalPriceToShow.requested.additionalPriceCurrency
- ),
- }
- )}
-
- ) : null}
-
-
-
- {intl.formatMessage({
- defaultMessage: "Total price",
- })}
-
-
- {formatPrice(
- intl,
- totalPriceToShow.local.price,
- totalPriceToShow.local.currency,
- totalPriceToShow.local.additionalPrice,
- totalPriceToShow.local.additionalPriceCurrency
- )}
-
-
- {summaryPriceText}
-
-
-
-
-
+ {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
+
Unable to render desktop summary}>
+
+
-
+ {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
+ Unable to render mobile summary
}>
+
+
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/utils.ts b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/utils.ts
index 6a2073b5d..d24d6a7f3 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/utils.ts
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/utils.ts
@@ -4,7 +4,10 @@ import { RateTypeEnum } from "@scandic-hotels/trpc/enums/rateType"
import { sumPackages } from "@/components/HotelReservation/utils"
import type { Packages } from "@scandic-hotels/trpc/types/packages"
-import type { RedemptionProduct } from "@scandic-hotels/trpc/types/roomAvailability"
+import type {
+ Product,
+ RedemptionProduct,
+} from "@scandic-hotels/trpc/types/roomAvailability"
import type { IntlShape } from "react-intl"
import type { Price } from "@/types/components/hotelReservation/price"
@@ -23,10 +26,8 @@ export function calculateTotalPrice(
const roomNr = idx + 1
const isMainRoom = roomNr === 1
let rate
- let publicRate
if (isUserLoggedIn && isMainRoom && room.product.member) {
rate = room.product.member
- publicRate = room.product.public
} else if (room.product.public) {
rate = room.product.public
}
@@ -50,16 +51,10 @@ export function calculateTotalPrice(
total.local.price =
total.local.price + rate.localPrice.pricePerStay + packagesPrice.local
- if (rate.rateType === RateTypeEnum.Regular && publicRate) {
+ if (rate.localPrice.regularPricePerStay) {
total.local.regularPrice =
(total.local.regularPrice || 0) +
- publicRate.localPrice.pricePerStay +
- packagesPrice.local
- } else {
- total.local.regularPrice =
- (total.local.regularPrice || 0) +
- (rate.localPrice.regularPricePerStay ||
- rate.localPrice.pricePerStay) +
+ rate.localPrice.regularPricePerStay +
packagesPrice.local
}
@@ -248,3 +243,23 @@ export function getTotalPrice(
return calculateTotalPrice(summaryArray, isUserLoggedIn)
}
+
+export function isBookingCodeRate(product: Product | undefined | null) {
+ if (!product) return false
+
+ if (
+ "corporateCheque" in product ||
+ "redemption" in product ||
+ "voucher" in product
+ ) {
+ return true
+ } else {
+ if (product.public) {
+ return product.public.rateType !== RateTypeEnum.Regular
+ }
+ if (product.member) {
+ return product.member.rateType !== RateTypeEnum.Regular
+ }
+ return false
+ }
+}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx
index cf079b746..3ac188e8e 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx
@@ -1,9 +1,7 @@
"use client"
-import { useSession } from "next-auth/react"
import { useIntl } from "react-intl"
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
-import { dt } from "@scandic-hotels/common/dt"
import { logger } from "@scandic-hotels/common/logger"
import Body from "@scandic-hotels/design-system/Body"
import Caption from "@scandic-hotels/design-system/Caption"
@@ -13,123 +11,40 @@ import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton
import Subtitle from "@scandic-hotels/design-system/Subtitle"
import { RateEnum } from "@scandic-hotels/trpc/enums/rate"
-import { useRatesStore } from "@/stores/select-rate"
-
import Chip from "@/components/TempDesignSystem/Chip"
-import { useRoomContext } from "@/contexts/SelectRate/Room"
-import { isValidClientSession } from "@/utils/clientSession"
+import { useSelectRateContext } from "@/contexts/SelectRate/SelectRateContext"
+import { useIsUserLoggedIn } from "@/hooks/useIsUserLoggedIn"
import styles from "./selectedRoomPanel.module.css"
-export default function SelectedRoomPanel() {
+export function SelectedRoomPanel({ roomIndex }: { roomIndex: number }) {
const intl = useIntl()
- const { dates, roomCategories, rooms } = useRatesStore((state) => ({
- dates: {
- from: state.booking.fromDate,
- to: state.booking.toDate,
- },
- roomCategories: state.roomCategories,
- rooms: state.rooms,
- }))
- const { data: session } = useSession()
- const isUserLoggedIn = isValidClientSession(session)
+
+ const isMainRoom = roomIndex === 0
+ const roomNr = roomIndex + 1
const {
- actions: { modifyRate },
- isMainRoom,
- roomNr,
- selectedPackages,
- selectedRate,
- } = useRoomContext()
- const nights = dt(dates.to).diff(dt(dates.from), "days")
+ selectedRates,
+ actions: { setActiveRoom },
+ } = useSelectRateContext()
+ const selectedRate = selectedRates.forRoom(roomIndex)
+ const images = selectedRate?.roomInfo?.roomInfo?.images
- const images = roomCategories.find((roomCategory) =>
- roomCategory.roomTypes.some(
- (roomType) => roomType.code === selectedRate?.roomTypeCode
- )
- )?.images
+ const rateTitle = useRateTitle(selectedRate?.rate)
- const freeCancelation = intl.formatMessage({
- defaultMessage: "Free cancellation",
- })
- const nonRefundable = intl.formatMessage({
- defaultMessage: "Non-refundable",
- })
- const freeBooking = intl.formatMessage({
- defaultMessage: "Free rebooking",
- })
- const payLater = intl.formatMessage({
- defaultMessage: "Pay later",
- })
- const payNow = intl.formatMessage({
- defaultMessage: "Pay now",
- })
-
- function getRateTitle(rate: RateEnum) {
- switch (rate) {
- case RateEnum.change:
- return `${freeBooking}, ${payNow}`
- case RateEnum.flex:
- return `${freeCancelation}, ${payLater}`
- case RateEnum.save:
- default:
- return `${nonRefundable}, ${payNow}`
- }
- }
+ const selectedProductTitle = useSelectedProductTitle({ roomIndex })
if (!selectedRate) {
return null
}
- const selectedPackagesCurrency = selectedPackages.find(
- (pkg) => pkg.localPrice.currency
- )
- const selectedPackagesPrice = selectedPackages.reduce(
- (total, pkg) => total + pkg.localPrice.totalPrice,
- 0
- )
- const selectedPackagesPricePerNight = Math.ceil(
- selectedPackagesPrice / nights
- )
-
- const night = intl.formatMessage({
- defaultMessage: "night",
- })
- let selectedProduct
- if (
- isUserLoggedIn &&
- isMainRoom &&
- "member" in selectedRate.product &&
- selectedRate.product.member
- ) {
- const { localPrice } = selectedRate.product.member
- selectedProduct = `${localPrice.pricePerNight + selectedPackagesPricePerNight} ${localPrice.currency} / ${night}`
- } else if ("public" in selectedRate.product && selectedRate.product.public) {
- const { localPrice } = selectedRate.product.public
- selectedProduct = `${localPrice.pricePerNight + selectedPackagesPricePerNight} ${localPrice.currency} / ${night}`
- } else if ("corporateCheque" in selectedRate.product) {
- const { localPrice } = selectedRate.product.corporateCheque
- selectedProduct = `${localPrice.numberOfCheques} ${CurrencyEnum.CC}`
- if (
- (localPrice.additionalPricePerStay || selectedPackagesPrice) &&
- localPrice.currency
- ) {
- selectedProduct = `${selectedProduct} + ${localPrice.additionalPricePerStay + selectedPackagesPrice} ${localPrice.currency}`
- }
- } else if ("voucher" in selectedRate.product) {
- selectedProduct = `${selectedRate.product.voucher.numberOfVouchers} ${CurrencyEnum.Voucher}`
- if (selectedPackagesPrice && selectedPackagesCurrency) {
- selectedProduct = `${selectedProduct} + ${selectedPackagesPrice} ${selectedPackagesCurrency}`
- }
- }
-
- if (!selectedProduct) {
+ if (!selectedProductTitle) {
logger.error("Selected product is unknown")
return null
}
const showModifyButton =
isMainRoom ||
- (!isMainRoom && rooms.slice(0, roomNr).every((room) => room.selectedRate))
+ (!isMainRoom && selectedRates.rates.slice(0, roomNr).every((room) => room))
return (
@@ -143,17 +58,19 @@ export default function SelectedRoomPanel() {
)}
- {selectedRate.roomType}
+ {selectedRate.roomInfo.roomType}
-
- {getRateTitle(selectedRate.product.rate)}
-
- {selectedProduct}
+ {rateTitle}
+ {selectedProductTitle}
{images?.[0]?.imageSizes?.tiny ? (
-
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/NoAvailabilityAlert/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/NoAvailabilityAlert/index.tsx
index 318ce9760..5bca5988d 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/NoAvailabilityAlert/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/NoAvailabilityAlert/index.tsx
@@ -5,31 +5,36 @@ import { alternativeHotels } from "@scandic-hotels/common/constants/routes/hotel
import { AvailabilityEnum } from "@scandic-hotels/trpc/enums/selectHotel"
import { AlertTypeEnum } from "@scandic-hotels/trpc/types/alertType"
-import { useRatesStore } from "@/stores/select-rate"
-
import Alert from "@/components/TempDesignSystem/Alert"
-import { useRoomContext } from "@/contexts/SelectRate/Room"
+import { useSelectRateContext } from "@/contexts/SelectRate/SelectRateContext"
import useLang from "@/hooks/useLang"
import styles from "./alert.module.css"
-export default function NoAvailabilityAlert() {
+export default function NoAvailabilityAlert({
+ roomIndex,
+}: {
+ roomIndex: number
+}) {
const lang = useLang()
const intl = useIntl()
- const [bookingCode, selectedRooms, activeRoom] = useRatesStore((state) => [
- state.booking.bookingCode,
- state.rooms,
- state.activeRoom,
- ])
- const { isFetchingPackages, rooms } = useRoomContext()
+ const { availability, input } = useSelectRateContext()
+ if (availability.isFetching || !availability.data) {
+ return null
+ }
- const noAvailableRooms = rooms.every(
- (roomConfig) => roomConfig.status === AvailabilityEnum.NotAvailable
- )
+ const indexed = availability.data[roomIndex]
+ const hasAvailabilityError = "error" in indexed
+ if (hasAvailabilityError) {
+ return null
+ }
+
+ const noAvailableRooms = hasAvailableRoomsForRoom(indexed.roomConfigurations)
const alertLink =
- activeRoom !== -1 && selectedRooms[activeRoom].selectedPackages.length === 0
+ roomIndex !== -1 &&
+ (input.data?.booking.rooms.at(roomIndex)?.packages ?? []).length === 0
? {
title: intl.formatMessage({
defaultMessage: "See alternative hotels",
@@ -39,10 +44,6 @@ export default function NoAvailabilityAlert() {
}
: null
- if (isFetchingPackages) {
- return null
- }
-
if (noAvailableRooms) {
const text = intl.formatMessage({
defaultMessage: "There are no rooms available that match your request.",
@@ -61,7 +62,7 @@ export default function NoAvailabilityAlert() {
)
}
- const isPublicPromotionWithCode = rooms.some((room) => {
+ const isPublicPromotionWithCode = indexed.roomConfigurations.some((room) => {
const filteredCampaigns = room.campaign.filter(Boolean)
return filteredCampaigns.length
? filteredCampaigns.every(
@@ -72,19 +73,20 @@ export default function NoAvailabilityAlert() {
const noAvailableBookingCodeRooms =
!isPublicPromotionWithCode &&
- rooms.every(
+ indexed.roomConfigurations.every(
(room) =>
room.status === AvailabilityEnum.NotAvailable || !room.code.length
)
- if (bookingCode && noAvailableBookingCodeRooms) {
+ if (input.bookingCode && noAvailableBookingCodeRooms) {
const bookingCodeText = intl.formatMessage(
{
defaultMessage:
"We found no available rooms using this booking code ({bookingCode}). See available rates below.",
},
- { bookingCode }
+ { bookingCode: input.bookingCode }
)
+
return (
["availability"]["data"]
+ >[number],
+ { roomConfigurations: unknown }
+ >["roomConfigurations"]
+) {
+ return roomConfigurations.every(
+ (roomConfig) => roomConfig.status === AvailabilityEnum.NotAvailable
+ )
+}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate2/RoomsContainer/Rooms/RoomsHeader/BookingCodeFilter/bookingCodeFilter.module.css b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/BookingCodeFilter/bookingCodeFilter.module.css
similarity index 100%
rename from apps/scandic-web/components/HotelReservation/SelectRate2/RoomsContainer/Rooms/RoomsHeader/BookingCodeFilter/bookingCodeFilter.module.css
rename to apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/BookingCodeFilter/bookingCodeFilter.module.css
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate2/RoomsContainer/Rooms/RoomsHeader/BookingCodeFilter/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/BookingCodeFilter/index.tsx
similarity index 100%
rename from apps/scandic-web/components/HotelReservation/SelectRate2/RoomsContainer/Rooms/RoomsHeader/BookingCodeFilter/index.tsx
rename to apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/BookingCodeFilter/index.tsx
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RemoveBookingCodeButton/RemoveBookingCodeButton.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RemoveBookingCodeButton/RemoveBookingCodeButton.tsx
index 92cf278de..197f24556 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RemoveBookingCodeButton/RemoveBookingCodeButton.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RemoveBookingCodeButton/RemoveBookingCodeButton.tsx
@@ -1,14 +1,12 @@
import { usePathname, useRouter, useSearchParams } from "next/navigation"
-import { useRatesStore } from "@/stores/select-rate"
-
import BookingCodeChip from "@/components/BookingCodeChip"
+import { useSelectRateContext } from "@/contexts/SelectRate/SelectRateContext"
export function RemoveBookingCodeButton() {
- const bookingCode = useRatesStore((state) => state.booking.bookingCode)
- const roomNr = useRatesStore((state) =>
- state.activeRoom !== -1 ? state.activeRoom : 0
- )
+ const {
+ input: { bookingCode },
+ } = useSelectRateContext()
const router = useRouter()
const searchParams = useSearchParams()
const pathname = usePathname()
@@ -26,9 +24,6 @@ export function RemoveBookingCodeButton() {
onClose={() => {
const newSearchParams = new URLSearchParams(searchParams)
newSearchParams.delete("bookingCode")
- newSearchParams.delete(`room[${roomNr}].bookingCode`)
- newSearchParams.delete(`room[${roomNr}].ratecode`)
- newSearchParams.delete(`room[${roomNr}].roomtype`)
const url = `${pathname}?${newSearchParams.toString()}`
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/Checkboxes/PetRoomMessage/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/Checkboxes/PetRoomMessage/index.tsx
index f2b777c5d..854051c64 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/Checkboxes/PetRoomMessage/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/Checkboxes/PetRoomMessage/index.tsx
@@ -1,19 +1,23 @@
"use client"
+
import { useIntl } from "react-intl"
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
import { Typography } from "@scandic-hotels/design-system/Typography"
-import { useRoomContext } from "@/contexts/SelectRate/Room"
-
import styles from "./petRoom.module.css"
-export default function PetRoomMessage() {
+export default function PetRoomMessage({
+ priceData,
+}: {
+ priceData?: { price: number; currency: string }
+}) {
const intl = useIntl()
- const { petRoomPackage } = useRoomContext()
- if (!petRoomPackage) {
+
+ if (!priceData) {
return null
}
+
return (
@@ -28,11 +32,7 @@ export default function PetRoomMessage() {
{str}
),
- price: formatPrice(
- intl,
- petRoomPackage.localPrice.price,
- petRoomPackage.localPrice.currency
- ),
+ price: formatPrice(intl, priceData.price, priceData.currency),
}
)}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/Checkboxes/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/Checkboxes/index.tsx
index 56c05d713..98a88e5c5 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/Checkboxes/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/Checkboxes/index.tsx
@@ -4,25 +4,29 @@ import { Controller, useFormContext } from "react-hook-form"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
+import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
-import { useRatesStore } from "@/stores/select-rate"
-
+import { usePackageLabels } from "../../usePackageLabels"
import { getIconNameByPackageCode } from "../../utils"
-import PetRoomMessage from "./PetRoomMessage"
-import {
- checkIsAllergyRoom,
- checkIsPetRoom,
- includesAllergyRoom,
- includesPetRoom,
-} from "./utils"
import styles from "./checkbox.module.css"
+import type { PackageEnum } from "@scandic-hotels/trpc/types/packages"
+import type { ReactNode } from "react"
+
import type { FormValues } from "../formValues"
-export default function Checkboxes() {
- const packageOptions = useRatesStore((state) => state.packageOptions)
+export function PackageCheckboxes({
+ availablePackages,
+}: {
+ availablePackages: {
+ code: RoomPackageCodeEnum
+ message?: ReactNode
+ }[]
+}) {
const { control } = useFormContext()
+ const packageLabels = usePackageLabels()
+
return (
- {packageOptions.map((option) => {
+ {availablePackages?.map((option) => {
const isAllergyRoom = checkIsAllergyRoom(option.code)
const isPetRoom = checkIsPetRoom(option.code)
const isDisabled =
@@ -59,13 +63,13 @@ export default function Checkboxes() {
className={styles.text}
variant="Body/Paragraph/mdRegular"
>
- {option.description}
+ {packageLabels[option.code]}
{iconName ? (
) : null}
- {isPetRoom ? : null}
+ {option.message}
)
})}
@@ -75,3 +79,23 @@ export default function Checkboxes() {
/>
)
}
+
+export function includesAllergyRoom(codes: PackageEnum[]) {
+ return codes.includes(RoomPackageCodeEnum.ALLERGY_ROOM)
+}
+
+export function includesPetRoom(codes: PackageEnum[]) {
+ return codes.includes(RoomPackageCodeEnum.PET_ROOM)
+}
+
+export function checkIsAllergyRoom(
+ code: PackageEnum
+): code is RoomPackageCodeEnum.ALLERGY_ROOM {
+ return code === RoomPackageCodeEnum.ALLERGY_ROOM
+}
+
+export function checkIsPetRoom(
+ code: PackageEnum
+): code is RoomPackageCodeEnum.PET_ROOM {
+ return code === RoomPackageCodeEnum.PET_ROOM
+}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/Checkboxes/utils.ts b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/Checkboxes/utils.ts
deleted file mode 100644
index fb9bc282c..000000000
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/Checkboxes/utils.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
-
-import type { PackageEnum } from "@scandic-hotels/trpc/types/packages"
-
-export function includesAllergyRoom(codes: PackageEnum[]) {
- return codes.includes(RoomPackageCodeEnum.ALLERGY_ROOM)
-}
-
-export function includesPetRoom(codes: PackageEnum[]) {
- return codes.includes(RoomPackageCodeEnum.PET_ROOM)
-}
-
-export function checkIsAllergyRoom(code: PackageEnum) {
- return code === RoomPackageCodeEnum.ALLERGY_ROOM
-}
-
-export function checkIsPetRoom(code: PackageEnum) {
- return code === RoomPackageCodeEnum.PET_ROOM
-}
diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/index.tsx
index 6ea6049de..14261ff95 100644
--- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/index.tsx
+++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/Form/index.tsx
@@ -5,76 +5,53 @@ import { useIntl } from "react-intl"
import { Button } from "@scandic-hotels/design-system/Button"
import { Divider } from "@scandic-hotels/design-system/Divider"
import { Typography } from "@scandic-hotels/design-system/Typography"
-import { trpc } from "@scandic-hotels/trpc/client"
-import { useRatesStore } from "@/stores/select-rate"
-
-import { useRoomContext } from "@/contexts/SelectRate/Room"
-import useLang from "@/hooks/useLang"
-
-import Checkboxes from "./Checkboxes"
+import { PackageCheckboxes } from "./Checkboxes"
import styles from "./form.module.css"
+import type { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
import type { PackageEnum } from "@scandic-hotels/trpc/types/packages"
+import type { ReactNode } from "react"
import type { FormValues } from "./formValues"
-export default function Form({ close }: { close: () => void }) {
+export function RoomPackagesForm({
+ close,
+ selectedPackages,
+ onSelectPackages,
+ availablePackages,
+}: {
+ close: () => void
+ availablePackages: {
+ code: RoomPackageCodeEnum
+ message: ReactNode
+ }[]
+ selectedPackages: PackageEnum[]
+ onSelectPackages: (packages: PackageEnum[]) => void
+}) {
const intl = useIntl()
- const lang = useLang()
- const utils = trpc.useUtils()
-
- const {
- actions: { removeSelectedPackages, selectPackages, updateRooms },
- bookingRoom,
- selectedPackages,
- } = useRoomContext()
- const booking = useRatesStore((state) => state.booking)
const methods = useForm({
values: {
- selectedPackages: selectedPackages.map((pkg) => pkg.code),
+ selectedPackages: selectedPackages,
},
})
- async function getFilteredRates(packages: PackageEnum[]) {
- const bookingCode = bookingRoom.rateCode
- ? bookingRoom.bookingCode
- : booking.bookingCode
- const filterRates = await utils.hotel.availability.selectRate.room.fetch({
- booking: {
- fromDate: booking.fromDate,
- hotelId: booking.hotelId,
- searchType: booking.searchType,
- toDate: booking.toDate,
- room: {
- ...bookingRoom,
- bookingCode: bookingCode ?? undefined,
- packages,
- },
- },
- lang,
- })
- updateRooms(filterRates?.roomConfigurations)
- }
-
function clearSelectedPackages() {
- removeSelectedPackages()
+ onSelectPackages([])
close()
- getFilteredRates([])
}
function onSubmit(data: FormValues) {
- selectPackages(data.selectedPackages)
+ onSelectPackages(data.selectedPackages)
close()
- getFilteredRates(data.selectedPackages)
}
return (