fix(SW-978) Checks for null data on hotels

This commit is contained in:
Pontus Dreij
2024-11-26 13:55:44 +01:00
parent 4de3f4717c
commit 3d78bdd671
10 changed files with 54 additions and 26 deletions

View File

@@ -14,6 +14,7 @@ import { setLang } from "@/i18n/serverContext"
import { fetchAvailableHotels, getFiltersFromHotels } from "../../utils"
import { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
import type { LangParams, PageArgs } from "@/types/params"
@@ -52,11 +53,15 @@ export default async function SelectHotelMapPage({
children,
})
const hotelPins = getHotelPins(hotels)
const filterList = getFiltersFromHotels(hotels)
const validHotels = hotels.filter(
(hotel): hotel is HotelData => hotel !== null
)
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 (
@@ -65,7 +70,7 @@ export default async function SelectHotelMapPage({
apiKey={googleMapsApiKey}
hotelPins={hotelPins}
mapId={googleMapId}
hotels={hotels}
hotels={validHotels}
filterList={filterList}
cityCoordinates={cityCoordinates}
/>

View File

@@ -33,6 +33,7 @@ import { setLang } from "@/i18n/serverContext"
import styles from "./page.module.css"
import { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
import { AlertTypeEnum } from "@/types/enums/alert"
import { LangParams, PageArgs } from "@/types/params"
@@ -82,7 +83,11 @@ export default async function SelectHotelPage({
children,
})
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" }),
@@ -177,7 +182,7 @@ export default async function SelectHotelPage({
})}
/>
)}
<HotelCardListing hotelData={hotels} />
<HotelCardListing hotelData={validHotels} />
</div>
</main>
</>

View File

@@ -1,10 +1,14 @@
import { getHotelData } from "@/lib/trpc/memoizedRequests"
import { serverClient } from "@/lib/trpc/server"
import { badRequestError } from "@/server/errors/trpc"
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 +34,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 +47,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 +59,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

@@ -41,18 +41,11 @@ function HotelCard({
const { hotelData } = hotel
const { price } = hotel
const amenities = hotelData.detailedFacilities.slice(0, 5)
const classNames = hotelCardVariants({
type,
state,
})
const handleMouseEnter = useCallback(() => {
if (onHotelCardHover) {
if (onHotelCardHover && hotelData) {
onHotelCardHover(hotelData.name)
}
}, [onHotelCardHover, hotelData.name])
}, [onHotelCardHover, hotelData])
const handleMouseLeave = useCallback(() => {
if (onHotelCardHover) {
@@ -60,6 +53,15 @@ function HotelCard({
}
}, [onHotelCardHover])
if (!hotel || !hotelData) return null
const amenities = hotelData.detailedFacilities.slice(0, 5)
const classNames = hotelCardVariants({
type,
state,
})
return (
<article
className={classNames}
@@ -82,8 +84,8 @@ function HotelCard({
<section className={styles.hotelInformation}>
<div className={styles.titleContainer}>
<HotelLogo
hotelId={hotel.hotelData.operaId}
hotelType={hotel.hotelData.hotelType}
hotelId={hotelData.operaId}
hotelType={hotelData.hotelType}
/>
<Subtitle textTransform="capitalize" color="uiTextHighContrast">
{hotelData.name}

View File

@@ -17,7 +17,7 @@ export default function HotelCardDialogListing({
activeCard,
onActiveCardChange,
}: HotelCardDialogListingProps) {
const hotelsPinData = getHotelPins(hotels)
const hotelsPinData = hotels ? getHotelPins(hotels) : []
const activeCardRef = useRef<HTMLDivElement | null>(null)
const observerRef = useRef<IntersectionObserver | null>(null)
const dialogRef = useRef<HTMLDivElement>(null)

View File

@@ -2,6 +2,8 @@ import type { HotelData } from "@/types/components/hotelReservation/selectHotel/
import type { HotelPin } from "@/types/components/hotelReservation/selectHotel/map"
export function getHotelPins(hotels: HotelData[]): HotelPin[] {
if (hotels.length === 0) return []
return hotels.map((hotel) => ({
coordinates: {
lat: hotel.hotelData.location.latitude,

View File

@@ -144,7 +144,7 @@ export const getBookingConfirmation = cache(
export const getCityCoordinates = cache(
async function getMemoizedCityCoordinates(input: {
city: string
hotel: { address: string }
hotel: { address: string | undefined }
}) {
return serverClient().hotel.map.city(input)
}

View File

@@ -77,6 +77,6 @@ export const getRoomPackagesInputSchema = z.object({
export const getCityCoordinatesInputSchema = z.object({
city: z.string(),
hotel: z.object({
address: z.string(),
address: z.string().optional(),
}),
})

View File

@@ -18,3 +18,7 @@ export type HotelData = {
hotelData: Hotel
price: ProductType
}
export interface NullableHotelData extends Omit<HotelData, "hotelData"> {
hotelData: HotelData["hotelData"] | null
}

View File

@@ -56,7 +56,7 @@ export interface HotelCardDialogProps {
}
export interface HotelCardDialogListingProps {
hotels: HotelData[]
hotels: HotelData[] | null
activeCard: string | null | undefined
onActiveCardChange: (hotelName: string | null) => void
}