mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-08-02 03:11:45 -04:00
Resolve Compass deep-link routing; handle internal URLs via client-side navigation instead of OS handoff
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import Link from 'next/link'
|
||||
import {internalPathOf} from 'web/lib/util/link'
|
||||
|
||||
export const CustomLink = ({
|
||||
href,
|
||||
@@ -11,10 +12,12 @@ export const CustomLink = ({
|
||||
}) => {
|
||||
if (!href) return <>{children}</>
|
||||
|
||||
// If href is internal, use Next.js Link
|
||||
if (href.startsWith('/')) {
|
||||
// If href points back into Compass — including as an absolute compassmeet.com URL, which is how a
|
||||
// shared link arrives in a chat message — route client-side instead of leaving the app.
|
||||
const path = internalPathOf(href)
|
||||
if (path) {
|
||||
return (
|
||||
<Link href={href} className={className}>
|
||||
<Link href={path} className={className}>
|
||||
{children}
|
||||
</Link>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import clsx from 'clsx'
|
||||
import Link from 'next/link'
|
||||
import {Fragment} from 'react'
|
||||
import {internalPathOf} from 'web/lib/util/link'
|
||||
|
||||
import {linkClass} from './site-link'
|
||||
|
||||
@@ -25,10 +26,12 @@ export function Linkify(props: {text: string; className?: string}) {
|
||||
const whitespace = match.match(/^\s/)
|
||||
const symbol = match.trim().substring(0, 1)
|
||||
const tag = match.trim().substring(1)
|
||||
const href =
|
||||
const rawHref =
|
||||
{
|
||||
'@': `/${tag}`,
|
||||
}[symbol] ?? match.trim()
|
||||
// A compassmeet.com URL routes client-side, so the app never hands it off to the OS browser.
|
||||
const href = internalPathOf(rawHref) ?? rawHref
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -58,7 +61,7 @@ export function Linkify(props: {text: string; className?: string}) {
|
||||
}
|
||||
|
||||
export const getLinkTarget = (href: string, newTab?: boolean) => {
|
||||
// TODO: make this more robust against domain changes?
|
||||
if (href.startsWith('http') && !href.startsWith(`https://compassmeet`)) return '_blank'
|
||||
// mailto:/tel: keep the caller's default — only a genuine off-site page wants a new tab.
|
||||
if (/^https?:\/\//i.test(href) && !internalPathOf(href)) return '_blank'
|
||||
return newTab ? '_blank' : '_self'
|
||||
}
|
||||
|
||||
37
web/lib/util/link.ts
Normal file
37
web/lib/util/link.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* The hosts the Android app claims in its deep-link intent filter (`android/app/src/main/AndroidManifest.xml`).
|
||||
* Other compassmeet subdomains (`dev.`, previews) stay external — the app doesn't intercept them, so
|
||||
* rewriting one to a path would silently land the user on the *current* environment's copy of the page.
|
||||
*/
|
||||
const COMPASS_HOSTS = ['compassmeet.com', 'www.compassmeet.com']
|
||||
|
||||
/**
|
||||
* The in-app path an href points at, or undefined if the link leaves Compass.
|
||||
*
|
||||
* A Compass link pasted into a chat message arrives as an absolute URL (`https://compassmeet.com/…`).
|
||||
* Rendered as-is, the Android WebView hands it to the OS, which opens Chrome, which bounces back
|
||||
* into the app through the deep-link intent filter — a visible round trip for what should be a
|
||||
* client-side route change. Resolving it to a path lets `next/link` handle it directly.
|
||||
*
|
||||
* The current origin counts as internal too: in the WebView the app is served from `https://localhost`,
|
||||
* and in local dev from `http://localhost:3000`.
|
||||
*/
|
||||
export const internalPathOf = (href: string): string | undefined => {
|
||||
if (href.startsWith('/')) return href
|
||||
|
||||
const base = typeof window === 'undefined' ? undefined : window.location.href
|
||||
let url: URL
|
||||
try {
|
||||
url = new URL(href, base)
|
||||
} catch {
|
||||
return undefined // mailto:, tel:, or not a URL at all
|
||||
}
|
||||
|
||||
if (url.protocol !== 'http:' && url.protocol !== 'https:') return undefined
|
||||
const isInternal =
|
||||
COMPASS_HOSTS.includes(url.hostname) ||
|
||||
(typeof window !== 'undefined' && url.host === window.location.host)
|
||||
if (!isInternal) return undefined
|
||||
|
||||
return url.pathname + url.search + url.hash
|
||||
}
|
||||
Reference in New Issue
Block a user