feat(SW-2863): Move contentstack router to trpc package * Add exports to packages and lint rule to prevent relative imports * Add env to trpc package * Add eslint to trpc package * Apply lint rules * Use direct imports from trpc package * Add lint-staged config to trpc * Move lang enum to common * Restructure trpc package folder structure * WIP first step * update internal imports in trpc * Fix most errors in scandic-web Just 100 left... * Move Props type out of trpc * Fix CategorizedFilters types * Move more schemas in hotel router * Fix deps * fix getNonContentstackUrls * Fix import error * Fix entry error handling * Fix generateMetadata metrics * Fix alertType enum * Fix duplicated types * lint:fix * Merge branch 'master' into feat/sw-2863-move-contentstack-router-to-trpc-package * Fix broken imports * Merge branch 'master' into feat/sw-2863-move-contentstack-router-to-trpc-package Approved-by: Linus Flood
83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
import { env } from "@/env/server"
|
|
|
|
import type {
|
|
BreadcrumbList,
|
|
Hotel as HotelSchema,
|
|
ListItem,
|
|
WithContext,
|
|
} from "schema-dts"
|
|
|
|
import type { HotelData } from "@scandic-hotels/trpc/types/hotel"
|
|
import type { Breadcrumbs } from "@scandic-hotels/trpc/types/breadcrumbs"
|
|
|
|
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.imageSizes.small,
|
|
caption: image.metaData.title,
|
|
}
|
|
}
|
|
|
|
if (ratings && ratings.rating && ratings.numberOfReviews) {
|
|
jsonLd.aggregateRating = {
|
|
"@type": "AggregateRating",
|
|
ratingValue: ratings.rating,
|
|
reviewCount: ratings.numberOfReviews,
|
|
}
|
|
}
|
|
|
|
return {
|
|
type: "application/ld+json",
|
|
jsonLd,
|
|
}
|
|
}
|