diff --git a/lib/src/Components/Map/UtopiaMapInner.tsx b/lib/src/Components/Map/UtopiaMapInner.tsx index 7f29a2d7..5e840159 100644 --- a/lib/src/Components/Map/UtopiaMapInner.tsx +++ b/lib/src/Components/Map/UtopiaMapInner.tsx @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ /* eslint-disable @typescript-eslint/restrict-plus-operands */ -/* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ @@ -15,6 +14,12 @@ import { toast } from 'react-toastify' import { useSetAppState } from '#components/AppShell/hooks/useAppState' import { useTheme } from '#components/AppShell/hooks/useTheme' import { containsUUID } from '#utils/ContainsUUID' +import { + removeItemFromUrl, + resetMetaTags as resetMetaTagsUtil, + setItemInUrl, + updateMetaTags, +} from '#utils/UrlHelper' import { useClusterRef, useSetClusterRef } from './hooks/useClusterRef' import { @@ -156,34 +161,19 @@ export function UtopiaMapInner({ popupopen: (e) => { const item = Object.entries(leafletRefs).find((r) => r[1].popup === e.popup)?.[1].item if (window.location.pathname.split('/')[1] !== item?.id) { - const params = new URLSearchParams(window.location.search) - if (!location.pathname.includes('/item/')) { - window.history.pushState( - {}, - '', - `/${item?.id}` + `${params.toString() !== '' ? `?${params}` : ''}`, - ) + if (!location.pathname.includes('/item/') && item?.id) { + setItemInUrl(item.id) + } + if (item?.name) { + updateMetaTags(item.name, item.text) } - let title = '' - if (item?.name) title = item.name - document.title = `${document.title.split('-')[0]} - ${title}` } }, popupclose: () => { // Remove UUID from URL when popup closes if (containsUUID(window.location.pathname)) { - const params = new URLSearchParams(window.location.search) - window.history.pushState({}, '', '/' + `${params.toString() !== '' ? `?${params}` : ''}`) - // Reset page title - document.title = document.title.split('-')[0] - // Reset meta tags - document.querySelector('meta[property="og:title"]')?.setAttribute('content', document.title) - document - .querySelector('meta[property="og:description"]') - ?.setAttribute( - 'content', - `${document.querySelector('meta[name="description"]')?.getAttribute('content')}`, - ) + removeItemFromUrl() + resetMetaTagsUtil() } }, }) @@ -202,15 +192,9 @@ export function UtopiaMapInner({ clusterRef?.zoomToShowLayer(ref.marker, () => { ref.marker.openPopup() }) - let title = '' - if (ref.item.name) title = ref.item.name - document.title = `${document.title.split('-')[0]} - ${title}` - document - .querySelector('meta[property="og:title"]') - ?.setAttribute('content', ref.item.name ?? '') - document - .querySelector('meta[property="og:description"]') - ?.setAttribute('content', ref.item.text ?? '') + if (ref.item.name) { + updateMetaTags(ref.item.name, ref.item.text) + } } } } @@ -222,18 +206,10 @@ export function UtopiaMapInner({ }, [leafletRefs, location]) const resetMetaTags = () => { - const params = new URLSearchParams(window.location.search) if (containsUUID(window.location.pathname)) { - window.history.pushState({}, '', '/' + `${params.toString() !== '' ? `?${params}` : ''}`) + removeItemFromUrl() } - document.title = document.title.split('-')[0] - document.querySelector('meta[property="og:title"]')?.setAttribute('content', document.title) - document - .querySelector('meta[property="og:description"]') - ?.setAttribute( - 'content', - `${document.querySelector('meta[name="description"]')?.getAttribute('content')}`, - ) + resetMetaTagsUtil() } const onEachFeature = (feature: Feature, layer: L.Layer) => { diff --git a/lib/src/Utils/UrlHelper.ts b/lib/src/Utils/UrlHelper.ts new file mode 100644 index 00000000..9af81e1a --- /dev/null +++ b/lib/src/Utils/UrlHelper.ts @@ -0,0 +1,74 @@ +/** + * Utility functions for managing browser URL and history + */ + +/** + * Updates the browser URL with an item ID while preserving query parameters + * @param itemId - The item UUID to add to the URL + */ +export function setItemInUrl(itemId: string): void { + const params = new URLSearchParams(window.location.search) + const paramsString = params.toString() + const newUrl = `/${itemId}${paramsString !== '' ? `?${paramsString}` : ''}` + window.history.pushState({}, '', newUrl) +} + +/** + * Removes the item ID from the browser URL while preserving query parameters + */ +export function removeItemFromUrl(): void { + const params = new URLSearchParams(window.location.search) + const paramsString = params.toString() + const newUrl = `/${paramsString !== '' ? `?${paramsString}` : ''}` + window.history.pushState({}, '', newUrl) +} + +/** + * Updates a specific query parameter in the URL while preserving the path + * @param key - The parameter key + * @param value - The parameter value + */ +export function setUrlParam(key: string, value: string): void { + const params = new URLSearchParams(window.location.search) + params.set(key, value) + const newUrl = window.location.pathname + '?' + params.toString() + window.history.pushState({}, '', newUrl) +} + +/** + * Removes a specific query parameter from the URL + * @param key - The parameter key to remove + */ +export function removeUrlParam(key: string): void { + const params = new URLSearchParams(window.location.search) + params.delete(key) + const paramsString = params.toString() + const newUrl = window.location.pathname + (paramsString !== '' ? `?${paramsString}` : '') + window.history.pushState({}, '', newUrl) +} + +/** + * Resets page title and OpenGraph meta tags to default values + */ +export function resetMetaTags(): void { + document.title = document.title.split('-')[0].trim() + document.querySelector('meta[property="og:title"]')?.setAttribute('content', document.title) + const description = document.querySelector('meta[name="description"]')?.getAttribute('content') + if (description) { + document.querySelector('meta[property="og:description"]')?.setAttribute('content', description) + } +} + +/** + * Updates page title and OpenGraph meta tags with item information + * @param itemName - The name of the item + * @param itemText - The text/description of the item + */ +export function updateMetaTags(itemName: string, itemText?: string): void { + const baseTitle = document.title.split('-')[0].trim() + document.title = `${baseTitle} - ${itemName}` + document.querySelector('meta[property="og:title"]')?.setAttribute('content', itemName) + if (itemText) { + document.querySelector('meta[property="og:description"]')?.setAttribute('content', itemText) + } +}