diff --git a/components/ContentType/HotelPage/index.tsx b/components/ContentType/HotelPage/index.tsx
index a603b5f55..8a658bbb6 100644
--- a/components/ContentType/HotelPage/index.tsx
+++ b/components/ContentType/HotelPage/index.tsx
@@ -9,7 +9,6 @@ import Breadcrumbs from "@/components/Breadcrumbs"
import SidePeekProvider from "@/components/SidePeeks/SidePeekProvider"
import Alert from "@/components/TempDesignSystem/Alert"
import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton"
-import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import { getRestaurantHeading } from "@/utils/facilityCards"
import { generateHotelSchema } from "@/utils/jsonSchemas"
@@ -49,8 +48,7 @@ import type {
export default async function HotelPage({ hotelId }: HotelPageProps) {
const lang = getLang()
- const [intl, hotelPageData, hotelData] = await Promise.all([
- getIntl(),
+ const [hotelPageData, hotelData] = await Promise.all([
getHotelPage(),
getHotelData({ hotelId, language: lang }),
])
@@ -84,6 +82,7 @@ export default async function HotelPage({ hotelId }: HotelPageProps) {
} = hotelData.data.attributes
const roomCategories = hotelData.included?.rooms || []
const restaurants = hotelData.included?.restaurants || []
+
const images = gallery?.smallerImages
const description = hotelContent.texts.descriptions.medium
@@ -200,6 +199,7 @@ export default async function HotelPage({ hotelId }: HotelPageProps) {
parking={parking}
checkInInformation={hotelFacts.checkin}
accessibility={hotelFacts.hotelInformation.accessibility}
+ restaurants={restaurants}
/>
{roomCategories.map((room) => (
diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json
index 7050f7cb8..a37354cdb 100644
--- a/i18n/dictionaries/da.json
+++ b/i18n/dictionaries/da.json
@@ -295,7 +295,7 @@
"Open language menu": "Åbn sprogmenuen",
"Open menu": "Åbn menuen",
"Open my pages menu": "Åbn mine sider menuen",
- "Opening Hours": "Åbningstider",
+ "Opening hours": "Åbningstider",
"Outdoor": "Udendørs",
"OutdoorPool": "Udendørs pool",
"Overview": "Oversigt",
@@ -549,5 +549,9 @@
"uppercase letter": "stort bogstav",
"{amount} out of {total}": "{amount} ud af {total}",
"{card} ending with {cardno}": "{card} slutter med {cardno}",
- "{difference}{amount} {currency}": "{difference}{amount} {currency}"
+ "{difference}{amount} {currency}": "{difference}{amount} {currency}",
+ "{number} persons": "{number} Personen",
+ "{number} square meters": "{number} Quadratmeter",
+ "{number} to {number} persons": "{lowest} bis {highest} Personen",
+ "{number} to {number} square meters": "{smallest} bis {largest} Quadratmeter"
}
diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json
index f42805b1d..2a31ba6b6 100644
--- a/i18n/dictionaries/de.json
+++ b/i18n/dictionaries/de.json
@@ -294,7 +294,7 @@
"Open language menu": "Sprachmenü öffnen",
"Open menu": "Menü öffnen",
"Open my pages menu": "Meine Seiten Menü öffnen",
- "Opening Hours": "Öffnungszeiten",
+ "Opening hours": "Öffnungszeiten",
"Outdoor": "Im Freien",
"OutdoorPool": "Außenpool",
"Overview": "Übersicht",
@@ -548,5 +548,9 @@
"uppercase letter": "großbuchstabe",
"{amount} out of {total}": "{amount} von {total}",
"{card} ending with {cardno}": "{card} endet mit {cardno}",
- "{difference}{amount} {currency}": "{difference}{amount} {currency}"
+ "{difference}{amount} {currency}": "{difference}{amount} {currency}",
+ "{number} persons": "{number} personer",
+ "{number} square meters": "{number} kvadratmeter",
+ "{number} to {number} persons": "{lowest} til {highest} personer",
+ "{number} to {number} square meters": "{smallest} til {largest} kvadratmeter"
}
diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json
index 782f8c114..1687e4da8 100644
--- a/i18n/dictionaries/en.json
+++ b/i18n/dictionaries/en.json
@@ -318,7 +318,7 @@
"Open language menu": "Open language menu",
"Open menu": "Open menu",
"Open my pages menu": "Open my pages menu",
- "Opening Hours": "Opening Hours",
+ "Opening hours": "Opening hours",
"Outdoor": "Outdoor",
"OutdoorPool": "Outdoor pool",
"Overview": "Overview",
@@ -598,5 +598,9 @@
"uppercase letter": "uppercase letter",
"{amount} out of {total}": "{amount} out of {total}",
"{card} ending with {cardno}": "{card} ending with {cardno}",
- "{difference}{amount} {currency}": "{difference}{amount} {currency}"
+ "{difference}{amount} {currency}": "{difference}{amount} {currency}",
+ "{number} persons": "{number} persons",
+ "{number} square meters": "{number} square meters",
+ "{number} to {number} persons": "{lowest} to {highest} persons",
+ "{number} to {number} square meters": "{smallest} to {largest} square meters"
}
diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json
index 6e20af368..cc5291366 100644
--- a/i18n/dictionaries/fi.json
+++ b/i18n/dictionaries/fi.json
@@ -295,7 +295,7 @@
"Open language menu": "Avaa kielivalikko",
"Open menu": "Avaa valikko",
"Open my pages menu": "Avaa omat sivut -valikko",
- "Opening Hours": "Aukioloajat",
+ "Opening hours": "Aukioloajat",
"Outdoor": "Ulkona",
"OutdoorPool": "Ulkouima-allas",
"Overview": "Yleiskatsaus",
@@ -547,5 +547,9 @@
"uppercase letter": "iso kirjain",
"{amount} out of {total}": "{amount}/{total}",
"{card} ending with {cardno}": "{card} päättyen {cardno}",
- "{difference}{amount} {currency}": "{difference}{amount} {currency}"
+ "{difference}{amount} {currency}": "{difference}{amount} {currency}",
+ "{number} persons": "{number} henkilöä",
+ "{number} square meters": "{number} neliömetriä",
+ "{number} to {number} persons": "{lowest} - {highest} henkilöä",
+ "{number} to {number} square meters": "{smallest} - {largest} neliömetriä"
}
diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json
index 28237b83b..5e6995716 100644
--- a/i18n/dictionaries/no.json
+++ b/i18n/dictionaries/no.json
@@ -294,7 +294,7 @@
"Open language menu": "Åpne språkmenyen",
"Open menu": "Åpne menyen",
"Open my pages menu": "Åpne mine sider menyen",
- "Opening Hours": "Åpningstider",
+ "Opening hours": "Åpningstider",
"Outdoor": "Utendørs",
"OutdoorPool": "Utendørs basseng",
"Overview": "Oversikt",
@@ -547,5 +547,9 @@
"uppercase letter": "stor bokstav",
"{amount} out of {total}": "{amount} av {total}",
"{card} ending with {cardno}": "{card} slutter med {cardno}",
- "{difference}{amount} {currency}": "{difference}{amount} {currency}"
+ "{difference}{amount} {currency}": "{difference}{amount} {currency}",
+ "{number} persons": "{number} personer",
+ "{number} square meters": "{number} kvadratmeter",
+ "{number} to {number} persons": "{lowest} til {highest} personer",
+ "{number} to {number} square meters": "{smallest} til {largest} kvadratmeter"
}
diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json
index d7c9327d7..ccdedebf6 100644
--- a/i18n/dictionaries/sv.json
+++ b/i18n/dictionaries/sv.json
@@ -294,7 +294,7 @@
"Open language menu": "Öppna språkmenyn",
"Open menu": "Öppna menyn",
"Open my pages menu": "Öppna mina sidor menyn",
- "Opening Hours": "Öppettider",
+ "Opening hours": "Öppettider",
"Outdoor": "Utomhus",
"OutdoorPool": "Utomhuspool",
"Overview": "Översikt",
@@ -549,5 +549,9 @@
"uppercase letter": "stor bokstav",
"{amount} out of {total}": "{amount} av {total}",
"{card} ending with {cardno}": "{card} som slutar på {cardno}",
- "{difference}{amount} {currency}": "{difference}{amount} {currency}"
+ "{difference}{amount} {currency}": "{difference}{amount} {currency}",
+ "{number} persons": "{number} personer",
+ "{number} square meters": "{number} kvadratmeter",
+ "{number} to {number} persons": "{lowest} till {highest} personer",
+ "{number} to {number} square meters": "{smallest} till {largest} kvadratmeter"
}
diff --git a/lib/trpc/memoizedRequests/index.ts b/lib/trpc/memoizedRequests/index.ts
index bd9367019..3ab4afd99 100644
--- a/lib/trpc/memoizedRequests/index.ts
+++ b/lib/trpc/memoizedRequests/index.ts
@@ -161,3 +161,12 @@ export const getCurrentRewards = cache(
return serverClient().contentstack.rewards.current()
}
)
+
+export const getMeetingRooms = cache(
+ async function getMemoizedMeetingRooms(input: {
+ hotelId: string
+ language: Lang
+ }) {
+ return serverClient().hotel.meetingRooms(input)
+ }
+)
diff --git a/server/routers/hotels/input.ts b/server/routers/hotels/input.ts
index 17270a2c6..938e78dc4 100644
--- a/server/routers/hotels/input.ts
+++ b/server/routers/hotels/input.ts
@@ -93,3 +93,8 @@ export const getCityCoordinatesInputSchema = z.object({
address: z.string().optional(),
}),
})
+
+export const getMeetingRoomsInputSchema = z.object({
+ hotelId: z.string(),
+ language: z.string(),
+})
diff --git a/server/routers/hotels/output.ts b/server/routers/hotels/output.ts
index 6658378d8..7ba5ef899 100644
--- a/server/routers/hotels/output.ts
+++ b/server/routers/hotels/output.ts
@@ -889,3 +889,49 @@ export const getHotelIdsByCityIdSchema = z
),
})
.transform((data) => data.data.map((hotel) => hotel.id))
+
+export const getMeetingRoomsSchema = z.object({
+ data: z.array(
+ z.object({
+ attributes: z.object({
+ name: z.string(),
+ email: z.string().optional(),
+ phoneNumber: z.string(),
+ size: z.number(),
+ doorWidth: z.number(),
+ doorHeight: z.number(),
+ length: z.number(),
+ width: z.number(),
+ height: z.number(),
+ floorNumber: z.number(),
+ content: z.object({
+ images: z.array(imageSchema),
+ texts: z.object({
+ facilityInformation: z.string().optional(),
+ surroundingInformation: z.string().optional(),
+ descriptions: z.object({
+ short: z.string().optional(),
+ medium: z.string().optional(),
+ }),
+ meetingDescription: z
+ .object({
+ short: z.string().optional(),
+ medium: z.string().optional(),
+ })
+ .optional(),
+ }),
+ }),
+ seatings: z.array(
+ z.object({
+ type: z.string(),
+ capacity: z.number(),
+ })
+ ),
+ lighting: z.string(),
+ sortOrder: z.number().optional(),
+ }),
+ id: z.string(),
+ type: z.string(),
+ })
+ ),
+})
diff --git a/server/routers/hotels/query.ts b/server/routers/hotels/query.ts
index fc6a118ae..b262e730e 100644
--- a/server/routers/hotels/query.ts
+++ b/server/routers/hotels/query.ts
@@ -21,6 +21,7 @@ import {
getHotelDataInputSchema,
getHotelsAvailabilityInputSchema,
getHotelsInput,
+ getMeetingRoomsInputSchema,
getRatesInputSchema,
getRoomPackagesInputSchema,
getRoomsAvailabilityInputSchema,
@@ -31,6 +32,7 @@ import {
breakfastPackagesSchema,
getHotelDataSchema,
getHotelsAvailabilitySchema,
+ getMeetingRoomsSchema,
getRatesSchema,
getRoomPackagesSchema,
getRoomsAvailabilitySchema,
@@ -51,6 +53,9 @@ import {
hotelsAvailabilityCounter,
hotelsAvailabilityFailCounter,
hotelsAvailabilitySuccessCounter,
+ meetingRoomsCounter,
+ meetingRoomsFailCounter,
+ meetingRoomsSuccessCounter,
roomsAvailabilityCounter,
roomsAvailabilityFailCounter,
roomsAvailabilitySuccessCounter,
@@ -1168,4 +1173,82 @@ export const hotelQueryRouter = router({
return location
}),
}),
+ meetingRooms: safeProtectedServiceProcedure
+ .input(getMeetingRoomsInputSchema)
+ .query(async function ({ ctx, input }) {
+ const { hotelId, language } = input
+
+ const params: Record
= {
+ hotelId,
+ language,
+ }
+ const metricsData = { ...params, hotelId: input.hotelId }
+ meetingRoomsCounter.add(1, metricsData)
+ console.info(
+ "api.hotels.meetingRooms start",
+ JSON.stringify({ query: { hotelId, params } })
+ )
+
+ const apiResponse = await api.get(
+ api.endpoints.v1.Hotel.Hotels.meetingRooms(input.hotelId),
+ {
+ cache: undefined,
+ headers: {
+ Authorization: `Bearer ${ctx.serviceToken}`,
+ },
+ next: {
+ revalidate: TWENTYFOUR_HOURS,
+ },
+ },
+ params
+ )
+
+ if (!apiResponse.ok) {
+ const text = await apiResponse.text()
+ meetingRoomsFailCounter.add(1, {
+ ...metricsData,
+ error_type: "http_error",
+ error: JSON.stringify({
+ status: apiResponse.status,
+ statusText: apiResponse.statusText,
+ text,
+ }),
+ })
+ console.error(
+ "api.hotels.meetingRooms error",
+ JSON.stringify({
+ query: { params },
+ error: {
+ status: apiResponse.status,
+ statusText: apiResponse.statusText,
+ text,
+ },
+ })
+ )
+ return null
+ }
+
+ const apiJson = await apiResponse.json()
+ const validatedMeetingRooms = getMeetingRoomsSchema.safeParse(apiJson)
+
+ if (!validatedMeetingRooms.success) {
+ console.error(
+ "api.hotels.meetingRooms validation error",
+ JSON.stringify({
+ query: { params },
+ error: validatedMeetingRooms.error,
+ })
+ )
+ throw badRequestError()
+ }
+ meetingRoomsSuccessCounter.add(1, {
+ hotelId,
+ })
+ console.info(
+ "api.hotels.meetingRooms success",
+ JSON.stringify({ query: { params } })
+ )
+
+ return validatedMeetingRooms.data.data
+ }),
})
diff --git a/server/routers/hotels/telemetry.ts b/server/routers/hotels/telemetry.ts
index 72ea046ca..dc5804792 100644
--- a/server/routers/hotels/telemetry.ts
+++ b/server/routers/hotels/telemetry.ts
@@ -72,3 +72,13 @@ export const getHotelIdsSuccessCounter = meter.createCounter(
export const getHotelIdsFailCounter = meter.createCounter(
"trpc.hotel.hotel-ids.get-fail"
)
+
+export const meetingRoomsCounter = meter.createCounter(
+ "trpc.hotels.meetingRooms"
+)
+export const meetingRoomsSuccessCounter = meter.createCounter(
+ "trpc.hotels.meetingRooms-success"
+)
+export const meetingRoomsFailCounter = meter.createCounter(
+ "trpc.hotels.meetingRooms-fail"
+)
diff --git a/types/components/hotelPage/meetingRooms.ts b/types/components/hotelPage/meetingRooms.ts
new file mode 100644
index 000000000..c49c3b536
--- /dev/null
+++ b/types/components/hotelPage/meetingRooms.ts
@@ -0,0 +1,6 @@
+import type { z } from "zod"
+
+import type { getMeetingRoomsSchema } from "@/server/routers/hotels/output"
+
+export type MeetingRoomData = z.infer
+export type MeetingRooms = MeetingRoomData["data"]
diff --git a/types/components/hotelPage/sidepeek/amenities.ts b/types/components/hotelPage/sidepeek/amenities.ts
index 8ded22722..fb6b1e023 100644
--- a/types/components/hotelPage/sidepeek/amenities.ts
+++ b/types/components/hotelPage/sidepeek/amenities.ts
@@ -1,12 +1,22 @@
-import type { Hotel } from "@/types/hotel"
+import type {
+ Hotel,
+ RestaurantData,
+ RestaurantOpeningHours,
+} from "@/types/hotel"
export type AmenitiesSidePeekProps = {
amenitiesList: Hotel["detailedFacilities"]
parking: Hotel["parking"]
checkInInformation: Hotel["hotelFacts"]["checkin"]
accessibility: Hotel["hotelFacts"]["hotelInformation"]["accessibility"]
+ restaurants: RestaurantData[]
}
export type FilteredAmenitiesProps = {
filteredAmenities: Hotel["detailedFacilities"]
}
+
+export interface BreakfastAmenityProps {
+ openingHours: RestaurantOpeningHours
+ alternateOpeningHours?: RestaurantOpeningHours
+}
diff --git a/types/components/hotelPage/sidepeek/meetingsAndConferences.ts b/types/components/hotelPage/sidepeek/meetingsAndConferences.ts
index 50dc76da0..075307f75 100644
--- a/types/components/hotelPage/sidepeek/meetingsAndConferences.ts
+++ b/types/components/hotelPage/sidepeek/meetingsAndConferences.ts
@@ -3,5 +3,6 @@ import type { Hotel } from "@/types/hotel"
export type MeetingsAndConferencesSidePeekProps = {
meetingFacilities: Hotel["conferencesAndMeetings"]
descriptions: Hotel["hotelContent"]["texts"]["meetingDescription"]
+ hotelId: string
link?: string
}
diff --git a/types/components/hotelPage/sidepeek/openingHours.ts b/types/components/hotelPage/sidepeek/openingHours.ts
new file mode 100644
index 000000000..e9b19eb62
--- /dev/null
+++ b/types/components/hotelPage/sidepeek/openingHours.ts
@@ -0,0 +1,6 @@
+import type { BreakfastAmenityProps } from "./amenities"
+
+export interface OpeningHoursProps extends BreakfastAmenityProps {
+ heading?: string
+ type?: "amenities" | "default"
+}
diff --git a/types/components/hotelPage/sidepeek/restaurantBar.ts b/types/components/hotelPage/sidepeek/restaurantBar.ts
index 3c7806fba..e774325a2 100644
--- a/types/components/hotelPage/sidepeek/restaurantBar.ts
+++ b/types/components/hotelPage/sidepeek/restaurantBar.ts
@@ -1,4 +1,4 @@
-import type { RestaurantData, RestaurantOpeningHours } from "@/types/hotel"
+import type { RestaurantData } from "@/types/hotel"
export enum DaysEnum {
Monday = "monday",
@@ -17,8 +17,3 @@ export interface RestaurantBarSidePeekProps {
export interface RestaurantBarItemProps {
restaurant: RestaurantData
}
-
-export interface RestaurantBarOpeningHoursProps {
- openingHours: RestaurantOpeningHours
- alternateOpeningHours?: RestaurantOpeningHours
-}
diff --git a/utils/facilityCards.ts b/utils/facilityCards.ts
index 8dd934c23..daf1e2219 100644
--- a/utils/facilityCards.ts
+++ b/utils/facilityCards.ts
@@ -31,9 +31,9 @@ export function isFacilityImage(card: FacilityCardType): card is FacilityImage {
function setCardProps(
theme: CardProps["theme"],
- heading: string,
buttonText: string,
href: string,
+ heading: string,
scriptedTopTitle?: string
): FacilityCard {
return {