diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/PaymentDetails/index.tsx b/apps/scandic-web/components/HotelReservation/BookingConfirmation/PaymentDetails/index.tsx index d25257c4d..9f85d4269 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/PaymentDetails/index.tsx +++ b/apps/scandic-web/components/HotelReservation/BookingConfirmation/PaymentDetails/index.tsx @@ -7,24 +7,20 @@ import { useBookingConfirmationStore } from "@/stores/booking-confirmation" import SkeletonShimmer from "@/components/SkeletonShimmer" import Body from "@/components/TempDesignSystem/Text/Body" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" -import { formatPrice } from "@/utils/numberFormatting" import styles from "./paymentDetails.module.css" export default function PaymentDetails() { const intl = useIntl() - const { rooms, currencyCode } = useBookingConfirmationStore((state) => ({ - rooms: state.rooms, - currencyCode: state.currencyCode, - })) + const { rooms, formattedTotalCost } = useBookingConfirmationStore( + (state) => ({ + rooms: state.rooms, + formattedTotalCost: state.formattedTotalCost, + }) + ) const hasAllRoomsLoaded = rooms.every((room) => room) - const grandTotal = rooms.reduce((acc, room) => { - const reservationTotalPrice = room?.totalPrice || 0 - return acc + reservationTotalPrice - }, 0) - return (
@@ -33,11 +29,12 @@ export default function PaymentDetails() {
{hasAllRoomsLoaded ? ( - {`${intl.formatMessage({ id: "Total cost" })}: ${formatPrice( - intl, - grandTotal, - currencyCode - )}`} + {intl.formatMessage( + { id: "Total cost: {amount}" }, + { + amount: formattedTotalCost, + } + )} ) : ( diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/PriceDetailsModal/index.tsx b/apps/scandic-web/components/HotelReservation/BookingConfirmation/PriceDetailsModal/index.tsx index 3ab7efef7..1ef8a394f 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/PriceDetailsModal/index.tsx +++ b/apps/scandic-web/components/HotelReservation/BookingConfirmation/PriceDetailsModal/index.tsx @@ -3,6 +3,7 @@ import React from "react" import { useIntl } from "react-intl" import { MaterialIcon } from "@scandic-hotels/design-system/Icons" +import { Typography } from "@scandic-hotels/design-system/Typography" import { dt } from "@/lib/dt" import { useBookingConfirmationStore } from "@/stores/booking-confirmation" @@ -61,15 +62,25 @@ function TableSectionHeader({ export default function PriceDetailsModal() { const intl = useIntl() const lang = useLang() - const { rooms, currencyCode, vat, fromDate, toDate, bookingCode } = - useBookingConfirmationStore((state) => ({ - rooms: state.rooms, - currencyCode: state.currencyCode, - vat: state.vat, - fromDate: state.fromDate, - toDate: state.toDate, - bookingCode: state.bookingCode, - })) + const { + rooms, + currencyCode, + vat, + fromDate, + toDate, + bookingCode, + isVatCurrency, + formattedTotalCost, + } = useBookingConfirmationStore((state) => ({ + rooms: state.rooms, + currencyCode: state.currencyCode, + vat: state.vat, + fromDate: state.fromDate, + toDate: state.toDate, + bookingCode: state.bookingCode, + isVatCurrency: state.isVatCurrency, + formattedTotalCost: state.formattedTotalCost, + })) if (!rooms[0]) { return null @@ -149,7 +160,7 @@ export default function PriceDetailsModal() { @@ -200,24 +211,28 @@ export default function PriceDetailsModal() { })} - - + {isVatCurrency ? ( + <> + + + + ) : null} - - {intl.formatMessage({ id: "Price including VAT" })} - + + {intl.formatMessage({ id: "Price including VAT" })} + - - {formatPrice(intl, bookingTotal.price, currencyCode)} - + + {formattedTotalCost} + {bookingCode && ( diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/index.tsx b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/index.tsx index 1eab74e01..8a942007b 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/index.tsx +++ b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/index.tsx @@ -3,6 +3,7 @@ import { useIntl } from "react-intl" import { MaterialIcon } from "@scandic-hotels/design-system/Icons" +import { Typography } from "@scandic-hotels/design-system/Typography" import { CancellationRuleEnum, ChildBedTypeEnum } from "@/constants/booking" import { useBookingConfirmationStore } from "@/stores/booking-confirmation" @@ -10,8 +11,6 @@ import { useBookingConfirmationStore } from "@/stores/booking-confirmation" import Modal from "@/components/Modal" import Button from "@/components/TempDesignSystem/Button" import Link from "@/components/TempDesignSystem/Link" -import Body from "@/components/TempDesignSystem/Text/Body" -import Caption from "@/components/TempDesignSystem/Text/Caption" import { formatPrice } from "@/utils/numberFormatting" import RoomSkeletonLoader from "./RoomSkeletonLoader" @@ -45,29 +44,37 @@ export default function ReceiptRoom({ return (
- {room.name} + +

{room.name}

+
{room.rateDefinition.isMemberRate ? (
- - {formatPrice(intl, room.roomPrice, currencyCode)} - + +

{room.formattedTotalCost}

+
) : ( - - {formatPrice(intl, room.roomPrice, currencyCode)} - + +

+ {formatPrice(intl, room.roomPrice, currencyCode)} +

+
)} - - {intl.formatMessage( - { id: "{totalAdults, plural, one {# adult} other {# adults}}" }, - { - totalAdults: room.adults, - } - )} - - - {room.rateDefinition.cancellationText} - + +

+ {intl.formatMessage( + { id: "{totalAdults, plural, one {# adult} other {# adults}}" }, + { + totalAdults: room.adults, + } + )} +

+
+ +

+ {room.rateDefinition.cancellationText} +

+
@@ -83,7 +90,11 @@ export default function ReceiptRoom({ } - title={room.rateDefinition.cancellationText || ""} + title={ + (room.roomPoints + ? room.rateDefinition.title + : room.rateDefinition.cancellationText) || "" + } subtitle={ room.rateDefinition.cancellationRule === CancellationRuleEnum.CancellableBefore6PM @@ -93,19 +104,21 @@ export default function ReceiptRoom({ >
{room.rateDefinition.generalTerms?.map((info) => ( - - - {info} - + + + {info} + + ))}
@@ -114,70 +127,98 @@ export default function ReceiptRoom({ ? room.roomFeatures.map((feature) => (
- {feature.description} + +

+ {feature.description} +

+
- - {formatPrice(intl, feature.totalPrice, feature.currency)} - + +

+ {formatPrice(intl, feature.totalPrice, feature.currency)} +

+
)) : null}
- {room.bedDescription} - - {formatPrice(intl, 0, currencyCode)} - + +

{room.bedDescription}

+
+ +

+ {formatPrice(intl, 0, currencyCode)} +

+
{childBedCrib ? (
- - {intl.formatMessage( - { id: "Crib (child) × {count}" }, - { count: childBedCrib.quantity } - )} - - - {intl.formatMessage({ id: "Based on availability" })} - + +

+ {intl.formatMessage( + { id: "Crib (child) × {count}" }, + { count: childBedCrib.quantity } + )} +

+
+ +

+ {intl.formatMessage({ id: "Based on availability" })} +

+
- - {formatPrice(intl, 0, currencyCode)} - + +

+ {formatPrice(intl, 0, currencyCode)} +

+
) : null} {childBedExtraBed ? (
- - {intl.formatMessage( - { id: "Extra bed (child) × {count}" }, - { - count: childBedExtraBed.quantity, - } - )} - + +

+ {intl.formatMessage( + { id: "Extra bed (child) × {count}" }, + { + count: childBedExtraBed.quantity, + } + )} +

+
- - {formatPrice(intl, 0, currencyCode)} - + +

+ {formatPrice(intl, 0, currencyCode)} +

+
) : null} {room.breakfast || breakfastIncluded ? (
- {intl.formatMessage({ id: "Breakfast buffet" })} + +

{intl.formatMessage({ id: "Breakfast buffet" })}

+
{breakfastIncluded ? ( - {intl.formatMessage({ id: "Included" })} + +

+ {intl.formatMessage({ id: "Included" })} +

+
) : null} {room.breakfast && !breakfastIncluded ? ( - - {formatPrice( - intl, - room.breakfast.totalPrice, - room.breakfast.currency - )} - + +

+ {formatPrice( + intl, + room.breakfast.totalPrice, + room.breakfast.currency + )} +

+
) : null}
) : null} diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/room.module.css b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/room.module.css index 5566b207b..68e58ada4 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/room.module.css +++ b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/room.module.css @@ -40,3 +40,15 @@ .terms .termsIcon { padding-right: var(--Spacing-x1); } + +.red { + color: var(--Scandic-Brand-Scandic-Red); +} + +.uiTextHighContrast { + color: var(--UI-Text-High-contrast); +} + +.uiTextMediumContrast { + color: var(--UI-Text-Medium-contrast); +} diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/TotalPrice/index.tsx b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/TotalPrice/index.tsx index 59f614d94..3b1852b01 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/TotalPrice/index.tsx +++ b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/TotalPrice/index.tsx @@ -2,12 +2,12 @@ import { useIntl } from "react-intl" +import { Typography } from "@scandic-hotels/design-system/Typography" + import { useBookingConfirmationStore } from "@/stores/booking-confirmation" import SkeletonShimmer from "@/components/SkeletonShimmer" import Divider from "@/components/TempDesignSystem/Divider" -import Body from "@/components/TempDesignSystem/Text/Body" -import { formatPrice } from "@/utils/numberFormatting" import PriceDetailsModal from "../../PriceDetailsModal" @@ -15,29 +15,27 @@ import styles from "./totalPrice.module.css" export default function TotalPrice() { const intl = useIntl() - const { rooms, currencyCode } = useBookingConfirmationStore((state) => ({ - rooms: state.rooms, - currencyCode: state.currencyCode, - })) + const { rooms, formattedTotalCost } = useBookingConfirmationStore( + (state) => ({ + rooms: state.rooms, + formattedTotalCost: state.formattedTotalCost, + }) + ) const hasAllRoomsLoaded = rooms.every((room) => room) - const grandTotal = rooms.reduce((acc, room) => { - const reservationTotalPrice = room?.totalPrice || 0 - return acc + reservationTotalPrice - }, 0) return ( <>
- - {intl.formatMessage({ id: "Total price" })} - + +

{intl.formatMessage({ id: "Total price" })}

+
{hasAllRoomsLoaded ? ( - - {formatPrice(intl, grandTotal, currencyCode)} - + +

{formattedTotalCost}

+
) : ( )} diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Rooms/LinkedReservation/index.tsx b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Rooms/LinkedReservation/index.tsx index 74602c14f..ce85304ce 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Rooms/LinkedReservation/index.tsx +++ b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Rooms/LinkedReservation/index.tsx @@ -1,11 +1,13 @@ "use client" import { useEffect } from "react" +import { useIntl } from "react-intl" import { trpc } from "@/lib/trpc/client" import { useBookingConfirmationStore } from "@/stores/booking-confirmation" import useLang from "@/hooks/useLang" +import { formatPrice } from "@/utils/numberFormatting" import { mapRoomState } from "../../utils" import Room from "../Room" @@ -25,14 +27,36 @@ export function LinkedReservation({ confirmationNumber, lang, }) - const setRoom = useBookingConfirmationStore((state) => state.actions.setRoom) + const { setRoom, setFormattedTotalCost, currencyCode, totalBookingPrice } = + useBookingConfirmationStore((state) => ({ + setRoom: state.actions.setRoom, + setFormattedTotalCost: state.actions.setFormattedTotalCost, + currencyCode: state.currencyCode, + totalBookingPrice: state.totalBookingPrice, + })) + const intl = useIntl() useEffect(() => { if (data?.room) { - const roomData = mapRoomState(data.booking, data.room) + const roomData = mapRoomState(data.booking, data.room, intl) setRoom(roomData, roomIndex) + + const formattedTotalCost = formatPrice( + intl, + totalBookingPrice, + currencyCode + ) + setFormattedTotalCost(formattedTotalCost) } - }, [data, roomIndex, setRoom]) + }, [ + data, + roomIndex, + setRoom, + intl, + totalBookingPrice, + currencyCode, + setFormattedTotalCost, + ]) if (isLoading) { return diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/index.tsx b/apps/scandic-web/components/HotelReservation/BookingConfirmation/index.tsx index 1f6b8b80b..91f39fb4f 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/index.tsx +++ b/apps/scandic-web/components/HotelReservation/BookingConfirmation/index.tsx @@ -10,6 +10,7 @@ import Receipt from "@/components/HotelReservation/BookingConfirmation/Receipt" import Rooms from "@/components/HotelReservation/BookingConfirmation/Rooms" import SidePanel from "@/components/HotelReservation/SidePanel" import Divider from "@/components/TempDesignSystem/Divider" +import { getIntl } from "@/i18n" import BookingConfirmationProvider from "@/providers/BookingConfirmationProvider" import Alerts from "./Alerts" @@ -38,6 +39,7 @@ export default async function BookingConfirmation({ `${booking.confirmationNumber},${booking.guest.lastName}` ) + const intl = await getIntl() return ( pkg.code === BreakfastPackageEnum.REGULAR_BREAKFAST @@ -13,6 +19,21 @@ export function mapRoomState( (pkg) => pkg.code === BreakfastPackageEnum.FREE_MEMBER_BREAKFAST ) + let formattedTotalCost = formatPrice( + intl, + booking.totalPrice, + booking.currencyCode + ) + if (booking.roomPoints) { + formattedTotalCost = formatPrice( + intl, + booking.roomPoints, + CurrencyEnum.POINTS, + booking.totalPrice, + booking.currencyCode + ) + } + return { adults: booking.adults, bedDescription: room.bedType.description, @@ -23,11 +44,13 @@ export function mapRoomState( childBedPreferences: booking.childBedPreferences, confirmationNumber: booking.confirmationNumber, currencyCode: booking.currencyCode, + formattedTotalCost, fromDate: booking.checkInDate, name: room.name, packages: booking.packages, rateDefinition: booking.rateDefinition, roomFeatures: booking.packages.filter((p) => p.type === "RoomFeature"), + roomPoints: booking.roomPoints, roomPrice: booking.roomPrice, roomTypeCode: booking.roomTypeCode, toDate: booking.checkOutDate, 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 5f976012c..1a9bb17a3 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 @@ -9,7 +9,7 @@ import { formId } from "@/components/HotelReservation/EnterDetails/Payment/Payme import Button from "@/components/TempDesignSystem/Button" import Caption from "@/components/TempDesignSystem/Text/Caption" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" -import { formatPriceWithAdditionalPrice } from "@/utils/numberFormatting" +import { formatPrice } from "@/utils/numberFormatting" import styles from "./bottomSheet.module.css" @@ -57,7 +57,7 @@ export default function SummaryBottomSheet({ children }: PropsWithChildren) { > {intl.formatMessage({ id: "Total price" })} - {formatPriceWithAdditionalPrice( + {formatPrice( intl, totalPrice.local.price, totalPrice.local.currency, 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 0c23092eb..38561b256 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx @@ -16,10 +16,7 @@ import Body from "@/components/TempDesignSystem/Text/Body" import Caption from "@/components/TempDesignSystem/Text/Caption" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import useLang from "@/hooks/useLang" -import { - formatPrice, - formatPriceWithAdditionalPrice, -} from "@/utils/numberFormatting" +import { formatPrice } from "@/utils/numberFormatting" import PriceDetailsTable from "./PriceDetailsTable" @@ -202,7 +199,7 @@ export default function SummaryUI({ memberPrice.amount, memberPrice.currency ) - : formatPriceWithAdditionalPrice( + : formatPrice( intl, room.roomPrice.perStay.local.price, room.roomPrice.perStay.local.currency, @@ -419,7 +416,7 @@ export default function SummaryUI({
- {formatPriceWithAdditionalPrice( + {formatPrice( intl, totalPrice.local.price, totalPrice.local.currency, @@ -444,9 +441,7 @@ export default function SummaryUI({ value: formatPrice( intl, totalPrice.requested.price, - totalPrice.requested.currency, - totalPrice.requested.additionalPrice, - totalPrice.requested.additionalPriceCurrency + totalPrice.requested.currency ), } )} 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 index f455c7643..18d028c59 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Summary.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/MobileSummary/Summary.tsx @@ -15,10 +15,7 @@ import Body from "@/components/TempDesignSystem/Text/Body" import Caption from "@/components/TempDesignSystem/Text/Caption" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import useLang from "@/hooks/useLang" -import { - formatPrice, - formatPriceWithAdditionalPrice, -} from "@/utils/numberFormatting" +import { formatPrice } from "@/utils/numberFormatting" import { isBookingCodeRate } from "./isBookingCodeRate" import PriceDetailsTable from "./PriceDetailsTable" @@ -160,7 +157,7 @@ export default function Summary({
{room.roomType} - {formatPriceWithAdditionalPrice( + {formatPrice( intl, room.roomPrice.perStay.local.price, room.roomPrice.perStay.local.currency, @@ -280,7 +277,7 @@ export default function Summary({ textTransform="bold" data-testid="total-price" > - {formatPriceWithAdditionalPrice( + {formatPrice( intl, totalPrice.local.price, totalPrice.local.currency, 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 9eaa80000..df642f60d 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 @@ -7,7 +7,7 @@ import { useRatesStore } from "@/stores/select-rate" import Button from "@/components/TempDesignSystem/Button" import Caption from "@/components/TempDesignSystem/Text/Caption" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" -import { formatPriceWithAdditionalPrice } from "@/utils/numberFormatting" +import { formatPrice } from "@/utils/numberFormatting" import { isBookingCodeRate } from "./isBookingCodeRate" import { mapRate } from "./mapRate" @@ -107,7 +107,7 @@ export default function MobileSummary({ color={showDiscounted ? "red" : "uiTextHighContrast"} className={styles.wrappedText} > - {formatPriceWithAdditionalPrice( + {formatPrice( intl, totalPriceToShow.local.price, totalPriceToShow.local.currency, 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 efdd22741..fea0cda89 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/index.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/index.tsx @@ -13,10 +13,7 @@ import Body from "@/components/TempDesignSystem/Text/Body" import Caption from "@/components/TempDesignSystem/Text/Caption" import Footnote from "@/components/TempDesignSystem/Text/Footnote" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" -import { - formatPrice, - formatPriceWithAdditionalPrice, -} from "@/utils/numberFormatting" +import { formatPrice } from "@/utils/numberFormatting" import MobileSummary from "./MobileSummary" import { @@ -299,7 +296,7 @@ export default function RateSummary({ isUserLoggedIn }: RateSummaryProps) { color={showDiscounted ? "red" : "uiTextHighContrast"} textAlign="right" > - {formatPriceWithAdditionalPrice( + {formatPrice( intl, totalPriceToShow.local.price, totalPriceToShow.local.currency, @@ -342,7 +339,7 @@ export default function RateSummary({ isUserLoggedIn }: RateSummaryProps) { {intl.formatMessage({ id: "Total price" })} - {formatPriceWithAdditionalPrice( + {formatPrice( intl, totalPriceToShow.local.price, totalPriceToShow.local.currency, diff --git a/apps/scandic-web/i18n/dictionaries/da.json b/apps/scandic-web/i18n/dictionaries/da.json index 070683a0b..9ef0d66a1 100644 --- a/apps/scandic-web/i18n/dictionaries/da.json +++ b/apps/scandic-web/i18n/dictionaries/da.json @@ -806,7 +806,7 @@ "To secure your reservation, we kindly ask you to provide your payment card details. Rest assured, no charges will be made at this time.": "For at sikre din reservation, beder vi om at du giver os dine betalingsoplysninger. Du kan så være sikker på, at ingen gebyrer vil blive opkrævet på dette tidspunkt.", "Too many failed attempts.": "Too many failed attempts.", "Total": "Total", - "Total cost": "Total cost", + "Total cost: {amount}": "Total cost: {amount}", "Total paid": "Total betalt", "Total points": "Samlet antal point", "Total price": "Samlet pris", diff --git a/apps/scandic-web/i18n/dictionaries/de.json b/apps/scandic-web/i18n/dictionaries/de.json index 141f5283b..af6ed871f 100644 --- a/apps/scandic-web/i18n/dictionaries/de.json +++ b/apps/scandic-web/i18n/dictionaries/de.json @@ -804,7 +804,7 @@ "To secure your reservation, we kindly ask you to provide your payment card details. Rest assured, no charges will be made at this time.": "Um Ihre Reservierung zu sichern, bitten wir Sie, Ihre Zahlungskarteninformationen zu geben. Sie können sicher sein, dass keine Gebühren zu diesem Zeitpunkt erhoben werden.", "Too many failed attempts.": "Too many failed attempts.", "Total": "Gesamt", - "Total cost": "Total cost", + "Total cost: {amount}": "Total cost: {amount}", "Total paid": "Gesamt bezahlt", "Total points": "Gesamtpunktzahl", "Total price": "Gesamtpreis", diff --git a/apps/scandic-web/i18n/dictionaries/en.json b/apps/scandic-web/i18n/dictionaries/en.json index 9fad48400..acba9b742 100644 --- a/apps/scandic-web/i18n/dictionaries/en.json +++ b/apps/scandic-web/i18n/dictionaries/en.json @@ -806,7 +806,7 @@ "To secure your reservation, we kindly ask you to provide your payment card details. Rest assured, no charges will be made at this time.": "To secure your reservation, we kindly ask you to provide your payment card details. Rest assured, no charges will be made at this time.", "Too many failed attempts.": "Too many failed attempts.", "Total": "Total", - "Total cost": "Total cost", + "Total cost: {amount}": "Total cost: {amount}", "Total paid": "Total paid", "Total points": "Total points", "Total price": "Total price", diff --git a/apps/scandic-web/i18n/dictionaries/fi.json b/apps/scandic-web/i18n/dictionaries/fi.json index d3ff7d377..52810a326 100644 --- a/apps/scandic-web/i18n/dictionaries/fi.json +++ b/apps/scandic-web/i18n/dictionaries/fi.json @@ -804,7 +804,7 @@ "To secure your reservation, we kindly ask you to provide your payment card details. Rest assured, no charges will be made at this time.": "Varmistaaksesi varauksen, pyydämme sinua antamaan meille maksukortin tiedot. Varmista, että ei veloiteta maksusi tällä hetkellä.", "Too many failed attempts.": "Too many failed attempts.", "Total": "Kokonais", - "Total cost": "Total cost", + "Total cost: {amount}": "Total cost: {amount}", "Total paid": "Kokonais maksamasi", "Total points": "Kokonaispisteet", "Total price": "Kokonaishinta", diff --git a/apps/scandic-web/i18n/dictionaries/no.json b/apps/scandic-web/i18n/dictionaries/no.json index b193b2c61..4a081941e 100644 --- a/apps/scandic-web/i18n/dictionaries/no.json +++ b/apps/scandic-web/i18n/dictionaries/no.json @@ -801,7 +801,7 @@ "To secure your reservation, we kindly ask you to provide your payment card details. Rest assured, no charges will be made at this time.": "For å sikre din reservasjon, ber vi om at du gir oss dine betalingskortdetaljer. Vær sikker på at ingen gebyrer vil bli belastet på dette tidspunktet.", "Too many failed attempts.": "Too many failed attempts.", "Total": "Total", - "Total cost": "Total cost", + "Total cost: {amount}": "Total cost: {amount}", "Total incl VAT": "Sum inkl mva", "Total paid": "Total betalt", "Total points": "Totale poeng", @@ -877,7 +877,7 @@ "When": "Når", "When guaranteeing your booking with a credit card, we will hold the booking until 07:00 the day after check-in.": "Når vi garanterer bestillingen med kredittkort, vil vi holde bestillingen til kl. 07.00 dagen etter innsjekking.", "When guaranteeing your booking, we will hold the booking until 07:00 until the day after check-in. This will provide you as a guest with added flexibility for check-in times.": "Når du garanterer din reservasjon, vil vi holde reservasjonen til 07:00 til dagen etter check-in. Dette vil gi deg som gjest tilføjet fleksibilitet for check-in-tider.", - "When you confirm the booking the room will be guaranteed for late arrival. If you fail to arrive without cancelling in advance or if you cancel after 18:00 local time, you will be charged for one reward night.": "", + "When you confirm the booking the room will be guaranteed for late arrival. If you fail to arrive without cancelling in advance or if you cancel after 18:00 local time, you will be charged for one reward night.": "When you confirm the booking the room will be guaranteed for late arrival. If you fail to arrive without cancelling in advance or if you cancel after 18:00 local time, you will be charged for one reward night.", "Where should you go next?": "Hvor ønsker du å reise neste gang?", "Where to?": "Hvor skal du?", "Which room class suits you the best?": "Hvilken romklasse passer deg best?", diff --git a/apps/scandic-web/i18n/dictionaries/sv.json b/apps/scandic-web/i18n/dictionaries/sv.json index ec4dfd062..103dd0f8d 100644 --- a/apps/scandic-web/i18n/dictionaries/sv.json +++ b/apps/scandic-web/i18n/dictionaries/sv.json @@ -802,7 +802,7 @@ "To secure your reservation, we kindly ask you to provide your payment card details. Rest assured, no charges will be made at this time.": "För att säkra din bokning ber vi om att du ger oss dina betalkortdetaljer. Välj säker på att ingen avgifter kommer att debiteras just nu.", "Too many failed attempts.": "Too many failed attempts.", "Total": "Totalt", - "Total cost": "Total cost", + "Total cost: {amount}": "Total cost: {amount}", "Total incl VAT": "Totalt inkl moms", "Total paid": "Total betalt", "Total points": "Poäng totalt", diff --git a/apps/scandic-web/providers/BookingConfirmationProvider.tsx b/apps/scandic-web/providers/BookingConfirmationProvider.tsx index 5d62b267e..14ec171e8 100644 --- a/apps/scandic-web/providers/BookingConfirmationProvider.tsx +++ b/apps/scandic-web/providers/BookingConfirmationProvider.tsx @@ -1,12 +1,15 @@ "use client" import { useRef } from "react" +import { useIntl } from "react-intl" import { createBookingConfirmationStore } from "@/stores/booking-confirmation" import { BookingConfirmationContext } from "@/contexts/BookingConfirmation" +import { formatPrice } from "@/utils/numberFormatting" import type { BookingConfirmationStore } from "@/types/contexts/booking-confirmation" +import { CurrencyEnum } from "@/types/enums/currency" import type { BookingConfirmationProviderProps } from "@/types/providers/booking-confirmation" export default function BookingConfirmationProvider({ @@ -18,9 +21,29 @@ export default function BookingConfirmationProvider({ rooms, vat, }: BookingConfirmationProviderProps) { + const intl = useIntl() const storeRef = useRef() if (!storeRef.current) { + const totalBookingPrice = rooms.reduce((acc, room) => { + const reservationTotalPrice = room?.totalPrice || 0 + return acc + reservationTotalPrice + }, 0) + let formattedTotalCost = formatPrice(intl, totalBookingPrice, currencyCode) + const totalBookingPoints = rooms.reduce((acc, room) => { + return acc + (room?.roomPoints ?? 0) + }, 0) + let isVatCurrency = true + if (totalBookingPoints) { + isVatCurrency = false + formattedTotalCost = formatPrice( + intl, + totalBookingPoints, + CurrencyEnum.POINTS, + totalBookingPrice, + currencyCode + ) + } const initialData = { bookingCode, currencyCode, @@ -28,6 +51,9 @@ export default function BookingConfirmationProvider({ toDate, rooms, vat, + isVatCurrency, + formattedTotalCost, + totalBookingPrice, } storeRef.current = createBookingConfirmationStore(initialData) diff --git a/apps/scandic-web/stores/booking-confirmation/index.ts b/apps/scandic-web/stores/booking-confirmation/index.ts index 6f47cdfc8..a4835b0d7 100644 --- a/apps/scandic-web/stores/booking-confirmation/index.ts +++ b/apps/scandic-web/stores/booking-confirmation/index.ts @@ -16,13 +16,24 @@ export function createBookingConfirmationStore(initialState: InitialState) { fromDate: initialState.fromDate, toDate: initialState.toDate, vat: initialState.vat, + formattedTotalCost: initialState.formattedTotalCost, + isVatCurrency: initialState.isVatCurrency, + totalBookingPrice: initialState.totalBookingPrice, actions: { setRoom: (room, idx) => { set((state) => { const rooms = [...state.rooms] rooms[idx] = room + const totalBookingPrice = rooms.reduce((acc, room) => { + return acc + (room?.totalPrice ?? 0) + }, 0) - return { rooms } + return { rooms, totalBookingPrice } + }) + }, + setFormattedTotalCost: (updatedFormattedTotalCost: string) => { + set((state) => { + return { ...state, formattedTotalCost: updatedFormattedTotalCost } }) }, }, diff --git a/apps/scandic-web/stores/my-stay/myStayTotalPrice.ts b/apps/scandic-web/stores/my-stay/myStayTotalPrice.ts index 1f6ca5594..1734b913a 100644 --- a/apps/scandic-web/stores/my-stay/myStayTotalPrice.ts +++ b/apps/scandic-web/stores/my-stay/myStayTotalPrice.ts @@ -57,7 +57,7 @@ export const useMyStayTotalPriceStore = create( }, 0) const totalPoints = newRooms.reduce((sum, r) => { - return sum + r.roomPoints + return sum + (r.roomPoints ?? 0) }, 0) return { diff --git a/apps/scandic-web/types/stores/booking-confirmation.ts b/apps/scandic-web/types/stores/booking-confirmation.ts index 4510274db..f5c898fab 100644 --- a/apps/scandic-web/types/stores/booking-confirmation.ts +++ b/apps/scandic-web/types/stores/booking-confirmation.ts @@ -22,8 +22,10 @@ export interface Room { fromDate: Date name: string packages: BookingConfirmation["booking"]["packages"] + formattedTotalCost: string rateDefinition: BookingConfirmation["booking"]["rateDefinition"] roomFeatures?: PackageSchema[] | null + roomPoints: number roomPrice: number roomTypeCode: string | null toDate: Date @@ -39,14 +41,23 @@ export interface InitialState { toDate: Date currencyCode: string vat: number + isVatCurrency: boolean + formattedTotalCost: string + totalBookingPrice: number } export interface BookingConfirmationState { bookingCode: string | null + isVatCurrency: boolean rooms: (Room | null)[] currencyCode: string vat: number fromDate: Date toDate: Date - actions: { setRoom: (room: Room, idx: number) => void } + formattedTotalCost: string | null + totalBookingPrice: number + actions: { + setRoom: (room: Room, idx: number) => void + setFormattedTotalCost: (updatedFormattedTotalCost: string) => void + } } diff --git a/apps/scandic-web/utils/numberFormatting.ts b/apps/scandic-web/utils/numberFormatting.ts index cdbe68a9e..370a57531 100644 --- a/apps/scandic-web/utils/numberFormatting.ts +++ b/apps/scandic-web/utils/numberFormatting.ts @@ -14,6 +14,8 @@ export function getSingleDecimal(n: Number | string) { * @param intl - react-intl object * @param price - number to be formatted * @param currency - currency code + * @param additionalPrice - number (obtained in reward nights and Corporate cheque scenarios) + * @param additionalPriceCurrency - currency code (obtained in reward nights and Corporate cheque scenarios) * @returns localized and formatted number in string type with currency */ export function formatPrice( @@ -26,21 +28,14 @@ export function formatPrice( const localizedPrice = intl.formatNumber(price, { minimumFractionDigits: 0, }) - return `${localizedPrice} ${currency} ${additionalPrice ? "+ " + additionalPrice + " " + additionalPriceCurrency : ""}` -} -// This will handle redemption and bonus cheque (corporate cheque) scneario with partial payments -export function formatPriceWithAdditionalPrice( - intl: IntlShape, - points: number, - pointsCurrency: string, - additionalPrice?: number, - additionalPriceCurrency?: string -) { - const formattedAdditionalPrice = - additionalPrice && additionalPriceCurrency - ? `+ ${formatPrice(intl, additionalPrice, additionalPriceCurrency)}` - : "" + let formattedAdditionalPrice: string = "" + if (additionalPrice && additionalPriceCurrency) { + const localizedAdditionalPrice = intl.formatNumber(additionalPrice, { + minimumFractionDigits: 0, + }) + formattedAdditionalPrice = ` ${localizedAdditionalPrice} ${additionalPriceCurrency}` + } - return `${formatPrice(intl, points, pointsCurrency)} ${formattedAdditionalPrice}` + return `${localizedPrice} ${currency}${formattedAdditionalPrice}` }