diff --git a/components/ContentType/DestinationPage/DestinationCityPage/CityMap/index.tsx b/components/ContentType/DestinationPage/DestinationCityPage/CityMap/index.tsx new file mode 100644 index 000000000..b90bff790 --- /dev/null +++ b/components/ContentType/DestinationPage/DestinationCityPage/CityMap/index.tsx @@ -0,0 +1,33 @@ +import { env } from "@/env/server" +import { getHotelsByCityIdentifier } from "@/lib/trpc/memoizedRequests" + +import Title from "@/components/TempDesignSystem/Text/Title" + +import Map from "../../Map" + +import type { CityLocation } from "@/types/trpc/routers/hotel/locations" + +interface CityMapProps { + city: CityLocation + cityIdentifier: string +} +export function preloadHotels(cityIdentifier: string) { + void getHotelsByCityIdentifier(cityIdentifier) +} +export default async function CityMap({ city, cityIdentifier }: CityMapProps) { + const hotels = await getHotelsByCityIdentifier(cityIdentifier) + + return ( + +
+ + {city.name} + +
+
+ ) +} diff --git a/components/ContentType/DestinationPage/DestinationCityPage/index.tsx b/components/ContentType/DestinationPage/DestinationCityPage/index.tsx index 38b1604d2..70d3eaa4d 100644 --- a/components/ContentType/DestinationPage/DestinationCityPage/index.tsx +++ b/components/ContentType/DestinationPage/DestinationCityPage/index.tsx @@ -16,6 +16,7 @@ import SidebarContentWrapper from "../SidebarContentWrapper" import DestinationPageSidePeek from "../Sidepeek" import StaticMap from "../StaticMap" import TopImages from "../TopImages" +import CityMap, { preloadHotels } from "./CityMap" import styles from "./destinationCityPage.module.css" @@ -28,7 +29,7 @@ export default async function DestinationCityPage() { return null } - const { tracking, destinationCityPage, cityIdentifier } = pageData + const { tracking, destinationCityPage, cityIdentifier, city } = pageData const { blocks, images, @@ -41,6 +42,8 @@ export default async function DestinationCityPage() { destination_settings, } = destinationCityPage + preloadHotels(cityIdentifier) + return ( <>
@@ -48,11 +51,7 @@ export default async function DestinationCityPage() { }> - {/* TODO: fetch translated city name from API when fetching hotel listing */} - +
}> @@ -78,6 +77,7 @@ export default async function DestinationCityPage() {
+ diff --git a/components/ContentType/DestinationPage/DestinationCountryPage/CountryMap/map.module.css b/components/ContentType/DestinationPage/DestinationCountryPage/CountryMap/map.module.css deleted file mode 100644 index d85a576d1..000000000 --- a/components/ContentType/DestinationPage/DestinationCountryPage/CountryMap/map.module.css +++ /dev/null @@ -1,23 +0,0 @@ -.countryMap { - --destination-map-height: 100dvh; - - position: absolute; - top: 0; - left: 0; - height: var(--destination-map-height); - width: 100dvw; - z-index: var(--hotel-dynamic-map-z-index); - display: flex; - background-color: var(--Base-Surface-Primary-light-Normal); -} -.wrapper { - position: absolute; - top: 0; - left: 0; -} - -.closeButton { - pointer-events: initial; - box-shadow: var(--button-box-shadow); - gap: var(--Spacing-x-half); -} diff --git a/components/ContentType/DestinationPage/HotelListing/index.tsx b/components/ContentType/DestinationPage/HotelListing/index.tsx index 1decdbdc1..e9769d47a 100644 --- a/components/ContentType/DestinationPage/HotelListing/index.tsx +++ b/components/ContentType/DestinationPage/HotelListing/index.tsx @@ -1,4 +1,4 @@ -import { getHotelListDataByCityIdentifier } from "@/lib/trpc/memoizedRequests" +import { getHotelsByCityIdentifier } from "@/lib/trpc/memoizedRequests" import HotelListingClient from "./Client" @@ -9,7 +9,7 @@ interface HotelListingProps { export default async function HotelListing({ cityIdentifier, }: HotelListingProps) { - const hotels = await getHotelListDataByCityIdentifier(cityIdentifier) + const hotels = await getHotelsByCityIdentifier(cityIdentifier) if (!hotels.length) { return null diff --git a/components/ContentType/DestinationPage/Map/DynamicMap/index.tsx b/components/ContentType/DestinationPage/Map/DynamicMap/index.tsx index bf8019538..711b63b03 100644 --- a/components/ContentType/DestinationPage/Map/DynamicMap/index.tsx +++ b/components/ContentType/DestinationPage/Map/DynamicMap/index.tsx @@ -49,14 +49,12 @@ export default function DynamicMap({ function zoomIn() { const currentZoom = map && map.getZoom() - console.log(currentZoom) if (currentZoom) { map.setZoom(currentZoom + 1) } } function zoomOut() { const currentZoom = map && map.getZoom() - console.log(currentZoom) if (currentZoom) { map.setZoom(currentZoom - 1) } @@ -65,6 +63,7 @@ export default function DynamicMap({ const mapOptions: MapProps = { defaultCenter: markers[0].coordinates, // Default center will be overridden by the bounds minZoom: 3, + maxZoom: 18, defaultZoom: 8, disableDefaultUI: true, clickableIcons: false, diff --git a/lib/trpc/memoizedRequests/index.ts b/lib/trpc/memoizedRequests/index.ts index 336fe6818..4c6eabc5e 100644 --- a/lib/trpc/memoizedRequests/index.ts +++ b/lib/trpc/memoizedRequests/index.ts @@ -213,20 +213,18 @@ export const getHotelsByCountry = cache( }) } ) +export const getHotelsByCityIdentifier = cache( + async function getMemoizedHotelsByCityIdentifier(cityIdentifier: string) { + return serverClient().hotel.hotels.byCityIdentifier.get({ + cityIdentifier, + }) + } +) export const getDestinationCityPage = cache( async function getMemoizedDestinationCityPage() { return serverClient().contentstack.destinationCityPage.get() } ) -export const getHotelListDataByCityIdentifier = cache( - async function getMemoizedHotelListDataByCityIdentifier( - cityIdentifier: string - ) { - return serverClient().contentstack.destinationCityPage.hotelList({ - cityIdentifier, - }) - } -) export const getStartPage = cache(async function getMemoizedStartPage() { return serverClient().contentstack.startPage.get() diff --git a/server/routers/contentstack/destinationCityPage/query.ts b/server/routers/contentstack/destinationCityPage/query.ts index b5a7e29f7..6efd41b74 100644 --- a/server/routers/contentstack/destinationCityPage/query.ts +++ b/server/routers/contentstack/destinationCityPage/query.ts @@ -8,8 +8,7 @@ import { contentStackUidWithServiceProcedure, router } from "@/server/trpc" import { generateTag } from "@/utils/generateTag" -import { getHotelListData } from "../../hotels/utils" -import { getHotelListDataInput } from "./input" +import { getCityByCityIdentifier } from "../../hotels/utils" import { destinationCityPageRefsSchema, destinationCityPageSchema, @@ -148,6 +147,27 @@ export const destinationCityPageQueryRouter = router({ ) return null } + const cityIdentifier = + validatedResponse.data.destinationCityPage.destination_settings.city + const city = await getCityByCityIdentifier(cityIdentifier, serviceToken) + + if (!city) { + getDestinationCityPageFailCounter.add(1, { + lang, + uid: `${uid}`, + error_type: "not_found", + error: `Couldn't find city with cityIdentifier: ${cityIdentifier}`, + }) + + console.error( + "contentstack.destinationCityPage not found error", + JSON.stringify({ + query: { lang, uid }, + error: `Couldn't find city with cityIdentifier: ${cityIdentifier}`, + }) + ) + return null + } getDestinationCityPageSuccessCounter.add(1, { lang, uid: `${uid}` }) console.info( @@ -159,18 +179,8 @@ export const destinationCityPageQueryRouter = router({ return { ...validatedResponse.data, - cityIdentifier: - validatedResponse.data.destinationCityPage.destination_settings.city, + cityIdentifier, + city, } }), - hotelList: contentStackUidWithServiceProcedure - .input(getHotelListDataInput) - .query(async ({ ctx, input }) => { - const { lang, serviceToken } = ctx - const { cityIdentifier } = input - - const hotels = await getHotelListData(lang, serviceToken, cityIdentifier) - - return hotels - }), }) diff --git a/server/routers/hotels/input.ts b/server/routers/hotels/input.ts index e2a8a52fb..3a12a77a4 100644 --- a/server/routers/hotels/input.ts +++ b/server/routers/hotels/input.ts @@ -121,3 +121,7 @@ export const getAdditionalDataInputSchema = z.object({ export const getHotelsByCountryInput = z.object({ country: z.nativeEnum(Country), }) + +export const getHotelsByCityIdentifierInput = z.object({ + cityIdentifier: z.string(), +}) diff --git a/server/routers/hotels/query.ts b/server/routers/hotels/query.ts index 7f2cc877d..5844e2257 100644 --- a/server/routers/hotels/query.ts +++ b/server/routers/hotels/query.ts @@ -24,6 +24,7 @@ import { breakfastPackageInputSchema, cityCoordinatesInputSchema, getAdditionalDataInputSchema, + getHotelsByCityIdentifierInput, getHotelsByCountryInput, getHotelsByCSFilterInput, getHotelsByHotelIdsAvailabilityInputSchema, @@ -51,7 +52,9 @@ import { getCitiesByCountry, getCountries, getHotelIdsByCityId, + getHotelIdsByCityIdentifier, getHotelIdsByCountry, + getHotelsByHotelIds, getLocations, } from "./utils" @@ -861,21 +864,22 @@ export const hotelQueryRouter = router({ hotelIdsParams ) - const hotels = await Promise.all( - hotelIds.map(async (hotelId) => { - const [hotelData, url] = await Promise.all([ - getHotel( - { hotelId, isCardOnlyPayment: false, language: lang }, - ctx.serviceToken - ), - getHotelPageUrl(lang, hotelId), - ]) + return await getHotelsByHotelIds(hotelIds, lang, serviceToken) + }), + }), + byCityIdentifier: router({ + get: contentStackBaseWithServiceProcedure + .input(getHotelsByCityIdentifierInput) + .query(async ({ ctx, input }) => { + const { lang, serviceToken } = ctx + const { cityIdentifier } = input - return hotelData ? { ...hotelData, url } : null - }) + const hotelIds = await getHotelIdsByCityIdentifier( + cityIdentifier, + serviceToken ) - return hotels.filter((hotel): hotel is HotelDataWithUrl => !!hotel) + return await getHotelsByHotelIds(hotelIds, lang, serviceToken) }), }), byCSFilter: router({ diff --git a/server/routers/hotels/utils.ts b/server/routers/hotels/utils.ts index e872b82fc..3280a7d1c 100644 --- a/server/routers/hotels/utils.ts +++ b/server/routers/hotels/utils.ts @@ -20,7 +20,7 @@ import { getHotel } from "./query" import type { Country } from "@/types/enums/country" import { PointOfInterestGroupEnum } from "@/types/enums/pointOfInterest" import type { RequestOptionsWithOutBody } from "@/types/fetch" -import type { HotelData } from "@/types/hotel" +import type { HotelDataWithUrl } from "@/types/hotel" import type { CitiesGroupedByCountry, CityLocation, @@ -423,15 +423,15 @@ export async function getHotelIdsByCityIdentifier( serviceToken: string ) { const apiLang = toApiLang(Lang.en) - const cityId = await getCityIdByCityIdentifier(cityIdentifier, serviceToken) + const city = await getCityByCityIdentifier(cityIdentifier, serviceToken) - if (!cityId) { + if (!city) { return [] } const hotelIdsParams = new URLSearchParams({ language: apiLang, - city: cityId, + city: city.id, }) const options: RequestOptionsWithOutBody = { // needs to clear default option as only @@ -444,11 +444,11 @@ export async function getHotelIdsByCityIdentifier( revalidate: env.CACHE_TIME_HOTELS, }, } - const hotelIds = await getHotelIdsByCityId(cityId, options, hotelIdsParams) + const hotelIds = await getHotelIdsByCityId(city.id, options, hotelIdsParams) return hotelIds } -export async function getCityIdByCityIdentifier( +export async function getCityByCityIdentifier( cityIdentifier: string, serviceToken: string ) { @@ -473,23 +473,18 @@ export async function getCityIdByCityIdentifier( return null } - const cityId = locations + const city = locations .filter((loc): loc is CityLocation => loc.type === "cities") - .find((loc) => loc.cityIdentifier === cityIdentifier)?.id + .find((loc) => loc.cityIdentifier === cityIdentifier) - return cityId ?? null + return city ?? null } -export async function getHotelListData( +export async function getHotelsByHotelIds( + hotelIds: string[], lang: Lang, - serviceToken: string, - cityIdentifier: string + serviceToken: string ) { - const hotelIds = await getHotelIdsByCityIdentifier( - cityIdentifier, - serviceToken - ) - const hotels = await Promise.all( hotelIds.map(async (hotelId) => { const [hotelData, url] = await Promise.all([ @@ -504,7 +499,5 @@ export async function getHotelListData( }) ) - return hotels.filter( - (hotel): hotel is HotelData & { url: string | null } => !!hotel - ) + return hotels.filter((hotel): hotel is HotelDataWithUrl => !!hotel) }