Files
web/components/TempDesignSystem/Link/index.tsx
Michael Zetterberg 6908cee0c5 fix: search params passed to Link overrides current search params
This changes the behavior of Link prop `keepSearchParams`. Previously it got
implicitly merged. Now, any search params in the given `href` prop to Link will
override any current search params available on the current page.

Handle the merging use case (if there is any) in the components that passes the
href to render Link.
2025-02-25 16:07:27 +01:00

127 lines
2.8 KiB
TypeScript

"use client"
import NextLink from "next/link"
import { usePathname, useSearchParams } from "next/navigation"
import { useCallback, useMemo } from "react"
import { useCheckIfExternalLink } from "@/hooks/useCheckIfExternalLink"
import { trackClick } from "@/utils/tracking"
import { linkVariants } from "./variants"
import type { LinkProps } from "./link"
export default function Link({
active,
className,
color,
href,
partialMatch = false,
textDecoration,
size,
scroll = true,
prefetch,
variant,
weight,
trackingId,
trackingParams,
onClick,
/**
* Decides if the link should include the current search params in the URL.
* If the given href also contains search params, they take precedence and
* override any current search params. If you need to merge them, handle that
* in your component that passes the href here.
*/
keepSearchParams,
appendToCurrentPath,
...props
}: LinkProps) {
const currentPageSlug = usePathname()
const searchParams = useSearchParams()
let isActive = active || currentPageSlug === href
if (partialMatch && !isActive) {
isActive = currentPageSlug === href
}
const classNames = linkVariants({
active: isActive,
className,
textDecoration,
color,
size,
weight,
variant,
})
const fullUrl = useMemo(() => {
let newPath = href
if (appendToCurrentPath) {
newPath = `${currentPageSlug}${newPath}`
}
if (keepSearchParams && searchParams.size) {
if (newPath.includes("?")) {
const newPathParts = newPath.split("?")
const newSearchParams = new URLSearchParams(newPathParts[1])
searchParams.forEach((v, k) => {
if (!newSearchParams.has(k)) {
newSearchParams.set(k, v)
}
})
return `${newPathParts[0]}?${newSearchParams}`
}
return `${newPath}?${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)
const trackClickById = useCallback(() => {
if (trackingId) {
trackClick(trackingId, trackingParams)
}
}, [trackingId, trackingParams])
const linkProps = {
href: fullUrl,
className: classNames,
}
return isExternal ? (
<a
{...linkProps}
{...props}
onClick={(e) => {
if (onClick) {
onClick(e)
}
}}
/>
) : (
<NextLink
scroll={scroll}
prefetch={prefetch}
onClick={(e) => {
if (onClick) {
onClick(e)
}
if (trackingId) {
trackClickById()
}
}}
id={trackingId}
{...props}
{...linkProps}
/>
)
}