diff --git a/apps/scandic-web/components/Blocks/Accordion/index.tsx b/apps/scandic-web/components/Blocks/Accordion/index.tsx
index e617293f9..fd0166058 100644
--- a/apps/scandic-web/components/Blocks/Accordion/index.tsx
+++ b/apps/scandic-web/components/Blocks/Accordion/index.tsx
@@ -12,7 +12,7 @@ import ShowMoreButton from "@/components/TempDesignSystem/ShowMoreButton"
import styles from "./accordion.module.css"
import type { AccordionProps } from "@/types/components/blocks/Accordion"
-import { HotelHashValues } from "@/types/components/hotelPage/tabNavigation"
+import { HotelHashValues } from "@/types/enums/hotelPage"
export default function AccordionSection({ accordion, title }: AccordionProps) {
const showToggleButton = accordion.length > 5
diff --git a/apps/scandic-web/components/ContentType/HotelPage/Facilities/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/Facilities/index.tsx
index a897cbd20..51facb18e 100644
--- a/apps/scandic-web/components/ContentType/HotelPage/Facilities/index.tsx
+++ b/apps/scandic-web/components/ContentType/HotelPage/Facilities/index.tsx
@@ -13,7 +13,7 @@ import {
type FacilityCardType,
type FacilityGrid,
} from "@/types/components/hotelPage/facilities"
-import { HotelHashValues } from "@/types/components/hotelPage/tabNavigation"
+import { HotelHashValues } from "@/types/enums/hotelPage"
export default async function Facilities({
facilities,
diff --git a/apps/scandic-web/components/ContentType/HotelPage/Rooms/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/Rooms/index.tsx
index 5fe01eee8..0b15642bf 100644
--- a/apps/scandic-web/components/ContentType/HotelPage/Rooms/index.tsx
+++ b/apps/scandic-web/components/ContentType/HotelPage/Rooms/index.tsx
@@ -2,7 +2,6 @@
import { cx } from "class-variance-authority"
import { useMemo, useRef, useState } from "react"
-import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
@@ -14,10 +13,9 @@ import { RoomCard } from "./RoomCard"
import styles from "./rooms.module.css"
import type { RoomsProps } from "@/types/components/hotelPage/room"
-import { HotelHashValues } from "@/types/components/hotelPage/tabNavigation"
+import { HotelHashValues } from "@/types/enums/hotelPage"
-export function Rooms({ rooms, preamble }: RoomsProps) {
- const intl = useIntl()
+export function Rooms({ heading, rooms, preamble }: RoomsProps) {
const showToggleButton = rooms.length > 3
const [allRoomsVisible, setAllRoomsVisible] = useState(!showToggleButton)
const sortedRooms = useMemo(() => {
@@ -40,12 +38,8 @@ export function Rooms({ rooms, preamble }: RoomsProps) {
>
-
-
- {intl.formatMessage({
- defaultMessage: "Rooms",
- })}
-
+
+ {heading}
{preamble && (
diff --git a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/MeetingsAndConferences/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/MeetingsAndConferences/index.tsx
index 14365f3f5..8d23c5657 100644
--- a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/MeetingsAndConferences/index.tsx
+++ b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/MeetingsAndConferences/index.tsx
@@ -19,6 +19,7 @@ export default async function MeetingsAndConferencesSidePeek({
descriptions,
meetingRooms,
meetingPageUrl,
+ heading,
}: MeetingsAndConferencesSidePeekProps) {
const intl = await getIntl()
const { seatingText, roomText } = await getConferenceRoomTexts(meetingRooms)
@@ -26,12 +27,7 @@ export default async function MeetingsAndConferencesSidePeek({
const meetingPageHref = await appendSlugToPathname(meetingPageUrl)
return (
-
+
diff --git a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/RestaurantBar/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/RestaurantBar/index.tsx
index 3d9646a59..a2ae9b6bd 100644
--- a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/RestaurantBar/index.tsx
+++ b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/RestaurantBar/index.tsx
@@ -1,5 +1,4 @@
import SidePeek from "@/components/TempDesignSystem/SidePeek"
-import { getIntl } from "@/i18n"
import RestaurantBarItem from "./RestaurantBarItem"
@@ -8,18 +7,12 @@ import styles from "./restaurantBar.module.css"
import { SidepeekSlugs } from "@/types/components/hotelPage/hotelPage"
import type { RestaurantBarSidePeekProps } from "@/types/components/hotelPage/sidepeek/restaurantBar"
-export default async function RestaurantBarSidePeek({
+export default function RestaurantBarSidePeek({
restaurants,
+ heading,
}: RestaurantBarSidePeekProps) {
- const intl = await getIntl()
-
return (
-
+
{restaurants.map((restaurant) => (
diff --git a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/WellnessAndExercise/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/WellnessAndExercise/index.tsx
index 28f97cc94..d75fe2c5c 100644
--- a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/WellnessAndExercise/index.tsx
+++ b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/WellnessAndExercise/index.tsx
@@ -14,6 +14,7 @@ export default async function WellnessAndExerciseSidePeek({
healthFacilities,
wellnessExercisePageUrl,
spaPage,
+ heading,
}: WellnessAndExerciseSidePeekProps) {
const intl = await getIntl()
const wellnessExercisePageHref = await appendSlugToPathname(
@@ -21,12 +22,7 @@ export default async function WellnessAndExerciseSidePeek({
)
return (
-
+
{healthFacilities.map((facility) => (
diff --git a/apps/scandic-web/components/ContentType/HotelPage/TabNavigation/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/TabNavigation/index.tsx
index 146d33813..47c3172a0 100644
--- a/apps/scandic-web/components/ContentType/HotelPage/TabNavigation/index.tsx
+++ b/apps/scandic-web/components/ContentType/HotelPage/TabNavigation/index.tsx
@@ -4,7 +4,6 @@ import { cx } from "class-variance-authority"
import NextLink from "next/link"
import { useRouter } from "next/navigation"
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from "react"
-import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
@@ -18,24 +17,19 @@ import { trackHotelTabClick } from "@/utils/tracking"
import styles from "./tabNavigation.module.css"
-import {
- HotelHashValues,
- type TabNavigationProps,
-} from "@/types/components/hotelPage/tabNavigation"
+import type { HotelPageSections } from "@/types/components/hotelPage/sections"
+import { HotelHashValues } from "@/types/enums/hotelPage"
-export default function TabNavigation({
- hasActivities,
- hasFAQ,
- hasMeetingRooms,
- hasRestaurants,
- hasWellness,
- tabValues,
-}: TabNavigationProps) {
- const hash = useHash()
- const intl = useIntl()
+interface TabNavigationProps {
+ pageSections: HotelPageSections
+}
+
+export default function TabNavigation({ pageSections }: TabNavigationProps) {
+ const activeHash = useHash()
const router = useRouter()
const tabNavigationRef = useRef
(null)
const tabRefs = useMemo(() => new Map(), [])
+ const tabLinks = Object.values(pageSections).map(({ hash }) => hash)
useStickyPosition({
ref: tabNavigationRef,
@@ -46,88 +40,7 @@ export default function TabNavigation({
const { containerRef, showLeftShadow, showRightShadow } =
useScrollShadows()
- const tabLinks: { hash: HotelHashValues; text: string }[] = [
- {
- hash: HotelHashValues.overview,
- text:
- tabValues?.overview ||
- intl.formatMessage({
- defaultMessage: "Overview",
- }),
- },
- {
- hash: HotelHashValues.rooms,
- text:
- tabValues?.rooms ||
- intl.formatMessage({
- defaultMessage: "Rooms",
- }),
- },
- ...(hasRestaurants
- ? [
- {
- hash: HotelHashValues.restaurant,
- text:
- tabValues?.restaurant_bar ||
- intl.formatMessage({
- defaultMessage: "Restaurant & Bar",
- }),
- },
- ]
- : []),
- ...(hasMeetingRooms
- ? [
- {
- hash: HotelHashValues.meetings,
- text:
- tabValues?.conferences_meetings ||
- intl.formatMessage({
- defaultMessage: "Meetings & Conferences",
- }),
- },
- ]
- : []),
- ...(hasWellness
- ? [
- {
- hash: HotelHashValues.wellness,
- text:
- tabValues?.health_wellness ||
- intl.formatMessage({
- defaultMessage: "Gym & Wellness",
- }),
- },
- ]
- : []),
- ...(hasActivities
- ? [
- {
- hash: HotelHashValues.activities,
- text:
- tabValues?.activities ||
- intl.formatMessage({
- defaultMessage: "Activities",
- }),
- },
- ]
- : []),
- ...(hasFAQ
- ? [
- {
- hash: HotelHashValues.faq,
- text:
- tabValues?.faq ||
- intl.formatMessage({
- defaultMessage: "FAQ",
- }),
- },
- ]
- : []),
- ]
-
- const { activeSectionId, pauseScrollSpy } = useScrollSpy(
- tabLinks.map(({ hash }) => hash)
- )
+ const { activeSectionId, pauseScrollSpy } = useScrollSpy(tabLinks)
const scrollLinkToCenter = useCallback(
(hash: string) => {
@@ -160,9 +73,9 @@ export default function TabNavigation({
)
useLayoutEffect(() => {
- const activeHash = hash || HotelHashValues.overview
- scrollLinkToCenter(activeHash)
- }, [hash, scrollLinkToCenter])
+ const hash = activeHash || HotelHashValues.overview
+ scrollLinkToCenter(hash)
+ }, [activeHash, scrollLinkToCenter])
useEffect(() => {
if (activeSectionId) {
@@ -179,19 +92,19 @@ export default function TabNavigation({
})}
>
-
+
{facilities && (
-
+
@@ -237,8 +244,9 @@ export default async function HotelPage({ hotelId }: HotelPageProps) {
ecoLabels={hotelFacts.ecoLabels}
descriptions={hotelContent.texts}
/>
- {hasWellness ? (
+ {pageSections.wellness ? (
) : null}
- {hasRestaurants ? (
-
+ {pageSections.restaurant ? (
+
) : null}
{activitiesCards.map((card) => (
))}
- {hasMeetingRooms && (
+ {pageSections.meetings ? (
- )}
+ ) : null}
{roomCategories.map((room) => (
))}
diff --git a/apps/scandic-web/components/ContentType/HotelPage/utils.ts b/apps/scandic-web/components/ContentType/HotelPage/utils.ts
index 718698ba6..4489f3fca 100644
--- a/apps/scandic-web/components/ContentType/HotelPage/utils.ts
+++ b/apps/scandic-web/components/ContentType/HotelPage/utils.ts
@@ -1,11 +1,16 @@
import type { IntlShape } from "react-intl"
import { HealthFacilitiesEnum } from "@/types/components/hotelPage/facilities"
+import type {
+ HotelPageSectionHeadings,
+ HotelPageSections,
+} from "@/types/components/hotelPage/sections"
import {
TrackingChannelEnum,
type TrackingSDKHotelInfo,
type TrackingSDKPageData,
} from "@/types/components/tracking"
+import { HotelHashValues } from "@/types/enums/hotelPage"
import type { Hotel, HotelData } from "@/types/hotel"
import type { HotelPage } from "@/types/trpc/routers/contentstack/hotelPage"
import type { Lang } from "@/constants/languages"
@@ -84,3 +89,94 @@ export function translateWellnessType(type: string, intl: IntlShape) {
})
}
}
+
+export function getPageSectionsData(
+ intl: IntlShape,
+ dynamicSections: {
+ hasWellness: boolean
+ hasRestaurants: boolean
+ hasMeetingRooms: boolean
+ hasActivities: boolean
+ hasFAQ: boolean
+ },
+ sectionHeadings?: HotelPageSectionHeadings | null
+) {
+ const {
+ hasWellness,
+ hasRestaurants,
+ hasMeetingRooms,
+ hasActivities,
+ hasFAQ,
+ } = dynamicSections
+ const sections: HotelPageSections = {
+ overview: {
+ hash: HotelHashValues.overview,
+ heading:
+ sectionHeadings?.overview ||
+ intl.formatMessage({
+ defaultMessage: "Overview",
+ }),
+ },
+ rooms: {
+ hash: HotelHashValues.rooms,
+ heading:
+ sectionHeadings?.rooms ||
+ intl.formatMessage({
+ defaultMessage: "Rooms",
+ }),
+ },
+ }
+
+ if (hasRestaurants) {
+ sections.restaurant = {
+ hash: HotelHashValues.restaurant,
+ heading:
+ sectionHeadings?.restaurant_bar ||
+ intl.formatMessage({
+ defaultMessage: "Restaurant & Bar",
+ }),
+ }
+ }
+ if (hasMeetingRooms) {
+ sections.meetings = {
+ hash: HotelHashValues.meetings,
+ heading:
+ sectionHeadings?.conferences_meetings ||
+ intl.formatMessage({
+ defaultMessage: "Meetings & Conferences",
+ }),
+ }
+ }
+ if (hasWellness) {
+ sections.wellness = {
+ hash: HotelHashValues.wellness,
+ heading:
+ sectionHeadings?.health_wellness ||
+ intl.formatMessage({
+ defaultMessage: "Gym & Wellness",
+ }),
+ }
+ }
+ if (hasActivities) {
+ sections.activities = {
+ hash: HotelHashValues.activities,
+ heading:
+ sectionHeadings?.activities ||
+ intl.formatMessage({
+ defaultMessage: "Activities",
+ }),
+ }
+ }
+ if (hasFAQ) {
+ sections.faq = {
+ hash: HotelHashValues.faq,
+ heading:
+ sectionHeadings?.faq ||
+ intl.formatMessage({
+ defaultMessage: "FAQ",
+ }),
+ }
+ }
+
+ return sections
+}
diff --git a/apps/scandic-web/server/routers/contentstack/hotelPage/output.ts b/apps/scandic-web/server/routers/contentstack/hotelPage/output.ts
index 740e3da00..0669f3b77 100644
--- a/apps/scandic-web/server/routers/contentstack/hotelPage/output.ts
+++ b/apps/scandic-web/server/routers/contentstack/hotelPage/output.ts
@@ -82,7 +82,7 @@ export const hotelPageSchema = z.object({
),
})
.transform(({ hotel_navigation, ...rest }) => ({
- tabValues: hotel_navigation,
+ sectionHeadings: hotel_navigation,
...rest,
})),
})
diff --git a/apps/scandic-web/types/components/hotelPage/hotelPage.ts b/apps/scandic-web/types/components/hotelPage/hotelPage.ts
index cba8c41d4..29ead7fc6 100644
--- a/apps/scandic-web/types/components/hotelPage/hotelPage.ts
+++ b/apps/scandic-web/types/components/hotelPage/hotelPage.ts
@@ -1,3 +1,5 @@
+import type { HotelHashValues } from "@/types/enums/hotelPage"
+
export interface HotelPageProps {
hotelId: string
}
@@ -10,3 +12,6 @@ export enum SidepeekSlugs {
meetings = "meetings",
wellness = "wellness",
}
+
+export type HotelHashValue =
+ (typeof HotelHashValues)[keyof typeof HotelHashValues]
diff --git a/apps/scandic-web/types/components/hotelPage/room.ts b/apps/scandic-web/types/components/hotelPage/room.ts
index 048958f43..0a8a8031c 100644
--- a/apps/scandic-web/types/components/hotelPage/room.ts
+++ b/apps/scandic-web/types/components/hotelPage/room.ts
@@ -5,6 +5,7 @@ export interface RoomCardProps {
}
export type RoomsProps = {
+ heading: string
preamble?: string
rooms: Room[]
}
diff --git a/apps/scandic-web/types/components/hotelPage/sections.ts b/apps/scandic-web/types/components/hotelPage/sections.ts
new file mode 100644
index 000000000..ca959a2c3
--- /dev/null
+++ b/apps/scandic-web/types/components/hotelPage/sections.ts
@@ -0,0 +1,27 @@
+import type { HotelHashValue } from "./hotelPage"
+
+export interface HotelPageSectionHeadings {
+ overview?: string | null
+ rooms?: string | null
+ restaurant_bar?: string | null
+ conferences_meetings?: string | null
+ health_wellness?: string | null
+ activities?: string | null
+ offers?: string | null
+ faq?: string | null
+}
+
+interface HotelPageSection {
+ hash: HotelHashValue
+ heading: string
+}
+
+export interface HotelPageSections {
+ overview: HotelPageSection
+ rooms: HotelPageSection
+ restaurant?: HotelPageSection
+ meetings?: HotelPageSection
+ wellness?: HotelPageSection
+ activities?: HotelPageSection
+ faq?: HotelPageSection
+}
diff --git a/apps/scandic-web/types/components/hotelPage/sidepeek/meetingsAndConferences.ts b/apps/scandic-web/types/components/hotelPage/sidepeek/meetingsAndConferences.ts
index a1a843022..3e681e4a1 100644
--- a/apps/scandic-web/types/components/hotelPage/sidepeek/meetingsAndConferences.ts
+++ b/apps/scandic-web/types/components/hotelPage/sidepeek/meetingsAndConferences.ts
@@ -6,4 +6,5 @@ export type MeetingsAndConferencesSidePeekProps = {
descriptions: Hotel["hotelContent"]["texts"]["meetingDescription"]
meetingRooms: MeetingRooms
meetingPageUrl: string | undefined
+ heading: string
}
diff --git a/apps/scandic-web/types/components/hotelPage/sidepeek/restaurantBar.ts b/apps/scandic-web/types/components/hotelPage/sidepeek/restaurantBar.ts
index 31ab6b4b7..f30200456 100644
--- a/apps/scandic-web/types/components/hotelPage/sidepeek/restaurantBar.ts
+++ b/apps/scandic-web/types/components/hotelPage/sidepeek/restaurantBar.ts
@@ -2,6 +2,7 @@ import type { Restaurant } from "@/types/hotel"
export interface RestaurantBarSidePeekProps {
restaurants: Restaurant[]
+ heading: string
}
export interface RestaurantBarItemProps {
diff --git a/apps/scandic-web/types/components/hotelPage/sidepeek/wellnessAndExercise.ts b/apps/scandic-web/types/components/hotelPage/sidepeek/wellnessAndExercise.ts
index 6897ab864..9d29980e1 100644
--- a/apps/scandic-web/types/components/hotelPage/sidepeek/wellnessAndExercise.ts
+++ b/apps/scandic-web/types/components/hotelPage/sidepeek/wellnessAndExercise.ts
@@ -7,4 +7,5 @@ export type WellnessAndExerciseSidePeekProps = {
buttonCTA: string
url: string
}
+ heading: string
}
diff --git a/apps/scandic-web/types/components/hotelPage/tabNavigation.ts b/apps/scandic-web/types/components/hotelPage/tabNavigation.ts
deleted file mode 100644
index de887691b..000000000
--- a/apps/scandic-web/types/components/hotelPage/tabNavigation.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-export enum HotelHashValues {
- overview = "overview",
- rooms = "rooms",
- restaurant = "restaurants",
- meetings = "meetings",
- wellness = "wellness",
- activities = "activities",
- faq = "faq",
-}
-
-type Tabs = {
- overview?: string | null
- rooms?: string | null
- restaurant_bar?: string | null
- conferences_meetings?: string | null
- health_wellness?: string | null
- activities?: string | null
- offers?: string | null
- faq?: string | null
-}
-
-export type TabNavigationProps = {
- hasActivities: boolean
- hasFAQ: boolean
- hasWellness: boolean
- hasRestaurants: boolean
- hasMeetingRooms: boolean
- tabValues?: Tabs | null
-}
diff --git a/apps/scandic-web/types/enums/hotelPage.ts b/apps/scandic-web/types/enums/hotelPage.ts
index 8cc5f8839..0b1c0260b 100644
--- a/apps/scandic-web/types/enums/hotelPage.ts
+++ b/apps/scandic-web/types/enums/hotelPage.ts
@@ -7,3 +7,13 @@ export namespace HotelPageEnum {
}
}
}
+
+export const HotelHashValues = {
+ overview: "overview",
+ rooms: "rooms",
+ restaurant: "restaurants",
+ meetings: "meetings",
+ wellness: "wellness",
+ activities: "activities",
+ faq: "faq",
+} as const
diff --git a/apps/scandic-web/utils/facilityCards.ts b/apps/scandic-web/utils/facilityCards.ts
index 265db8c3a..c2f3b29cc 100644
--- a/apps/scandic-web/utils/facilityCards.ts
+++ b/apps/scandic-web/utils/facilityCards.ts
@@ -11,9 +11,13 @@ import {
RestaurantHeadings,
WellnessHeadings,
} from "@/types/components/hotelPage/facilities"
-import { SidepeekSlugs } from "@/types/components/hotelPage/hotelPage"
-import { HotelHashValues } from "@/types/components/hotelPage/tabNavigation"
+import {
+ type HotelHashValue,
+ SidepeekSlugs,
+} from "@/types/components/hotelPage/hotelPage";
+import type { HotelPageSections } from "@/types/components/hotelPage/sections"
import { FacilityEnum } from "@/types/enums/facilities"
+import { HotelHashValues } from "@/types/enums/hotelPage"
import type {
Amenities,
Facility,
@@ -26,24 +30,34 @@ export function setFacilityCards(
restaurantImages: FacilityData | undefined,
conferencesAndMeetings: FacilityData | undefined,
healthAndWellness: FacilityData | undefined,
- hasRestaurants: boolean,
- hasMeetingRooms: boolean,
- hasWellness: boolean
+ pageSections: HotelPageSections
): Facility[] {
const facilities = []
- if (hasRestaurants) {
+ if (pageSections.restaurant) {
facilities.push(
- setFacilityCard(restaurantImages, FacilityCardTypeEnum.restaurant)
+ setFacilityCard(
+ restaurantImages,
+ FacilityCardTypeEnum.restaurant,
+ pageSections.restaurant.heading
+ )
)
}
- if (hasMeetingRooms) {
+ if (pageSections.meetings) {
facilities.push(
- setFacilityCard(conferencesAndMeetings, FacilityCardTypeEnum.conference)
+ setFacilityCard(
+ conferencesAndMeetings,
+ FacilityCardTypeEnum.conference,
+ pageSections.meetings.heading
+ )
)
}
- if (hasWellness) {
+ if (pageSections.wellness) {
facilities.push(
- setFacilityCard(healthAndWellness, FacilityCardTypeEnum.wellness)
+ setFacilityCard(
+ healthAndWellness,
+ FacilityCardTypeEnum.wellness,
+ pageSections.wellness.heading
+ )
)
}
return facilities
@@ -51,12 +65,13 @@ export function setFacilityCards(
function setFacilityCard(
facility: FacilityData | undefined,
- type: FacilityCardTypeEnum
+ type: FacilityCardTypeEnum,
+ heading: string
): Facility {
return {
...facility,
id: type,
- headingText: facility?.headingText ?? "",
+ headingText: heading,
heroImages: facility?.heroImages ?? [],
}
}
@@ -72,7 +87,7 @@ export function isFacilityImage(card: FacilityCardType): card is FacilityImage {
function setCardProps(
theme: CardProps["theme"],
buttonText: (typeof FacilityCardButtonText)[keyof typeof FacilityCardButtonText],
- href: HotelHashValues,
+ href: HotelHashValue,
heading: string,
slug: SidepeekSlugs,
scriptedTopTitle?: string