import { z } from "zod" import { baseUrls } from "@/constants/routes/baseUrls" import { findMyBooking } from "@/constants/routes/findMyBooking" import { hotelreservation } from "@/constants/routes/hotelReservation" import { myStay } from "@/constants/routes/myStay" import { env } from "@/env/server" import { attributesSchema as hotelAttributesSchema } from "../../hotels/schemas/hotel" import { additionalDataAttributesSchema } from "../../hotels/schemas/hotel/include/additionalData" import { imageSchema } from "../../hotels/schemas/image" import { tempImageVaultAssetSchema } from "../schemas/imageVault" import { systemSchema } from "../schemas/system" import { getDescription, getImage, getTitle } from "./utils" import type { Metadata } from "next" import { Country } from "@/types/enums/country" import type { LanguageSwitcherData } from "@/types/requests/languageSwitcher" import { RTETypeEnum } from "@/types/rte/enums" import type { Lang } from "@/constants/languages" const metaDataJsonSchema = z.object({ children: z.array( z.object({ type: z.nativeEnum(RTETypeEnum), children: z.array( z.object({ text: z.string().optional(), }) ), }) ), }) const metaDataBlocksSchema = z .array( z.object({ content: z .object({ content: z .object({ json: metaDataJsonSchema, }) .optional() .nullable(), }) .optional() .nullable(), }) ) .optional() .nullable() export const rawMetadataSchema = z.object({ web: z .object({ seo_metadata: z .object({ title: z.string().optional().nullable(), description: z.string().optional().nullable(), noindex: z.boolean().optional().nullable(), seo_image: tempImageVaultAssetSchema.nullable(), }) .optional() .nullable(), breadcrumbs: z .object({ title: z.string().optional().nullable(), }) .optional() .nullable(), }) .optional() .nullable(), destination_settings: z .object({ city_denmark: z.string().optional().nullable(), city_finland: z.string().optional().nullable(), city_germany: z.string().optional().nullable(), city_poland: z.string().optional().nullable(), city_norway: z.string().optional().nullable(), city_sweden: z.string().optional().nullable(), country: z.nativeEnum(Country).optional().nullable(), }) .optional() .nullable(), heading: z.string().optional().nullable(), preamble: z.string().optional().nullable(), header: z .object({ heading: z.string().optional().nullable(), preamble: z.string().optional().nullable(), hero_image: tempImageVaultAssetSchema.nullable(), }) .optional() .nullable(), hero_image: tempImageVaultAssetSchema.nullable(), blocks: metaDataBlocksSchema, hotel_page_id: z.string().optional().nullable(), hotelData: hotelAttributesSchema .pick({ name: true, address: true, hotelContent: true, healthFacilities: true, }) .optional() .nullable(), additionalHotelData: additionalDataAttributesSchema .pick({ gallery: true, hotelParking: true, healthAndFitness: true, hotelSpecialNeeds: true, meetingRooms: true, parkingImages: true, accessibility: true, conferencesAndMeetings: true, }) .optional() .nullable(), hotelRestaurants: z .array( z.object({ nameInUrl: z.string().optional().nullable(), elevatorPitch: z.string().optional().nullable(), name: z.string().optional().nullable(), content: z .object({ images: z.array(imageSchema).optional().nullable(), }) .optional() .nullable(), }) ) .optional() .nullable(), subpageUrl: z.string().optional().nullable(), location: z.string().optional().nullable(), filter: z.string().optional().nullable(), filterType: z.enum(["facility", "surroundings"]).optional().nullable(), system: systemSchema, }) export const metadataSchema = rawMetadataSchema.transform(async (data) => { const noIndex = !!data.web?.seo_metadata?.noindex const metadata: Metadata = { metadataBase: env.PUBLIC_URL ? new URL(env.PUBLIC_URL) : undefined, title: await getTitle(data), description: getDescription(data), openGraph: { images: getImage(data), }, } if (noIndex) { metadata.robots = { index: false, follow: false, } } return metadata }) // Several pages are not currently routed within contentstack context. // This function is used to generate the urls for these pages. export function getNonContentstackUrls(lang: Lang, pathName: string) { if (Object.values(findMyBooking).includes(pathName)) { const urls: LanguageSwitcherData = {} return Object.entries(findMyBooking).reduce((acc, [lang, url]) => { acc[lang as Lang] = { url } return urls }, urls) } if (Object.values(myStay).includes(pathName)) { const urls: LanguageSwitcherData = {} return Object.entries(myStay).reduce((acc, [lang, url]) => { acc[lang as Lang] = { url } return urls }, urls) } if (pathName.startsWith(hotelreservation(lang))) { return baseUrls } return { [lang]: { url: pathName } } }