Merge branch 'master' into feature/tracking

This commit is contained in:
Linus Flood
2024-11-21 07:53:58 +01:00
213 changed files with 3486 additions and 1990 deletions

View File

@@ -0,0 +1,5 @@
import LoadingSpinner from "@/components/LoadingSpinner"
export default function LoadingModal() {
return <LoadingSpinner />
}

View File

@@ -15,7 +15,7 @@ import { MapModal } from "@/components/MapModal"
import TrackingSDK from "@/components/TrackingSDK"
import { setLang } from "@/i18n/serverContext"
import { fetchAvailableHotels } from "../../utils"
import { fetchAvailableHotels, getFiltersFromHotels } from "../../utils"
import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
import {
@@ -92,6 +92,7 @@ export default async function SelectHotelMapPage({
}
const hotelPins = getHotelPins(hotels)
const filterList = getFiltersFromHotels(hotels)
return (
<MapModal>
@@ -100,6 +101,7 @@ export default async function SelectHotelMapPage({
hotelPins={hotelPins}
mapId={googleMapId}
hotels={hotels}
filterList={filterList}
/>
<TrackingSDK pageData={pageTrackingData} hotelInfo={hotelsTrackingData} />
</MapModal>

View File

@@ -20,10 +20,13 @@
gap: var(--Spacing-x1);
}
.sorter {
display: none;
}
.sideBar {
display: flex;
flex-direction: column;
max-width: 340px;
}
.link {
@@ -47,6 +50,10 @@
gap: var(--Spacing-x3);
}
.filter {
display: none;
}
@media (min-width: 768px) {
.main {
padding: var(--Spacing-x5);
@@ -58,6 +65,11 @@
var(--Spacing-x5);
}
.sorter {
display: block;
width: 339px;
}
.title {
margin: 0 auto;
display: flex;
@@ -65,6 +77,14 @@
align-items: center;
justify-content: space-between;
}
.sideBar {
max-width: 340px;
}
.filter {
display: block;
}
.link {
display: flex;
padding-bottom: var(--Spacing-x6);

View File

@@ -10,6 +10,7 @@ import {
getFiltersFromHotels,
} from "@/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils"
import HotelCardListing from "@/components/HotelReservation/HotelCardListing"
import HotelCount from "@/components/HotelReservation/SelectHotel/HotelCount"
import HotelFilter from "@/components/HotelReservation/SelectHotel/HotelFilter"
import HotelSorter from "@/components/HotelReservation/SelectHotel/HotelSorter"
import MobileMapButtonContainer from "@/components/HotelReservation/SelectHotel/MobileMapButtonContainer"
@@ -22,7 +23,6 @@ import StaticMap from "@/components/Maps/StaticMap"
import Alert from "@/components/TempDesignSystem/Alert"
import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link"
import Preamble from "@/components/TempDesignSystem/Text/Preamble"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import TrackingSDK from "@/components/TrackingSDK"
import { getIntl } from "@/i18n"
@@ -76,6 +76,8 @@ export default async function SelectHotelPage({
const filterList = getFiltersFromHotels(hotels)
const isAllUnavailable = hotels.every((hotel) => hotel.price === undefined)
const pageTrackingData: TrackingSDKPageData = {
pageId: "select-hotel",
domainLanguage: params.lang as Lang,
@@ -107,11 +109,13 @@ export default async function SelectHotelPage({
<div className={styles.title}>
<div className={styles.cityInformation}>
<Subtitle>{city.name}</Subtitle>
<Preamble>{hotels.length} hotels</Preamble>
<HotelCount />
</div>
<div className={styles.sorter}>
<HotelSorter discreet />
</div>
<HotelSorter />
</div>
<MobileMapButtonContainer city={searchParams.city} />
<MobileMapButtonContainer filters={filterList} />
</header>
<main className={styles.main}>
<div className={styles.sideBar}>
@@ -119,7 +123,7 @@ export default async function SelectHotelPage({
<Link
className={styles.link}
color="burgundy"
href={selectHotelMap[params.lang]}
href={selectHotelMap(params.lang)}
keepSearchParams
>
<div className={styles.mapContainer}>
@@ -153,10 +157,10 @@ export default async function SelectHotelPage({
/>
</div>
)}
<HotelFilter filters={filterList} />
<HotelFilter filters={filterList} className={styles.filter} />
</div>
<div className={styles.hotelList}>
{!hotels.length && (
{isAllUnavailable && (
<Alert
type={AlertTypeEnum.Info}
heading={intl.formatMessage({ id: "No availability" })}

View File

@@ -9,8 +9,6 @@ import type {
CategorizedFilters,
Filter,
} from "@/types/components/hotelReservation/selectHotel/hotelFilters"
import type { HotelPin } from "@/types/components/hotelReservation/selectHotel/map"
import { HotelListingEnum } from "@/types/enums/hotelListing"
const hotelSurroundingsFilterNames = [
"Hotel surroundings",
@@ -21,6 +19,15 @@ const hotelSurroundingsFilterNames = [
"Omgivningar",
]
const hotelFacilitiesFilterNames = [
"Hotel facilities",
"Hotellfaciliteter",
"Hotelfaciliteter",
"Hotel faciliteter",
"Hotel-Infos",
"Hotellin palvelut",
]
export async function fetchAvailableHotels(
input: AvailabilityInput
): Promise<HotelData[]> {
@@ -29,24 +36,8 @@ export async function fetchAvailableHotels(
if (!availableHotels) throw new Error()
const language = getLang()
const hotelMap = new Map<number, any>()
availableHotels.availability.forEach((hotel) => {
const existingHotel = hotelMap.get(hotel.hotelId)
if (existingHotel) {
if (hotel.ratePlanSet === HotelListingEnum.RatePlanSet.PUBLIC) {
existingHotel.bestPricePerNight.regularAmount =
hotel.bestPricePerNight?.regularAmount
} else if (hotel.ratePlanSet === HotelListingEnum.RatePlanSet.MEMBER) {
existingHotel.bestPricePerNight.memberAmount =
hotel.bestPricePerNight?.memberAmount
}
} else {
hotelMap.set(hotel.hotelId, { ...hotel })
}
})
const hotels = Array.from(hotelMap.values()).map(async (hotel) => {
const hotels = availableHotels.availability.map(async (hotel) => {
const hotelData = await getHotelData({
hotelId: hotel.hotelId.toString(),
language,
@@ -56,7 +47,7 @@ export async function fetchAvailableHotels(
return {
hotelData: hotelData.data.attributes,
price: hotel.bestPricePerNight,
price: hotel.productType,
}
})
@@ -70,6 +61,7 @@ export function getFiltersFromHotels(hotels: HotelData[]): CategorizedFilters {
const filterList: Filter[] = uniqueFilterIds
.map((filterId) => filters.find((filter) => filter.id === filterId))
.filter((filter): filter is Filter => filter !== undefined)
.sort((a, b) => b.sortOrder - a.sortOrder)
return filterList.reduce<CategorizedFilters>(
(acc, filter) => {
@@ -79,10 +71,13 @@ export function getFiltersFromHotels(hotels: HotelData[]): CategorizedFilters {
surroundingsFilters: [...acc.surroundingsFilters, filter],
}
return {
facilityFilters: [...acc.facilityFilters, filter],
surroundingsFilters: acc.surroundingsFilters,
}
if (filter.filter && hotelFacilitiesFilterNames.includes(filter.filter))
return {
facilityFilters: [...acc.facilityFilters, filter],
surroundingsFilters: acc.surroundingsFilters,
}
return acc
},
{ facilityFilters: [], surroundingsFilters: [] }
)