Files
Hrishikesh Vaipurkar c5e294c7ea Merged in feat/SW-1356-reward-night-booking-2- (pull request #1559)
feat: SW-1356 Reward night bookingflow

* feat: SW-1356 Reward night bookingflow

* feat: SW-1356 Removed extra param booking call

* feat: SW-1356 Optimized as review comments

* feat: SW-1356 Schema validation updates

* feat: SW-1356 Fix after rebase

* feat: SW-1356 Optimised price.redemptions check

* feat: SW-1356 Updated Props naming


Approved-by: Arvid Norlin
2025-03-24 08:54:02 +00:00

177 lines
5.3 KiB
TypeScript

"use client"
import { useEffect, useRef, useState } from "react"
import { useIntl } from "react-intl"
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 Summary from "./Summary"
import styles from "./mobileSummary.module.css"
import type { MobileSummaryProps } from "@/types/components/hotelReservation/selectRate/rateSummary"
import { RateTypeEnum } from "@/types/enums/rateType"
import type { RoomsAvailability } from "@/types/trpc/routers/hotel/roomAvailability"
export default function MobileSummary({
isAllRoomsSelected,
isUserLoggedIn,
totalPriceToShow,
}: MobileSummaryProps) {
const intl = useIntl()
const scrollY = useRef(0)
const [isSummaryOpen, setIsSummaryOpen] = useState(false)
const { booking, bookingRooms, roomsAvailability, rateSummary, vat } =
useRatesStore((state) => ({
booking: state.booking,
bookingRooms: state.booking.rooms,
roomsAvailability: state.roomsAvailability,
rateSummary: state.rateSummary,
vat: state.vat,
}))
function toggleSummaryOpen() {
setIsSummaryOpen(!isSummaryOpen)
}
useEffect(() => {
if (isSummaryOpen) {
scrollY.current = window.scrollY
document.body.style.position = "fixed"
document.body.style.top = `-${scrollY.current}px`
document.body.style.width = "100%"
} else {
document.body.style.position = ""
document.body.style.top = ""
document.body.style.width = ""
window.scrollTo({
top: scrollY.current,
left: 0,
behavior: "instant",
})
}
return () => {
document.body.style.position = ""
document.body.style.top = ""
}
}, [isSummaryOpen])
const roomRateDefinitions = roomsAvailability?.find(
(ra): ra is RoomsAvailability => "rateDefinitions" in ra
)
if (!roomRateDefinitions) {
return null
}
const rateDefinitions = roomRateDefinitions.rateDefinitions
const rooms = rateSummary.map((room, index) => ({
adults: bookingRooms[index].adults,
childrenInRoom: bookingRooms[index].childrenInRoom ?? undefined,
roomType: room.roomType,
roomPrice: {
perNight: {
local: {
price: (room.public?.localPrice.pricePerNight ||
room.member?.localPrice.pricePerNight)!,
currency: (room.public?.localPrice.currency ||
room.member?.localPrice.currency)!,
},
requested: undefined,
},
perStay: {
local: {
price: (room.public?.localPrice.pricePerStay ||
room.member?.localPrice.pricePerStay)!,
currency: (room.public?.localPrice.currency ||
room.member?.localPrice.currency)!,
},
requested: undefined,
},
currency: (room.public?.localPrice.currency ||
room.member?.localPrice.currency)!,
},
roomRate: {
...room.public,
memberRate: room.member,
publicRate: room.public,
},
rateDetails: rateDefinitions.find(
(rate) =>
rate.rateCode === room.public?.rateCode ||
rate.rateCode === room.member?.rateCode
)?.generalTerms,
cancellationText:
rateDefinitions.find(
(rate) =>
rate.rateCode === room.public?.rateCode ||
rate.rateCode === room.member?.rateCode
)?.cancellationText ?? "",
}))
const containsBookingCodeRate = rateSummary.find(
(rate) => rate.public?.rateType !== RateTypeEnum.Regular
)
const showDiscounted = containsBookingCodeRate || isUserLoggedIn
return (
<div className={styles.wrapper} data-open={isSummaryOpen}>
<div className={styles.content}>
<div className={styles.summaryAccordion}>
<Summary
booking={booking}
rooms={rooms}
isMember={isUserLoggedIn}
totalPrice={totalPriceToShow}
vat={vat}
toggleSummaryOpen={toggleSummaryOpen}
/>
</div>
</div>
<div className={styles.bottomSheet}>
<button
data-open={isSummaryOpen}
onClick={(e) => {
e.preventDefault()
toggleSummaryOpen()
}}
className={styles.priceDetailsButton}
>
<Caption>{intl.formatMessage({ id: "Total price" })}</Caption>
<Subtitle
color={showDiscounted ? "red" : "uiTextHighContrast"}
className={styles.wrappedText}
>
{formatPriceWithAdditionalPrice(
intl,
totalPriceToShow.local.price,
totalPriceToShow.local.currency,
totalPriceToShow.local.additionalPrice,
totalPriceToShow.local.additionalPriceCurrency
)}
</Subtitle>
<Caption color="baseTextHighContrast" type="underline">
{intl.formatMessage({ id: "See details" })}
</Caption>
</button>
<Button
intent="primary"
theme="base"
size="large"
type="submit"
fullWidth
disabled={!isAllRoomsSelected}
>
{intl.formatMessage({ id: "Continue" })}
</Button>
</div>
</div>
)
}