Skip to content

Commit

Permalink
feat: Programmatically determine when links should open in new tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
meissadia committed Dec 20, 2024
1 parent 367f3dd commit b96809e
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 17 deletions.
5 changes: 3 additions & 2 deletions src/components/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import {
IconExternalLink,
isExternalLinkImplied,
isNewTabImplied,
useIsNewTabImplied,
} from './Link.utils';

interface LinkProperties extends DesignSystemReactLinkProperties {
Expand Down Expand Up @@ -38,7 +38,8 @@ export function Link({
let icon;

// Open link in new tab
const openInNewTab = isNewTab ?? isNewTabImplied(href);
const isNewTabImplied = useIsNewTabImplied(href);
const openInNewTab = isNewTab ?? isNewTabImplied;
if (openInNewTab) otherProperties.target = '_blank';

// Treat as an External link
Expand Down
79 changes: 64 additions & 15 deletions src/components/Link.utils.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import useSblAuth from 'api/useSblAuth';
import { Icon } from 'design-system-react';
import type { ReactElement } from 'react';
import { useLocation } from 'react-router-dom';

// Link to specific regulation
// Ex: /rules-policy/regulations/1002/109/#a-1-ii
const regsLinkPattern = /\/rules-policy\/regulations\/\d+\/\d+\/#.+/;

// Link to specific FIG subsection
// Ex: /small-business-lending/filing-instructions-guide/2024-guide/#4.4.1
const figLinkPattern = /\/filing-instructions-guide\/\d{4}-guide\/#.+/;

/**
* Programmatically determine if a link is external to the CFPB sphere of websites
*/
export const isExternalLinkImplied = (targetUrl: string): boolean => {
// Parse URL string into URL object
const parseURL = (url: string): URL | false => {
let parsed;

try {
parsed = new URL(targetUrl);
parsed = new URL(url);
} catch {
return false; // Relative targets will fail parsing (ex. '/home')
}

return parsed;
};

/**
* Programmatically determine if a link is external to the CFPB sphere of websites
*/
export const isExternalLinkImplied = (targetUrl: string): boolean => {
const parsed = parseURL(targetUrl);
if (!parsed) return false; // Invalid URL or Relative URL (ex. '/home')

const externalProtocols = ['http', 'tel:', 'sms:', 'ftp:'];
if (externalProtocols.includes(parsed.protocol)) return true;

Expand All @@ -46,7 +48,54 @@ export function IconExternalLink(): ReactElement {
);
}

export function isNewTabImplied(href: string | undefined): boolean {
// Determine if the the target href should open in a new tab
export function useIsNewTabImplied(href: string | undefined): boolean {
const { ...auth } = useSblAuth();
const { pathname } = useLocation();

// No link to open
if (!href) return false;
return regsLinkPattern.test(href) || figLinkPattern.test(href);

// User is NOT logged-in to Login.gov / Keycloak
if (!auth.isAuthenticated) return false;

// User is on a "Complete user profile" page, which qualifies as "Not logged-in"
// (Once associated with an LEI, users are always redirected away from these pages)
if (pathname.includes('/profile/complete')) return false;

// Login.gov account page opens in same tab
if (href === 'https://secure.login.gov/account/') return false;

// Open a new tab when the user is logged-in but visiting an unauthenticated page
const isCollectionAndReportingRequirements = href.endsWith(
'/compliance/compliance-resources/',
);
const isFinalRule = href.endsWith('/rules-policy/final-rules/');
const isPaperworkReductionAct = href.endsWith(
'/paperwork-reduction-act-notice',
);
const isUnauthenticatedHomepage = href.toString() === '/';
const isViewPrivacyNotice = href.endsWith('/privacy-notice');

if (
isViewPrivacyNotice ||
isPaperworkReductionAct ||
isFinalRule ||
isCollectionAndReportingRequirements ||
isUnauthenticatedHomepage
)
return true;

// Open in the same tab if the target is within our app
const parsed = parseURL(href);
if (!parsed) return false;

const isTargetWithinOurAppDomain = new RegExp(
`([\\S]*\\.)?(${window.location.host})`,
).test(parsed.host);

if (isTargetWithinOurAppDomain) return false;

// All other links will open in a new tab
return true;
}

0 comments on commit b96809e

Please sign in to comment.