|
| 1 | +"use client"; |
| 2 | +import { UrlObject } from "url"; |
| 3 | +import Link, { LinkProps } from "next/link"; |
| 4 | +import { ComponentProps } from "react"; |
| 5 | +import { useDevFAQRouter } from "../../hooks/useDevFAQRouter"; |
| 6 | +import { escapeStringRegexp } from "../../lib/escapeStringRegex"; |
| 7 | + |
| 8 | +type Url = LinkProps["href"]; |
| 9 | + |
| 10 | +const origin = process.env.NEXT_PUBLIC_APP_URL || "http://dummy.localhost:8080"; |
| 11 | + |
| 12 | +const urlObjectToUrl = (urlObject: UrlObject, origin: string): URL => { |
| 13 | + const url = new URL(origin); |
| 14 | + if (urlObject.protocol) url.protocol = urlObject.protocol; |
| 15 | + if (urlObject.auth) { |
| 16 | + const auth = urlObject.auth.split(":"); |
| 17 | + url.username = auth[0] || url.username; |
| 18 | + url.password = auth[1] || url.password; |
| 19 | + } |
| 20 | + if (urlObject.host) url.host = urlObject.host; |
| 21 | + if (urlObject.hostname) url.hostname = urlObject.hostname; |
| 22 | + if (urlObject.port) url.port = urlObject.port.toString(); |
| 23 | + if (urlObject.hash) url.hash = urlObject.hash; |
| 24 | + if (urlObject.search) url.search = urlObject.search; |
| 25 | + if (urlObject.query) |
| 26 | + url.search = new URLSearchParams(urlObject.query as Record<string, string> | string).toString(); |
| 27 | + if (urlObject.pathname) url.pathname = urlObject.pathname; |
| 28 | + |
| 29 | + return url; |
| 30 | +}; |
| 31 | + |
| 32 | +export const createQueryHref = (href: Url, query: Record<string, string>): string => { |
| 33 | + const url = typeof href === "string" ? new URL(href, origin) : urlObjectToUrl(href, origin); |
| 34 | + Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, value)); |
| 35 | + |
| 36 | + const newHref = url.toString().replace(new RegExp("^" + escapeStringRegexp(origin)), ""); |
| 37 | + |
| 38 | + if (newHref.startsWith("/") && typeof href === "string" && !href.startsWith("/")) { |
| 39 | + // trim slash |
| 40 | + return newHref.slice(1); |
| 41 | + } |
| 42 | + return newHref; |
| 43 | +}; |
| 44 | + |
| 45 | +type LinkWithQueryProps = Readonly<{ |
| 46 | + mergeQuery?: boolean; |
| 47 | +}> & |
| 48 | + ComponentProps<typeof Link>; |
| 49 | + |
| 50 | +export const LinkWithQuery = ({ href, mergeQuery, ...props }: LinkWithQueryProps) => { |
| 51 | + const { queryParams } = useDevFAQRouter(); |
| 52 | + |
| 53 | + const linkHref = mergeQuery ? createQueryHref(href, queryParams) : createQueryHref(href, {}); |
| 54 | + |
| 55 | + return <Link href={linkHref} {...props} />; |
| 56 | +}; |
0 commit comments