fix(SW-2754): Fixed issue where server rendered html included faulty links

Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-05-16 06:21:09 +00:00
parent 4f8483305d
commit 2401615caa
12 changed files with 67 additions and 78 deletions

View File

@@ -1,8 +1,7 @@
"use client"
import Link from "next/link"
import { usePathname } from "next/navigation"
import { type ComponentProps, type PropsWithChildren, useMemo } from "react"
import { type ComponentProps, type PropsWithChildren } from "react"
import { trackClick } from "@/utils/tracking"
@@ -16,7 +15,6 @@ export interface ButtonLinkProps
VariantProps<typeof variants> {
trackingId?: string
trackingParams?: Record<string, string>
appendToCurrentPath?: boolean
}
export default function ButtonLink({
@@ -31,10 +29,8 @@ export default function ButtonLink({
onClick = () => {},
trackingId,
trackingParams,
appendToCurrentPath,
...props
}: ButtonLinkProps) {
const currentPageSlug = usePathname()
const classNames = variants({
variant,
color,
@@ -44,19 +40,10 @@ export default function ButtonLink({
className,
})
const fullUrl = useMemo(() => {
let newPath = href
if (appendToCurrentPath) {
newPath = `${currentPageSlug}${newPath}`
}
return newPath
}, [href, appendToCurrentPath, currentPageSlug])
return (
<Link
className={classNames}
href={fullUrl}
href={href}
target={target}
onClick={(e) => {
onClick(e)

View File

@@ -6,6 +6,7 @@ import AdditionalAmenities from "@/components/SidePeeks/AmenitiesSidepeekContent
import Accordion from "@/components/TempDesignSystem/Accordion"
import SidePeek from "@/components/TempDesignSystem/SidePeek"
import { getIntl } from "@/i18n"
import { appendSlugToPathname } from "@/utils/appendSlugToPathname"
import { SidepeekSlugs } from "@/types/components/hotelPage/hotelPage"
import type { AmenitiesSidePeekProps } from "@/types/components/hotelPage/sidepeek/amenities"
@@ -20,6 +21,11 @@ export default async function AmenitiesSidePeek({
}: AmenitiesSidePeekProps) {
const intl = await getIntl()
const parkingPageHref = appendSlugToPathname(parking.parkingPageUrl)
const accessibilityPageHref = appendSlugToPathname(
accessibility.accessibilityPageUrl
)
return (
<SidePeek
contentKey={SidepeekSlugs.amenities}
@@ -31,7 +37,7 @@ export default async function AmenitiesSidePeek({
<ParkingAccordionItem
parking={parking.parking}
elevatorPitch={parking.parkingElevatorPitch}
parkingPageUrl={parking.parkingPageUrl}
parkingPageHref={parkingPageHref}
/>
<BreakfastAccordionItem
restaurants={restaurants}
@@ -39,7 +45,7 @@ export default async function AmenitiesSidePeek({
/>
<CheckInCheckOutAccordionItem checkInData={checkInInformation} />
<AccessibilityAccordionItem
accessibilityPageUrl={accessibility.accessibilityPageUrl}
accessibilityPageHref={accessibilityPageHref}
elevatorPitch={accessibility.elevatorPitch}
/>
<AdditionalAmenities amenities={amenitiesList} />

View File

@@ -1,10 +1,10 @@
import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link"
import ButtonLink from "@/components/ButtonLink"
import SidePeek from "@/components/TempDesignSystem/SidePeek"
import Body from "@/components/TempDesignSystem/Text/Body"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import { appendSlugToPathname } from "@/utils/appendSlugToPathname"
import SidePeekImages from "../Images"
import { getConferenceRoomTexts } from "./util"
@@ -23,6 +23,7 @@ export default async function MeetingsAndConferencesSidePeek({
const intl = await getIntl()
const { seatingText, roomText } = await getConferenceRoomTexts(meetingRooms)
const visibleImages = meetingFacilities?.heroImages.slice(0, 2)
const meetingPageHref = appendSlugToPathname(meetingPageUrl)
return (
<SidePeek
@@ -53,22 +54,21 @@ export default async function MeetingsAndConferencesSidePeek({
</Body>
) : null}
{meetingPageUrl && (
{meetingPageHref ? (
<div className={styles.buttonContainer}>
<Button fullWidth theme="base" intent="secondary" asChild>
<Link
href={`/${meetingPageUrl}`}
weight="bold"
color="burgundy"
appendToCurrentPath
>
{intl.formatMessage({
defaultMessage: "Read more",
})}
</Link>
</Button>
<ButtonLink
variant="Secondary"
color="Primary"
size="Medium"
href={meetingPageHref}
typography="Body/Paragraph/mdBold"
>
{intl.formatMessage({
defaultMessage: "Read more",
})}
</ButtonLink>
</div>
)}
) : null}
</div>
</SidePeek>
)

View File

@@ -5,6 +5,7 @@ import ButtonLink from "@/components/ButtonLink"
import OpeningHours from "@/components/OpeningHours"
import Link from "@/components/TempDesignSystem/Link"
import { getIntl } from "@/i18n"
import { appendSlugToPathname } from "@/utils/appendSlugToPathname"
import SidePeekImages from "../../Images"
@@ -27,6 +28,10 @@ export default async function RestaurantBarItem({
} = restaurant
const visibleImages = restaurant.content.images.slice(0, 2)
const restaurantPageHref = restaurantPage
? appendSlugToPathname(restaurant.nameInUrl)
: null
return (
<div className={styles.restaurantBarItem}>
<div className={styles.stickyHeading}>
@@ -87,8 +92,8 @@ export default async function RestaurantBarItem({
</ul>
</div>
) : null}
{/* If (restaurantPage && bookTableUrl && mainBody==empty), link to external restaurant page. */}
{bookTableUrl || restaurantPage ? (
{/* If (restaurantPageHref && bookTableUrl && mainBody==empty), link to external restaurant page. */}
{bookTableUrl || restaurantPageHref ? (
<div className={styles.ctaWrapper}>
{bookTableUrl ? (
<ButtonLink
@@ -101,7 +106,7 @@ export default async function RestaurantBarItem({
trackingId="book a table"
trackingParams={{ restaurantName: name }}
>
{restaurantPage && !mainBody?.length
{restaurantPageHref && !mainBody?.length
? intl.formatMessage({
defaultMessage: "Read more",
})
@@ -110,14 +115,13 @@ export default async function RestaurantBarItem({
})}
</ButtonLink>
) : null}
{restaurantPage && mainBody?.length ? (
{restaurantPageHref && mainBody?.length ? (
<ButtonLink
variant="Secondary"
color="Primary"
size="Medium"
typography="Body/Paragraph/mdBold"
href={`/${restaurant.nameInUrl}`}
appendToCurrentPath
href={restaurantPageHref}
>
{intl.formatMessage(
{

View File

@@ -1,6 +1,7 @@
import ButtonLink from "@/components/ButtonLink"
import SidePeek from "@/components/TempDesignSystem/SidePeek"
import { getIntl } from "@/i18n"
import { appendSlugToPathname } from "@/utils/appendSlugToPathname"
import Facility from "./Facility"
@@ -15,6 +16,7 @@ export default async function WellnessAndExerciseSidePeek({
spaPage,
}: WellnessAndExerciseSidePeekProps) {
const intl = await getIntl()
const wellnessExercisePageHref = appendSlugToPathname(wellnessExercisePageUrl)
return (
<SidePeek
@@ -40,19 +42,18 @@ export default async function WellnessAndExerciseSidePeek({
{spaPage.buttonCTA}
</ButtonLink>
)}
{wellnessExercisePageUrl && (
{wellnessExercisePageHref ? (
<ButtonLink
href={`/${wellnessExercisePageUrl}`}
href={wellnessExercisePageHref}
color="Primary"
variant="Secondary"
typography="Body/Paragraph/mdBold"
appendToCurrentPath
>
{intl.formatMessage({
defaultMessage: "Show Gym & Wellness",
})}
</ButtonLink>
)}
) : null}
</div>
)}
</SidePeek>

View File

@@ -14,11 +14,11 @@ import type { AccessibilityAccordionItemProps } from "@/types/components/sidePee
export default function AccessibilityAccordionItem({
elevatorPitch,
accessibilityPageUrl,
accessibilityPageHref,
}: AccessibilityAccordionItemProps) {
const intl = useIntl()
if (!elevatorPitch && !accessibilityPageUrl) {
if (!elevatorPitch && !accessibilityPageHref) {
return null
}
@@ -36,18 +36,17 @@ export default function AccessibilityAccordionItem({
<Typography variant="Body/Paragraph/mdRegular">
<p>{elevatorPitch}</p>
</Typography>
{accessibilityPageUrl && (
{accessibilityPageHref ? (
<ButtonLink
href={`/${accessibilityPageUrl}`}
href={accessibilityPageHref}
variant="Secondary"
color="Primary"
size="Medium"
typography="Body/Paragraph/mdBold"
appendToCurrentPath
>
{intl.formatMessage({ defaultMessage: "About accessibility" })}
</ButtonLink>
)}
) : null}
</div>
</AccordionItem>
)

View File

@@ -16,7 +16,7 @@ import type { ParkingAccordionItemProps } from "@/types/components/sidePeeks/ame
export default function ParkingAccordionItem({
parking,
elevatorPitch,
parkingPageUrl,
parkingPageHref,
}: ParkingAccordionItemProps) {
const intl = useIntl()
@@ -39,20 +39,19 @@ export default function ParkingAccordionItem({
{parking.map((data) => (
<ParkingInformation key={data.type} parking={data} />
))}
{parkingPageUrl && (
{parkingPageHref ? (
<ButtonLink
href={`/${parkingPageUrl}`}
href={parkingPageHref}
variant="Secondary"
color="Primary"
size="Medium"
typography="Body/Paragraph/mdBold"
appendToCurrentPath
>
{intl.formatMessage({
defaultMessage: "About parking",
})}
</ButtonLink>
)}
) : null}
</div>
</AccordionItem>
)

View File

@@ -32,7 +32,6 @@ export default function Link({
* in your component that passes the href here.
*/
keepSearchParams,
appendToCurrentPath,
...props
}: LinkProps) {
const currentPageSlug = usePathname()
@@ -55,9 +54,6 @@ export default function Link({
const fullUrl = useMemo(() => {
let newPath = href
if (appendToCurrentPath) {
newPath = `${currentPageSlug}${newPath}`
}
if (keepSearchParams && searchParams.size) {
if (newPath.includes("?")) {
@@ -74,13 +70,7 @@ export default function Link({
}
return newPath
}, [
href,
searchParams,
keepSearchParams,
appendToCurrentPath,
currentPageSlug,
])
}, [href, searchParams, keepSearchParams])
// TODO: Remove this check (and hook) and only return <Link /> when current web is deleted
const isExternal = useCheckIfExternalLink(href)

View File

@@ -12,5 +12,4 @@ export interface LinkProps
trackingId?: string
trackingParams?: Record<string, string>
keepSearchParams?: boolean
appendToCurrentPath?: boolean
}

View File

@@ -1,10 +0,0 @@
import type { ButtonPropsSlot } from "@/components/TempDesignSystem/Button/button"
export type ButtonLinkProps = React.PropsWithChildren &
Omit<ButtonPropsSlot, "asChild"> &
Pick<React.AnchorHTMLAttributes<HTMLAnchorElement>, "onClick" | "target"> & {
href: string
trackingId?: string
trackingParams?: Record<string, string>
appendToCurrentPath?: boolean
}

View File

@@ -6,7 +6,7 @@ import type {
} from "@/types/hotel"
export interface ParkingAccordionItemProps {
parkingPageUrl?: string
parkingPageHref?: string | null
parking: Parking[]
elevatorPitch?: string
}
@@ -22,7 +22,7 @@ export interface CheckInCheckOutAccordionItemProps {
export interface AccessibilityAccordionItemProps {
elevatorPitch?: string
accessibilityPageUrl?: string
accessibilityPageHref?: string | null
}
export interface AdditionalAmenitiesProps {

View File

@@ -0,0 +1,14 @@
import { headers } from "next/headers"
import { getLang } from "@/i18n/serverContext"
export function appendSlugToPathname(slug?: string) {
const pathname = headers().get("x-pathname")
const lang = getLang()
if (!pathname || !slug) {
return null
}
return `/${lang}${pathname}/${slug}`
}