Merged in feature/select-room-ux-one-page (pull request #523)
This updates the select room page according to the new UX. It has different sections on the same page, but with specific URLs per section. Since neither UX, UI nor API is completely done both design and data structures are a bit temporary. Approved-by: Simon.Emanuelsson
This commit is contained in:
@@ -1,7 +1,3 @@
|
||||
.hotelInfo {
|
||||
margin-bottom: 64px;
|
||||
}
|
||||
|
||||
.page {
|
||||
min-height: 100dvh;
|
||||
padding-top: var(--Spacing-x6);
|
||||
@@ -12,6 +8,18 @@
|
||||
|
||||
.content {
|
||||
max-width: 1134px;
|
||||
margin-top: var(--Spacing-x5);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: var(--Spacing-x7);
|
||||
}
|
||||
|
||||
.main {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.summary {
|
||||
max-width: 340px;
|
||||
}
|
||||
188
app/[lang]/(live)/(public)/hotelreservation/[section]/page.tsx
Normal file
188
app/[lang]/(live)/(public)/hotelreservation/[section]/page.tsx
Normal file
@@ -0,0 +1,188 @@
|
||||
import { notFound } from "next/navigation"
|
||||
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import HotelCard from "@/components/HotelReservation/HotelCard"
|
||||
import BedSelection from "@/components/HotelReservation/SelectRate/BedSelection"
|
||||
import BreakfastSelection from "@/components/HotelReservation/SelectRate/BreakfastSelection"
|
||||
import Details from "@/components/HotelReservation/SelectRate/Details"
|
||||
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)
|
||||
|
||||
// TODO: pass the correct hotel ID
|
||||
const hotelResponse = await serverClient().hotel.get({
|
||||
hotelId: "879",
|
||||
language: params.lang,
|
||||
})
|
||||
if (!hotelResponse) {
|
||||
return notFound()
|
||||
}
|
||||
const { hotel } = hotelResponse
|
||||
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: "1",
|
||||
})
|
||||
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()
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HotelCard hotel={hotel} />
|
||||
|
||||
<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 />}
|
||||
</SectionAccordion>
|
||||
<SectionAccordion
|
||||
header={intl.formatMessage({ id: "Payment info" })}
|
||||
path={`payment?${currentSearchParams}`}
|
||||
>
|
||||
{params.section === "payment" && <Payment />}
|
||||
</SectionAccordion>
|
||||
</div>
|
||||
<div className={styles.summary}>
|
||||
<Summary />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
import tempHotelData from "@/server/routers/hotels/tempHotelData.json"
|
||||
|
||||
import HotelCard from "@/components/HotelReservation/HotelCard"
|
||||
import BedSelection from "@/components/HotelReservation/SelectRate/BedSelection"
|
||||
import BreakfastSelection from "@/components/HotelReservation/SelectRate/BreakfastSelection"
|
||||
import FlexibilitySelection from "@/components/HotelReservation/SelectRate/FlexibilitySelection"
|
||||
import RoomSelection from "@/components/HotelReservation/SelectRate/RoomSelection"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function SelectRate({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
// TODO: Use real endpoint.
|
||||
const hotel = tempHotelData.data.attributes
|
||||
|
||||
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: "1",
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<main className={styles.content}>
|
||||
<div className={styles.hotelInfo}>
|
||||
<HotelCard hotel={hotel} />
|
||||
</div>
|
||||
<RoomSelection rooms={rooms} />
|
||||
<FlexibilitySelection />
|
||||
<BreakfastSelection />
|
||||
<BedSelection />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user