Merged in feat/sw-452-select-room-form-submit (pull request #711)
Feat/sw 452 select room form submit Approved-by: Simon.Emanuelsson
This commit is contained in:
@@ -2,6 +2,7 @@ import { getProfileSafely } from "@/lib/trpc/memoizedRequests"
|
|||||||
import { serverClient } from "@/lib/trpc/server"
|
import { serverClient } from "@/lib/trpc/server"
|
||||||
|
|
||||||
import RoomSelection from "@/components/HotelReservation/SelectRate/RoomSelection"
|
import RoomSelection from "@/components/HotelReservation/SelectRate/RoomSelection"
|
||||||
|
import getHotelReservationQueryParams from "@/components/HotelReservation/SelectRate/RoomSelection/utils"
|
||||||
import { setLang } from "@/i18n/serverContext"
|
import { setLang } from "@/i18n/serverContext"
|
||||||
|
|
||||||
import styles from "./page.module.css"
|
import styles from "./page.module.css"
|
||||||
@@ -15,6 +16,12 @@ export default async function SelectRatePage({
|
|||||||
}: PageArgs<LangParams & { section: string }, SelectRateSearchParams>) {
|
}: PageArgs<LangParams & { section: string }, SelectRateSearchParams>) {
|
||||||
setLang(params.lang)
|
setLang(params.lang)
|
||||||
|
|
||||||
|
const selecetRoomParams = new URLSearchParams(searchParams)
|
||||||
|
const selecetRoomParamsObject =
|
||||||
|
getHotelReservationQueryParams(selecetRoomParams)
|
||||||
|
const adults = selecetRoomParamsObject.room[0].adults // TODO: Handle multiple rooms
|
||||||
|
const children = selecetRoomParamsObject.room[0].child.length // TODO: Handle multiple rooms
|
||||||
|
|
||||||
const [hotelData, roomConfigurations, user] = await Promise.all([
|
const [hotelData, roomConfigurations, user] = await Promise.all([
|
||||||
serverClient().hotel.hotelData.get({
|
serverClient().hotel.hotelData.get({
|
||||||
hotelId: searchParams.hotel,
|
hotelId: searchParams.hotel,
|
||||||
@@ -23,9 +30,10 @@ export default async function SelectRatePage({
|
|||||||
}),
|
}),
|
||||||
serverClient().hotel.availability.rooms({
|
serverClient().hotel.availability.rooms({
|
||||||
hotelId: parseInt(searchParams.hotel, 10),
|
hotelId: parseInt(searchParams.hotel, 10),
|
||||||
roomStayStartDate: "2024-11-02",
|
roomStayStartDate: searchParams.fromDate,
|
||||||
roomStayEndDate: "2024-11-03",
|
roomStayEndDate: searchParams.toDate,
|
||||||
adults: 1,
|
adults: adults,
|
||||||
|
children: children,
|
||||||
}),
|
}),
|
||||||
getProfileSafely(),
|
getProfileSafely(),
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export default function FlexibilityOption({
|
|||||||
paymentTerm,
|
paymentTerm,
|
||||||
priceInformation,
|
priceInformation,
|
||||||
roomType,
|
roomType,
|
||||||
|
roomTypeCode,
|
||||||
handleSelectRate,
|
handleSelectRate,
|
||||||
}: FlexibilityOptionProps) {
|
}: FlexibilityOptionProps) {
|
||||||
const [rootDiv, setRootDiv] = useState<Element | undefined>(undefined)
|
const [rootDiv, setRootDiv] = useState<Element | undefined>(undefined)
|
||||||
@@ -46,7 +47,8 @@ export default function FlexibilityOption({
|
|||||||
|
|
||||||
function onChange() {
|
function onChange() {
|
||||||
const rate = {
|
const rate = {
|
||||||
roomType: roomType,
|
roomTypeCode,
|
||||||
|
roomType,
|
||||||
priceName: name,
|
priceName: name,
|
||||||
public: publicPrice,
|
public: publicPrice,
|
||||||
member: memberPrice,
|
member: memberPrice,
|
||||||
|
|||||||
@@ -24,17 +24,15 @@ export default function RateSummary({
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.summaryPrice}>
|
<div className={styles.summaryPrice}>
|
||||||
<div className={styles.summaryPriceText}>
|
<div className={styles.summaryPriceText}>
|
||||||
<>
|
<Subtitle color={isUserLoggedIn ? "red" : "uiTextHighContrast"}>
|
||||||
<Subtitle color={isUserLoggedIn ? "red" : "uiTextHighContrast"}>
|
{priceToShow?.localPrice.pricePerStay}{" "}
|
||||||
{priceToShow?.localPrice.pricePerStay}{" "}
|
{priceToShow?.localPrice.currency}
|
||||||
{priceToShow?.localPrice.currency}
|
</Subtitle>
|
||||||
</Subtitle>
|
<Body color="uiTextMediumContrast">
|
||||||
<Body color="uiTextMediumContrast">
|
{intl.formatMessage({ id: "Approx." })}{" "}
|
||||||
{intl.formatMessage({ id: "Approx." })}{" "}
|
{priceToShow?.requestedPrice?.pricePerStay}{" "}
|
||||||
{priceToShow?.requestedPrice?.pricePerStay}{" "}
|
{priceToShow?.requestedPrice?.currency}
|
||||||
{priceToShow?.requestedPrice?.currency}
|
</Body>
|
||||||
</Body>
|
|
||||||
</>
|
|
||||||
</div>
|
</div>
|
||||||
<Button type="submit" theme="base">
|
<Button type="submit" theme="base">
|
||||||
{intl.formatMessage({ id: "Continue" })}
|
{intl.formatMessage({ id: "Continue" })}
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ export default function RoomCard({
|
|||||||
priceInformation={getPriceForRate(saveRate)}
|
priceInformation={getPriceForRate(saveRate)}
|
||||||
handleSelectRate={handleSelectRate}
|
handleSelectRate={handleSelectRate}
|
||||||
roomType={roomConfiguration.roomType}
|
roomType={roomConfiguration.roomType}
|
||||||
|
roomTypeCode={roomConfiguration.roomTypeCode}
|
||||||
/>
|
/>
|
||||||
<FlexibilityOption
|
<FlexibilityOption
|
||||||
name={intl.formatMessage({ id: "Free rebooking" })}
|
name={intl.formatMessage({ id: "Free rebooking" })}
|
||||||
@@ -125,6 +126,7 @@ export default function RoomCard({
|
|||||||
priceInformation={getPriceForRate(changeRate)}
|
priceInformation={getPriceForRate(changeRate)}
|
||||||
handleSelectRate={handleSelectRate}
|
handleSelectRate={handleSelectRate}
|
||||||
roomType={roomConfiguration.roomType}
|
roomType={roomConfiguration.roomType}
|
||||||
|
roomTypeCode={roomConfiguration.roomTypeCode}
|
||||||
/>
|
/>
|
||||||
<FlexibilityOption
|
<FlexibilityOption
|
||||||
name={intl.formatMessage({ id: "Free cancellation" })}
|
name={intl.formatMessage({ id: "Free cancellation" })}
|
||||||
@@ -134,6 +136,7 @@ export default function RoomCard({
|
|||||||
priceInformation={getPriceForRate(flexRate)}
|
priceInformation={getPriceForRate(flexRate)}
|
||||||
handleSelectRate={handleSelectRate}
|
handleSelectRate={handleSelectRate}
|
||||||
roomType={roomConfiguration.roomType}
|
roomType={roomConfiguration.roomType}
|
||||||
|
roomTypeCode={roomConfiguration.roomTypeCode}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useState } from "react"
|
|||||||
|
|
||||||
import RateSummary from "./RateSummary"
|
import RateSummary from "./RateSummary"
|
||||||
import RoomCard from "./RoomCard"
|
import RoomCard from "./RoomCard"
|
||||||
|
import getHotelReservationQueryParams from "./utils"
|
||||||
|
|
||||||
import styles from "./roomSelection.module.css"
|
import styles from "./roomSelection.module.css"
|
||||||
|
|
||||||
@@ -19,12 +20,29 @@ export default function RoomSelection({
|
|||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const searchParams = useSearchParams()
|
const searchParams = useSearchParams()
|
||||||
|
const isUserLoggedIn = !!user
|
||||||
|
|
||||||
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
const searchParamsObject = getHotelReservationQueryParams(searchParams)
|
||||||
|
|
||||||
const queryParams = new URLSearchParams(searchParams)
|
const queryParams = new URLSearchParams(searchParams)
|
||||||
queryParams.set("roomClass", e.currentTarget.roomClass?.value)
|
|
||||||
queryParams.set("flexibility", e.currentTarget.flexibility?.value)
|
searchParamsObject.room.forEach((item, index) => {
|
||||||
|
if (rateSummary?.roomTypeCode) {
|
||||||
|
queryParams.set(`room[${index}].roomtype`, rateSummary.roomTypeCode)
|
||||||
|
}
|
||||||
|
if (rateSummary?.public?.rateCode) {
|
||||||
|
queryParams.set(`room[${index}].ratecode`, rateSummary.public.rateCode)
|
||||||
|
}
|
||||||
|
if (rateSummary?.member?.rateCode) {
|
||||||
|
queryParams.set(
|
||||||
|
`room[${index}].counterratecode`,
|
||||||
|
rateSummary.member.rateCode
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
router.push(`select-bed?${queryParams}`)
|
router.push(`select-bed?${queryParams}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +66,10 @@ export default function RoomSelection({
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
{rateSummary && (
|
{rateSummary && (
|
||||||
<RateSummary rateSummary={rateSummary} isUserLoggedIn={!!user} />
|
<RateSummary
|
||||||
|
rateSummary={rateSummary}
|
||||||
|
isUserLoggedIn={isUserLoggedIn}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||||
|
|
||||||
|
function getHotelReservationQueryParams(searchParams: URLSearchParams) {
|
||||||
|
const searchParamsObject: Record<string, unknown> = Array.from(
|
||||||
|
searchParams.entries()
|
||||||
|
).reduce<Record<string, unknown>>(
|
||||||
|
(acc, [key, value]) => {
|
||||||
|
const keys = key.replace(/\]/g, "").split(/\[|\./) // Split keys by '[' or '.'
|
||||||
|
keys.reduce((nestedAcc, k, i) => {
|
||||||
|
if (i === keys.length - 1) {
|
||||||
|
// Convert value to number if the key is 'adults' or 'age'
|
||||||
|
;(nestedAcc as Record<string, unknown>)[k] =
|
||||||
|
k === "adults" || k === "age" ? Number(value) : value
|
||||||
|
} else {
|
||||||
|
if (!nestedAcc[k]) {
|
||||||
|
nestedAcc[k] = isNaN(Number(keys[i + 1])) ? {} : [] // Initialize as object or array
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nestedAcc[k] as Record<string, unknown>
|
||||||
|
}, acc)
|
||||||
|
return acc
|
||||||
|
},
|
||||||
|
{} as Record<string, unknown>
|
||||||
|
)
|
||||||
|
return searchParamsObject as SelectRateSearchParams
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getHotelReservationQueryParams
|
||||||
@@ -269,6 +269,8 @@ export const hotelQueryRouter = router({
|
|||||||
hotels: serviceProcedure
|
hotels: serviceProcedure
|
||||||
.input(getHotelsAvailabilityInputSchema)
|
.input(getHotelsAvailabilityInputSchema)
|
||||||
.query(async ({ input, ctx }) => {
|
.query(async ({ input, ctx }) => {
|
||||||
|
const { lang } = ctx
|
||||||
|
const apiLang = toApiLang(lang)
|
||||||
const {
|
const {
|
||||||
cityId,
|
cityId,
|
||||||
roomStayStartDate,
|
roomStayStartDate,
|
||||||
@@ -288,6 +290,7 @@ export const hotelQueryRouter = router({
|
|||||||
promotionCode,
|
promotionCode,
|
||||||
reservationProfileType,
|
reservationProfileType,
|
||||||
attachedProfileId,
|
attachedProfileId,
|
||||||
|
language: apiLang,
|
||||||
}
|
}
|
||||||
|
|
||||||
hotelsAvailabilityCounter.add(1, {
|
hotelsAvailabilityCounter.add(1, {
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
import { Product, productTypePriceSchema } from "@/server/routers/hotels/output"
|
import {
|
||||||
|
Product,
|
||||||
|
productTypePriceSchema,
|
||||||
|
RoomConfiguration,
|
||||||
|
} from "@/server/routers/hotels/output"
|
||||||
|
|
||||||
import { Rate } from "./selectRate"
|
import { Rate } from "./selectRate"
|
||||||
|
|
||||||
@@ -12,7 +16,8 @@ export type FlexibilityOptionProps = {
|
|||||||
value: string
|
value: string
|
||||||
paymentTerm: string
|
paymentTerm: string
|
||||||
priceInformation?: Array<string>
|
priceInformation?: Array<string>
|
||||||
roomType: string
|
roomType: RoomConfiguration["roomType"]
|
||||||
|
roomTypeCode: RoomConfiguration["roomTypeCode"]
|
||||||
handleSelectRate: (rate: Rate) => void
|
handleSelectRate: (rate: Rate) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,28 @@
|
|||||||
import { Product } from "@/server/routers/hotels/output"
|
import { Product, RoomConfiguration } from "@/server/routers/hotels/output"
|
||||||
|
|
||||||
|
interface Child {
|
||||||
|
bed: string
|
||||||
|
age: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Room {
|
||||||
|
adults: number
|
||||||
|
roomtypecode: string
|
||||||
|
ratecode: string
|
||||||
|
child: Child[]
|
||||||
|
}
|
||||||
|
|
||||||
export interface SelectRateSearchParams {
|
export interface SelectRateSearchParams {
|
||||||
fromDate: string
|
|
||||||
toDate: string
|
|
||||||
hotel: string
|
hotel: string
|
||||||
|
fromdate: string
|
||||||
|
todate: string
|
||||||
|
room: Room[]
|
||||||
|
[key: string]: string | string[] | Room[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Rate {
|
export interface Rate {
|
||||||
roomType: string
|
roomType: RoomConfiguration["roomType"]
|
||||||
|
roomTypeCode: RoomConfiguration["roomTypeCode"]
|
||||||
priceName: string
|
priceName: string
|
||||||
public: Product["productType"]["public"]
|
public: Product["productType"]["public"]
|
||||||
member: Product["productType"]["member"]
|
member: Product["productType"]["member"]
|
||||||
|
|||||||
Reference in New Issue
Block a user