Feat/SW-431 payment flow * feat(SW-431): Update mock hotel data * feat(SW-431): Added route handler and trpc routes * feat(SW-431): List payment methods and handle booking status and redirection * feat(SW-431): Updated booking page to poll for booking status * feat(SW-431): Updated create booking contract * feat(SW-431): small fix * fix(SW-431): Added intl string and sorted dictionaries * fix(SW-431): Changes from PR * fix(SW-431): fixes from PR * fix(SW-431): add todo comments * fix(SW-431): update schema prop Approved-by: Simon.Emanuelsson
198 lines
5.8 KiB
TypeScript
198 lines
5.8 KiB
TypeScript
import { notFound } from "next/navigation"
|
|
|
|
import { getProfileSafely } from "@/lib/trpc/memoizedRequests"
|
|
import { serverClient } from "@/lib/trpc/server"
|
|
|
|
import Details from "@/components/HotelReservation/EnterDetails/Details"
|
|
import HotelSelectionHeader from "@/components/HotelReservation/HotelSelectionHeader"
|
|
import BedSelection from "@/components/HotelReservation/SelectRate/BedSelection"
|
|
import BreakfastSelection from "@/components/HotelReservation/SelectRate/BreakfastSelection"
|
|
import Payment from "@/components/HotelReservation/SelectRate/Payment"
|
|
import RoomSelection from "@/components/HotelReservation/SelectRate/RoomSelection"
|
|
import SectionAccordion from "@/components/HotelReservation/SelectRate/SectionAccordion"
|
|
import Summary from "@/components/HotelReservation/SelectRate/Summary"
|
|
import { getIntl } from "@/i18n"
|
|
import { setLang } from "@/i18n/serverContext"
|
|
|
|
import styles from "./page.module.css"
|
|
|
|
import { SectionPageProps } from "@/types/components/hotelReservation/selectRate/section"
|
|
import { LangParams, PageArgs } from "@/types/params"
|
|
|
|
const bedAlternatives = [
|
|
{
|
|
value: "queen",
|
|
name: "Queen bed",
|
|
payment: "160 cm",
|
|
pricePerNight: 0,
|
|
membersPricePerNight: 0,
|
|
currency: "SEK",
|
|
},
|
|
{
|
|
value: "king",
|
|
name: "King bed",
|
|
payment: "160 cm",
|
|
pricePerNight: 0,
|
|
membersPricePerNight: 0,
|
|
currency: "SEK",
|
|
},
|
|
{
|
|
value: "twin",
|
|
name: "Twin bed",
|
|
payment: "90 cm + 90 cm",
|
|
pricePerNight: 82,
|
|
membersPricePerNight: 67,
|
|
currency: "SEK",
|
|
},
|
|
]
|
|
|
|
const breakfastAlternatives = [
|
|
{
|
|
value: "no",
|
|
name: "No breakfast",
|
|
payment: "Always cheeper to get it online",
|
|
pricePerNight: 0,
|
|
currency: "SEK",
|
|
},
|
|
{
|
|
value: "buffe",
|
|
name: "Breakfast buffé",
|
|
payment: "Always cheeper to get it online",
|
|
pricePerNight: 150,
|
|
currency: "SEK",
|
|
},
|
|
]
|
|
|
|
const getFlexibilityMessage = (value: string) => {
|
|
switch (value) {
|
|
case "non-refundable":
|
|
return "Non refundable"
|
|
case "free-rebooking":
|
|
return "Free rebooking"
|
|
case "free-cancellation":
|
|
return "Free cancellation"
|
|
}
|
|
return undefined
|
|
}
|
|
|
|
export default async function SectionsPage({
|
|
params,
|
|
searchParams,
|
|
}: PageArgs<LangParams & { section: string }, SectionPageProps>) {
|
|
setLang(params.lang)
|
|
|
|
const hotel = await serverClient().hotel.hotelData.get({
|
|
hotelId: "811",
|
|
language: params.lang,
|
|
})
|
|
|
|
if (!hotel) {
|
|
// TODO: handle case with hotel missing
|
|
return notFound()
|
|
}
|
|
|
|
const rooms = await serverClient().hotel.rates.get({
|
|
// TODO: pass the correct hotel ID and all other parameters that should be included in the search
|
|
hotelId: hotel.data.id,
|
|
})
|
|
const intl = await getIntl()
|
|
|
|
const selectedBed = searchParams.bed
|
|
? bedAlternatives.find((a) => a.value === searchParams.bed)?.name
|
|
: undefined
|
|
|
|
const selectedBreakfast = searchParams.breakfast
|
|
? breakfastAlternatives.find((a) => a.value === searchParams.breakfast)
|
|
?.name
|
|
: undefined
|
|
|
|
const selectedRoom = searchParams.roomClass
|
|
? rooms.find((room) => room.id.toString() === searchParams.roomClass)?.name
|
|
: undefined
|
|
const selectedFlexibility = searchParams.flexibility
|
|
? getFlexibilityMessage(searchParams.flexibility)
|
|
: undefined
|
|
|
|
const currentSearchParams = new URLSearchParams(searchParams).toString()
|
|
|
|
let user = null
|
|
if (profile && !("error" in profile)) {
|
|
user = profile
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<HotelSelectionHeader hotel={hotel.data.attributes} />
|
|
|
|
<div className={styles.content}>
|
|
<div className={styles.main}>
|
|
<SectionAccordion
|
|
header={intl.formatMessage({ id: "Room & Terms" })}
|
|
selection={
|
|
selectedRoom
|
|
? [
|
|
selectedRoom,
|
|
intl.formatMessage({ id: selectedFlexibility }),
|
|
]
|
|
: undefined
|
|
}
|
|
path={`select-rate?${currentSearchParams}`}
|
|
>
|
|
{params.section === "select-rate" && (
|
|
<RoomSelection
|
|
alternatives={rooms}
|
|
nextPath="select-bed"
|
|
// TODO: Get real value
|
|
nrOfNights={1}
|
|
// TODO: Get real value
|
|
nrOfAdults={1}
|
|
/>
|
|
)}
|
|
</SectionAccordion>
|
|
<SectionAccordion
|
|
header={intl.formatMessage({ id: "Bed type" })}
|
|
selection={selectedBed}
|
|
path={`select-bed?${currentSearchParams}`}
|
|
>
|
|
{params.section === "select-bed" && (
|
|
<BedSelection
|
|
nextPath="breakfast"
|
|
alternatives={bedAlternatives}
|
|
/>
|
|
)}
|
|
</SectionAccordion>
|
|
<SectionAccordion
|
|
header={intl.formatMessage({ id: "Breakfast" })}
|
|
selection={selectedBreakfast}
|
|
path={`breakfast?${currentSearchParams}`}
|
|
>
|
|
{params.section === "breakfast" && (
|
|
<BreakfastSelection
|
|
alternatives={breakfastAlternatives}
|
|
nextPath="details"
|
|
/>
|
|
)}
|
|
</SectionAccordion>
|
|
<SectionAccordion
|
|
header={intl.formatMessage({ id: "Your details" })}
|
|
path={`details?${currentSearchParams}`}
|
|
>
|
|
{params.section === "details" ? <Details user={user} /> : null}
|
|
</SectionAccordion>
|
|
<SectionAccordion
|
|
header={intl.formatMessage({ id: "Payment info" })}
|
|
path={`payment?${currentSearchParams}`}
|
|
>
|
|
{params.section === "payment" && (
|
|
<Payment hotel={hotel.data.attributes} />
|
|
)}
|
|
</SectionAccordion>
|
|
</div>
|
|
<div className={styles.summary}>
|
|
<Summary />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|