Merged in feat/SW-1296-hotel-subpages (pull request #1233)
feat(SW-1296): added Subpage for hotel pages and its routing * feat(SW-1296): added Subpage for hotel pages and its routing Approved-by: Fredrik Thorsson
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { parkingSubPage } from "@/constants/routes/hotelSubpages"
|
||||
|
||||
import { OpenInNewIcon } from "@/components/Icons"
|
||||
import AccordionItem from "@/components/TempDesignSystem/Accordion/AccordionItem"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
@@ -6,6 +8,7 @@ import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { getLang } from "@/i18n/serverContext"
|
||||
|
||||
import ParkingList from "./ParkingList"
|
||||
import ParkingPrices from "./ParkingPrices"
|
||||
@@ -20,6 +23,7 @@ export default async function ParkingAmenity({
|
||||
parkingElevatorPitch,
|
||||
hasExtraParkingPage,
|
||||
}: ParkingAmenityProps) {
|
||||
const lang = getLang()
|
||||
const intl = await getIntl()
|
||||
|
||||
return (
|
||||
@@ -85,20 +89,25 @@ export default async function ParkingAmenity({
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{hasExtraParkingPage && (
|
||||
<Button
|
||||
className={styles.parkingPageLink}
|
||||
theme="base"
|
||||
intent="secondary"
|
||||
asChild
|
||||
>
|
||||
{/* TODO: URL Should possibly be something more dynamic */}
|
||||
<Link
|
||||
href={`/${parkingSubPage[lang]}`}
|
||||
color="burgundy"
|
||||
weight="bold"
|
||||
appendToCurrentPath
|
||||
>
|
||||
{intl.formatMessage({ id: "About parking" })}
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{hasExtraParkingPage && (
|
||||
<Button
|
||||
className={styles.parkingPageLink}
|
||||
theme="base"
|
||||
intent="secondary"
|
||||
asChild
|
||||
>
|
||||
{/* TODO: Add URL to separate parking page */}
|
||||
<Link href="#" color="burgundy" weight="bold">
|
||||
{intl.formatMessage({ id: "About parking" })}
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
</AccordionItem>
|
||||
)
|
||||
}
|
||||
|
||||
75
components/ContentType/HotelSubpage/hotelSubpage.module.css
Normal file
75
components/ContentType/HotelSubpage/hotelSubpage.module.css
Normal file
@@ -0,0 +1,75 @@
|
||||
.hotelSubpage {
|
||||
padding-bottom: var(--Spacing-x9);
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: var(--Base-Surface-Subtle-Normal);
|
||||
padding: var(--Spacing-x4) 0;
|
||||
}
|
||||
|
||||
.heroContainer {
|
||||
width: 100%;
|
||||
padding: var(--Spacing-x4) var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.heroContainer img {
|
||||
max-width: var(--max-width-content);
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.contentContainer {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"main"
|
||||
"sidebar";
|
||||
gap: var(--Spacing-x4);
|
||||
align-items: start;
|
||||
width: 100%;
|
||||
padding: var(--Spacing-x4) var(--Spacing-x2) 0;
|
||||
}
|
||||
|
||||
.mainContent {
|
||||
grid-area: main;
|
||||
display: grid;
|
||||
width: 100%;
|
||||
gap: var(--Spacing-x6);
|
||||
margin: 0 auto;
|
||||
max-width: var(--max-width-content);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.contentContainer {
|
||||
padding: var(--Spacing-x4) 0;
|
||||
}
|
||||
|
||||
.heroContainer {
|
||||
padding: var(--Spacing-x4) 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: var(--Spacing-x4) 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1367px) {
|
||||
.heroContainer {
|
||||
padding: var(--Spacing-x4) 0;
|
||||
}
|
||||
|
||||
.contentContainer {
|
||||
grid-template-areas: "main sidebar";
|
||||
grid-template-columns: var(--max-width-text-block) 1fr;
|
||||
gap: var(--Spacing-x9);
|
||||
padding: var(--Spacing-x4) 0 0;
|
||||
max-width: var(--max-width-content);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.mainContent {
|
||||
gap: var(--Spacing-x9);
|
||||
padding: 0;
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
61
components/ContentType/HotelSubpage/index.tsx
Normal file
61
components/ContentType/HotelSubpage/index.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import { notFound } from "next/navigation"
|
||||
|
||||
import { getHotel, getHotelPage } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getLang } from "@/i18n/serverContext"
|
||||
|
||||
import { getSubpageData } from "./utils"
|
||||
|
||||
import styles from "./hotelSubpage.module.css"
|
||||
|
||||
interface HotelSubpageProps {
|
||||
hotelId: string
|
||||
subpage: string
|
||||
}
|
||||
|
||||
export default async function HotelSubpage({
|
||||
hotelId,
|
||||
subpage,
|
||||
}: HotelSubpageProps) {
|
||||
const lang = getLang()
|
||||
const [hotelPageData, hotel] = await Promise.all([
|
||||
getHotelPage(),
|
||||
getHotel({ hotelId, language: lang }),
|
||||
])
|
||||
|
||||
if (!hotel?.hotel || !hotelPageData) {
|
||||
notFound()
|
||||
}
|
||||
const pageData = getSubpageData(subpage, lang, hotel.additionalData)
|
||||
if (!pageData) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
const hotelData = hotel.hotel
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className={styles.hotelSubpage}>
|
||||
<header className={styles.header}>
|
||||
{/* breadcrumbs */}
|
||||
<div className={styles.heroContainer}>{/* hero image */}</div>
|
||||
</header>
|
||||
|
||||
<div className={styles.contentContainer}>
|
||||
<main className={styles.mainContent}>
|
||||
{/* Main content */}
|
||||
<Title level="h1">
|
||||
{subpage} for {hotelData.name}
|
||||
</Title>
|
||||
<Body>{pageData.elevatorPitch}</Body>
|
||||
</main>
|
||||
|
||||
{/* Sidebar */}
|
||||
</div>
|
||||
</section>
|
||||
{/* Tracking */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
17
components/ContentType/HotelSubpage/utils.ts
Normal file
17
components/ContentType/HotelSubpage/utils.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { parkingSubPage } from "@/constants/routes/hotelSubpages"
|
||||
|
||||
import type { HotelData } from "@/types/hotel"
|
||||
import type { Lang } from "@/constants/languages"
|
||||
|
||||
export function getSubpageData(
|
||||
subpage: string,
|
||||
lang: Lang,
|
||||
additionalData: HotelData["additionalData"]
|
||||
) {
|
||||
switch (subpage) {
|
||||
case parkingSubPage[lang]:
|
||||
return additionalData.hotelParking
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ export default function Link({
|
||||
* Decides if the link should include the current search params in the URL
|
||||
*/
|
||||
keepSearchParams,
|
||||
appendToCurrentPath,
|
||||
...props
|
||||
}: LinkProps) {
|
||||
const currentPageSlug = usePathname()
|
||||
@@ -50,11 +51,24 @@ export default function Link({
|
||||
})
|
||||
|
||||
const fullUrl = useMemo(() => {
|
||||
if (!keepSearchParams || !searchParams.size) return href
|
||||
let newPath = href
|
||||
if (appendToCurrentPath) {
|
||||
newPath = `${currentPageSlug}${newPath}`
|
||||
}
|
||||
|
||||
const delimiter = href.includes("?") ? "&" : "?"
|
||||
return `${href}${delimiter}${searchParams}`
|
||||
}, [href, searchParams, keepSearchParams])
|
||||
if (keepSearchParams && searchParams.size) {
|
||||
const delimiter = newPath.includes("?") ? "&" : "?"
|
||||
return `${newPath}${delimiter}${searchParams}`
|
||||
}
|
||||
|
||||
return newPath
|
||||
}, [
|
||||
href,
|
||||
searchParams,
|
||||
keepSearchParams,
|
||||
appendToCurrentPath,
|
||||
currentPageSlug,
|
||||
])
|
||||
|
||||
// TODO: Remove this check (and hook) and only return <Link /> when current web is deleted
|
||||
const isExternal = useCheckIfExternalLink(href)
|
||||
|
||||
@@ -12,4 +12,5 @@ export interface LinkProps
|
||||
trackingId?: string
|
||||
trackingParams?: Record<string, string>
|
||||
keepSearchParams?: boolean
|
||||
appendToCurrentPath?: boolean
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user