reafactor: decouple SidePeek from URL params

This commit is contained in:
Arvid Norlin
2024-08-12 14:30:31 +02:00
parent 68694ef914
commit da36036379
8 changed files with 961 additions and 915 deletions

View File

@@ -1,10 +1,8 @@
import { Lang } from "@/constants/languages"
import { amenities } from "@/constants/routes/hotelPageParams"
import { mapFacilityToIcon } from "@/components/ContentType/HotelPage/data"
import { ChevronRightIcon } from "@/components/Icons"
import Link from "@/components/TempDesignSystem/Link"
import { generateSidePeekLink } from "@/components/TempDesignSystem/SidePeek/data"
import Body from "@/components/TempDesignSystem/Text/Body"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import { getIntl } from "@/i18n"
@@ -12,21 +10,18 @@ import { getIntl } from "@/i18n"
import styles from "./amenitiesList.module.css"
import { HotelData } from "@/types/hotel"
import { getLang } from "@/i18n/serverContext"
export default async function AmenitiesList({
detailedFacilities,
// TODO: remove prop drilling once getLang() is merged
lang,
}: {
detailedFacilities: HotelData["data"]["attributes"]["detailedFacilities"]
lang: Lang
}) {
const { formatMessage } = await getIntl()
const sidePeekLink = generateSidePeekLink(amenities[lang])
const sortedAmenities = detailedFacilities
.sort((a, b) => b.sortOrder - a.sortOrder)
.slice(0, 5)
const lang = getLang()
return (
<section className={styles.amenitiesContainer}>
<Subtitle type="two" color="black">
@@ -43,7 +38,12 @@ export default async function AmenitiesList({
)
})}
</div>
<Link scroll={false} href={sidePeekLink} color="burgundy" variant="icon">
<Link
scroll={false}
href={`?s=${amenities[lang]}`}
color="burgundy"
variant="icon"
>
{formatMessage({ id: "Show all amenities" })}
<ChevronRightIcon />
</Link>

View File

@@ -1,14 +1,11 @@
import { about, amenities } from "@/constants/routes/hotelPageParams"
import { serverClient } from "@/lib/trpc/server"
import { getLang } from "@/i18n/serverContext"
import SidePeek from "@/components/TempDesignSystem/SidePeek"
import SidePeekItem from "@/components/TempDesignSystem/SidePeek/Item"
import { getIntl } from "@/i18n"
import AmenitiesList from "./AmenitiesList"
import IntroSection from "./IntroSection"
import { Rooms } from "./Rooms"
import SidePeeks from "./SidePeeks"
import TabNavigation from "./TabNavigation"
import styles from "./hotelPage.module.css"
@@ -27,8 +24,6 @@ export default async function HotelPage() {
include: ["RoomCategories"],
})
const { formatMessage } = await getIntl()
return (
<div className={styles.pageContainer}>
<TabNavigation />
@@ -41,25 +36,8 @@ export default async function HotelPage() {
address={attributes.address}
tripAdvisor={attributes.ratings.tripAdvisor}
/>
<SidePeek>
<SidePeekItem
contentKey={amenities[lang]}
title={formatMessage({ id: "Amenities" })}
>
{/* TODO: Render amenities as per the design. */}
Read more about the amenities here
</SidePeekItem>
<SidePeekItem
contentKey={about[lang]}
title={formatMessage({ id: "About the hotel" })}
>
Some additional information about the hotel
</SidePeekItem>
</SidePeek>
<AmenitiesList
detailedFacilities={attributes.detailedFacilities}
lang={lang}
/>
<SidePeeks />
<AmenitiesList detailedFacilities={attributes.detailedFacilities} />
</div>
<Rooms rooms={roomCategories} />
</main>

View File

@@ -3,7 +3,6 @@ import { about } from "@/constants/routes/hotelPageParams"
import ArrowRight from "@/components/Icons/ArrowRight"
import TripAdvisorIcon from "@/components/Icons/TripAdvisor"
import Link from "@/components/TempDesignSystem/Link"
import { generateSidePeekLink } from "@/components/TempDesignSystem/SidePeek/data"
import BiroScript from "@/components/TempDesignSystem/Text/BiroScript"
import Body from "@/components/TempDesignSystem/Text/Body"
import Preamble from "@/components/TempDesignSystem/Text/Preamble"
@@ -35,7 +34,6 @@ export default async function IntroSection({
{ id: "Tripadvisor reviews" },
{ rating: tripAdvisor.rating, count: tripAdvisor.numberOfReviews }
)
const aboutTheHotelLink = generateSidePeekLink(about[lang])
return (
<section className={styles.introSection}>
@@ -66,7 +64,7 @@ export default async function IntroSection({
color="peach80"
textDecoration="underline"
variant="icon"
href={aboutTheHotelLink}
href={`?s=${about[lang]}`}
>
{formatMessage({ id: "Read more about the hotel" })}
<ArrowRight color="peach80" />

View File

@@ -0,0 +1,63 @@
"use client"
import { usePathname, useRouter, useSearchParams } from "next/navigation"
import { useEffect, useState } from "react"
import { useIntl } from "react-intl"
import { about, amenities } from "@/constants/routes/hotelPageParams"
import SidePeek from "@/components/TempDesignSystem/SidePeek"
import SidePeekItem from "@/components/TempDesignSystem/SidePeek/Item"
import { SidePeekContentKey } from "@/components/TempDesignSystem/SidePeek/types"
import useLang from "@/hooks/useLang"
function SidePeekContainer() {
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
const [activeSidePeek, setActiveSidePeek] =
useState<SidePeekContentKey | null>(() => {
const sidePeekParam = searchParams.get("s") as SidePeekContentKey | null
return sidePeekParam || null
})
const { formatMessage } = useIntl()
const lang = useLang()
useEffect(() => {
const sidePeekParam = searchParams.get("s") as SidePeekContentKey | null
if (sidePeekParam !== activeSidePeek) {
setActiveSidePeek(sidePeekParam)
}
}, [searchParams, activeSidePeek])
function handleClose(isOpen: boolean) {
if (!isOpen) {
setActiveSidePeek(null)
const nextSearchParams = new URLSearchParams(searchParams.toString())
nextSearchParams.delete("s")
router.push(`${pathname}?${nextSearchParams}`, { scroll: false })
}
}
return (
<SidePeek handleClose={handleClose} activeSidePeek={activeSidePeek}>
<SidePeekItem
contentKey={amenities[lang]}
title={formatMessage({ id: "Amenities" })}
>
{/* TODO: Render amenities as per the design. */}
Read more about the amenities here
</SidePeekItem>
<SidePeekItem
contentKey={about[lang]}
title={formatMessage({ id: "About the hotel" })}
>
Some additional information about the hotel
</SidePeekItem>
</SidePeek>
)
}
export default SidePeekContainer

View File

@@ -1,6 +0,0 @@
import { SidePeekContentKey } from "./types"
export const generateSidePeekLink = (key: SidePeekContentKey) => {
// what should the parameter be named to make sense in all use cases/languages? single caracter? like`s=`?
return `?open=${key}`
}

View File

@@ -1,8 +1,7 @@
"use client"
import { useIsSSR } from "@react-aria/ssr"
import { usePathname, useRouter, useSearchParams } from "next/navigation"
import React, { Children, cloneElement, useEffect, useState } from "react"
import React, { Children, cloneElement } from "react"
import {
Dialog,
DialogTrigger,
@@ -14,39 +13,13 @@ import { SidePeekContentKey } from "@/components/TempDesignSystem/SidePeek/types
import styles from "./sidePeek.module.css"
function SidePeek({ children }: React.PropsWithChildren) {
// TODO: to make this more reusable,
// should the param logic be moved up/out so this component can be
// controlled by e.g. URL segments
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
const [activeSidePeek, setActiveSidePeek] =
useState<SidePeekContentKey | null>(() => {
const sidePeekParam = searchParams.get(
"open"
) as SidePeekContentKey | null
return sidePeekParam || null
})
useEffect(() => {
const sidePeekParam = searchParams.get("open") as SidePeekContentKey | null
if (sidePeekParam !== activeSidePeek) {
setActiveSidePeek(sidePeekParam)
}
}, [searchParams, activeSidePeek])
function handleClose(isOpen: boolean) {
if (!isOpen) {
setActiveSidePeek(null)
const nextSearchParams = new URLSearchParams(searchParams.toString())
nextSearchParams.delete("open")
router.push(`${pathname}?${nextSearchParams}`, { scroll: false })
}
}
import type { SidePeekProps } from "./sidePeek"
function SidePeek({
children,
handleClose,
activeSidePeek,
}: React.PropsWithChildren<SidePeekProps>) {
const sidePeekChildren = Children.map(children, (child) => {
if (!React.isValidElement(child)) {
return child
@@ -77,4 +50,4 @@ function SidePeek({ children }: React.PropsWithChildren) {
)
}
export default SidePeek
export default SidePeek

View File

@@ -0,0 +1,4 @@
export interface SidePeekProps {
handleClose: (isOpen: boolean) => void
activeSidePeek: string | null
}

1712
package-lock.json generated

File diff suppressed because it is too large Load Diff