feat: Add tab navigation to hotel page

This commit is contained in:
Chuma McPhoy
2024-07-18 00:40:49 +02:00
parent 9b0ee16282
commit ebe79c43e0
14 changed files with 145 additions and 20 deletions

View File

@@ -108,6 +108,7 @@ html,
body {
margin: 0;
padding: 0;
scroll-behavior: smooth;
}
body {

View File

@@ -3,6 +3,7 @@ import { serverClient } from "@/lib/trpc/server"
import AmenitiesList from "./AmenitiesList"
import IntroSection from "./IntroSection"
import { Rooms } from "./Rooms"
import TabNavigation from "./TabNavigation"
import styles from "./hotelPage.module.css"
@@ -23,18 +24,21 @@ export default async function HotelPage({ lang }: LangParams) {
})
return (
<main className={styles.pageContainer}>
<div className={styles.introContainer}>
<IntroSection
hotelName={attributes.name}
hotelDescription={attributes.hotelContent.texts.descriptions.short}
location={attributes.location}
address={attributes.address}
tripAdvisor={attributes.ratings.tripAdvisor}
/>
<AmenitiesList detailedFacilities={attributes.detailedFacilities} />
</div>
<Rooms rooms={roomCategories} />
</main>
<div className={styles.pageContainer}>
<TabNavigation />
<main className={styles.mainSection}>
<div className={styles.introContainer}>
<IntroSection
hotelName={attributes.name}
hotelDescription={attributes.hotelContent.texts.descriptions.short}
location={attributes.location}
address={attributes.address}
tripAdvisor={attributes.ratings.tripAdvisor}
/>
<AmenitiesList detailedFacilities={attributes.detailedFacilities} />
</div>
<Rooms rooms={roomCategories} />
</main>
</div>
)
}

View File

@@ -30,10 +30,10 @@ export async function Rooms({ rooms }: RoomsProps) {
.sort((a, b) => a.sortOrder - b.sortOrder)
.slice(0, 3) //TODO: Remove this and render all rooms once we've implemented "show more" logic in SW-203.
return (
<SectionContainer>
<SectionContainer id="rooms-section">
<SectionHeader
textTransform="uppercase"
title={formatMessage({ id: "hotelPages.rooms.title" })}
title={formatMessage({ id: "Rooms" })}
subtitle={null}
/>
<Grids.Stackable>

View File

@@ -0,0 +1,44 @@
"use client"
import { useIntl } from "react-intl"
import Link from "@/components/TempDesignSystem/Link"
import useHash from "@/hooks/useHash"
import { HotelHashValues } from "./types"
import styles from "./tabNavigation.module.css"
export default function TabNavigation() {
const hash = useHash()
const { formatMessage } = useIntl()
const hotelTabLinks: { href: HotelHashValues; text: string }[] = [
{ href: "#overview", text: "Overview" },
{ href: "#rooms-section", text: "Rooms" },
{ href: "#restaurant-and-bar", text: "Restaurant & Bar" },
{ href: "#meetings-and-conferences", text: "Meetings & Conferences" },
{ href: "#wellness-and-exercise", text: "Wellness & Exercise" },
{ href: "#activities", text: "Activities" },
{ href: "#faq", text: "FAQ" },
]
return (
<nav className={styles.tabsContainer}>
{hotelTabLinks.map((link) => {
const isActive =
hash === link.href || (hash === "" && link.href === "#overview")
console.log("isActive", isActive, "hash", hash, "link.href", link.href)
return (
<Link
key={link.href}
href={link.href}
active={isActive}
variant="tab"
color="burgundy"
textDecoration="none"
>
{formatMessage({ id: link.text })}
</Link>
)
})}
</nav>
)
}

View File

@@ -0,0 +1,11 @@
.tabsContainer {
display: flex;
overflow-x: auto;
white-space: nowrap;
gap: var(--Spacing-x4);
background: var(--Base-Surface-Subtle-Normal);
justify-content: flex-start;
padding-left: var(--Spacing-x4);
padding-right: var(--Spacing-x3);
border-bottom: 1px solid var(--Base-Border-Subtle);
}

View File

@@ -0,0 +1,8 @@
export type HotelHashValues =
| "#overview"
| "#rooms-section"
| "#restaurant-and-bar"
| "#meetings-and-conferences"
| "#wellness-and-exercise"
| "#activities"
| "#faq"

View File

@@ -1,4 +1,13 @@
.pageContainer {
overflow-x: auto;
}
.pageContainer > * {
padding-left: var(--Spacing-x4);
padding-right: var(--Spacing-x3);
}
.mainSection {
display: grid;
gap: var(--Spacing-x9);
padding: var(--Spacing-x5) var(--Spacing-x3) var(--Spacing-x4);
@@ -11,9 +20,14 @@
}
@media screen and (min-width: 1367px) {
.pageContainer {
.pageContainer > *:not(nav) {
padding: var(--Spacing-x9) var(--Spacing-x5);
}
.pageContainer > nav {
padding-left: var(--Spacing-x5);
padding-right: var(--Spacing-x5);
}
.introContainer {
display: grid;
/* use justify-content: space between once we have the map component*/

View File

@@ -8,7 +8,7 @@ import styles from "./breadcrumbs.module.css"
export default async function Breadcrumbs() {
const breadcrumbs = await serverClient().contentstack.breadcrumbs.get()
if (!breadcrumbs) {
if (!breadcrumbs || breadcrumbs.length === 0) {
return null
}
const homeBreadcrumb = breadcrumbs.shift()

View File

@@ -10,6 +10,7 @@ import { linkVariants } from "./variants"
import type { LinkProps } from "./link"
export default function Link({
active,
className,
color,
href,
@@ -23,10 +24,12 @@ export default function Link({
...props
}: LinkProps) {
const currentPageSlug = usePathname()
let isActive = currentPageSlug === href
let isActive = active || currentPageSlug === href
if (partialMatch && !isActive) {
isActive = currentPageSlug === href
}
const classNames = linkVariants({
active: isActive,
className,

View File

@@ -93,6 +93,17 @@
background-color: var(--Scandic-Peach-20);
}
.tab {
font-family: var(--typography-Body-Regular-fontFamily);
padding: var(--Spacing-x2) var(--Spacing-x0);
color: var(--Base-Text-High-contrast);
text-decoration: none;
}
.tab.active {
border-bottom: 2px solid var(--Scandic-Brand-Burgundy);
}
.black {
color: #000;
}

View File

@@ -31,6 +31,7 @@ export const linkVariants = cva(styles.link, {
myPageMobileDropdown: styles.myPageMobileDropdown,
shortcut: styles.shortcut,
sidebar: styles.sidebar,
tab: styles.tab,
},
},
defaultVariants: {

22
hooks/useHash.tsx Normal file
View File

@@ -0,0 +1,22 @@
"use client"
import { useParams } from "next/navigation"
import { useEffect, useState } from "react"
const getHash = () =>
typeof window !== "undefined" ? window.location.hash : undefined
const useHash = () => {
const [isClient, setIsClient] = useState(false)
const [hash, setHash] = useState(getHash())
const params = useParams()
useEffect(() => {
setIsClient(true)
setHash(getHash())
}, [params])
return isClient ? hash : null
}
export default useHash

View File

@@ -1,5 +1,6 @@
{
"A photo of the room": "A photo of the room",
"Activities": "Activities",
"Add new card": "Add new card",
"Address": "Address",
"All our beds are from Bliss, allowing you to adjust the firmness for your perfect comfort.": "All our beds are from Bliss, allowing you to adjust the firmness for your perfect comfort.",
@@ -44,12 +45,12 @@
"Email": "Email",
"There are no transactions to display": "There are no transactions to display",
"Explore all levels and benefits": "Explore all levels and benefits",
"FAQ": "FAQ",
"Find booking": "Find booking",
"Flexibility": "Flexibility",
"From": "From",
"Get inspired": "Get inspired",
"Go back to overview": "Go back to overview",
"hotelPages.rooms.title": "Rooms",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "persons",
"hotelPages.rooms.roomCard.seeRoomDetails": "See room details",
@@ -63,6 +64,7 @@
"Log in": "Log in",
"Log in here": "Log in here",
"Log out": "Log out",
"Meetings & Conferences": "Meetings & Conferences",
"Members": "Members",
"Membership cards": "Membership cards",
"Membership ID": "Membership ID",
@@ -85,6 +87,7 @@
"On your journey": "On your journey",
"Open": "Open",
"or": "or",
"Overview": "Overview",
"Password": "Password",
"Phone": "Phone",
"Phone is required": "Phone is required",
@@ -98,7 +101,9 @@
"Previous victories": "Previous victories",
"Read more": "Read more",
"Read more about the hotel": "Read more about the hotel",
"Restaurant & Bar": "Restaurant & Bar",
"Retype new password": "Retype new password",
"Rooms": "Rooms",
"Save": "Save",
"Select a country": "Select a country",
"Select country of residence": "Select country of residence",
@@ -121,6 +126,7 @@
"Welcome": "Welcome",
"Visiting address": "Visiting address",
"Welcome to": "Welcome to",
"Wellness & Exercise": "Wellness & Exercise",
"Where should you go next?": "Where should you go next?",
"Which room class suits you the best?": "Which room class suits you the best?",
"Year": "Year",

View File

@@ -51,7 +51,6 @@
"Highest level": "Högsta nivå",
"How do you want to sleep?": "Hur vill du sova?",
"How it works": "Hur det fungerar",
"hotelPages.rooms.title": "Rum",
"hotelPages.rooms.roomCard.person": "person",
"hotelPages.rooms.roomCard.persons": "personer",
"hotelPages.rooms.roomCard.seeRoomDetails": "Se rumsdetaljer",
@@ -98,6 +97,7 @@
"Read more": "Läs mer",
"Read more about the hotel": "Läs mer om hotellet",
"Retype new password": "Upprepa nytt lösenord",
"Rooms": "Rum",
"Save": "Spara",
"Select a country": "Välj ett land",
"Select country of residence": "Välj bosättningsland",