feat(SW-718): Created store for selectRate
This commit is contained in:
@@ -4,6 +4,8 @@ import { useSearchParams } from "next/navigation"
|
|||||||
import { useEffect, useRef } from "react"
|
import { useEffect, useRef } from "react"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { useRateSelectionStore } from "@/stores/rate-selection"
|
||||||
|
|
||||||
import { CheckIcon, InfoCircleIcon } from "@/components/Icons"
|
import { CheckIcon, InfoCircleIcon } from "@/components/Icons"
|
||||||
import Modal from "@/components/Modal"
|
import Modal from "@/components/Modal"
|
||||||
import Button from "@/components/TempDesignSystem/Button"
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
@@ -24,16 +26,11 @@ export default function FlexibilityOption({
|
|||||||
priceInformation,
|
priceInformation,
|
||||||
roomTypeCode,
|
roomTypeCode,
|
||||||
petRoomPackage,
|
petRoomPackage,
|
||||||
handleSelectRate,
|
|
||||||
roomListIndex,
|
roomListIndex,
|
||||||
}: FlexibilityOptionProps) {
|
}: FlexibilityOptionProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const inputElementRef = useRef<HTMLInputElement>(null)
|
const inputElementRef = useRef<HTMLInputElement>(null)
|
||||||
const handleSelectRateRef = useRef(handleSelectRate)
|
const { selectRate, selectedRates } = useRateSelectionStore()
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleSelectRateRef.current = handleSelectRate
|
|
||||||
}, [handleSelectRate])
|
|
||||||
|
|
||||||
const searchParams = useSearchParams()
|
const searchParams = useSearchParams()
|
||||||
|
|
||||||
@@ -57,24 +54,30 @@ export default function FlexibilityOption({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSelectRateRef.current((prev) => {
|
// Check if there's already a selection for this room index
|
||||||
// If the user already has made a new selection we respect that and don't do anything else
|
const existingSelection = selectedRates[roomListIndex]
|
||||||
if (prev) {
|
if (existingSelection) return
|
||||||
return prev
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputElementRef.current) {
|
selectRate(roomListIndex, {
|
||||||
inputElementRef.current.checked = true
|
publicRateCode: product.productType.public.rateCode,
|
||||||
}
|
roomTypeCode: roomTypeCode,
|
||||||
|
name: name,
|
||||||
return {
|
paymentTerm: paymentTerm,
|
||||||
publicRateCode: product.productType.public.rateCode,
|
|
||||||
roomTypeCode: roomTypeCode,
|
|
||||||
name: name,
|
|
||||||
paymentTerm: paymentTerm,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}, [searchParams, roomListIndex, product, roomTypeCode, name, paymentTerm])
|
|
||||||
|
if (inputElementRef.current) {
|
||||||
|
inputElementRef.current.checked = true
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
searchParams,
|
||||||
|
roomListIndex,
|
||||||
|
product,
|
||||||
|
roomTypeCode,
|
||||||
|
name,
|
||||||
|
paymentTerm,
|
||||||
|
selectedRates,
|
||||||
|
selectRate,
|
||||||
|
])
|
||||||
|
|
||||||
if (!product) {
|
if (!product) {
|
||||||
return (
|
return (
|
||||||
@@ -98,22 +101,20 @@ export default function FlexibilityOption({
|
|||||||
const { public: publicPrice, member: memberPrice } = product.productType
|
const { public: publicPrice, member: memberPrice } = product.productType
|
||||||
|
|
||||||
const onClick: React.MouseEventHandler<HTMLInputElement> = (e) => {
|
const onClick: React.MouseEventHandler<HTMLInputElement> = (e) => {
|
||||||
handleSelectRateRef.current((prev) => {
|
if (
|
||||||
if (
|
selectedRates[roomListIndex]?.publicRateCode === publicPrice.rateCode &&
|
||||||
prev &&
|
selectedRates[roomListIndex]?.roomTypeCode === roomTypeCode
|
||||||
prev.publicRateCode === publicPrice.rateCode &&
|
) {
|
||||||
prev.roomTypeCode === roomTypeCode
|
if (e.currentTarget?.checked) e.currentTarget.checked = false
|
||||||
) {
|
selectRate(roomListIndex, undefined)
|
||||||
if (e.currentTarget?.checked) e.currentTarget.checked = false
|
} else {
|
||||||
return undefined
|
selectRate(roomListIndex, {
|
||||||
} else
|
publicRateCode: publicPrice.rateCode,
|
||||||
return {
|
roomTypeCode: roomTypeCode,
|
||||||
publicRateCode: publicPrice.rateCode,
|
name: name,
|
||||||
roomTypeCode: roomTypeCode,
|
paymentTerm: paymentTerm,
|
||||||
name: name,
|
})
|
||||||
paymentTerm: paymentTerm,
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
import { createElement, useCallback } from "react"
|
import { createElement, useCallback } from "react"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { useRateSelectionStore } from "@/stores/rate-selection"
|
||||||
|
|
||||||
import ToggleSidePeek from "@/components/HotelReservation/EnterDetails/SelectedRoom/ToggleSidePeek"
|
import ToggleSidePeek from "@/components/HotelReservation/EnterDetails/SelectedRoom/ToggleSidePeek"
|
||||||
import { getIconForFeatureCode } from "@/components/HotelReservation/utils"
|
import { getIconForFeatureCode } from "@/components/HotelReservation/utils"
|
||||||
import { ErrorCircleIcon } from "@/components/Icons"
|
import { ErrorCircleIcon } from "@/components/Icons"
|
||||||
@@ -29,11 +31,14 @@ export default function RoomCard({
|
|||||||
roomCategories,
|
roomCategories,
|
||||||
selectedPackages,
|
selectedPackages,
|
||||||
packages,
|
packages,
|
||||||
handleSelectRate,
|
|
||||||
roomListIndex,
|
roomListIndex,
|
||||||
}: RoomCardProps) {
|
}: RoomCardProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
|
||||||
|
const selectedRate = useRateSelectionStore(
|
||||||
|
(state) => state.selectedRates[roomListIndex]
|
||||||
|
)
|
||||||
|
|
||||||
const rates = {
|
const rates = {
|
||||||
saveRate: rateDefinitions.find(
|
saveRate: rateDefinitions.find(
|
||||||
(rate) => rate.cancellationRule === "NotCancellable"
|
(rate) => rate.cancellationRule === "NotCancellable"
|
||||||
@@ -215,13 +220,12 @@ export default function RoomCard({
|
|||||||
) : (
|
) : (
|
||||||
Object.entries(rates).map(([key, rate]) => (
|
Object.entries(rates).map(([key, rate]) => (
|
||||||
<FlexibilityOption
|
<FlexibilityOption
|
||||||
key={key}
|
key={`${roomListIndex}-${rate?.rateCode}-${selectedRate?.roomTypeCode || "unselected"}`}
|
||||||
name={rateKey(key)}
|
name={rateKey(key)}
|
||||||
value={key.toLowerCase()}
|
value={key.toLowerCase()}
|
||||||
paymentTerm={key === "flexRate" ? payLater : payNow}
|
paymentTerm={key === "flexRate" ? payLater : payNow}
|
||||||
product={findProductForRate(rate)}
|
product={findProductForRate(rate)}
|
||||||
priceInformation={getRateDefinitionForRate(rate)?.generalTerms}
|
priceInformation={getRateDefinitionForRate(rate)?.generalTerms}
|
||||||
handleSelectRate={handleSelectRate}
|
|
||||||
roomTypeCode={roomConfiguration.roomTypeCode}
|
roomTypeCode={roomConfiguration.roomTypeCode}
|
||||||
petRoomPackage={petRoomPackage}
|
petRoomPackage={petRoomPackage}
|
||||||
roomListIndex={roomListIndex}
|
roomListIndex={roomListIndex}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ export default function RoomList({
|
|||||||
roomCategories,
|
roomCategories,
|
||||||
availablePackages,
|
availablePackages,
|
||||||
selectedPackages,
|
selectedPackages,
|
||||||
setRateCode,
|
|
||||||
hotelType,
|
hotelType,
|
||||||
roomListIndex,
|
roomListIndex,
|
||||||
}: RoomListProps) {
|
}: RoomListProps) {
|
||||||
@@ -27,7 +26,6 @@ export default function RoomList({
|
|||||||
rateDefinitions={rateDefinitions}
|
rateDefinitions={rateDefinitions}
|
||||||
roomConfiguration={roomConfiguration}
|
roomConfiguration={roomConfiguration}
|
||||||
roomCategories={roomCategories}
|
roomCategories={roomCategories}
|
||||||
handleSelectRate={setRateCode}
|
|
||||||
selectedPackages={selectedPackages}
|
selectedPackages={selectedPackages}
|
||||||
packages={availablePackages}
|
packages={availablePackages}
|
||||||
key={roomConfiguration.roomTypeCode}
|
key={roomConfiguration.roomTypeCode}
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
.wrapper {
|
|
||||||
padding-bottom: var(--Spacing-x3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.roomList {
|
.roomList {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ export function RoomSelectionPanel({
|
|||||||
roomCategories,
|
roomCategories,
|
||||||
availablePackages,
|
availablePackages,
|
||||||
selectedPackages,
|
selectedPackages,
|
||||||
setSelectedRate,
|
|
||||||
hotelType,
|
hotelType,
|
||||||
handleFilter,
|
handleFilter,
|
||||||
defaultPackages,
|
defaultPackages,
|
||||||
@@ -27,7 +26,6 @@ export function RoomSelectionPanel({
|
|||||||
roomCategories={roomCategories}
|
roomCategories={roomCategories}
|
||||||
availablePackages={availablePackages}
|
availablePackages={availablePackages}
|
||||||
selectedPackages={selectedPackages}
|
selectedPackages={selectedPackages}
|
||||||
setRateCode={setSelectedRate}
|
|
||||||
hotelType={hotelType}
|
hotelType={hotelType}
|
||||||
roomListIndex={roomListIndex}
|
roomListIndex={roomListIndex}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { usePathname, useRouter, useSearchParams } from "next/navigation"
|
import { usePathname, useRouter, useSearchParams } from "next/navigation"
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react"
|
import { useCallback, useEffect, useMemo } from "react"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
import { useRateSelectionStore } from "@/stores/rate-selection"
|
||||||
|
|
||||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||||
import { useRateSummary } from "@/hooks/selectRate/useRateSummary"
|
import { useRateSummary } from "@/hooks/selectRate/useRateSummary"
|
||||||
import { useRoomFiltering } from "@/hooks/selectRate/useRoomFiltering"
|
import { useRoomFiltering } from "@/hooks/selectRate/useRoomFiltering"
|
||||||
@@ -23,14 +24,9 @@ import {
|
|||||||
RoomPackageCodeEnum,
|
RoomPackageCodeEnum,
|
||||||
} from "@/types/components/hotelReservation/selectRate/roomFilter"
|
} from "@/types/components/hotelReservation/selectRate/roomFilter"
|
||||||
import type { SelectRateProps } from "@/types/components/hotelReservation/selectRate/roomSelection"
|
import type { SelectRateProps } from "@/types/components/hotelReservation/selectRate/roomSelection"
|
||||||
import type {
|
import type { Rate } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||||
Rate,
|
|
||||||
RateCode,
|
|
||||||
} from "@/types/components/hotelReservation/selectRate/selectRate"
|
|
||||||
import type { RoomConfiguration } from "@/server/routers/hotels/output"
|
import type { RoomConfiguration } from "@/server/routers/hotels/output"
|
||||||
|
|
||||||
type SelectedRates = (RateCode | undefined)[]
|
|
||||||
|
|
||||||
export default function Rooms({
|
export default function Rooms({
|
||||||
roomsAvailability,
|
roomsAvailability,
|
||||||
roomCategories = [],
|
roomCategories = [],
|
||||||
@@ -46,19 +42,22 @@ export default function Rooms({
|
|||||||
const arrivalDate = searchParams.get("fromDate")
|
const arrivalDate = searchParams.get("fromDate")
|
||||||
const departureDate = searchParams.get("toDate")
|
const departureDate = searchParams.get("toDate")
|
||||||
|
|
||||||
|
const { modifyRate, selectedRates, setSelectedRates } =
|
||||||
|
useRateSelectionStore()
|
||||||
|
|
||||||
const searchedRoomsAndGuests = useMemo(
|
const searchedRoomsAndGuests = useMemo(
|
||||||
() => parseRoomParams(searchParams),
|
() => parseRoomParams(searchParams),
|
||||||
[searchParams]
|
[searchParams]
|
||||||
)
|
)
|
||||||
|
|
||||||
const [selectedRates, setSelectedRates] = useState<SelectedRates>(
|
|
||||||
new Array(searchedRoomsAndGuests.length).fill(undefined)
|
|
||||||
)
|
|
||||||
|
|
||||||
const isMultipleRooms = searchedRoomsAndGuests.length > 1
|
const isMultipleRooms = searchedRoomsAndGuests.length > 1
|
||||||
|
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectedRates(new Array(searchedRoomsAndGuests.length).fill(undefined))
|
||||||
|
}, [setSelectedRates, searchedRoomsAndGuests.length])
|
||||||
|
|
||||||
const visibleRooms: RoomConfiguration[] = useMemo(() => {
|
const visibleRooms: RoomConfiguration[] = useMemo(() => {
|
||||||
const deduped = filterDuplicateRoomTypesByLowestPrice(
|
const deduped = filterDuplicateRoomTypesByLowestPrice(
|
||||||
roomsAvailability.roomConfigurations
|
roomsAvailability.roomConfigurations
|
||||||
@@ -173,16 +172,11 @@ export default function Rooms({
|
|||||||
router.push(`select-bed?${queryParams}`)
|
router.push(`select-bed?${queryParams}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const setSelectedRateForRoom = useCallback(
|
const handleModify = useCallback(
|
||||||
(index: number) => (value: React.SetStateAction<RateCode | undefined>) => {
|
(index: number) => () => {
|
||||||
setSelectedRates((prev) => {
|
modifyRate(index)
|
||||||
const newRates = [...prev]
|
|
||||||
newRates[index] =
|
|
||||||
typeof value === "function" ? value(prev[index]) : value
|
|
||||||
return newRates
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
[]
|
[modifyRate]
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleFilterForRoom = useCallback(
|
const handleFilterForRoom = useCallback(
|
||||||
@@ -193,6 +187,25 @@ export default function Rooms({
|
|||||||
[handleFilter]
|
[handleFilter]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const SCROLL_OFFSET = 100
|
||||||
|
const roomElements = document.querySelectorAll(`.${styles.roomContainer}`)
|
||||||
|
const index = selectedRates.findIndex((rate) => rate === undefined)
|
||||||
|
const selectedRoom = roomElements[index - 1]
|
||||||
|
|
||||||
|
if (selectedRoom) {
|
||||||
|
const elementPosition = selectedRoom.getBoundingClientRect().top
|
||||||
|
const offsetPosition = elementPosition + window.scrollY - SCROLL_OFFSET
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: offsetPosition,
|
||||||
|
behavior: "smooth",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 0)
|
||||||
|
}, [selectedRates])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
{isMultipleRooms ? (
|
{isMultipleRooms ? (
|
||||||
@@ -232,6 +245,7 @@ export default function Rooms({
|
|||||||
room={room}
|
room={room}
|
||||||
selectedRate={rateSummary[index]}
|
selectedRate={rateSummary[index]}
|
||||||
roomCategories={roomCategories}
|
roomCategories={roomCategories}
|
||||||
|
handleModify={handleModify(index)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.roomSelectionPanel}>
|
<div className={styles.roomSelectionPanel}>
|
||||||
@@ -240,7 +254,6 @@ export default function Rooms({
|
|||||||
roomCategories={roomCategories}
|
roomCategories={roomCategories}
|
||||||
availablePackages={availablePackages}
|
availablePackages={availablePackages}
|
||||||
selectedPackages={selectedPackagesByRoom[index]}
|
selectedPackages={selectedPackagesByRoom[index]}
|
||||||
setSelectedRate={setSelectedRateForRoom(index)}
|
|
||||||
hotelType={hotelType}
|
hotelType={hotelType}
|
||||||
handleFilter={handleFilterForRoom(index)}
|
handleFilter={handleFilterForRoom(index)}
|
||||||
defaultPackages={defaultPackages}
|
defaultPackages={defaultPackages}
|
||||||
@@ -256,7 +269,6 @@ export default function Rooms({
|
|||||||
roomCategories={roomCategories}
|
roomCategories={roomCategories}
|
||||||
availablePackages={availablePackages}
|
availablePackages={availablePackages}
|
||||||
selectedPackages={selectedPackagesByRoom[0]}
|
selectedPackages={selectedPackagesByRoom[0]}
|
||||||
setSelectedRate={setSelectedRateForRoom(0)}
|
|
||||||
hotelType={hotelType}
|
hotelType={hotelType}
|
||||||
handleFilter={handleFilterForRoom(0)}
|
handleFilter={handleFilterForRoom(0)}
|
||||||
defaultPackages={defaultPackages}
|
defaultPackages={defaultPackages}
|
||||||
|
|||||||
@@ -10,10 +10,9 @@
|
|||||||
.roomContainer {
|
.roomContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--Spacing-x2);
|
|
||||||
border: 1px solid var(--Base-Border-Subtle);
|
border: 1px solid var(--Base-Border-Subtle);
|
||||||
border-radius: var(--Corner-radius-Large);
|
border-radius: var(--Corner-radius-Large);
|
||||||
padding: var(--Spacing-x2) var(--Spacing-x2) 0 var(--Spacing-x2);
|
padding: var(--Spacing-x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.roomSelectionPanel {
|
.roomSelectionPanel {
|
||||||
@@ -24,6 +23,7 @@
|
|||||||
opacity 0.3s ease,
|
opacity 0.3s ease,
|
||||||
grid-template-rows 0.5s ease;
|
grid-template-rows 0.5s ease;
|
||||||
height: 0;
|
height: 0;
|
||||||
|
gap: var(--Spacing-x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.roomSelectionPanel > * {
|
.roomSelectionPanel > * {
|
||||||
@@ -48,9 +48,11 @@
|
|||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
height: auto;
|
height: auto;
|
||||||
padding-bottom: var(--Spacing-x2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.roomSelectionPanelContainer[data-selected="true"] .roomSelectionPanel {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
.roomSelectionPanelContainer[data-active-panel="true"] .roomSelectionPanel {
|
.roomSelectionPanelContainer[data-active-panel="true"] .roomSelectionPanel {
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { EditIcon } from "@/components/Icons"
|
||||||
import Image from "@/components/Image"
|
import Image from "@/components/Image"
|
||||||
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||||
|
|
||||||
@@ -16,11 +18,13 @@ export default function SelectedRoomPanel({
|
|||||||
room,
|
room,
|
||||||
selectedRate,
|
selectedRate,
|
||||||
roomCategories,
|
roomCategories,
|
||||||
|
handleModify,
|
||||||
}: {
|
}: {
|
||||||
roomIndex: number
|
roomIndex: number
|
||||||
room: RoomParam
|
room: RoomParam
|
||||||
selectedRate: Rate | null
|
selectedRate: Rate | null
|
||||||
roomCategories: RoomData[]
|
roomCategories: RoomData[]
|
||||||
|
handleModify: () => void
|
||||||
}) {
|
}) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const images = roomCategories.find((roomCategory) =>
|
const images = roomCategories.find((roomCategory) =>
|
||||||
@@ -67,12 +71,25 @@ export default function SelectedRoomPanel({
|
|||||||
})}
|
})}
|
||||||
</Caption>
|
</Caption>
|
||||||
</div>
|
</div>
|
||||||
<Image
|
<div className={styles.imageAndModifyButtonContainer}>
|
||||||
src={images?.[0]?.imageSizes?.tiny ?? ""}
|
{images && (
|
||||||
alt={selectedRate?.roomType ?? images?.[0]?.metaData?.altText ?? ""}
|
<div className={styles.imageContainer}>
|
||||||
width={240}
|
<Image
|
||||||
height={160}
|
src={images[0].imageSizes?.tiny ?? ""}
|
||||||
/>
|
alt={selectedRate?.roomType ?? images[0].metaData?.altText ?? ""}
|
||||||
|
fill
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className={styles.modifyButtonContainer}>
|
||||||
|
<Button variant="icon" size="small" onClick={handleModify}>
|
||||||
|
<EditIcon />
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: "Modify",
|
||||||
|
})}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,35 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modifyButtonContainer {
|
||||||
|
position: absolute;
|
||||||
|
right: var(--Spacing-x2);
|
||||||
|
bottom: var(--Spacing-x2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.imageContainer {
|
||||||
|
width: 240px;
|
||||||
|
height: 160px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.imageContainer {
|
||||||
|
width: 120px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
.imageAndModifyButtonContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: var(--Spacing-x1);
|
||||||
|
}
|
||||||
|
.modifyButtonContainer {
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
stores/rate-selection.ts
Normal file
27
stores/rate-selection.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { create } from "zustand"
|
||||||
|
|
||||||
|
import type { RateCode } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||||
|
|
||||||
|
interface RateSelectionState {
|
||||||
|
selectedRates: (RateCode | undefined)[]
|
||||||
|
setSelectedRates: (rates: (RateCode | undefined)[]) => void
|
||||||
|
modifyRate: (index: number) => void
|
||||||
|
selectRate: (index: number, rate: RateCode | undefined) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useRateSelectionStore = create<RateSelectionState>((set) => ({
|
||||||
|
selectedRates: [],
|
||||||
|
setSelectedRates: (rates) => set({ selectedRates: rates }),
|
||||||
|
modifyRate: (index) =>
|
||||||
|
set((state) => {
|
||||||
|
const newRates = [...state.selectedRates]
|
||||||
|
newRates[index] = undefined
|
||||||
|
return { selectedRates: newRates }
|
||||||
|
}),
|
||||||
|
selectRate: (index, rate) =>
|
||||||
|
set((state) => {
|
||||||
|
const newRates = [...state.selectedRates]
|
||||||
|
newRates[index] = rate
|
||||||
|
return { selectedRates: newRates }
|
||||||
|
}),
|
||||||
|
}))
|
||||||
@@ -7,7 +7,6 @@ import type {
|
|||||||
RoomConfiguration,
|
RoomConfiguration,
|
||||||
} from "@/server/routers/hotels/output"
|
} from "@/server/routers/hotels/output"
|
||||||
import type { RoomPackage } from "./roomFilter"
|
import type { RoomPackage } from "./roomFilter"
|
||||||
import type { RateCode } from "./selectRate"
|
|
||||||
|
|
||||||
type ProductPrice = z.output<typeof productTypePriceSchema>
|
type ProductPrice = z.output<typeof productTypePriceSchema>
|
||||||
export type RoomPriceSchema = z.output<typeof priceSchema>
|
export type RoomPriceSchema = z.output<typeof priceSchema>
|
||||||
@@ -20,12 +19,11 @@ export type FlexibilityOptionProps = {
|
|||||||
priceInformation?: Array<string>
|
priceInformation?: Array<string>
|
||||||
roomTypeCode: RoomConfiguration["roomTypeCode"]
|
roomTypeCode: RoomConfiguration["roomTypeCode"]
|
||||||
petRoomPackage: RoomPackage | undefined
|
petRoomPackage: RoomPackage | undefined
|
||||||
handleSelectRate: React.Dispatch<React.SetStateAction<RateCode | undefined>>
|
|
||||||
roomListIndex: number
|
roomListIndex: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PriceListProps {
|
export interface PriceListProps {
|
||||||
publicPrice?: ProductPrice | Record<string, never>
|
publicPrice?: ProductPrice | Record<string, never>
|
||||||
memberPrice?: ProductPrice | Record<string, never>
|
memberPrice?: ProductPrice | Record<string, never>
|
||||||
petRoomPackage?: RoomPackage | undefined
|
petRoomPackage?: RoomPackage
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import type {
|
|||||||
} from "@/server/routers/hotels/output"
|
} from "@/server/routers/hotels/output"
|
||||||
import type { RoomPriceSchema } from "./flexibilityOption"
|
import type { RoomPriceSchema } from "./flexibilityOption"
|
||||||
import type { RoomPackageCodes, RoomPackageData } from "./roomFilter"
|
import type { RoomPackageCodes, RoomPackageData } from "./roomFilter"
|
||||||
import type { RateCode } from "./selectRate"
|
|
||||||
|
|
||||||
export type RoomCardProps = {
|
export type RoomCardProps = {
|
||||||
hotelId: string
|
hotelId: string
|
||||||
@@ -18,7 +17,6 @@ export type RoomCardProps = {
|
|||||||
roomCategories: RoomData[]
|
roomCategories: RoomData[]
|
||||||
selectedPackages: RoomPackageCodes[]
|
selectedPackages: RoomPackageCodes[]
|
||||||
packages: RoomPackageData | undefined
|
packages: RoomPackageData | undefined
|
||||||
handleSelectRate: React.Dispatch<React.SetStateAction<RateCode | undefined>>
|
|
||||||
roomListIndex: number
|
roomListIndex: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,12 @@ import type {
|
|||||||
RoomPackageCodes,
|
RoomPackageCodes,
|
||||||
RoomPackageData,
|
RoomPackageData,
|
||||||
} from "./roomFilter"
|
} from "./roomFilter"
|
||||||
import type { RateCode } from "./selectRate"
|
|
||||||
|
|
||||||
export interface RoomListProps {
|
export interface RoomListProps {
|
||||||
roomsAvailability: RoomsAvailability
|
roomsAvailability: RoomsAvailability
|
||||||
roomCategories: RoomData[]
|
roomCategories: RoomData[]
|
||||||
availablePackages: RoomPackageData | undefined
|
availablePackages: RoomPackageData | undefined
|
||||||
selectedPackages: RoomPackageCodes[]
|
selectedPackages: RoomPackageCodes[]
|
||||||
setRateCode: React.Dispatch<React.SetStateAction<RateCode | undefined>>
|
|
||||||
hotelType: string | undefined
|
hotelType: string | undefined
|
||||||
roomListIndex: number
|
roomListIndex: number
|
||||||
}
|
}
|
||||||
@@ -32,7 +30,6 @@ export interface RoomSelectionPanelProps {
|
|||||||
roomCategories: RoomData[]
|
roomCategories: RoomData[]
|
||||||
availablePackages: RoomPackage[]
|
availablePackages: RoomPackage[]
|
||||||
selectedPackages: RoomPackageCodes[]
|
selectedPackages: RoomPackageCodes[]
|
||||||
setSelectedRate: React.Dispatch<React.SetStateAction<RateCode | undefined>>
|
|
||||||
hotelType: string | undefined
|
hotelType: string | undefined
|
||||||
handleFilter: (
|
handleFilter: (
|
||||||
filter: Record<RoomPackageCodeEnum, boolean | undefined>
|
filter: Record<RoomPackageCodeEnum, boolean | undefined>
|
||||||
|
|||||||
Reference in New Issue
Block a user