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:
Pontus Dreij
2024-10-17 11:46:49 +00:00
9 changed files with 107 additions and 24 deletions

View File

@@ -2,6 +2,7 @@ import { getProfileSafely } from "@/lib/trpc/memoizedRequests"
import { serverClient } from "@/lib/trpc/server"
import RoomSelection from "@/components/HotelReservation/SelectRate/RoomSelection"
import getHotelReservationQueryParams from "@/components/HotelReservation/SelectRate/RoomSelection/utils"
import { setLang } from "@/i18n/serverContext"
import styles from "./page.module.css"
@@ -15,6 +16,12 @@ export default async function SelectRatePage({
}: PageArgs<LangParams & { section: string }, SelectRateSearchParams>) {
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([
serverClient().hotel.hotelData.get({
hotelId: searchParams.hotel,
@@ -23,9 +30,10 @@ export default async function SelectRatePage({
}),
serverClient().hotel.availability.rooms({
hotelId: parseInt(searchParams.hotel, 10),
roomStayStartDate: "2024-11-02",
roomStayEndDate: "2024-11-03",
adults: 1,
roomStayStartDate: searchParams.fromDate,
roomStayEndDate: searchParams.toDate,
adults: adults,
children: children,
}),
getProfileSafely(),
])

View File

@@ -18,6 +18,7 @@ export default function FlexibilityOption({
paymentTerm,
priceInformation,
roomType,
roomTypeCode,
handleSelectRate,
}: FlexibilityOptionProps) {
const [rootDiv, setRootDiv] = useState<Element | undefined>(undefined)
@@ -46,7 +47,8 @@ export default function FlexibilityOption({
function onChange() {
const rate = {
roomType: roomType,
roomTypeCode,
roomType,
priceName: name,
public: publicPrice,
member: memberPrice,

View File

@@ -24,17 +24,15 @@ export default function RateSummary({
</div>
<div className={styles.summaryPrice}>
<div className={styles.summaryPriceText}>
<>
<Subtitle color={isUserLoggedIn ? "red" : "uiTextHighContrast"}>
{priceToShow?.localPrice.pricePerStay}{" "}
{priceToShow?.localPrice.currency}
</Subtitle>
<Body color="uiTextMediumContrast">
{intl.formatMessage({ id: "Approx." })}{" "}
{priceToShow?.requestedPrice?.pricePerStay}{" "}
{priceToShow?.requestedPrice?.currency}
</Body>
</>
<Subtitle color={isUserLoggedIn ? "red" : "uiTextHighContrast"}>
{priceToShow?.localPrice.pricePerStay}{" "}
{priceToShow?.localPrice.currency}
</Subtitle>
<Body color="uiTextMediumContrast">
{intl.formatMessage({ id: "Approx." })}{" "}
{priceToShow?.requestedPrice?.pricePerStay}{" "}
{priceToShow?.requestedPrice?.currency}
</Body>
</div>
<Button type="submit" theme="base">
{intl.formatMessage({ id: "Continue" })}

View File

@@ -116,6 +116,7 @@ export default function RoomCard({
priceInformation={getPriceForRate(saveRate)}
handleSelectRate={handleSelectRate}
roomType={roomConfiguration.roomType}
roomTypeCode={roomConfiguration.roomTypeCode}
/>
<FlexibilityOption
name={intl.formatMessage({ id: "Free rebooking" })}
@@ -125,6 +126,7 @@ export default function RoomCard({
priceInformation={getPriceForRate(changeRate)}
handleSelectRate={handleSelectRate}
roomType={roomConfiguration.roomType}
roomTypeCode={roomConfiguration.roomTypeCode}
/>
<FlexibilityOption
name={intl.formatMessage({ id: "Free cancellation" })}
@@ -134,6 +136,7 @@ export default function RoomCard({
priceInformation={getPriceForRate(flexRate)}
handleSelectRate={handleSelectRate}
roomType={roomConfiguration.roomType}
roomTypeCode={roomConfiguration.roomTypeCode}
/>
</div>
</div>

View File

@@ -4,6 +4,7 @@ import { useState } from "react"
import RateSummary from "./RateSummary"
import RoomCard from "./RoomCard"
import getHotelReservationQueryParams from "./utils"
import styles from "./roomSelection.module.css"
@@ -19,12 +20,29 @@ export default function RoomSelection({
const router = useRouter()
const searchParams = useSearchParams()
const isUserLoggedIn = !!user
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
const searchParamsObject = getHotelReservationQueryParams(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}`)
}
@@ -48,7 +66,10 @@ export default function RoomSelection({
))}
</ul>
{rateSummary && (
<RateSummary rateSummary={rateSummary} isUserLoggedIn={!!user} />
<RateSummary
rateSummary={rateSummary}
isUserLoggedIn={isUserLoggedIn}
/>
)}
</form>
</div>

View File

@@ -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

View File

@@ -269,6 +269,8 @@ export const hotelQueryRouter = router({
hotels: serviceProcedure
.input(getHotelsAvailabilityInputSchema)
.query(async ({ input, ctx }) => {
const { lang } = ctx
const apiLang = toApiLang(lang)
const {
cityId,
roomStayStartDate,
@@ -288,6 +290,7 @@ export const hotelQueryRouter = router({
promotionCode,
reservationProfileType,
attachedProfileId,
language: apiLang,
}
hotelsAvailabilityCounter.add(1, {

View File

@@ -1,6 +1,10 @@
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"
@@ -12,7 +16,8 @@ export type FlexibilityOptionProps = {
value: string
paymentTerm: string
priceInformation?: Array<string>
roomType: string
roomType: RoomConfiguration["roomType"]
roomTypeCode: RoomConfiguration["roomTypeCode"]
handleSelectRate: (rate: Rate) => void
}

View File

@@ -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 {
fromDate: string
toDate: string
hotel: string
fromdate: string
todate: string
room: Room[]
[key: string]: string | string[] | Room[]
}
export interface Rate {
roomType: string
roomType: RoomConfiguration["roomType"]
roomTypeCode: RoomConfiguration["roomTypeCode"]
priceName: string
public: Product["productType"]["public"]
member: Product["productType"]["member"]