From ca2f60253ff6e97e975d1fcd19481a4d84bb9aeb Mon Sep 17 00:00:00 2001 From: Erik Tiekstra Date: Mon, 18 Nov 2024 14:55:24 +0100 Subject: [PATCH] feat(SW-201): Refactoring how we fetch hotel page data --- .../(public)/[contentType]/[uid]/page.tsx | 10 +- components/ContentType/HotelPage/index.tsx | 129 +++++++++------ lib/trpc/memoizedRequests/index.ts | 4 + server/routers/contentstack/metadata/utils.ts | 2 +- server/routers/hotels/query.ts | 149 +----------------- types/components/hotelPage/facilities.ts | 2 +- types/components/hotelPage/hotelPage.ts | 3 + 7 files changed, 99 insertions(+), 200 deletions(-) create mode 100644 types/components/hotelPage/hotelPage.ts diff --git a/app/[lang]/(live)/(public)/[contentType]/[uid]/page.tsx b/app/[lang]/(live)/(public)/[contentType]/[uid]/page.tsx index 215e3aec8..f81aa2edf 100644 --- a/app/[lang]/(live)/(public)/[contentType]/[uid]/page.tsx +++ b/app/[lang]/(live)/(public)/[contentType]/[uid]/page.tsx @@ -3,6 +3,7 @@ import { notFound } from "next/navigation" import { isSignupPage } from "@/constants/routes/signup" import { env } from "@/env/server" +import { getHotelPage } from "@/lib/trpc/memoizedRequests" import HotelPage from "@/components/ContentType/HotelPage" import LoyaltyPage from "@/components/ContentType/LoyaltyPage" @@ -19,7 +20,7 @@ import { export { generateMetadata } from "@/utils/generateMetadata" -export default function ContentTypePage({ +export default async function ContentTypePage({ params, }: PageArgs) { setLang(params.lang) @@ -57,7 +58,12 @@ export default function ContentTypePage({ if (env.HIDE_FOR_NEXT_RELEASE) { return notFound() } - return + const hotelPageData = await getHotelPage() + return hotelPageData ? ( + + ) : ( + notFound() + ) default: const type: never = params.contentType console.error(`Unsupported content type given: ${type}`) diff --git a/components/ContentType/HotelPage/index.tsx b/components/ContentType/HotelPage/index.tsx index 3e4893065..f5acca331 100644 --- a/components/ContentType/HotelPage/index.tsx +++ b/components/ContentType/HotelPage/index.tsx @@ -1,6 +1,8 @@ +import { notFound } from "next/navigation" + import hotelPageParams from "@/constants/routes/hotelPageParams" import { env } from "@/env/server" -import { serverClient } from "@/lib/trpc/server" +import { getHotelData, getHotelPage } from "@/lib/trpc/memoizedRequests" import AccordionSection from "@/components/Blocks/Accordion" import HotelReservationSidePeek from "@/components/HotelReservation/SidePeek" @@ -16,65 +18,96 @@ import MapCard from "./Map/MapCard" import MapWithCardWrapper from "./Map/MapWithCard" import MobileMapToggle from "./Map/MobileMapToggle" import StaticMap from "./Map/StaticMap" +import WellnessAndExerciseSidePeek from "./SidePeeks/WellnessAndExercise" import AmenitiesList from "./AmenitiesList" import Facilities from "./Facilities" import IntroSection from "./IntroSection" import PreviewImages from "./PreviewImages" import { Rooms } from "./Rooms" -import { AboutTheHotelSidePeek, WellnessAndExerciseSidePeek } from "./SidePeeks" +import { AboutTheHotelSidePeek } from "./SidePeeks" import TabNavigation from "./TabNavigation" import styles from "./hotelPage.module.css" +import { FacilityCardTypeEnum } from "@/types/components/hotelPage/facilities" +import { HotelPageProps } from "@/types/components/hotelPage/hotelPage" import { HotelHashValues } from "@/types/components/hotelPage/tabNavigation" +import { Facility } from "@/types/hotel" -export default async function HotelPage() { - const intl = await getIntl() - const lang = getLang() +export default async function HotelPage({ hotelId }: HotelPageProps) { const googleMapsApiKey = env.GOOGLE_STATIC_MAP_KEY const googleMapId = env.GOOGLE_DYNAMIC_MAP_ID - const hotelData = await serverClient().hotel.get() - if (!hotelData) { - return null + const lang = getLang() + const [intl, hotelPageData, hotelData] = await Promise.all([ + getIntl(), + getHotelPage(), + getHotelData({ hotelId, language: lang }), + ]) + + if (!hotelData?.data || !hotelPageData) { + return notFound() } + const { faq, content } = hotelPageData const { - hotelId, - hotelName, - hotelDescriptions, - hotelLocation, - hotelAddress, - hotelRatings, - hotelDetailedFacilities, - hotelImages, - roomCategories, - activitiesCard, + name, + address, pointsOfInterest, - facilities, - faq, - alerts, + gallery, + specialAlerts, + healthAndWellness, + restaurantImages, + conferencesAndMeetings, + hotelContent, + detailedFacilities, healthFacilities, - contact, - socials, - ecoLabels, - } = hotelData + contactInformation, + socialMedia, + hotelFacts, + location, + ratings, + } = hotelData.data.attributes + const roomCategories = + hotelData.included?.filter((item) => item.type === "roomcategories") || [] + const images = gallery?.smallerImages + const description = hotelContent.texts.descriptions.short + const activitiesCard = content?.[0]?.upcoming_activities_card || null + + const facilities: Facility[] = [ + { + ...restaurantImages, + id: FacilityCardTypeEnum.restaurant, + headingText: restaurantImages?.headingText ?? "", + heroImages: restaurantImages?.heroImages ?? [], + }, + { + ...conferencesAndMeetings, + id: FacilityCardTypeEnum.conference, + headingText: conferencesAndMeetings?.headingText ?? "", + heroImages: conferencesAndMeetings?.heroImages ?? [], + }, + { + ...healthAndWellness, + id: FacilityCardTypeEnum.wellness, + headingText: healthAndWellness?.headingText ?? "", + heroImages: healthAndWellness?.heroImages ?? [], + }, + ] const topThreePois = pointsOfInterest.slice(0, 3) const coordinates = { - lat: hotelLocation.latitude, - lng: hotelLocation.longitude, + lat: location.latitude, + lng: location.longitude, } return (
- {hotelImages?.length && ( - - )} + {images?.length && }
@@ -82,18 +115,18 @@ export default async function HotelPage() {
- +
- {alerts.length ? ( + {specialAlerts.length ? (
- {alerts.map((alert) => ( + {specialAlerts.map((alert) => ( ( - GetHotelPage, - { - locale: lang, - uid, - }, - { - cache: "force-cache", - next: { - tags, - }, - } - ) - - if (!response.data) { - throw notFound(response) - } - - const hotelPageData = hotelPageSchema.safeParse(response.data) - if (!hotelPageData.success) { - console.error( - `Failed to validate Hotel Page - (uid: ${uid}, lang: ${lang})` - ) - console.error(hotelPageData.error) - return null - } - - return hotelPageData.data.hotel_page -} - export const getHotelData = cache( async (input: HotelDataInput, serviceToken: string) => { const { hotelId, language, isCardOnlyPayment } = input @@ -273,90 +210,6 @@ export const getHotelData = cache( ) export const hotelQueryRouter = router({ - get: contentStackUidWithServiceProcedure.query(async ({ ctx }) => { - const { lang, uid } = ctx - - const contentstackData = await getContentstackData(lang, uid) - const hotelId = contentstackData?.hotel_page_id - - if (!hotelId) { - throw notFound(`Hotel not found for uid: ${uid}`) - } - - const hotelData = await getHotelData( - { - hotelId, - language: ctx.lang, - }, - ctx.serviceToken - ) - - if (!hotelData) { - throw notFound() - } - - const included = hotelData.included || [] - - const hotelAttributes = hotelData.data.attributes - const images = hotelAttributes.gallery?.smallerImages - const hotelAlerts = hotelAttributes.specialAlerts - - const roomCategories = included - ? included.filter((item) => item.type === "roomcategories") - : [] - - const activities = contentstackData?.content - ? contentstackData?.content[0] - : null - - const facilities: Facility[] = [ - { - ...hotelData.data.attributes.restaurantImages, - id: FacilityCardTypeEnum.restaurant, - headingText: - hotelData?.data.attributes.restaurantImages?.headingText ?? "", - heroImages: - hotelData?.data.attributes.restaurantImages?.heroImages ?? [], - }, - { - ...hotelData.data.attributes.conferencesAndMeetings, - id: FacilityCardTypeEnum.conference, - headingText: - hotelData?.data.attributes.conferencesAndMeetings?.headingText ?? "", - heroImages: - hotelData?.data.attributes.conferencesAndMeetings?.heroImages ?? [], - }, - { - ...hotelData.data.attributes.healthAndWellness, - id: FacilityCardTypeEnum.wellness, - headingText: - hotelData?.data.attributes.healthAndWellness?.headingText ?? "", - heroImages: - hotelData?.data.attributes.healthAndWellness?.heroImages ?? [], - }, - ] - - return { - hotelId, - hotelName: hotelAttributes.name, - hotelDescriptions: hotelAttributes.hotelContent.texts, - hotelLocation: hotelAttributes.location, - hotelAddress: hotelAttributes.address, - hotelRatings: hotelAttributes.ratings, - hotelDetailedFacilities: hotelAttributes.detailedFacilities, - hotelImages: images, - pointsOfInterest: hotelAttributes.pointsOfInterest, - roomCategories, - activitiesCard: activities?.upcoming_activities_card, - facilities, - alerts: hotelAlerts, - faq: contentstackData?.faq, - healthFacilities: hotelAttributes.healthFacilities, - contact: hotelAttributes.contactInformation, - socials: hotelAttributes.socialMedia, - ecoLabels: hotelAttributes.hotelFacts.ecoLabels, - } - }), availability: router({ hotels: serviceProcedure .input(getHotelsAvailabilityInputSchema) diff --git a/types/components/hotelPage/facilities.ts b/types/components/hotelPage/facilities.ts index 333313fe0..eedb4e89e 100644 --- a/types/components/hotelPage/facilities.ts +++ b/types/components/hotelPage/facilities.ts @@ -4,7 +4,7 @@ import type { CardProps } from "@/components/TempDesignSystem/Card/card" export type FacilitiesProps = { facilities: Facility[] - activitiesCard?: ActivityCard + activitiesCard: ActivityCard | null } export type FacilityImage = { diff --git a/types/components/hotelPage/hotelPage.ts b/types/components/hotelPage/hotelPage.ts new file mode 100644 index 000000000..bcbb79d5d --- /dev/null +++ b/types/components/hotelPage/hotelPage.ts @@ -0,0 +1,3 @@ +export interface HotelPageProps { + hotelId: string +}