From e101ff0edc8219e97f80c94c3362802343c6d17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Sch=C3=A4r?= <59233938+schaertim@users.noreply.github.com> Date: Wed, 8 Jan 2025 09:32:39 +0100 Subject: [PATCH 1/2] chore(header): changed how the matching for the `active-route` prop works by allowing for usage of relative paths. --- .changeset/tall-rabbits-sparkle.md | 5 +++++ .../src/services/route.service.ts | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 .changeset/tall-rabbits-sparkle.md diff --git a/.changeset/tall-rabbits-sparkle.md b/.changeset/tall-rabbits-sparkle.md new file mode 100644 index 0000000000..0758245c5c --- /dev/null +++ b/.changeset/tall-rabbits-sparkle.md @@ -0,0 +1,5 @@ +--- +'@swisspost/internet-header': minor +--- + +Changed how the matching for the `active-route` prop works by allowing for usage of relative paths. diff --git a/packages/internet-header/src/services/route.service.ts b/packages/internet-header/src/services/route.service.ts index 01b75cdcb2..f9684e6e34 100644 --- a/packages/internet-header/src/services/route.service.ts +++ b/packages/internet-header/src/services/route.service.ts @@ -29,7 +29,7 @@ export const markActiveRoute = ( compareUrl = new URL(window.location.href); } else { try { - compareUrl = new URL(activeRouteProp, document.location.origin); + compareUrl = ensureUrlWithOrigin(activeRouteProp); } catch (error) { console.warn( `Active Route: ${activeRouteProp} is not a valid URL. Navigation highlighting has been disabled.`, @@ -52,6 +52,20 @@ export const markActiveRoute = ( return config; }; +/** + * Ensure URL has an origin by adding current origin if needed + * @param url URL or path string + * @returns URL with origin + */ +const ensureUrlWithOrigin = (url: string): URL => { + try { + return new URL(url); + } catch { + // If URL construction fails, it's likely relative, so prepend origin + return new URL(url, document.location.origin); + } +}; + /** * Check if the portal config set any active route * @param config Main navigation config @@ -183,7 +197,7 @@ export const compareRoutes = ( matchMode?: 'auto' | 'exact', ): number => { // One url is not defined or they don't share the same orign - if (baseUrl === null || compareUrl === null || baseUrl.origin !== compareUrl.origin) { + if (baseUrl === null || compareUrl === null) { return 0; } From 5455155a2f0a7003b818229cf55199241c5a2d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Sch=C3=A4r?= <59233938+schaertim@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:27:41 +0100 Subject: [PATCH 2/2] chore(tests): updated to work with new setup --- .../src/services/route.service.spec.ts | 56 ++++++++++--------- .../src/services/route.service.ts | 7 ++- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/packages/internet-header/src/services/route.service.spec.ts b/packages/internet-header/src/services/route.service.spec.ts index 4f32f0c333..072c306802 100644 --- a/packages/internet-header/src/services/route.service.spec.ts +++ b/packages/internet-header/src/services/route.service.spec.ts @@ -1,4 +1,5 @@ import { + ensureUrlWithOrigin, compareRoutes, compileScoreList, getSimilarityScore, @@ -50,46 +51,47 @@ describe('route.service.ts', () => { }); describe('compareRoutes', () => { - const post = new URL('https://post.ch'); - const letters = new URL('https://post.ch/briefe'); - const deep = new URL('https://post.ch/briefe/inland'); - const search = new URL('https://post.ch/briefe?q=search'); - const hash = new URL('https://post.ch/briefe#hash'); - const nope = new URL('https://post.de/briefe'); - const upper = new URL('https://post.ch/Briefe'); + const urls = { + post: ensureUrlWithOrigin('https://post.ch'), + letters: ensureUrlWithOrigin('https://post.ch/briefe'), + deep: ensureUrlWithOrigin('https://post.ch/briefe/inland'), + search: ensureUrlWithOrigin('https://post.ch/briefe?q=search'), + hash: ensureUrlWithOrigin('https://post.ch/briefe#hash'), + nope: ensureUrlWithOrigin('https://post.de/briefe'), + upper: ensureUrlWithOrigin('https://post.ch/Briefe'), + }; it('Correctly scores routes in auto mode', () => { // Left: current browser URL, right: URL in Nav - expect(compareRoutes(letters, post, 'auto')).toBe(1); - expect(compareRoutes(deep, letters, 'auto')).toBe(2); - expect(compareRoutes(search, letters, 'auto')).toBe(Infinity); - expect(compareRoutes(search, hash, 'auto')).toBe(Infinity); - expect(compareRoutes(letters, deep, 'auto')).toBe(0); - expect(compareRoutes(nope, letters, 'auto')).toBe(0); - expect(compareRoutes(letters, upper, 'auto')).toBe(Infinity); - expect(compareRoutes(deep, upper, 'auto')).toBe(2); + expect(compareRoutes(urls.letters, urls.post, 'auto')).toBe(1); + expect(compareRoutes(urls.deep, urls.letters, 'auto')).toBe(2); + expect(compareRoutes(urls.search, urls.letters, 'auto')).toBe(Infinity); + expect(compareRoutes(urls.search, urls.hash, 'auto')).toBe(Infinity); + expect(compareRoutes(urls.letters, urls.deep, 'auto')).toBe(0); + expect(compareRoutes(urls.nope, urls.letters, 'auto')).toBe(0); + expect(compareRoutes(urls.letters, urls.upper, 'auto')).toBe(Infinity); + expect(compareRoutes(urls.deep, urls.upper, 'auto')).toBe(2); }); it('Correctly scores routes in exact mode', () => { - // Left: current browser URL, right: URL in Nav - expect(compareRoutes(post, letters)).toBe(0); - expect(compareRoutes(letters, deep)).toBe(0); - expect(compareRoutes(letters, search)).toBe(Infinity); - expect(compareRoutes(hash, search)).toBe(Infinity); - expect(compareRoutes(deep, letters)).toBe(0); - expect(compareRoutes(letters, nope)).toBe(0); - expect(compareRoutes(nope, letters)).toBe(0); - expect(compareRoutes(letters, nope, 'exact')).toBe(0); - expect(compareRoutes(letters, upper, 'exact')).toBe(Infinity); + expect(compareRoutes(urls.post, urls.letters, 'exact')).toBe(0); + expect(compareRoutes(urls.letters, urls.deep, 'exact')).toBe(0); + expect(compareRoutes(urls.letters, urls.search, 'exact')).toBe(Infinity); + expect(compareRoutes(urls.hash, urls.search, 'exact')).toBe(Infinity); + expect(compareRoutes(urls.deep, urls.letters, 'exact')).toBe(0); + expect(compareRoutes(urls.letters, urls.nope, 'exact')).toBe(0); + expect(compareRoutes(urls.nope, urls.letters, 'exact')).toBe(0); + expect(compareRoutes(urls.letters, urls.nope, 'exact')).toBe(0); + expect(compareRoutes(urls.letters, urls.upper, 'exact')).toBe(Infinity); }); it('Does not fail on invalid arguments', () => { // @ts-expect-error - expect(compareRoutes(null, nope, 'auto')).toBe(0); + expect(compareRoutes(null, urls.nope, 'auto')).toBe(0); // @ts-expect-error expect(compareRoutes(null, undefined, 'auto')).toBe(0); // @ts-expect-error - expect(compareRoutes(post, nope, null)).toBe(0); + expect(compareRoutes(urls.post, urls.nope, null)).toBe(0); }); }); diff --git a/packages/internet-header/src/services/route.service.ts b/packages/internet-header/src/services/route.service.ts index f9684e6e34..bb2f8fe4b3 100644 --- a/packages/internet-header/src/services/route.service.ts +++ b/packages/internet-header/src/services/route.service.ts @@ -57,7 +57,7 @@ export const markActiveRoute = ( * @param url URL or path string * @returns URL with origin */ -const ensureUrlWithOrigin = (url: string): URL => { +export const ensureUrlWithOrigin = (url: string): URL => { try { return new URL(url); } catch { @@ -201,6 +201,11 @@ export const compareRoutes = ( return 0; } + const normalizeOrigin = (origin: string) => origin.replace('www.', ''); + if (normalizeOrigin(baseUrl.origin) !== normalizeOrigin(compareUrl.origin)) { + return 0; + } + const baseUrlPath = baseUrl.pathname.toLocaleLowerCase(); const compareUrlPath = compareUrl.pathname.toLocaleLowerCase();