From b14a1a70974eeb910b119ed84bc661399676f2c8 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Mon, 9 Dec 2024 11:05:44 +0100 Subject: [PATCH] feat(SW-1111) Added Suspense on map --- .env.test | 1 + .../(standard)/select-hotel/map/layout.tsx | 20 ----- .../(standard)/select-hotel/map/page.tsx | 59 +++++--------- .../SelectHotelMapContainer.tsx | 77 +++++++++++++++++++ ...SelectHotelMapContainerSkeleton.module.css | 34 ++++++++ .../SelectHotelMapContainerSkeleton.tsx | 23 ++++++ .../SelectHotel/SelectHotelMap/index.tsx | 3 + .../SelectRate/Rooms/index.tsx | 1 + components/MapContainer/index.tsx | 32 ++++++++ 9 files changed, 190 insertions(+), 60 deletions(-) delete mode 100644 app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/layout.tsx create mode 100644 components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer.tsx create mode 100644 components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton.module.css create mode 100644 components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton.tsx diff --git a/.env.test b/.env.test index 0355b15cc..a353c6d88 100644 --- a/.env.test +++ b/.env.test @@ -7,6 +7,7 @@ CMS_API_KEY="test" CMS_PREVIEW_TOKEN="test" CMS_PREVIEW_URL="test" CMS_URL="test" +CMS_BRANCH="development" CURITY_CLIENT_ID_SERVICE="test" CURITY_CLIENT_SECRET_SERVICE="test" CURITY_CLIENT_ID_USER="test" diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/layout.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/layout.tsx deleted file mode 100644 index 45b344441..000000000 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/layout.tsx +++ /dev/null @@ -1,20 +0,0 @@ -"use client" - -import { useEffect } from "react" - -import styles from "../layout.module.css" - -import { LangParams, LayoutArgs } from "@/types/params" - -export default function HotelReservationLayout({ - children, -}: React.PropsWithChildren>) { - useEffect(() => { - document.body.style.overflow = "hidden" - - return () => { - document.body.style.overflow = "" - } - }, []) - return
{children}
-} diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx index 33d4f4096..bdb47df57 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx @@ -1,10 +1,10 @@ import { notFound } from "next/navigation" +import { Suspense } from "react" -import { env } from "@/env/server" -import { getCityCoordinates, getLocations } from "@/lib/trpc/memoizedRequests" +import { getLocations } from "@/lib/trpc/memoizedRequests" -import { getHotelPins } from "@/components/HotelReservation/HotelCardDialogListing/utils" -import SelectHotelMap from "@/components/HotelReservation/SelectHotel/SelectHotelMap" +import { SelectHotelMapContainer } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer" +import { SelectHotelMapContainerSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton" import { generateChildrenString, getHotelReservationQueryParams, @@ -12,9 +12,8 @@ import { import { MapContainer } from "@/components/MapContainer" import { setLang } from "@/i18n/serverContext" -import { fetchAvailableHotels, getFiltersFromHotels } from "../utils" +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 type { LangParams, PageArgs } from "@/types/params" @@ -34,46 +33,26 @@ export default async function SelectHotelMapPage({ ) if (!city) return notFound() - const googleMapId = env.GOOGLE_DYNAMIC_MAP_ID - const googleMapsApiKey = env.GOOGLE_STATIC_MAP_KEY - const selectHotelParams = new URLSearchParams(searchParams) const selectHotelParamsObject = getHotelReservationQueryParams(selectHotelParams) - const adults = selectHotelParamsObject.room[0].adults // TODO: Handle multiple rooms - const children = selectHotelParamsObject.room[0].child + const adultsInRoom = selectHotelParamsObject.room[0].adults // TODO: Handle multiple rooms + const childrenInRoom = selectHotelParamsObject.room[0].child ? generateChildrenString(selectHotelParamsObject.room[0].child) : undefined // TODO: Handle multiple rooms - const hotels = await fetchAvailableHotels({ - cityId: city.id, - roomStayStartDate: searchParams.fromDate, - roomStayEndDate: searchParams.toDate, - adults, - children, - }) - - 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 }, - }) - return ( - - - +
+ }> + + + + +
) } diff --git a/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer.tsx b/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer.tsx new file mode 100644 index 000000000..a32b1f773 --- /dev/null +++ b/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer.tsx @@ -0,0 +1,77 @@ +import { env } from "@/env/server" +import { getCityCoordinates } from "@/lib/trpc/memoizedRequests" + +import { + fetchAvailableHotels, + getFiltersFromHotels, +} from "@/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils" +import { safeTry } from "@/utils/safeTry" + +import { getHotelPins } from "../../HotelCardDialogListing/utils" +import SelectHotelMap from "." + +import type { + HotelData, + NullableHotelData, +} from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps" +import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams" +import type { Location } from "@/types/trpc/routers/hotel/locations" + +function isHotelData(hotel: NullableHotelData): hotel is HotelData { + return hotel !== null && hotel !== undefined +} + +type Props = { + city: Location + searchParams: SelectHotelSearchParams + adultsInRoom: number + childrenInRoom: string | undefined +} + +export async function SelectHotelMapContainer({ + city, + searchParams, + adultsInRoom, + childrenInRoom, +}: Props) { + const googleMapId = env.GOOGLE_DYNAMIC_MAP_ID + const googleMapsApiKey = env.GOOGLE_STATIC_MAP_KEY + + const fetchAvailableHotelsPromise = safeTry( + fetchAvailableHotels({ + cityId: city.id, + roomStayStartDate: searchParams.fromDate, + roomStayEndDate: searchParams.toDate, + adults: adultsInRoom, + children: childrenInRoom, + }) + ) + + const [hotels, hotelsError] = await fetchAvailableHotelsPromise + + if (hotelsError) { + // TODO: show proper error component + console.error("[SelectHotelMapContainer] unable to fetch hotels") + return null + } + + const validHotels = hotels?.filter(isHotelData) || [] + + const hotelPins = getHotelPins(validHotels) + const filterList = getFiltersFromHotels(validHotels) + const cityCoordinates = await getCityCoordinates({ + city: city.name, + hotel: { address: hotels?.[0]?.hotelData?.address.streetAddress }, + }) + + return ( + + ) +} diff --git a/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton.module.css b/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton.module.css new file mode 100644 index 000000000..c6e0fa3bf --- /dev/null +++ b/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton.module.css @@ -0,0 +1,34 @@ +.container { + max-width: var(--max-width); + height: 100%; +} + +.listingContainer { + background-color: var(--Base-Surface-Secondary-light-Normal); + padding: var(--Spacing-x3) var(--Spacing-x4); + overflow-y: auto; + max-width: 505px; + position: relative; + height: 100%; +} + +.skeletonContainer { + display: none; + overflow: hidden; + flex-direction: row; + flex-wrap: wrap; + margin-top: 20px; + gap: var(--Spacing-x2); + padding-top: var(--Spacing-x6); + height: 100%; +} + +.skeletonItem { + width: 440px; +} + +@media (min-width: 768px) { + .skeletonContainer { + display: flex; + } +} diff --git a/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton.tsx b/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton.tsx new file mode 100644 index 000000000..604dde098 --- /dev/null +++ b/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton.tsx @@ -0,0 +1,23 @@ +import { RoomCardSkeleton } from "../../SelectRate/RoomSelection/RoomCard/RoomCardSkeleton" + +import styles from "./SelectHotelMapContainerSkeleton.module.css" + +type Props = { + count?: number +} + +export async function SelectHotelMapContainerSkeleton({ count = 2 }: Props) { + return ( +
+
+
+ {Array.from({ length: count }).map((_, index) => ( +
+ +
+ ))} +
+
+
+ ) +} diff --git a/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx b/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx index d64a4e883..952c8b11a 100644 --- a/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx +++ b/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx @@ -1,4 +1,5 @@ "use client" + import { APIProvider } from "@vis.gl/react-google-maps" import { useSearchParams } from "next/navigation" import { useEffect, useMemo, useRef, useState } from "react" @@ -95,6 +96,8 @@ export default function SelectHotelMap({ [activeFilters, hotelPins] ) + console.log("hotelPins", hotelPins) + const closeButton = (