Files
web/packages/trpc/lib/routers/contentstack/metadata/output.ts
Hrishikesh Vaipurkar d3368e9b85 Merged in feat/SW-2782-create-sas-branded-header (pull request #2878)
feat(SW-2782): Updated header as per design, added language switcher and user menu

* feat(SW-2782): Updated header as per design, added language switcher and user menu

* feat(SW-2782): Updated UI as per design

* feat(SW-2782): Optimised code with use of Popover and modal from RAC


Approved-by: Anton Gunnarsson
2025-10-06 08:46:26 +00:00

285 lines
7.0 KiB
TypeScript

import { z } from "zod"
import {
type FindMyBookingRoute,
findMyBookingRoutes,
} from "@scandic-hotels/common/constants/routes/findMyBookingRoutes"
import { myStay } from "@scandic-hotels/common/constants/routes/myStay"
import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/imageVault"
import { Country } from "../../../types/country"
import { RTETypeEnum } from "../../../types/RTEenums"
import { destinationFilterSchema } from "../schemas/destinationFilters"
import { systemSchema } from "../schemas/system"
import type {
Lang,
LanguageSwitcherData,
} from "@scandic-hotels/common/constants/language"
import type { ImageVaultAsset } from "@scandic-hotels/common/utils/imageVault"
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,
})
.nullish(),
})
.nullish(),
})
)
.nullish()
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
.object({
title: z.string().nullish(),
description: z.string().nullish(),
noindex: z.boolean().nullish(),
seo_image: transformedImageVaultAssetSchema,
})
.nullish()
export const rawMetadataSchema = z.object({
web: z
.object({
seo_metadata: seoMetadataSchema,
breadcrumbs: z
.object({
title: z.string().nullish(),
})
.nullish(),
})
.nullish(),
destination_settings: z
.object({
city_denmark: z.string().nullish(),
city_finland: z.string().nullish(),
city_germany: z.string().nullish(),
city_poland: z.string().nullish(),
city_norway: z.string().nullish(),
city_sweden: z.string().nullish(),
country: z.nativeEnum(Country).nullish(),
})
.nullish(),
heading: z.string().nullish(),
preamble: z
.union([
z.string(),
z.object({
first_column: z.string(),
}),
])
.transform((preamble) => {
if (typeof preamble === "string") {
return preamble
}
return preamble?.first_column || null
})
.nullish(),
header: z
.object({
heading: z.string().nullish(),
preamble: z.string().nullish(),
hero_image: transformedImageVaultAssetSchema,
})
.nullish(),
hero_image: transformedImageVaultAssetSchema,
images: z
.array(z.object({ image: transformedImageVaultAssetSchema }).nullish())
.transform((images) =>
images
.map((image) => image?.image)
.filter((image): image is ImageVaultAsset => !!image)
)
.nullish(),
blocks: metaDataBlocksSchema,
hotel_page_id: z
.string()
.nullish()
.transform((id) => id?.trim() || null),
hotelData: metaDataHotelDataSchema,
additionalHotelData: metaDataAdditionalHotelDataSchema,
hotelRestaurants: metaDataHotelRestaurantsSchema,
subpageUrl: z.string().nullish(),
destinationData: z
.object({
location: z.string().nullish(),
filter: z.string().nullish(),
filterType: z.enum(["facility", "surroundings"]).nullish(),
hotelCount: z.number().nullish(),
cities: z.array(z.string()).nullish(),
})
.nullish(),
seo_filters: z
.array(
destinationFilterSchema.merge(
z.object({ seo_metadata: seoMetadataSchema })
)
)
.nullish(),
system: systemSchema,
})
export interface RawMetadataSchema extends z.output<typeof rawMetadataSchema> {}
// 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 (isFindMyBookingUrl(pathName)) {
const urls: LanguageSwitcherData = {}
return Object.entries(findMyBookingRoutes).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 } }
}
const baseUrls: LanguageSwitcherData = {
da: { url: "/da/" },
de: { url: "/de/" },
en: { url: "/en/" },
fi: { url: "/fi/" },
no: { url: "/no/" },
sv: { url: "/sv/" },
}
function hotelreservation(lang: Lang) {
return `/${lang}/hotelreservation`
}
function isFindMyBookingUrl(value: string): value is FindMyBookingRoute {
return Object.values(
findMyBookingRoutes as unknown as readonly string[]
).includes(value)
}