From 5204146ba57fab6729145ef4183466c09beed1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20J=C3=A4derberg?= Date: Mon, 18 Nov 2024 14:52:22 +0100 Subject: [PATCH 1/2] fix: load room availabiltity separately --- .../HotelInfoCard/NoRoomsAlert.module.css | 5 + .../SelectRate/HotelInfoCard/NoRoomsAlert.tsx | 73 ++++++++++++++ .../SelectRate/Rooms/RoomsContainer.tsx | 96 +++++++++++++++++++ utils/safeTry.ts | 11 +++ 4 files changed, 185 insertions(+) create mode 100644 components/HotelReservation/SelectRate/HotelInfoCard/NoRoomsAlert.module.css create mode 100644 components/HotelReservation/SelectRate/HotelInfoCard/NoRoomsAlert.tsx create mode 100644 components/HotelReservation/SelectRate/Rooms/RoomsContainer.tsx create mode 100644 utils/safeTry.ts diff --git a/components/HotelReservation/SelectRate/HotelInfoCard/NoRoomsAlert.module.css b/components/HotelReservation/SelectRate/HotelInfoCard/NoRoomsAlert.module.css new file mode 100644 index 000000000..3bb1f51a7 --- /dev/null +++ b/components/HotelReservation/SelectRate/HotelInfoCard/NoRoomsAlert.module.css @@ -0,0 +1,5 @@ +.hotelAlert { + max-width: var(--max-width-navigation); + margin: 0 auto; + padding-top: var(--Spacing-x-one-and-half); +} diff --git a/components/HotelReservation/SelectRate/HotelInfoCard/NoRoomsAlert.tsx b/components/HotelReservation/SelectRate/HotelInfoCard/NoRoomsAlert.tsx new file mode 100644 index 000000000..bfca1364f --- /dev/null +++ b/components/HotelReservation/SelectRate/HotelInfoCard/NoRoomsAlert.tsx @@ -0,0 +1,73 @@ +import { Lang } from "@/constants/languages" +import { dt } from "@/lib/dt" +import { getRoomAvailability } from "@/lib/trpc/memoizedRequests" + +import Alert from "@/components/TempDesignSystem/Alert" +import { getIntl } from "@/i18n" +import { safeTry } from "@/utils/safeTry" + +import { generateChildrenString } from "../RoomSelection/utils" + +import styles from "./NoRoomsAlert.module.css" + +import { Child } from "@/types/components/hotelReservation/selectRate/selectRate" +import { AlertTypeEnum } from "@/types/enums/alert" + +type Props = { + hotelId: number + lang: Lang + adultCount: number + childArray: Child[] + fromDate: Date + toDate: Date +} + +export async function NoRoomsAlert({ + hotelId, + fromDate, + toDate, + childArray, + adultCount, + lang, +}: Props) { + const [availability, availabilityError] = await safeTry( + getRoomAvailability({ + hotelId: hotelId, + roomStayStartDate: dt(fromDate).format("YYYY-MM-DD"), + roomStayEndDate: dt(toDate).format("YYYY-MM-DD"), + adults: adultCount, + children: generateChildrenString(childArray), // TODO: Handle multiple rooms, + }) + ) + + if (!availability) { + return null + } + + if (availabilityError) { + // TODO: Handle error + } + + const noRoomsAvailable = availability.roomConfigurations.reduce( + (acc, room) => { + return acc && room.status === "NotAvailable" + }, + true + ) + + if (!noRoomsAvailable) { + return null + } + + const intl = await getIntl(lang) + return ( +
+ +
+ ) +} diff --git a/components/HotelReservation/SelectRate/Rooms/RoomsContainer.tsx b/components/HotelReservation/SelectRate/Rooms/RoomsContainer.tsx new file mode 100644 index 000000000..d0c662431 --- /dev/null +++ b/components/HotelReservation/SelectRate/Rooms/RoomsContainer.tsx @@ -0,0 +1,96 @@ +import { Lang } from "@/constants/languages" +import { dt } from "@/lib/dt" +import { + getHotelData, + getPackages, + getProfileSafely, + getRoomAvailability, +} from "@/lib/trpc/memoizedRequests" +import { serverClient } from "@/lib/trpc/server" + +import { safeTry } from "@/utils/safeTry" + +import { generateChildrenString } from "../RoomSelection/utils" +import Rooms from "." + +import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" +import { Child } from "@/types/components/hotelReservation/selectRate/selectRate" + +export type Props = { + hotelId: number + fromDate: Date + toDate: Date + adultCount: number + childArray: Child[] + lang: Lang +} + +export async function RoomsContainer({ + hotelId, + fromDate, + toDate, + adultCount, + childArray, + lang, +}: Props) { + const user = await getProfileSafely() + + const fromDateString = dt(fromDate).format("YYYY-MM-DD") + const toDateString = dt(toDate).format("YYYY-MM-DD") + + const hotelDataPromise = safeTry( + getHotelData({ hotelId: hotelId.toString(), language: lang }) + ) + + const packagesPromise = safeTry( + getPackages({ + hotelId: hotelId.toString(), + startDate: fromDateString, + endDate: toDateString, + adults: adultCount, + children: childArray.length > 0 ? childArray.length : undefined, + packageCodes: [ + RoomPackageCodeEnum.ACCESSIBILITY_ROOM, + RoomPackageCodeEnum.PET_ROOM, + RoomPackageCodeEnum.ALLERGY_ROOM, + ], + }) + ) + + const roomsAvailabilityPromise = safeTry( + getRoomAvailability({ + hotelId: hotelId, + roomStayStartDate: fromDateString, + roomStayEndDate: toDateString, + adults: adultCount, + children: generateChildrenString(childArray), + }) + ) + + const [hotelData, hotelDataError] = await hotelDataPromise + const [packages, packagesError] = await packagesPromise + const [roomsAvailability, roomsAvailabilityError] = + await roomsAvailabilityPromise + + if (packagesError) { + console.error("packagesError", { ...packagesError }) + + return ( +
Unable to get packages. {JSON.stringify({ ...packagesError })}
+ ) + } + + if (roomsAvailabilityError || !roomsAvailability) { + console.error("roomsAvailabilityError", roomsAvailabilityError) + return
Unable to get room availability
+ } + + return ( + + ) +} diff --git a/utils/safeTry.ts b/utils/safeTry.ts new file mode 100644 index 000000000..d3bb81596 --- /dev/null +++ b/utils/safeTry.ts @@ -0,0 +1,11 @@ +export type SafeTryResult = Promise< + [T, undefined] | [undefined, Error | unknown] +> + +export async function safeTry(func: Promise): SafeTryResult { + try { + return [await func, undefined] + } catch (err) { + return [undefined, err] + } +} From 8c3715a5b33c474bb306ad957407dafd0af08e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20J=C3=A4derberg?= Date: Mon, 18 Nov 2024 15:25:46 +0100 Subject: [PATCH 2/2] fix: load room availability separately --- .../(standard)/select-rate/page.tsx | 107 +++++++----------- .../SelectRate/HotelInfoCard/index.tsx | 71 +++++++----- 2 files changed, 80 insertions(+), 98 deletions(-) diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx index fd9db4d6c..5682773c3 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx @@ -1,22 +1,16 @@ import { notFound } from "next/navigation" +import { Suspense } from "react" import { dt } from "@/lib/dt" -import { - getHotelData, - getLocations, - getProfileSafely, -} from "@/lib/trpc/memoizedRequests" -import { serverClient } from "@/lib/trpc/server" +import { getHotelData, getLocations } from "@/lib/trpc/memoizedRequests" +import LoadingSpinner from "@/components/Current/LoadingSpinner" import HotelInfoCard from "@/components/HotelReservation/SelectRate/HotelInfoCard" -import Rooms from "@/components/HotelReservation/SelectRate/Rooms" -import { - generateChildrenString, - getHotelReservationQueryParams, -} from "@/components/HotelReservation/SelectRate/RoomSelection/utils" +import { RoomsContainer } from "@/components/HotelReservation/SelectRate/Rooms/RoomsContainer" +import { getHotelReservationQueryParams } from "@/components/HotelReservation/SelectRate/RoomSelection/utils" import { setLang } from "@/i18n/serverContext" +import { safeTry } from "@/utils/safeTry" -import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate" import type { LangParams, PageArgs } from "@/types/params" @@ -45,71 +39,48 @@ export default async function SelectRatePage({ return notFound() } - const validFromDate = + const fromDate = searchParams.fromDate && dt(searchParams.fromDate).isAfter(dt().subtract(1, "day")) - ? searchParams.fromDate - : dt().utc().format("YYYY-MM-DD") - const validToDate = - searchParams.toDate && dt(searchParams.toDate).isAfter(validFromDate) - ? searchParams.toDate - : dt().utc().add(1, "day").format("YYYY-MM-DD") + ? dt(searchParams.fromDate) + : dt().utc() + const toDate = + searchParams.toDate && dt(searchParams.toDate).isAfter(fromDate) + ? dt(searchParams.toDate) + : dt().utc().add(1, "day") + const adults = selectRoomParamsObject.room[0].adults || 1 // TODO: Handle multiple rooms - const childrenCount = selectRoomParamsObject.room[0].child?.length - const children = selectRoomParamsObject.room[0].child - ? generateChildrenString(selectRoomParamsObject.room[0].child) - : undefined // TODO: Handle multiple rooms + const children = selectRoomParamsObject.room[0].child // TODO: Handle multiple rooms - const [hotelData, roomsAvailability, packages, user] = await Promise.all([ - getHotelData({ hotelId: searchParams.hotel, language: params.lang }), - serverClient().hotel.availability.rooms({ - hotelId: parseInt(searchParams.hotel, 10), - roomStayStartDate: validFromDate, - roomStayEndDate: validToDate, - adults, - children, - }), - serverClient().hotel.packages.get({ - hotelId: searchParams.hotel, - startDate: searchParams.fromDate, - endDate: searchParams.toDate, - adults, - children: childrenCount, - packageCodes: [ - RoomPackageCodeEnum.ACCESSIBILITY_ROOM, - RoomPackageCodeEnum.PET_ROOM, - RoomPackageCodeEnum.ALLERGY_ROOM, - ], - }), - getProfileSafely(), - ]) - - if (!roomsAvailability) { - return "No rooms found" // TODO: Add a proper error message - } - - if (!hotelData) { - return "No hotel data found" // TODO: Add a proper error message - } - - const roomCategories = hotelData?.included - - const noRoomsAvailable = roomsAvailability.roomConfigurations.reduce( - (acc, room) => { - return acc && room.status === "NotAvailable" - }, - true + const [hotelData, hotelDataError] = await safeTry( + getHotelData({ hotelId: searchParams.hotel, language: params.lang }) ) + if (!hotelData && !hotelDataError) { + return notFound() + } + + const hotelId = +searchParams.hotel return ( <> - - + }> + + ) } diff --git a/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx b/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx index 946b82ad2..92eebc27d 100644 --- a/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx +++ b/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx @@ -1,7 +1,8 @@ -"use client" -import { useEffect } from "react" +import { Suspense, useEffect } from "react" import { useIntl } from "react-intl" +import { Lang } from "@/constants/languages" +import { getHotelData } from "@/lib/trpc/memoizedRequests" import useRoomAvailableStore from "@/stores/roomAvailability" import { mapFacilityToIcon } from "@/components/ContentType/HotelPage/data" @@ -11,38 +12,54 @@ import Divider from "@/components/TempDesignSystem/Divider" import Body from "@/components/TempDesignSystem/Text/Body" import Caption from "@/components/TempDesignSystem/Text/Caption" import Title from "@/components/TempDesignSystem/Text/Title" +import { getIntl } from "@/i18n" import ReadMore from "../../ReadMore" import TripAdvisorChip from "../../TripAdvisorChip" +import { NoRoomsAlert } from "./NoRoomsAlert" import styles from "./hotelInfoCard.module.css" -import type { HotelInfoCardProps } from "@/types/components/hotelReservation/selectRate/hotelInfoCardProps" -import { AlertTypeEnum } from "@/types/enums/alert" +import { Child } from "@/types/components/hotelReservation/selectRate/selectRate" + +type Props = { + hotelId: number + lang: Lang + fromDate: Date + toDate: Date + adultCount: number + childArray: Child[] +} + +export default async function HotelInfoCard({ + hotelId, + lang, + ...props +}: Props) { + const hotelData = await getHotelData({ + hotelId: hotelId.toString(), + language: lang, + }) -export default function HotelInfoCard({ - hotelData, - noAvailability = false, -}: HotelInfoCardProps) { const hotelAttributes = hotelData?.data.attributes - const intl = useIntl() + const intl = await getIntl() - const noRoomsAvailable = useRoomAvailableStore( - (state) => state.noRoomsAvailable - ) - const setNoRoomsAvailable = useRoomAvailableStore( - (state) => state.setNoRoomsAvailable - ) + // const noRoomsAvailable = useRoomAvailableStore( + // (state) => state.noRoomsAvailable + // ) + // const setNoRoomsAvailable = useRoomAvailableStore( + // (state) => state.setNoRoomsAvailable + // ) const sortedFacilities = hotelAttributes?.detailedFacilities .sort((a, b) => b.sortOrder - a.sortOrder) .slice(0, 5) - useEffect(() => { - if (noAvailability) { - setNoRoomsAvailable() - } - }, [noAvailability, setNoRoomsAvailable]) + // useEffect(() => { + // if (noAvailability) { + // setNoRoomsAvailable() + // } + // }, [noAvailability, setNoRoomsAvailable]) return (
@@ -117,16 +134,10 @@ export default function HotelInfoCard({ ) })} - {noRoomsAvailable ? ( -
- -
- ) : null} + + + +
) }