Merged in fix/metadata-schema (pull request #2893)

fix: Updated metadata schema to handle transformed hotel data

* fix: Updated metadata schema to handle transformed hotel data


Approved-by: Linus Flood
This commit is contained in:
Erik Tiekstra
2025-10-01 11:33:58 +00:00
committed by Linus Flood
parent 57315baf97
commit 4f151b143e
4 changed files with 134 additions and 77 deletions

View File

@@ -21,14 +21,14 @@ function getSubpageDescription(
} }
switch (subpageUrl) { switch (subpageUrl) {
case additionalHotelData.hotelParking.nameInUrl: case additionalHotelData.hotelParking?.nameInUrl:
return additionalHotelData.hotelParking.elevatorPitch return additionalHotelData.hotelParking?.elevatorPitch
case additionalHotelData.healthAndFitness.nameInUrl: case additionalHotelData.healthAndFitness?.nameInUrl:
return additionalHotelData.healthAndFitness.elevatorPitch return additionalHotelData.healthAndFitness?.elevatorPitch
case additionalHotelData.hotelSpecialNeeds.nameInUrl: case additionalHotelData.hotelSpecialNeeds?.nameInUrl:
return additionalHotelData.hotelSpecialNeeds.elevatorPitch return additionalHotelData.hotelSpecialNeeds?.elevatorPitch
case additionalHotelData.meetingRooms.nameInUrl: case additionalHotelData.meetingRooms?.nameInUrl:
return additionalHotelData.meetingRooms.elevatorPitch return additionalHotelData.meetingRooms?.elevatorPitch
default: default:
return null return null
} }
@@ -57,7 +57,7 @@ export async function getHotelPageDescription(data: RawMetadataSchema) {
const location = hotelData.translatedCityName const location = hotelData.translatedCityName
const amenities = hotelData.detailedFacilities const amenities = hotelData.detailedFacilities
if (amenities.length < 4) { if (!amenities || amenities.length < 4) {
return intl.formatMessage( return intl.formatMessage(
{ defaultMessage: "{hotelName} in {location}. Book your stay now!" }, { defaultMessage: "{hotelName} in {location}. Book your stay now!" },
{ hotelName, location } { hotelName, location }

View File

@@ -12,27 +12,28 @@ export function getHotelPageImage(data: RawMetadataSchema) {
(restaurant) => restaurant.nameInUrl === subpageUrl (restaurant) => restaurant.nameInUrl === subpageUrl
) )
const restaurantImage = restaurantSubPage?.content?.images?.[0] const restaurantImage = restaurantSubPage?.content?.images?.[0]
if (restaurantImage) { if (restaurantImage?.src) {
subpageImage = { subpageImage = {
url: restaurantImage.src, url: restaurantImage.src,
alt: restaurantImage.altText || restaurantImage.altText_En || undefined, alt: restaurantImage.altText || restaurantImage.altText_En || undefined,
} }
} else { } else {
switch (subpageUrl) { switch (subpageUrl) {
case additionalHotelData?.hotelParking.nameInUrl: case additionalHotelData?.hotelParking?.nameInUrl:
const parkingImage = additionalHotelData?.parkingImages?.heroImages[0] const parkingImage =
if (parkingImage) { additionalHotelData?.parkingImages?.heroImages?.[0]
if (parkingImage?.src) {
subpageImage = { subpageImage = {
url: parkingImage.src, url: parkingImage.src,
alt: parkingImage.altText || parkingImage.altText_En || undefined, alt: parkingImage.altText || parkingImage.altText_En || undefined,
} }
} }
break break
case additionalHotelData?.healthAndFitness.nameInUrl: case additionalHotelData?.healthAndFitness?.nameInUrl:
const wellnessImage = hotelData.healthFacilities.find( const wellnessImage = hotelData?.healthFacilities?.find(
(fac) => fac.content.images.length (fac) => fac?.content?.images?.length
)?.content.images[0] )?.content?.images[0]
if (wellnessImage) { if (wellnessImage?.src) {
subpageImage = { subpageImage = {
url: wellnessImage.src, url: wellnessImage.src,
alt: alt:
@@ -40,10 +41,10 @@ export function getHotelPageImage(data: RawMetadataSchema) {
} }
} }
break break
case additionalHotelData?.hotelSpecialNeeds.nameInUrl: case additionalHotelData?.hotelSpecialNeeds?.nameInUrl:
const accessibilityImage = const accessibilityImage =
additionalHotelData?.accessibility?.heroImages[0] additionalHotelData?.accessibility?.heroImages?.[0]
if (accessibilityImage) { if (accessibilityImage?.src) {
subpageImage = { subpageImage = {
url: accessibilityImage.src, url: accessibilityImage.src,
alt: alt:
@@ -53,10 +54,10 @@ export function getHotelPageImage(data: RawMetadataSchema) {
} }
} }
break break
case additionalHotelData?.meetingRooms.nameInUrl: case additionalHotelData?.meetingRooms?.nameInUrl:
const meetingImage = const meetingImage =
additionalHotelData?.conferencesAndMeetings?.heroImages[0] additionalHotelData?.conferencesAndMeetings?.heroImages?.[0]
if (meetingImage) { if (meetingImage?.src) {
subpageImage = { subpageImage = {
url: meetingImage.src, url: meetingImage.src,
alt: meetingImage.altText || meetingImage.altText_En || undefined, alt: meetingImage.altText || meetingImage.altText_En || undefined,
@@ -77,7 +78,7 @@ export function getHotelPageImage(data: RawMetadataSchema) {
additionalHotelData?.gallery?.heroImages?.[0] || additionalHotelData?.gallery?.heroImages?.[0] ||
additionalHotelData?.gallery?.smallerImages?.[0] additionalHotelData?.gallery?.smallerImages?.[0]
if (hotelImage) { if (hotelImage?.src) {
return { return {
url: hotelImage.src, url: hotelImage.src,
alt: hotelImage.altText || undefined, alt: hotelImage.altText || undefined,

View File

@@ -46,7 +46,7 @@ async function getSubpageTitle(
} }
switch (subpageUrl) { switch (subpageUrl) {
case additionalHotelData.hotelParking.nameInUrl: case additionalHotelData.hotelParking?.nameInUrl:
const parkingTitleLong = intl.formatMessage( const parkingTitleLong = intl.formatMessage(
{ {
defaultMessage: defaultMessage:
@@ -63,7 +63,7 @@ async function getSubpageTitle(
return parkingTitleShort return parkingTitleShort
} }
return parkingTitleLong return parkingTitleLong
case additionalHotelData.healthAndFitness.nameInUrl: case additionalHotelData.healthAndFitness?.nameInUrl:
const wellnessTitleLong = intl.formatMessage( const wellnessTitleLong = intl.formatMessage(
{ {
defaultMessage: defaultMessage:
@@ -80,7 +80,7 @@ async function getSubpageTitle(
return wellnessTitleShort return wellnessTitleShort
} }
return wellnessTitleLong return wellnessTitleLong
case additionalHotelData.hotelSpecialNeeds.nameInUrl: case additionalHotelData.hotelSpecialNeeds?.nameInUrl:
const accessibilityTitleLong = intl.formatMessage( const accessibilityTitleLong = intl.formatMessage(
{ {
defaultMessage: defaultMessage:
@@ -97,7 +97,7 @@ async function getSubpageTitle(
return accessibilityTitleShort return accessibilityTitleShort
} }
return accessibilityTitleLong return accessibilityTitleLong
case additionalHotelData.meetingRooms.nameInUrl: case additionalHotelData.meetingRooms?.nameInUrl:
const meetingsTitleLong = intl.formatMessage( const meetingsTitleLong = intl.formatMessage(
{ {
defaultMessage: defaultMessage:

View File

@@ -7,11 +7,8 @@ import {
import { myStay } from "@scandic-hotels/common/constants/routes/myStay" import { myStay } from "@scandic-hotels/common/constants/routes/myStay"
import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/imageVault" import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/imageVault"
import { attributesSchema as hotelAttributesSchema } from "../../../routers/hotels/schemas/hotel"
import { Country } from "../../../types/country" import { Country } from "../../../types/country"
import { RTETypeEnum } from "../../../types/RTEenums" import { RTETypeEnum } from "../../../types/RTEenums"
import { additionalDataAttributesSchema } from "../../hotels/schemas/hotel/include/additionalData"
import { imageSchema } from "../../hotels/schemas/image"
import { destinationFilterSchema } from "../schemas/destinationFilters" import { destinationFilterSchema } from "../schemas/destinationFilters"
import { systemSchema } from "../schemas/system" import { systemSchema } from "../schemas/system"
@@ -42,15 +39,110 @@ const metaDataBlocksSchema = z
.object({ .object({
json: metaDataJsonSchema, json: metaDataJsonSchema,
}) })
.optional() .nullish(),
.nullable(),
}) })
.optional() .nullish(),
.nullable(),
}) })
) )
.optional() .nullish()
.nullable()
const metaDataImageSchema = z.object({
src: z.string().nullish(),
altText: z.string().nullish(),
altText_En: z.string().nullish(),
})
const metaDataHotelDataSchema = z
.object({
name: z.string(),
detailedFacilities: z
.array(
z.object({
name: z.string(),
})
)
.nullish(),
healthFacilities: z
.array(
z
.object({
content: z
.object({
images: z.array(metaDataImageSchema),
})
.nullish(),
})
.nullish()
)
.nullish(),
translatedCityName: z.string(),
})
.nullish()
const metaDataAdditionalHotelDataSchema = z
.object({
gallery: z
.object({
heroImages: z.array(metaDataImageSchema).nullish(),
smallerImages: z.array(metaDataImageSchema).nullish(),
})
.nullish(),
hotelParking: z
.object({
nameInUrl: z.string().nullish(),
elevatorPitch: z.string().nullish(),
})
.nullish(),
healthAndFitness: z
.object({
nameInUrl: z.string().nullish(),
elevatorPitch: z.string().nullish(),
})
.nullish(),
hotelSpecialNeeds: z
.object({
nameInUrl: z.string().nullish(),
elevatorPitch: z.string().nullish(),
})
.nullish(),
meetingRooms: z
.object({
nameInUrl: z.string().nullish(),
elevatorPitch: z.string().nullish(),
})
.nullish(),
parkingImages: z
.object({
heroImages: z.array(metaDataImageSchema).nullish(),
})
.nullish(),
accessibility: z
.object({
heroImages: z.array(metaDataImageSchema).nullish(),
})
.nullish(),
conferencesAndMeetings: z
.object({
heroImages: z.array(metaDataImageSchema).nullish(),
})
.nullish(),
})
.nullish()
const metaDataHotelRestaurantsSchema = z
.array(
z.object({
nameInUrl: z.string().nullish(),
elevatorPitch: z.string().nullish(),
name: z.string().nullish(),
content: z
.object({
images: z.array(metaDataImageSchema).nullish(),
})
.nullish(),
})
)
.nullish()
export const seoMetadataSchema = z export const seoMetadataSchema = z
.object({ .object({
@@ -120,45 +212,9 @@ export const rawMetadataSchema = z.object({
.string() .string()
.nullish() .nullish()
.transform((id) => id?.trim() || null), .transform((id) => id?.trim() || null),
hotelData: hotelAttributesSchema hotelData: metaDataHotelDataSchema,
.pick({ additionalHotelData: metaDataAdditionalHotelDataSchema,
name: true, hotelRestaurants: metaDataHotelRestaurantsSchema,
detailedFacilities: true,
hotelContent: true,
healthFacilities: true,
})
.merge(
z.object({
translatedCityName: z.string(),
})
)
.nullish(),
additionalHotelData: additionalDataAttributesSchema
.pick({
gallery: true,
hotelParking: true,
healthAndFitness: true,
hotelSpecialNeeds: true,
meetingRooms: true,
parkingImages: true,
accessibility: true,
conferencesAndMeetings: true,
})
.nullish(),
hotelRestaurants: z
.array(
z.object({
nameInUrl: z.string().nullish(),
elevatorPitch: z.string().nullish(),
name: z.string().nullish(),
content: z
.object({
images: z.array(imageSchema).nullish(),
})
.nullish(),
})
)
.nullish(),
subpageUrl: z.string().nullish(), subpageUrl: z.string().nullish(),
destinationData: z destinationData: z
.object({ .object({