Files
web/apps/scandic-web/utils/jsonSchemas.ts
Erik Tiekstra f04fe467da feat(SW-3151): Added original to imageSchema and added transform to a more generic image type
Approved-by: Bianca Widstam
Approved-by: Chuma Mcphoy (We Ahead)
Approved-by: Matilda Landström
2025-09-10 08:29:05 +00:00

82 lines
2.2 KiB
TypeScript

import { env } from "@/env/server"
import type { Breadcrumbs } from "@scandic-hotels/trpc/types/breadcrumbs"
import type { HotelData } from "@scandic-hotels/trpc/types/hotel"
import type {
BreadcrumbList,
Hotel as HotelSchema,
ListItem,
WithContext,
} from "schema-dts"
export function generateBreadcrumbsSchema(breadcrumbs: Breadcrumbs) {
const itemListElement: ListItem[] = breadcrumbs.map((item, index) => ({
"@type": "ListItem",
position: index + 1,
name: item.title,
// Only include "item" if "href" exists; otherwise, omit it
...(item.href ? { item: `${env.PUBLIC_URL}${item.href}` } : {}),
}))
const jsonLd: WithContext<BreadcrumbList> = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement,
}
return {
key: "breadcrumbs",
type: "application/ld+json",
jsonLd,
}
}
export function generateHotelSchema(hotelData: HotelData) {
const { hotel, additionalData } = hotelData
const ratings = hotel.ratings?.tripAdvisor
const checkinData = hotel.hotelFacts.checkin
const image =
additionalData.gallery?.heroImages[0] ||
additionalData.gallery?.smallerImages[0]
const facilities = hotel.detailedFacilities
const jsonLd: WithContext<HotelSchema> = {
"@context": "https://schema.org",
"@type": "Hotel",
name: hotel.name,
address: {
"@type": "PostalAddress",
streetAddress: hotel.address.streetAddress,
addressLocality: hotel.address.city,
postalCode: hotel.address.zipCode,
addressCountry: hotel.address.country,
},
checkinTime: checkinData.checkInTime,
checkoutTime: checkinData.checkOutTime,
amenityFeature: facilities.map((facility) => ({
"@type": "LocationFeatureSpecification",
name: facility.name,
})),
}
if (image) {
jsonLd.image = {
"@type": "ImageObject",
url: image.src,
caption: image.title || image.title_En,
}
}
if (ratings && ratings.rating && ratings.numberOfReviews) {
jsonLd.aggregateRating = {
"@type": "AggregateRating",
ratingValue: ratings.rating,
reviewCount: ratings.numberOfReviews,
}
}
return {
type: "application/ld+json",
jsonLd,
}
}