Merged in feat/SW-1437-price-change-scenario (pull request #1532)

Feat/SW-1437 price change scenario

* wip price change scenario

* feat(SW-1437): added updated room prices to summary

* fix: spinner not centered on page

* fix: feedback fixes


Approved-by: Arvid Norlin
Approved-by: Simon.Emanuelsson
This commit is contained in:
Tobias Johansson
2025-03-14 12:39:50 +00:00
parent abd401c4f4
commit c0b543f18d
16 changed files with 489 additions and 75 deletions

View File

@@ -1,26 +1,68 @@
import { Dialog, Modal, ModalOverlay } from "react-aria-components"
import { useIntl } from "react-intl"
import { useEnterDetailsStore } from "@/stores/enter-details"
import { InfoCircleIcon } from "@/components/Icons"
import Button from "@/components/TempDesignSystem/Button"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import Title from "@/components/TempDesignSystem/Text/Title"
import { formatPrice } from "@/utils/numberFormatting"
import styles from "./priceChangeDialog.module.css"
import { calculateTotalRoomPrice } from "../Payment/helpers"
import PriceChangeSummary from "./PriceChangeSummary"
import type { PriceChangeDialogProps } from "@/types/components/hotelReservation/enterDetails/priceChangeDialog"
import styles from "./priceChangeDialog.module.css"
import { PriceChangeData } from "@/types/components/hotelReservation/enterDetails/payment"
type PriceDetailsState = {
newTotalPrice: number
roomPrices: { prevPrice: number; newPrice?: number }[]
}
type PriceChangeDialogProps = {
isOpen: boolean
priceChangeData: PriceChangeData
prevTotalPrice: number
currency: string
onCancel: () => void
onAccept: () => void
}
export default function PriceChangeDialog({
isOpen,
oldPrice,
newPrice,
priceChangeData,
prevTotalPrice,
currency,
onCancel,
onAccept,
}: PriceChangeDialogProps) {
const intl = useIntl()
const title = intl.formatMessage({ id: "The price has increased" })
const title = intl.formatMessage({ id: "Price change" })
const rooms = useEnterDetailsStore((state) => state.rooms)
const { newTotalPrice, roomPrices } = rooms.reduce<PriceDetailsState>(
(acc, room, idx) => {
const roomPrice = room.room.roomPrice.perStay.local.price
const priceChange = priceChangeData[idx]
const { totalPrice } = calculateTotalRoomPrice(
room,
priceChange?.roomPrice
)
acc.newTotalPrice += totalPrice
acc.roomPrices.push({
prevPrice: roomPrice,
newPrice: priceChange?.roomPrice,
})
return acc
},
{ newTotalPrice: 0, roomPrices: [] }
)
return (
<ModalOverlay
@@ -37,34 +79,46 @@ export default function PriceChangeDialog({
level="h1"
as="h3"
textAlign="center"
textTransform="regular"
textTransform="uppercase"
>
{title}
</Title>
</div>
<Body textAlign="center">
{intl.formatMessage({
id: "The price has increased since you selected your room.",
})}
<br />
{intl.formatMessage({
id: "You can still book the room but you need to confirm that you accept the new price",
})}
<br />
<span className={styles.oldPrice}>
{formatPrice(intl, oldPrice, currency)}
</span>
<strong className={styles.newPrice}>
{formatPrice(intl, newPrice, currency)}
</strong>
{intl.formatMessage(
{
id: "Prices have increased since you selected your {totalRooms, plural, one {room} other {rooms}}.{br} To continue your booking, accept the updated price,{br} or go back to select {totalRooms, plural, one {a new room} other {new rooms}}.",
},
{ totalRooms: rooms.length, br: <br /> }
)}
</Body>
<div>
<Subtitle textAlign="center" color="burgundy">
{intl.formatMessage({ id: "New total" })}
</Subtitle>
<div className={styles.prices}>
<Caption striked>
{formatPrice(intl, prevTotalPrice, currency)}
</Caption>
<Body textAlign="center" textTransform="bold">
{formatPrice(intl, newTotalPrice, currency)}
</Body>
</div>
</div>
<PriceChangeSummary
rooms={rooms}
roomPrices={roomPrices}
newTotalPrice={{ price: newTotalPrice, currency }}
onAccept={onAccept}
onCancel={onCancel}
/>
</header>
<footer className={styles.footer}>
<Button intent="secondary" onClick={onCancel}>
{intl.formatMessage({ id: "Cancel" })}
{intl.formatMessage({ id: "Back to select room" })}
</Button>
<Button onClick={onAccept}>
{intl.formatMessage({ id: "Accept new price" })}
{intl.formatMessage({ id: "Continue with new price" })}
</Button>
</footer>
</Dialog>