feat: consume serach params in summary and step page
This commit is contained in:
@@ -1,52 +1,43 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { dt } from "@/lib/dt"
|
||||
import { trpc } from "@/lib/trpc/client"
|
||||
import { useEnterDetailsStore } from "@/stores/enter-details"
|
||||
|
||||
import { ArrowRightIcon } from "@/components/Icons"
|
||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
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 { formatNumber } from "@/utils/format"
|
||||
|
||||
import styles from "./summary.module.css"
|
||||
|
||||
import { RoomsData } from "@/types/components/hotelReservation/enterDetails/bookingData"
|
||||
|
||||
export default function Summary({ isMember }: { isMember: boolean }) {
|
||||
export default function Summary({
|
||||
isMember,
|
||||
room,
|
||||
}: {
|
||||
isMember: boolean
|
||||
room: RoomsData
|
||||
}) {
|
||||
const [chosenBed, setChosenBed] = useState<string | undefined>()
|
||||
const [chosenBreakfast, setCosenBreakfast] = useState<string | undefined>()
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
const { fromDate, toDate, rooms, hotel, bedType, breakfast } =
|
||||
useEnterDetailsStore((state) => ({
|
||||
fromDate: state.roomData.fromdate,
|
||||
toDate: state.roomData.todate,
|
||||
const { fromDate, toDate, bedType, breakfast } = useEnterDetailsStore(
|
||||
(state) => ({
|
||||
fromDate: state.roomData.fromDate,
|
||||
toDate: state.roomData.toDate,
|
||||
rooms: state.roomData.room,
|
||||
hotel: state.roomData.hotel,
|
||||
bedType: state.userData.bedType,
|
||||
breakfast: state.userData.breakfast,
|
||||
}))
|
||||
|
||||
const totalAdults = rooms.reduce((total, room) => total + room.adults, 0)
|
||||
|
||||
const {
|
||||
data: availabilityData,
|
||||
isLoading,
|
||||
error,
|
||||
} = trpc.hotel.availability.rooms.useQuery(
|
||||
{
|
||||
hotelId: parseInt(hotel),
|
||||
adults: totalAdults,
|
||||
roomStayStartDate: dt(fromDate).format("YYYY-MM-DD"),
|
||||
roomStayEndDate: dt(toDate).format("YYYY-MM-DD"),
|
||||
},
|
||||
{ enabled: !!hotel && !!fromDate && !!toDate }
|
||||
})
|
||||
)
|
||||
|
||||
const diff = dt(toDate).diff(fromDate, "days")
|
||||
@@ -56,37 +47,15 @@ export default function Summary({ isMember }: { isMember: boolean }) {
|
||||
{ totalNights: diff }
|
||||
)
|
||||
|
||||
if (isLoading) {
|
||||
return <LoadingSpinner />
|
||||
let color: "uiTextHighContrast" | "red" = "uiTextHighContrast"
|
||||
if (isMember) {
|
||||
color = "red"
|
||||
}
|
||||
const populatedRooms = rooms
|
||||
.map((room) => {
|
||||
const chosenRoom = availabilityData?.roomConfigurations.find(
|
||||
(availRoom) => room.roomtypecode === availRoom.roomTypeCode
|
||||
)
|
||||
const cancellationText = availabilityData?.rateDefinitions.find(
|
||||
(rate) => rate.rateCode === room.ratecode
|
||||
)?.cancellationText
|
||||
|
||||
if (chosenRoom) {
|
||||
const memberPrice = chosenRoom.products.find(
|
||||
(rate) => rate.productType.member?.rateCode === room.ratecode
|
||||
)?.productType.member?.localPrice.pricePerStay
|
||||
const publicPrice = chosenRoom.products.find(
|
||||
(rate) => rate.productType.public?.rateCode === room.ratecode
|
||||
)?.productType.public?.localPrice.pricePerStay
|
||||
|
||||
return {
|
||||
roomType: chosenRoom.roomType,
|
||||
memberPrice: memberPrice && formatNumber(parseInt(memberPrice)),
|
||||
publicPrice: publicPrice && formatNumber(parseInt(publicPrice)),
|
||||
adults: room.adults,
|
||||
children: room.child,
|
||||
cancellationText,
|
||||
}
|
||||
}
|
||||
})
|
||||
.filter((room): room is RoomsData => room !== undefined)
|
||||
useEffect(() => {
|
||||
setChosenBed(bedType)
|
||||
setCosenBreakfast(breakfast)
|
||||
}, [bedType, breakfast])
|
||||
|
||||
return (
|
||||
<section className={styles.summary}>
|
||||
@@ -100,14 +69,48 @@ export default function Summary({ isMember }: { isMember: boolean }) {
|
||||
</header>
|
||||
<Divider color="primaryLightSubtle" />
|
||||
<div className={styles.addOns}>
|
||||
{populatedRooms.map((room, idx) => (
|
||||
<RoomBreakdown key={idx} room={room} isMember={isMember} />
|
||||
))}
|
||||
|
||||
{bedType ? (
|
||||
<div>
|
||||
<div className={styles.entry}>
|
||||
<Body color="textHighContrast">{bedType}</Body>
|
||||
<Caption color="red">
|
||||
<Body color="textHighContrast">{room.roomType}</Body>
|
||||
<Caption color={color}>
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: room.price, currency: "SEK" }
|
||||
)}
|
||||
</Caption>
|
||||
</div>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "booking.adults" },
|
||||
{ totalAdults: room.adults }
|
||||
)}
|
||||
</Caption>
|
||||
{room.children?.length ? (
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "booking.children" },
|
||||
{ totalChildren: room.children.length }
|
||||
)}
|
||||
</Caption>
|
||||
) : null}
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{room.cancellationText}
|
||||
</Caption>
|
||||
<Link color="burgundy" href="#" variant="underscored" size="small">
|
||||
{intl.formatMessage({ id: "Rate details" })}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{chosenBed ? (
|
||||
<div className={styles.entry}>
|
||||
<div>
|
||||
<Body color="textHighContrast">{chosenBed}</Body>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage({ id: "Based on availability" })}
|
||||
</Caption>
|
||||
</div>
|
||||
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: "0", currency: "SEK" }
|
||||
@@ -115,10 +118,11 @@ export default function Summary({ isMember }: { isMember: boolean }) {
|
||||
</Caption>
|
||||
</div>
|
||||
) : null}
|
||||
{breakfast ? (
|
||||
|
||||
{chosenBreakfast ? (
|
||||
<div className={styles.entry}>
|
||||
<Body color="textHighContrast">{breakfast}</Body>
|
||||
<Caption color="red">
|
||||
<Body color="textHighContrast">{chosenBreakfast}</Body>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: "0", currency: "SEK" }
|
||||
@@ -130,77 +134,35 @@ export default function Summary({ isMember }: { isMember: boolean }) {
|
||||
<Divider color="primaryLightSubtle" />
|
||||
<div className={styles.total}>
|
||||
<div className={styles.entry}>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({ id: "Total price (incl VAT)" })}
|
||||
</Body>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: "4686", currency: "SEK" }
|
||||
)}
|
||||
</Body>
|
||||
</div>
|
||||
<div className={styles.entry}>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage({ id: "Approx." })}
|
||||
</Caption>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: "455", currency: "EUR" }
|
||||
)}
|
||||
</Caption>
|
||||
<div>
|
||||
<Body>
|
||||
{intl.formatMessage<React.ReactNode>(
|
||||
{ id: "<b>Total price</b> (incl VAT)" },
|
||||
{ b: (str) => <b>{str}</b> }
|
||||
)}
|
||||
</Body>
|
||||
<Link color="burgundy" href="#" variant="underscored" size="small">
|
||||
{intl.formatMessage({ id: "Price details" })}
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: room.price, currency: "SEK" } // TODO: calculate total price
|
||||
)}
|
||||
</Body>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage({ id: "Approx." })}{" "}
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: "455", currency: "EUR" }
|
||||
)}
|
||||
</Caption>
|
||||
</div>
|
||||
</div>
|
||||
<Divider color="primaryLightSubtle" />
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function RoomBreakdown({
|
||||
room,
|
||||
isMember,
|
||||
}: {
|
||||
room: RoomsData
|
||||
isMember: boolean
|
||||
}) {
|
||||
const intl = useIntl()
|
||||
|
||||
let color: "uiTextHighContrast" | "red" = "uiTextHighContrast"
|
||||
let price = room.publicPrice
|
||||
if (isMember) {
|
||||
color = "red"
|
||||
price = room.memberPrice
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.entry}>
|
||||
<Body color="textHighContrast">{room.roomType}</Body>
|
||||
<Caption color={color}>
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: price, currency: "SEK" }
|
||||
)}
|
||||
</Caption>
|
||||
</div>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "booking.adults" },
|
||||
{ totalAdults: room.adults }
|
||||
)}
|
||||
</Caption>
|
||||
{room.children?.length ? (
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "booking.children" },
|
||||
{ totalChildren: room.children.length }
|
||||
)}
|
||||
</Caption>
|
||||
) : null}
|
||||
<Caption color="uiTextMediumContrast">{room.cancellationText}</Caption>
|
||||
<Link color="burgundy" href="#" variant="underscored" size="small">
|
||||
{intl.formatMessage({ id: "Rate details" })}
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user