Merged in feat(SW-2083)-missing-booking-codes-scenarios-my-stay (pull request #1680)

Feat(SW-2083) missing booking codes scenarios my stay

* feat(SW-2083) Show points instead of reward nights

* feat(SW-2083) added support for cheque and voucher for totalPrice


Approved-by: Niclas Edenvin
This commit is contained in:
Pontus Dreij
2025-03-31 11:42:47 +00:00
parent 7434f30c20
commit b48053b8b4
23 changed files with 240 additions and 33 deletions

View File

@@ -30,8 +30,14 @@ export default function BookingSummary({ hotel }: BookingSummaryProps) {
const bookedRoom = useMyStayRoomDetailsStore((state) => state.bookedRoom) const bookedRoom = useMyStayRoomDetailsStore((state) => state.bookedRoom)
const { isCancelled, createDateTime, guaranteeInfo, checkInDate, isPrePaid } = const {
bookedRoom isCancelled,
createDateTime,
guaranteeInfo,
checkInDate,
isPrePaid,
priceType,
} = bookedRoom
const directionsUrl = `https://www.google.com/maps/dir/?api=1&destination=${hotel.location.latitude},${hotel.location.longitude}` const directionsUrl = `https://www.google.com/maps/dir/?api=1&destination=${hotel.location.latitude},${hotel.location.longitude}`
@@ -57,7 +63,9 @@ export default function BookingSummary({ hotel }: BookingSummaryProps) {
</Typography> </Typography>
<div className={styles.bookingSummaryContent}> <div className={styles.bookingSummaryContent}>
<SummaryCard <SummaryCard
title={<TotalPrice variant="Body/Paragraph/mdBold" />} title={
<TotalPrice variant="Body/Paragraph/mdBold" type={priceType} />
}
image={{ image={{
src: "/_static/img/scandic-coin.svg", src: "/_static/img/scandic-coin.svg",
alt: "Scandic coin", alt: "Scandic coin",

View File

@@ -59,6 +59,7 @@ export default function ActionPanel({ hotel }: ActionPanelProps) {
createDateTime, createDateTime,
canChangeDate, canChangeDate,
isPrePaid, isPrePaid,
priceType,
} = bookedRoom } = bookedRoom
const datetimeIsInThePast = useMemo( const datetimeIsInThePast = useMemo(
@@ -71,6 +72,7 @@ export default function ActionPanel({ hotel }: ActionPanelProps) {
datetimeIsInThePast, datetimeIsInThePast,
isCancelled: bookedRoom.isCancelled, isCancelled: bookedRoom.isCancelled,
isPrePaid, isPrePaid,
isRewardNight: priceType === "points",
}) })
const isCancelable = checkCancelable({ const isCancelable = checkCancelable({

View File

@@ -7,6 +7,7 @@ interface ModificationConditions {
isNotPast: boolean isNotPast: boolean
isNotCancelled: boolean isNotCancelled: boolean
isNotPrePaid: boolean isNotPrePaid: boolean
isNotRewardNight: boolean
} }
interface GuaranteeConditions { interface GuaranteeConditions {
@@ -25,17 +26,20 @@ export function checkDateModifiable({
datetimeIsInThePast, datetimeIsInThePast,
isCancelled, isCancelled,
isPrePaid, isPrePaid,
isRewardNight,
}: { }: {
canChangeDate: boolean canChangeDate: boolean
datetimeIsInThePast: boolean datetimeIsInThePast: boolean
isCancelled: boolean isCancelled: boolean
isPrePaid: boolean isPrePaid: boolean
isRewardNight: boolean
}): boolean { }): boolean {
const conditions: ModificationConditions = { const conditions: ModificationConditions = {
canModify: canChangeDate, canModify: canChangeDate,
isNotPast: !datetimeIsInThePast, isNotPast: !datetimeIsInThePast,
isNotCancelled: !isCancelled, isNotCancelled: !isCancelled,
isNotPrePaid: !isPrePaid, isNotPrePaid: !isPrePaid,
isNotRewardNight: !isRewardNight,
} }
return Object.values(conditions).every(Boolean) return Object.values(conditions).every(Boolean)

View File

@@ -16,6 +16,7 @@ import IconChip from "@/components/TempDesignSystem/IconChip"
import useLang from "@/hooks/useLang" import useLang from "@/hooks/useLang"
import { IconForFeatureCode } from "../../utils" import { IconForFeatureCode } from "../../utils"
import Points from "../Points"
import Price from "../Price" import Price from "../Price"
import { hasBreakfastPackage } from "../utils/hasBreakfastPackage" import { hasBreakfastPackage } from "../utils/hasBreakfastPackage"
import { mapRoomDetails } from "../utils/mapRoomDetails" import { mapRoomDetails } from "../utils/mapRoomDetails"
@@ -91,6 +92,7 @@ export default function MultiRoom({
totalPrice: isBookingCancelled ? 0 : bookingInfo.totalPrice, totalPrice: isBookingCancelled ? 0 : bookingInfo.totalPrice,
currencyCode: bookingInfo.currencyCode, currencyCode: bookingInfo.currencyCode,
isMainBooking: false, isMainBooking: false,
roomPoints: bookingInfo.roomPoints,
}) })
// Add room details to the store // Add room details to the store
@@ -120,10 +122,13 @@ export default function MultiRoom({
confirmationNumber, confirmationNumber,
cancellationNumber, cancellationNumber,
hotelId, hotelId,
roomPoints,
roomPrice, roomPrice,
packages, packages,
rateDefinition, rateDefinition,
isCancelled, isCancelled,
priceType,
vouchers,
} = multiRoom } = multiRoom
const fromDate = dt(checkInDate).locale(lang) const fromDate = dt(checkInDate).locale(lang)
@@ -293,11 +298,24 @@ export default function MultiRoom({
<Typography variant="Body/Lead text"> <Typography variant="Body/Lead text">
<p>{intl.formatMessage({ id: "Room total" })}</p> <p>{intl.formatMessage({ id: "Room total" })}</p>
</Typography> </Typography>
<Price {priceType === "points" ? (
price={isCancelled ? 0 : roomPrice.perStay.local.price} <Points points={roomPoints} variant="Body/Paragraph/mdBold" />
variant="Body/Paragraph/mdBold" ) : priceType === "voucher" ? (
isMember={rateDefinition.isMemberRate} <Typography variant="Body/Paragraph/mdBold">
/> <p>
{intl.formatMessage(
{ id: "{count} voucher" },
{ count: vouchers }
)}
</p>
</Typography>
) : (
<Price
price={isCancelled ? 0 : roomPrice.perStay.local.price}
variant="Body/Paragraph/mdBold"
isMember={rateDefinition.isMemberRate}
/>
)}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,31 @@
"use client"
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import SkeletonShimmer from "@/components/SkeletonShimmer"
import type { Variant } from "../Rooms/TotalPrice"
export default function Points({
points,
variant,
}: {
points: number | null
variant: Variant
}) {
const intl = useIntl()
if (points === null) {
return <SkeletonShimmer width={"100px"} />
}
return (
<Typography variant={variant}>
<p>
{intl.formatNumber(points)} {intl.formatMessage({ id: "Points" })}
</p>
</Typography>
)
}

View File

@@ -11,10 +11,7 @@ import { formatPrice } from "@/utils/numberFormatting"
import styles from "./price.module.css" import styles from "./price.module.css"
export type Variant = import type { Variant } from "../Rooms/TotalPrice"
| "Title/Subtitle/lg"
| "Title/Subtitle/md"
| "Body/Paragraph/mdBold"
export default function Price({ export default function Price({
price, price,

View File

@@ -66,7 +66,6 @@ export function ReferenceCard({
const addRoomPrice = useMyStayTotalPriceStore( const addRoomPrice = useMyStayTotalPriceStore(
(state) => state.actions.addRoomPrice (state) => state.actions.addRoomPrice
) )
// Initialize store with server data // Initialize store with server data
useEffect(() => { useEffect(() => {
// Add price and details for booked room (main room or single room) // Add price and details for booked room (main room or single room)
@@ -78,6 +77,7 @@ export function ReferenceCard({
: booking.totalPrice, : booking.totalPrice,
currencyCode: booking.currencyCode, currencyCode: booking.currencyCode,
isMainBooking: true, isMainBooking: true,
roomPoints: booking.roomPoints,
}) })
addBookedRoom( addBookedRoom(
mapRoomDetails({ mapRoomDetails({
@@ -99,6 +99,8 @@ export function ReferenceCard({
checkOutDate, checkOutDate,
isCancelled, isCancelled,
bookingCode, bookingCode,
rateDefinition,
priceType,
} = bookedRoom } = bookedRoom
const fromDate = dt(checkInDate).locale(lang) const fromDate = dt(checkInDate).locale(lang)
@@ -270,7 +272,7 @@ export function ReferenceCard({
<Typography variant="Title/Overline/sm"> <Typography variant="Title/Overline/sm">
<p>{intl.formatMessage({ id: "Total" })}</p> <p>{intl.formatMessage({ id: "Total" })}</p>
</Typography> </Typography>
<TotalPrice variant="Title/Subtitle/md" /> <TotalPrice variant="Title/Subtitle/md" type={priceType} />
</div> </div>
{bookingCode && ( {bookingCode && (
<div className={styles.referenceRow}> <div className={styles.referenceRow}>
@@ -315,7 +317,7 @@ export function ReferenceCard({
<p <p
className={`${styles.note} ${allRoomsCancelled ? styles.cancelledNote : ""}`} className={`${styles.note} ${allRoomsCancelled ? styles.cancelledNote : ""}`}
> >
{booking.rateDefinition.generalTerms.map((term) => ( {rateDefinition.generalTerms.map((term) => (
<span key={term}> <span key={term}>
{term} {term}
{term.endsWith(".") ? " " : ". "} {term.endsWith(".") ? " " : ". "}

View File

@@ -1,11 +1,73 @@
"use client" "use client"
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { useMyStayRoomDetailsStore } from "@/stores/my-stay/myStayRoomDetailsStore"
import { useMyStayTotalPriceStore } from "@/stores/my-stay/myStayTotalPrice" import { useMyStayTotalPriceStore } from "@/stores/my-stay/myStayTotalPrice"
import Price, { type Variant } from "../../Price" import Points from "../../Points"
import Price from "../../Price"
export default function TotalPrice({ variant }: { variant: Variant }) { import styles from "./totalPrice.module.css"
const { totalPrice } = useMyStayTotalPriceStore()
return <Price price={totalPrice} variant={variant} /> import type { PriceType } from "@/types/components/hotelReservation/myStay/myStay"
export type Variant =
| "Title/Subtitle/lg"
| "Title/Subtitle/md"
| "Body/Paragraph/mdBold"
interface TotalPriceProps {
variant: Variant
type?: PriceType
}
export default function TotalPrice({
variant,
type = "money",
}: TotalPriceProps) {
const totalPrice = useMyStayTotalPriceStore((state) => state.totalPrice)
const totalPoints = useMyStayTotalPriceStore((state) => state.totalPoints)
const bookedRoom = useMyStayRoomDetailsStore((state) => state.bookedRoom)
const { vouchers, cheques } = bookedRoom
const intl = useIntl()
if (type === "money") {
return <Price price={totalPrice} variant={variant} />
}
if (type === "voucher") {
return (
<Typography variant={variant}>
<p>
{intl.formatMessage({ id: "{count} voucher" }, { count: vouchers })}
</p>
</Typography>
)
}
if (type === "cheque") {
return (
<div className={styles.totalPrice}>
<Typography variant={variant}>
<p>{cheques} CC + </p>
</Typography>
<Price price={totalPrice} variant={variant} />
</div>
)
}
if (totalPrice && totalPrice > 0 && type === "points") {
return (
<div className={styles.totalPrice}>
<Points points={totalPoints} variant={variant} /> +{" "}
<Price price={totalPrice} variant={variant} />
</div>
)
}
return <Points points={totalPoints} variant={variant} />
} }

View File

@@ -0,0 +1,5 @@
.totalPrice {
display: flex;
align-items: center;
gap: 10px;
}

View File

@@ -10,6 +10,7 @@ import MultiRoom from "../MultiRoom"
import MultiRoomSkeleton from "../MultiRoom/MultiRoomSkeleton" import MultiRoomSkeleton from "../MultiRoom/MultiRoomSkeleton"
import PriceDetails from "../PriceDetails" import PriceDetails from "../PriceDetails"
import { SingleRoom } from "../SingleRoom" import { SingleRoom } from "../SingleRoom"
import { getPriceType } from "../utils/getPriceType"
import TotalPrice from "./TotalPrice" import TotalPrice from "./TotalPrice"
import styles from "./rooms.module.css" import styles from "./rooms.module.css"
@@ -92,7 +93,14 @@ export default async function Rooms({
<Typography variant="Body/Lead text"> <Typography variant="Body/Lead text">
<p>{intl.formatMessage({ id: "Booking total" })}:</p> <p>{intl.formatMessage({ id: "Booking total" })}:</p>
</Typography> </Typography>
<TotalPrice variant="Title/Subtitle/lg" /> <TotalPrice
variant="Title/Subtitle/lg"
type={getPriceType({
rateDefinition: booking.rateDefinition,
vouchers: booking.vouchers,
cheques: booking.cheques,
})}
/>
</div> </div>
<PriceDetails /> <PriceDetails />

View File

@@ -18,6 +18,7 @@ import IconChip from "@/components/TempDesignSystem/IconChip"
import useLang from "@/hooks/useLang" import useLang from "@/hooks/useLang"
import GuestDetails from "../GuestDetails" import GuestDetails from "../GuestDetails"
import Points from "../Points"
import Price from "../Price" import Price from "../Price"
import PriceDetails from "../PriceDetails" import PriceDetails from "../PriceDetails"
import { hasBreakfastPackage } from "../utils/hasBreakfastPackage" import { hasBreakfastPackage } from "../utils/hasBreakfastPackage"
@@ -62,9 +63,12 @@ export function SingleRoom({ bedType, image, hotel, user }: RoomProps) {
confirmationNumber, confirmationNumber,
bookingCode, bookingCode,
roomPrice, roomPrice,
roomPoints,
packages, packages,
rateDefinition, rateDefinition,
isCancelled, isCancelled,
priceType,
vouchers,
} = bookedRoom } = bookedRoom
const mainBedWidthValueMsg = intl.formatMessage( const mainBedWidthValueMsg = intl.formatMessage(
@@ -357,11 +361,24 @@ export function SingleRoom({ bedType, image, hotel, user }: RoomProps) {
{intl.formatMessage({ id: "Room total" })} {intl.formatMessage({ id: "Room total" })}
</p> </p>
</Typography> </Typography>
<Price {priceType === "points" ? (
price={isCancelled ? 0 : roomPrice.perStay.local.price} <Points points={roomPoints} variant="Title/Subtitle/lg" />
variant="Title/Subtitle/lg" ) : priceType === "voucher" ? (
isMember={rateDefinition.isMemberRate} <Typography variant="Title/Subtitle/lg">
/> <p>
{intl.formatMessage(
{ id: "{count} voucher" },
{ count: vouchers }
)}
</p>
</Typography>
) : (
<Price
price={isCancelled ? 0 : roomPrice.perStay.local.price}
variant="Title/Subtitle/lg"
isMember={rateDefinition.isMemberRate}
/>
)}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,18 @@
import type { PriceType } from "@/types/components/hotelReservation/myStay/myStay"
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
type PriceTypeParams = Pick<
BookingConfirmation["booking"],
"rateDefinition" | "vouchers" | "cheques"
>
export function getPriceType({
rateDefinition,
vouchers,
cheques,
}: PriceTypeParams): PriceType {
if (rateDefinition.title === "Reward Night") return "points"
if (vouchers > 0) return "voucher"
if (cheques > 0) return "cheque"
return "money"
}

View File

@@ -3,6 +3,7 @@ import { dt } from "@/lib/dt"
import { formatChildBedPreferences } from "../utils" import { formatChildBedPreferences } from "../utils"
import { convertToChildType } from "./convertToChildType" import { convertToChildType } from "./convertToChildType"
import { getPriceType } from "./getPriceType"
import type { BreakfastPackage } from "@/types/components/hotelReservation/breakfast" import type { BreakfastPackage } from "@/types/components/hotelReservation/breakfast"
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
@@ -76,6 +77,12 @@ export function mapRoomDetails({
booking.rateDefinition.cancellationRule !== booking.rateDefinition.cancellationRule !==
CancellationRuleEnum.CancellableBefore6PM CancellationRuleEnum.CancellableBefore6PM
const priceType = getPriceType({
rateDefinition: booking.rateDefinition,
vouchers: booking.vouchers,
cheques: booking.cheques,
})
return { return {
hotelId: booking.hotelId, hotelId: booking.hotelId,
roomTypeCode: booking.roomTypeCode, roomTypeCode: booking.roomTypeCode,
@@ -90,6 +97,8 @@ export function mapRoomDetails({
guaranteeInfo: booking.guaranteeInfo, guaranteeInfo: booking.guaranteeInfo,
linkedReservations: booking.linkedReservations, linkedReservations: booking.linkedReservations,
bookingCode: booking.bookingCode, bookingCode: booking.bookingCode,
cheques: booking.cheques,
vouchers: booking.vouchers,
isCancelable: booking.isCancelable, isCancelable: booking.isCancelable,
multiRoom: booking.multiRoom, multiRoom: booking.multiRoom,
canChangeDate: booking.canChangeDate, canChangeDate: booking.canChangeDate,
@@ -123,6 +132,7 @@ export function mapRoomDetails({
description: room?.bedType.mainBed.description ?? "", description: room?.bedType.mainBed.description ?? "",
roomTypeCode: room?.bedType.code ?? "", roomTypeCode: room?.bedType.code ?? "",
}, },
roomPoints: booking.roomPoints,
roomPrice: { roomPrice: {
perNight: { perNight: {
local: { local: {
@@ -141,5 +151,6 @@ export function mapRoomDetails({
}, },
breakfast, breakfast,
isPrePaid, isPrePaid,
priceType,
} }
} }

View File

@@ -973,6 +973,7 @@
"{count} number": "{count} nummer", "{count} number": "{count} nummer",
"{count} special character": "{count} speciel karakter", "{count} special character": "{count} speciel karakter",
"{count} uppercase letter": "{count} stort bogstav", "{count} uppercase letter": "{count} stort bogstav",
"{count} voucher": "{count} voucher",
"{difference}{amount} {currency}": "{difference}{amount} {currency}", "{difference}{amount} {currency}": "{difference}{amount} {currency}",
"{distanceInKm} km": "{distanceInKm} km", "{distanceInKm} km": "{distanceInKm} km",
"{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# gæst} other {# gæster}}", "{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# gæst} other {# gæster}}",

View File

@@ -971,6 +971,7 @@
"{count} number": "{count} nummer", "{count} number": "{count} nummer",
"{count} special character": "{count} sonderzeichen", "{count} special character": "{count} sonderzeichen",
"{count} uppercase letter": "{count} großbuchstabe", "{count} uppercase letter": "{count} großbuchstabe",
"{count} voucher": "{count} voucher",
"{difference}{amount} {currency}": "{difference}{amount} {currency}", "{difference}{amount} {currency}": "{difference}{amount} {currency}",
"{distanceInKm} km": "{distanceInKm} km", "{distanceInKm} km": "{distanceInKm} km",
"{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# gast} other {# gäste}}", "{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# gast} other {# gäste}}",

View File

@@ -966,6 +966,7 @@
"{count} number": "{count} number", "{count} number": "{count} number",
"{count} special character": "{count} special character", "{count} special character": "{count} special character",
"{count} uppercase letter": "{count} uppercase letter", "{count} uppercase letter": "{count} uppercase letter",
"{count} voucher": "{count} voucher",
"{difference}{amount} {currency}": "{difference}{amount} {currency}", "{difference}{amount} {currency}": "{difference}{amount} {currency}",
"{distanceInKm} km": "{distanceInKm} km", "{distanceInKm} km": "{distanceInKm} km",
"{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# guest} other {# guests}}", "{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# guest} other {# guests}}",

View File

@@ -971,6 +971,7 @@
"{count} number": "{count} määrä", "{count} number": "{count} määrä",
"{count} special character": "{count} erikoishahmo", "{count} special character": "{count} erikoishahmo",
"{count} uppercase letter": "{count} iso kirjain", "{count} uppercase letter": "{count} iso kirjain",
"{count} voucher": "{count} voucher",
"{difference}{amount} {currency}": "{difference}{amount} {currency}", "{difference}{amount} {currency}": "{difference}{amount} {currency}",
"{distanceInKm} km": "{distanceInKm} km", "{distanceInKm} km": "{distanceInKm} km",
"{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# vieras} other {# vieraita}}", "{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# vieras} other {# vieraita}}",

View File

@@ -967,6 +967,7 @@
"{count} number": "{count} antall", "{count} number": "{count} antall",
"{count} special character": "{count} spesiell karakter", "{count} special character": "{count} spesiell karakter",
"{count} uppercase letter": "{count} stor bokstav", "{count} uppercase letter": "{count} stor bokstav",
"{count} voucher": "{count} voucher",
"{difference}{amount} {currency}": "{difference}{amount} {currency}", "{difference}{amount} {currency}": "{difference}{amount} {currency}",
"{distanceInKm} km": "{distanceInKm} km", "{distanceInKm} km": "{distanceInKm} km",
"{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# gjest} other {# gjester}}", "{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# gjest} other {# gjester}}",

View File

@@ -971,6 +971,7 @@
"{count} number": "{count} nummer", "{count} number": "{count} nummer",
"{count} special character": "{count} speciell karaktär", "{count} special character": "{count} speciell karaktär",
"{count} uppercase letter": "{count} stor bokstav", "{count} uppercase letter": "{count} stor bokstav",
"{count} voucher": "{count} voucher",
"{difference}{amount} {currency}": "{difference}{amount} {currency}", "{difference}{amount} {currency}": "{difference}{amount} {currency}",
"{distanceInKm} km": "{distanceInKm} km", "{distanceInKm} km": "{distanceInKm} km",
"{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# gäst} other {# gäster}}", "{guests, plural, one {# guest} other {# guests}}": "{guests, plural, one {# gäst} other {# gäster}}",

View File

@@ -205,6 +205,8 @@ export const bookingConfirmationSchema = z
childrenAges: z.array(z.number().int()).default([]), childrenAges: z.array(z.number().int()).default([]),
canChangeDate: z.boolean(), canChangeDate: z.boolean(),
bookingCode: z.string().nullable(), bookingCode: z.string().nullable(),
cheques: z.number(),
vouchers: z.number(),
guaranteeInfo: z guaranteeInfo: z
.object({ .object({
maskedCard: z.string(), maskedCard: z.string(),
@@ -227,8 +229,10 @@ export const bookingConfirmationSchema = z
packages: z.array(packageSchema).default([]), packages: z.array(packageSchema).default([]),
rateDefinition: rateDefinitionSchema, rateDefinition: rateDefinitionSchema,
reservationStatus: z.string().nullable().default(""), reservationStatus: z.string().nullable().default(""),
roomPoints: z.number(),
roomPrice: z.number(), roomPrice: z.number(),
roomTypeCode: z.string().default(""), roomTypeCode: z.string().default(""),
totalPoints: z.number(),
totalPrice: z.number(), totalPrice: z.number(),
totalPriceExVat: z.number(), totalPriceExVat: z.number(),
vatAmount: z.number(), vatAmount: z.number(),

View File

@@ -3,6 +3,7 @@ import { create } from "zustand"
import type { BreakfastPackage } from "@/types/components/hotelReservation/breakfast" import type { BreakfastPackage } from "@/types/components/hotelReservation/breakfast"
import type { BedTypeSchema } from "@/types/components/hotelReservation/enterDetails/bedType" import type { BedTypeSchema } from "@/types/components/hotelReservation/enterDetails/bedType"
import type { RoomPrice } from "@/types/components/hotelReservation/enterDetails/details" import type { RoomPrice } from "@/types/components/hotelReservation/enterDetails/details"
import type { PriceType } from "@/types/components/hotelReservation/myStay/myStay"
import type { Child } from "@/types/components/hotelReservation/selectRate/selectRate" import type { Child } from "@/types/components/hotelReservation/selectRate/selectRate"
import type { Packages } from "@/types/requests/packages" import type { Packages } from "@/types/requests/packages"
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation" import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
@@ -21,6 +22,8 @@ export type Room = Pick<
| "confirmationNumber" | "confirmationNumber"
| "cancellationNumber" | "cancellationNumber"
| "bookingCode" | "bookingCode"
| "cheques"
| "vouchers"
| "isCancelable" | "isCancelable"
| "multiRoom" | "multiRoom"
| "canChangeDate" | "canChangeDate"
@@ -28,6 +31,7 @@ export type Room = Pick<
| "roomTypeCode" | "roomTypeCode"
| "currencyCode" | "currencyCode"
| "vatPercentage" | "vatPercentage"
| "roomPoints"
> & { > & {
roomName: string roomName: string
roomNumber: number | null roomNumber: number | null
@@ -41,6 +45,7 @@ export type Room = Pick<
breakfast: BreakfastPackage | false breakfast: BreakfastPackage | false
mainRoom: boolean mainRoom: boolean
isPrePaid: boolean isPrePaid: boolean
priceType: PriceType
} }
interface MyStayRoomDetailsState { interface MyStayRoomDetailsState {
@@ -66,6 +71,8 @@ export const useMyStayRoomDetailsStore = create<MyStayRoomDetailsState>(
confirmationNumber: "", confirmationNumber: "",
cancellationNumber: null, cancellationNumber: null,
bookingCode: null, bookingCode: null,
cheques: 0,
vouchers: 0,
currencyCode: "", currencyCode: "",
guest: { guest: {
email: "", email: "",
@@ -85,6 +92,7 @@ export const useMyStayRoomDetailsStore = create<MyStayRoomDetailsState>(
rateCode: "", rateCode: "",
title: null, title: null,
}, },
roomPoints: 0,
roomPrice: { roomPrice: {
perNight: { perNight: {
requested: { requested: {
@@ -129,6 +137,7 @@ export const useMyStayRoomDetailsStore = create<MyStayRoomDetailsState>(
linkedReservations: [], linkedReservations: [],
isCancelable: false, isCancelable: false,
isPrePaid: false, isPrePaid: false,
priceType: "money",
}, },
linkedReservationRooms: [], linkedReservationRooms: [],
actions: { actions: {

View File

@@ -5,25 +5,27 @@ interface RoomPrice {
totalPrice: number totalPrice: number
currencyCode: string currencyCode: string
isMainBooking?: boolean isMainBooking?: boolean
roomPoints: number
} }
interface MyStayTotalPriceState { interface MyStayTotalPriceState {
rooms: RoomPrice[] rooms: RoomPrice[]
totalPrice: number | null totalPrice: number | null
currencyCode: string currencyCode: string
totalPoints: number
actions: { actions: {
// Add a single room price // Add a single room price
addRoomPrice: (room: RoomPrice) => void addRoomPrice: (room: RoomPrice) => void
// Get the calculated total
getTotalPrice: () => number | null
} }
} }
export const useMyStayTotalPriceStore = create<MyStayTotalPriceState>( export const useMyStayTotalPriceStore = create<MyStayTotalPriceState>(
(set, get) => ({ (set) => ({
rooms: [], rooms: [],
totalPrice: null, totalPrice: null,
totalPoints: 0,
totalCheques: 0,
totalVouchers: 0,
currencyCode: "", currencyCode: "",
actions: { actions: {
addRoomPrice: (room) => { addRoomPrice: (room) => {
@@ -52,17 +54,18 @@ export const useMyStayTotalPriceStore = create<MyStayTotalPriceState>(
return sum return sum
}, 0) }, 0)
const totalPoints = newRooms.reduce((sum, r) => {
return sum + r.roomPoints
}, 0)
return { return {
rooms: newRooms, rooms: newRooms,
totalPrice: total, totalPrice: total,
currencyCode, currencyCode,
totalPoints,
} }
}) })
}, },
getTotalPrice: () => {
return get().totalPrice
},
}, },
}) })
) )

View File

@@ -2,3 +2,5 @@ export enum MODAL_STEPS {
INITIAL = 1, INITIAL = 1,
CONFIRMATION = 2, CONFIRMATION = 2,
} }
export type PriceType = "points" | "money" | "voucher" | "cheque"