Merge branch 'master' into feature/tracking

This commit is contained in:
Linus Flood
2024-12-03 07:48:59 +01:00
159 changed files with 2609 additions and 1227 deletions

View File

@@ -1,7 +1,3 @@
import { notFound } from "next/navigation"
import { env } from "@/env/server"
import styles from "./layout.module.css"
import { LangParams, LayoutArgs } from "@/types/params"
@@ -12,9 +8,6 @@ export default function HotelReservationLayout({
}: React.PropsWithChildren<LayoutArgs<LangParams>> & {
sidePeek: React.ReactNode
}) {
if (!env.ENABLE_BOOKING_FLOW) {
return notFound()
}
return (
<div className={styles.layout}>
{children}

View File

@@ -17,6 +17,7 @@ import { setLang } from "@/i18n/serverContext"
import { fetchAvailableHotels, getFiltersFromHotels } from "../../utils"
import type { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
import {
TrackingChannelEnum,
@@ -59,6 +60,10 @@ export default async function SelectHotelMapPage({
children,
})
const validHotels = hotels.filter(
(hotel): hotel is HotelData => hotel !== null
)
const arrivalDate = new Date(searchParams.fromDate)
const departureDate = new Date(searchParams.toDate)
@@ -85,15 +90,15 @@ export default async function SelectHotelMapPage({
leadTime: differenceInCalendarDays(arrivalDate, new Date()),
searchType: "destination",
bookingTypeofDay: isWeekend(arrivalDate) ? "weekend" : "weekday",
country: hotels?.[0].hotelData.address.country,
region: hotels?.[0].hotelData.address.city,
country: validHotels?.[0].hotelData.address.country,
region: validHotels?.[0].hotelData.address.city,
}
const hotelPins = getHotelPins(hotels)
const filterList = getFiltersFromHotels(hotels)
const hotelPins = getHotelPins(validHotels)
const filterList = getFiltersFromHotels(validHotels)
const cityCoordinates = await getCityCoordinates({
city: city.name,
hotel: { address: hotels[0].hotelData.address.streetAddress },
hotel: { address: hotels?.[0]?.hotelData?.address.streetAddress },
})
return (
@@ -102,7 +107,7 @@ export default async function SelectHotelMapPage({
apiKey={googleMapsApiKey}
hotelPins={hotelPins}
mapId={googleMapId}
hotels={hotels}
hotels={validHotels}
filterList={filterList}
cityCoordinates={cityCoordinates}
/>

View File

@@ -36,6 +36,7 @@ import { setLang } from "@/i18n/serverContext"
import styles from "./page.module.css"
import type { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
import {
TrackingChannelEnum,
@@ -69,6 +70,14 @@ export default async function SelectHotelPage({
const selectHotelParams = new URLSearchParams(searchParams)
const selectHotelParamsObject =
getHotelReservationQueryParams(selectHotelParams)
if (
!selectHotelParamsObject.room ||
selectHotelParamsObject.room.length === 0
) {
return notFound()
}
const adults = selectHotelParamsObject.room[0].adults // TODO: Handle multiple rooms
const child = selectHotelParamsObject.room[0].child // TODO: Handle multiple rooms
const children = child ? generateChildrenString(child) : undefined
@@ -84,7 +93,11 @@ export default async function SelectHotelPage({
const arrivalDate = new Date(searchParams.fromDate)
const departureDate = new Date(searchParams.toDate)
const filterList = getFiltersFromHotels(hotels)
const validHotels = hotels.filter(
(hotel): hotel is HotelData => hotel !== null
)
const filterList = getFiltersFromHotels(validHotels)
const breadcrumbs = [
{
title: intl.formatMessage({ id: "Home" }),
@@ -132,8 +145,8 @@ export default async function SelectHotelPage({
leadTime: differenceInCalendarDays(arrivalDate, new Date()),
searchType: "destination",
bookingTypeofDay: isWeekend(arrivalDate) ? "weekend" : "weekday",
country: hotels?.[0].hotelData.address.country,
region: hotels?.[0].hotelData.address.city,
country: validHotels?.[0].hotelData.address.country,
region: validHotels?.[0].hotelData.address.city,
}
return (
@@ -206,7 +219,7 @@ export default async function SelectHotelPage({
})}
/>
)}
<HotelCardListing hotelData={hotels} />
<HotelCardListing hotelData={validHotels} />
</div>
<TrackingSDK
pageData={pageTrackingData}

View File

@@ -4,7 +4,10 @@ import { serverClient } from "@/lib/trpc/server"
import { getLang } from "@/i18n/serverContext"
import type { AvailabilityInput } from "@/types/components/hotelReservation/selectHotel/availabilityInput"
import type { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
import type {
HotelData,
NullableHotelData,
} from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
import type {
CategorizedFilters,
Filter,
@@ -30,10 +33,10 @@ const hotelFacilitiesFilterNames = [
export async function fetchAvailableHotels(
input: AvailabilityInput
): Promise<HotelData[]> {
): Promise<NullableHotelData[]> {
const availableHotels = await serverClient().hotel.availability.hotels(input)
if (!availableHotels) throw new Error()
if (!availableHotels) return []
const language = getLang()
@@ -43,7 +46,7 @@ export async function fetchAvailableHotels(
language,
})
if (!hotelData) throw new Error()
if (!hotelData) return { hotelData: null, price: hotel.productType }
return {
hotelData: hotelData.data.attributes,
@@ -55,7 +58,13 @@ export async function fetchAvailableHotels(
}
export function getFiltersFromHotels(hotels: HotelData[]): CategorizedFilters {
const filters = hotels.flatMap((hotel) => hotel.hotelData.detailedFacilities)
if (hotels.length === 0)
return { facilityFilters: [], surroundingsFilters: [] }
const filters = hotels.flatMap((hotel) => {
if (!hotel.hotelData) return []
return hotel.hotelData.detailedFacilities
})
const uniqueFilterIds = [...new Set(filters.map((filter) => filter.id))]
const filterList: Filter[] = uniqueFilterIds

View File

@@ -4,7 +4,8 @@
}
.content {
margin: var(--Spacing-x3) var(--Spacing-x2) 0;
width: var(--max-width-page);
margin: var(--Spacing-x3) auto 0;
}
.summary {
@@ -16,14 +17,17 @@
@media screen and (min-width: 1367px) {
.container {
width: var(--max-width-page);
grid-template-columns: 1fr 340px;
grid-template-rows: auto 1fr;
margin: var(--Spacing-x5) auto 0;
/* simulates padding on viewport smaller than --max-width-navigation */
width: min(
calc(100dvw - (var(--Spacing-x2) * 2)),
var(--max-width-navigation)
);
}
.content {
width: 100%;
margin: var(--Spacing-x3) 0 0;
}
.summary {

View File

@@ -19,7 +19,8 @@ import HistoryStateManager from "@/components/HotelReservation/EnterDetails/Hist
import Payment from "@/components/HotelReservation/EnterDetails/Payment"
import SectionAccordion from "@/components/HotelReservation/EnterDetails/SectionAccordion"
import SelectedRoom from "@/components/HotelReservation/EnterDetails/SelectedRoom"
import Summary from "@/components/HotelReservation/EnterDetails/Summary"
import DesktopSummary from "@/components/HotelReservation/EnterDetails/Summary/Desktop"
import MobileSummary from "@/components/HotelReservation/EnterDetails/Summary/Mobile"
import {
generateChildrenString,
getQueryParamsForEnterDetails,
@@ -182,6 +183,13 @@ export default async function StepPage({
//lowestRoomPrice:
}
const summary = {
cancellationText: roomAvailability.cancellationText,
isMember: !!user,
rateDetails: roomAvailability.rateDetails,
roomType: roomAvailability.selectedRoom.roomType,
}
return (
<EnterDetailsProvider
bedTypes={roomAvailability.bedTypes}
@@ -262,16 +270,8 @@ export default async function StepPage({
</section>
</div>
<aside className={styles.summary}>
<Summary
adults={adults}
fromDate={fromDate}
hotelId={hotelId}
kids={children}
packageCodes={packageCodes}
rateCode={rateCode}
roomTypeCode={roomTypeCode}
toDate={toDate}
/>
<MobileSummary {...summary} />
<DesktopSummary {...summary} />
</aside>
</div>
</main>