feat(SW-718) Refactor select rate to support multiroom
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import SkeletonShimmer from "@/components/SkeletonShimmer"
|
||||
|
||||
import { RoomCardSkeleton } from "../../SelectRate/RoomSelection/RoomCard/RoomCardSkeleton"
|
||||
import { RoomCardSkeleton } from "../../SelectRate/RoomList/RoomCard/RoomCardSkeleton"
|
||||
|
||||
import styles from "./SelectHotelMapContainerSkeleton.module.css"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { selectHotel } from "@/constants/routes/hotelReservation"
|
||||
import { useHotelFilterStore } from "@/stores/hotel-filters"
|
||||
import { useHotelsMapStore } from "@/stores/hotels-map"
|
||||
|
||||
import { RoomCardSkeleton } from "@/components/HotelReservation/SelectRate/RoomSelection/RoomCard/RoomCardSkeleton"
|
||||
import { RoomCardSkeleton } from "@/components/HotelReservation/SelectRate/RoomList/RoomCard/RoomCardSkeleton"
|
||||
import { CloseIcon, CloseLargeIcon } from "@/components/Icons"
|
||||
import InteractiveMap from "@/components/Maps/InteractiveMap"
|
||||
import { BackToTopButton } from "@/components/TempDesignSystem/BackToTopButton"
|
||||
|
||||
@@ -4,7 +4,6 @@ import { createElement, useCallback } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import ToggleSidePeek from "@/components/HotelReservation/EnterDetails/SelectedRoom/ToggleSidePeek"
|
||||
import FlexibilityOption from "@/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption"
|
||||
import { getIconForFeatureCode } from "@/components/HotelReservation/utils"
|
||||
import { ErrorCircleIcon } from "@/components/Icons"
|
||||
import ImageGallery from "@/components/ImageGallery"
|
||||
@@ -12,6 +11,7 @@ import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
|
||||
import FlexibilityOption from "../FlexibilityOption"
|
||||
import { cardVariants } from "./cardVariants"
|
||||
|
||||
import styles from "./roomCard.module.css"
|
||||
38
components/HotelReservation/SelectRate/RoomList/index.tsx
Normal file
38
components/HotelReservation/SelectRate/RoomList/index.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
"use client"
|
||||
|
||||
import RoomCard from "./RoomCard"
|
||||
|
||||
import styles from "./roomSelection.module.css"
|
||||
|
||||
import type { RoomListProps } from "@/types/components/hotelReservation/selectRate/roomSelection"
|
||||
|
||||
export default function RoomList({
|
||||
roomsAvailability,
|
||||
roomCategories,
|
||||
availablePackages,
|
||||
selectedPackages,
|
||||
setRateCode,
|
||||
hotelType,
|
||||
}: RoomListProps) {
|
||||
const { roomConfigurations, rateDefinitions } = roomsAvailability
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<ul className={styles.roomList}>
|
||||
{roomConfigurations.map((roomConfiguration, index) => (
|
||||
<RoomCard
|
||||
hotelId={roomsAvailability.hotelId.toString()}
|
||||
hotelType={hotelType}
|
||||
rateDefinitions={rateDefinitions}
|
||||
roomConfiguration={roomConfiguration}
|
||||
roomCategories={roomCategories}
|
||||
handleSelectRate={setRateCode}
|
||||
selectedPackages={selectedPackages}
|
||||
packages={availablePackages}
|
||||
key={roomConfiguration.roomTypeCode}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
"use client"
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation"
|
||||
import { useMemo } from "react"
|
||||
|
||||
import { convertObjToSearchParams } from "@/utils/url"
|
||||
|
||||
import RateSummary from "./RateSummary"
|
||||
import RoomCard from "./RoomCard"
|
||||
|
||||
import styles from "./roomSelection.module.css"
|
||||
|
||||
import type { RoomSelectionProps } from "@/types/components/hotelReservation/selectRate/roomSelection"
|
||||
|
||||
export default function RoomSelection({
|
||||
roomsAvailability,
|
||||
roomCategories,
|
||||
availablePackages,
|
||||
selectedPackages,
|
||||
isUserLoggedIn,
|
||||
setRateCode,
|
||||
rateSummary,
|
||||
hotelType,
|
||||
}: RoomSelectionProps) {
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const searchParams = useSearchParams()
|
||||
const { roomConfigurations, rateDefinitions } = roomsAvailability
|
||||
|
||||
const queryParams = useMemo(() => {
|
||||
// TODO: handle multiple rooms
|
||||
const newSearchParams = convertObjToSearchParams(
|
||||
{
|
||||
rooms: [
|
||||
{
|
||||
roomTypeCode: rateSummary?.roomTypeCode,
|
||||
rateCode: rateSummary?.public.rateCode,
|
||||
counterRateCode: rateSummary?.member?.rateCode,
|
||||
packages: selectedPackages,
|
||||
},
|
||||
],
|
||||
},
|
||||
searchParams
|
||||
)
|
||||
|
||||
return newSearchParams
|
||||
}, [searchParams, rateSummary, selectedPackages])
|
||||
|
||||
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault()
|
||||
|
||||
window.history.replaceState(
|
||||
null,
|
||||
"",
|
||||
`${pathname}?${queryParams.toString()}`
|
||||
)
|
||||
router.push(`select-bed?${queryParams}`)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<form
|
||||
method="GET"
|
||||
action={`select-bed?${searchParams}`}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<ul className={styles.roomList}>
|
||||
{roomConfigurations.map((roomConfiguration, index) => (
|
||||
<RoomCard
|
||||
hotelId={roomsAvailability.hotelId.toString()}
|
||||
hotelType={hotelType}
|
||||
rateDefinitions={rateDefinitions}
|
||||
roomConfiguration={roomConfiguration}
|
||||
roomCategories={roomCategories}
|
||||
handleSelectRate={setRateCode}
|
||||
selectedPackages={selectedPackages}
|
||||
packages={availablePackages}
|
||||
key={roomConfiguration.roomTypeCode}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
{rateSummary && (
|
||||
<RateSummary
|
||||
rateSummary={rateSummary}
|
||||
isUserLoggedIn={isUserLoggedIn}
|
||||
packages={availablePackages}
|
||||
roomsAvailability={roomsAvailability}
|
||||
/>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import RoomFilter from "../RoomFilter"
|
||||
import RoomList from "../RoomList"
|
||||
|
||||
import type { RoomSelectionPanelProps } from "@/types/components/hotelReservation/selectRate/roomSelection"
|
||||
|
||||
export function RoomSelectionPanel({
|
||||
rooms,
|
||||
roomCategories,
|
||||
availablePackages,
|
||||
selectedPackages,
|
||||
setSelectedRate,
|
||||
hotelType,
|
||||
handleFilter,
|
||||
defaultPackages,
|
||||
}: RoomSelectionPanelProps) {
|
||||
return (
|
||||
<>
|
||||
<RoomFilter
|
||||
numberOfRooms={rooms.roomConfigurations.length}
|
||||
onFilter={handleFilter}
|
||||
filterOptions={defaultPackages}
|
||||
/>
|
||||
<RoomList
|
||||
roomsAvailability={rooms}
|
||||
roomCategories={roomCategories}
|
||||
availablePackages={availablePackages}
|
||||
selectedPackages={selectedPackages}
|
||||
setRateCode={setSelectedRate}
|
||||
hotelType={hotelType}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RoomCardSkeleton } from "../RoomSelection/RoomCard/RoomCardSkeleton"
|
||||
import { RoomCardSkeleton } from "../RoomList/RoomCard/RoomCardSkeleton"
|
||||
|
||||
import styles from "./RoomsContainerSkeleton.module.css"
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
"use client"
|
||||
|
||||
import { useSearchParams } from "next/navigation"
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation"
|
||||
import { useCallback, useEffect, useMemo, useState } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import { trackLowestRoomPrice } from "@/utils/tracking"
|
||||
import { convertObjToSearchParams } from "@/utils/url"
|
||||
|
||||
import RoomFilter from "../RoomFilter"
|
||||
import RoomSelection from "../RoomSelection"
|
||||
import RateSummary from "../RateSummary"
|
||||
import { RoomSelectionPanel } from "../RoomSelectionPanel"
|
||||
import { filterDuplicateRoomTypesByLowestPrice, parseRoomParams } from "./utils"
|
||||
|
||||
import styles from "./rooms.module.css"
|
||||
@@ -32,6 +33,8 @@ export default function Rooms({
|
||||
hotelType,
|
||||
isUserLoggedIn,
|
||||
}: SelectRateProps) {
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
const hotelId = searchParams.get("hotel")
|
||||
@@ -43,6 +46,8 @@ export default function Rooms({
|
||||
[searchParams]
|
||||
)
|
||||
|
||||
const isMultipleRooms = searchedRoomsAndGuests.length > 1
|
||||
|
||||
const intl = useIntl()
|
||||
|
||||
const visibleRooms: RoomConfiguration[] = useMemo(() => {
|
||||
@@ -218,33 +223,94 @@ export default function Rooms({
|
||||
})
|
||||
}, [arrivalDate, departureDate, hotelId, rooms.roomConfigurations])
|
||||
|
||||
const queryParams = useMemo(() => {
|
||||
// TODO: handle multiple rooms
|
||||
const newSearchParams = convertObjToSearchParams(
|
||||
{
|
||||
rooms: [
|
||||
{
|
||||
roomTypeCode: rateSummary?.roomTypeCode,
|
||||
rateCode: rateSummary?.public.rateCode,
|
||||
counterRateCode: rateSummary?.member?.rateCode,
|
||||
packages: selectedPackages,
|
||||
},
|
||||
],
|
||||
},
|
||||
searchParams
|
||||
)
|
||||
|
||||
return newSearchParams
|
||||
}, [searchParams, rateSummary, selectedPackages])
|
||||
|
||||
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault()
|
||||
|
||||
window.history.replaceState(
|
||||
null,
|
||||
"",
|
||||
`${pathname}?${queryParams.toString()}`
|
||||
)
|
||||
router.push(`select-bed?${queryParams}`)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{searchedRoomsAndGuests.map((room, index) => (
|
||||
<div key={index} className={styles.content}>
|
||||
<Subtitle>
|
||||
{`Room ${index + 1}, ${room.adults} adults`}
|
||||
{room.children &&
|
||||
room.children.length > 0 &&
|
||||
`, ${room.children.length} children`}
|
||||
</Subtitle>
|
||||
<RoomFilter
|
||||
numberOfRooms={rooms.roomConfigurations.length}
|
||||
onFilter={handleFilter}
|
||||
filterOptions={defaultPackages}
|
||||
/>
|
||||
<RoomSelection
|
||||
roomsAvailability={rooms}
|
||||
roomCategories={roomCategories}
|
||||
availablePackages={availablePackages}
|
||||
selectedPackages={selectedPackages}
|
||||
setRateCode={setSelectedRate}
|
||||
<div className={styles.content}>
|
||||
{isMultipleRooms ? (
|
||||
searchedRoomsAndGuests.map((room, index) => (
|
||||
<div key={index}>
|
||||
<Subtitle>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: room.children?.length
|
||||
? "Room {roomIndex}, {adults} adults, {children} children"
|
||||
: "Room {roomIndex}, {adults} adults",
|
||||
},
|
||||
{
|
||||
roomIndex: index + 1,
|
||||
adults: room.adults,
|
||||
children: room.children?.length,
|
||||
}
|
||||
)}
|
||||
</Subtitle>
|
||||
<RoomSelectionPanel
|
||||
rooms={rooms}
|
||||
roomCategories={roomCategories}
|
||||
availablePackages={availablePackages}
|
||||
selectedPackages={selectedPackages}
|
||||
setSelectedRate={setSelectedRate}
|
||||
hotelType={hotelType}
|
||||
handleFilter={handleFilter}
|
||||
defaultPackages={defaultPackages}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<RoomSelectionPanel
|
||||
rooms={rooms}
|
||||
roomCategories={roomCategories}
|
||||
availablePackages={availablePackages}
|
||||
selectedPackages={selectedPackages}
|
||||
setSelectedRate={setSelectedRate}
|
||||
hotelType={hotelType}
|
||||
handleFilter={handleFilter}
|
||||
defaultPackages={defaultPackages}
|
||||
/>
|
||||
)}
|
||||
|
||||
{rateSummary && (
|
||||
<form
|
||||
method="GET"
|
||||
action={`select-bed?${searchParams}`}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<RateSummary
|
||||
rateSummary={rateSummary}
|
||||
hotelType={hotelType}
|
||||
isUserLoggedIn={isUserLoggedIn}
|
||||
packages={availablePackages}
|
||||
roomsAvailability={roomsAvailability}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -381,6 +381,8 @@
|
||||
"Room & Terms": "Værelse & Vilkår",
|
||||
"Room charge": "Værelsesafgift",
|
||||
"Room facilities": "Værelsesfaciliteter",
|
||||
"Room {roomIndex}, {adults} adults": "Værelse {roomIndex}, {adults, plural, one {# voksen} other {# voksne}}",
|
||||
"Room {roomIndex}, {adults} adults, {children} children": "Værelse {roomIndex}, {adults, plural, one {# voksen} other {# voksne}}, {children, plural, one {# barn} other {# børn}}",
|
||||
"Rooms": "Værelser",
|
||||
"Rooms & Guests": "Værelser & gæster",
|
||||
"Sat-Sun Always open": "Lør-Søn Altid åben",
|
||||
|
||||
@@ -376,10 +376,11 @@
|
||||
"Restaurant & Bar": "Restaurant & Bar",
|
||||
"Restaurants & Bars": "Restaurants & Bars",
|
||||
"Retype new password": "Neues Passwort erneut eingeben",
|
||||
"Room": "Zimmer",
|
||||
"Room & Terms": "Zimmer & Bedingungen",
|
||||
"Room charge": "Zimmerpreis",
|
||||
"Room facilities": "Zimmerausstattung",
|
||||
"Room {roomIndex}, {adults} adults": "Zimmer {roomIndex}, {adults, plural, one {# Erwachsene} other {# Erwachsene}}",
|
||||
"Room {roomIndex}, {adults} adults, {children} children": "Zimmer {roomIndex}, {adults, plural, one {# Erwachsene} other {# Erwachsene}}, {children, plural, one {# Kind} other {# Kinder}}",
|
||||
"Rooms": "Räume",
|
||||
"Rooms & Guests": "Zimmer & Gäste",
|
||||
"Sat-Sun Always open": "Sa-So Immer geöffnet",
|
||||
|
||||
@@ -417,10 +417,11 @@
|
||||
"Restaurant & Bar": "Restaurant & Bar",
|
||||
"Restaurants & Bars": "Restaurants & Bars",
|
||||
"Retype new password": "Retype new password",
|
||||
"Room": "Room",
|
||||
"Room & Terms": "Room & Terms",
|
||||
"Room charge": "Room charge",
|
||||
"Room facilities": "Room facilities",
|
||||
"Room {roomIndex}, {adults} adults": "Room {roomIndex}, {adults, plural, one {# adult} other {# adults}}",
|
||||
"Room {roomIndex}, {adults} adults, {children} children": "Room {roomIndex}, {adults, plural, one {# adult} other {# adults}}, {children, plural, one {# child} other {# children}}",
|
||||
"Rooms": "Rooms",
|
||||
"Rooms & Guests": "Rooms & Guests",
|
||||
"Sat-Sun Always open": "Sat-Sun Always open",
|
||||
|
||||
@@ -381,6 +381,8 @@
|
||||
"Room & Terms": "Huone & Ehdot",
|
||||
"Room charge": "Huonemaksu",
|
||||
"Room facilities": "Huoneen varustelu",
|
||||
"Room {roomIndex}, {adults} adults": "Huone {roomIndex}, {adults, plural, one {# vieras} other {# vieraita}}",
|
||||
"Room {roomIndex}, {adults} adults, {children} children": "Huone {roomIndex}, {adults, plural, one {# vieras} other {# vieraita}}, {children, plural, one {# lapsi} other {# lapsia}}",
|
||||
"Rooms": "Huoneet",
|
||||
"Rooms & Guests": "Huoneet & Vieraat",
|
||||
"Rooms & Guestss": "Huoneet & Vieraat",
|
||||
|
||||
@@ -380,6 +380,8 @@
|
||||
"Room & Terms": "Rom & Vilkår",
|
||||
"Room charge": "Pris for rom",
|
||||
"Room facilities": "Romfasiliteter",
|
||||
"Room {roomIndex}, {adults} adults": "Rom {roomIndex}, {adults, plural, one {# voksen} other {# voksne}}",
|
||||
"Room {roomIndex}, {adults} adults, {children} children": "Rom {roomIndex}, {adults, plural, one {# voksen} other {# voksne}}, {children, plural, one {# barn} other {# børn}}",
|
||||
"Rooms": "Rom",
|
||||
"Rooms & Guests": "Rom og gjester",
|
||||
"Sat-Sun Always open": "Lør-Søn Alltid åpen",
|
||||
|
||||
@@ -380,6 +380,8 @@
|
||||
"Room & Terms": "Rum & Villkor",
|
||||
"Room charge": "Rumspris",
|
||||
"Room facilities": "Rumfaciliteter",
|
||||
"Room {roomIndex}, {adults} adults": "Rum {roomIndex}, {adults, plural, one {# vuxen} other {# vuxna}}",
|
||||
"Room {roomIndex}, {adults} adults, {children} children": "Rum {roomIndex}, {adults, plural, one {# vuxen} other {# vuxna}}, {children, plural, one {# barn} other {# barn}}",
|
||||
"Rooms": "Rum",
|
||||
"Rooms & Guests": "Rum och gäster",
|
||||
"Sat-Sun Always open": "Lör-Sön Alltid öppet",
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
import type { RoomData } from "@/types/hotel"
|
||||
import type { SafeUser } from "@/types/user"
|
||||
import type { RoomsAvailability } from "@/server/routers/hotels/output"
|
||||
import type { RoomPackageCodes, RoomPackageData } from "./roomFilter"
|
||||
import type { Rate, RateCode } from "./selectRate"
|
||||
import type {
|
||||
DefaultFilterOptions,
|
||||
RoomPackage,
|
||||
RoomPackageCodeEnum,
|
||||
RoomPackageCodes,
|
||||
RoomPackageData,
|
||||
} from "./roomFilter"
|
||||
import type { RateCode } from "./selectRate"
|
||||
|
||||
export interface RoomSelectionProps {
|
||||
export interface RoomListProps {
|
||||
roomsAvailability: RoomsAvailability
|
||||
roomCategories: RoomData[]
|
||||
availablePackages: RoomPackageData | undefined
|
||||
selectedPackages: RoomPackageCodes[]
|
||||
setRateCode: React.Dispatch<React.SetStateAction<RateCode | undefined>>
|
||||
rateSummary: Rate | null
|
||||
hotelType: string | undefined
|
||||
isUserLoggedIn: boolean
|
||||
}
|
||||
|
||||
export interface SelectRateProps {
|
||||
@@ -22,3 +25,16 @@ export interface SelectRateProps {
|
||||
hotelType: string | undefined
|
||||
isUserLoggedIn: boolean
|
||||
}
|
||||
|
||||
export interface RoomSelectionPanelProps {
|
||||
rooms: RoomsAvailability
|
||||
roomCategories: RoomData[]
|
||||
availablePackages: RoomPackage[]
|
||||
selectedPackages: RoomPackageCodes[]
|
||||
setSelectedRate: React.Dispatch<React.SetStateAction<RateCode | undefined>>
|
||||
hotelType: string | undefined
|
||||
handleFilter: (
|
||||
filter: Record<RoomPackageCodeEnum, boolean | undefined>
|
||||
) => void
|
||||
defaultPackages: DefaultFilterOptions[]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user