From 2b10b01a93feeac113fc6455fded6e4e36ea13a2 Mon Sep 17 00:00:00 2001 From: Carla Goncalves Date: Fri, 12 Dec 2025 12:26:04 +0000 Subject: [PATCH 1/5] Remove leftover code tentative fix on docs utm persistence --- content/300-accelerate/index.mdx | 1 - content/700-optimize/index.mdx | 1 - src/hooks/useUTMParams.ts | 15 +++++++++ src/theme/NavbarItem/NavbarNavLink.tsx | 44 ++++++++++++++++++++++++-- 4 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 src/hooks/useUTMParams.ts diff --git a/content/300-accelerate/index.mdx b/content/300-accelerate/index.mdx index 10ad80c7bb..8a0c35304a 100644 --- a/content/300-accelerate/index.mdx +++ b/content/300-accelerate/index.mdx @@ -10,7 +10,6 @@ pagination_next: 'accelerate/getting-started' import { Bolt, - BorderBox, BoxTitle, Database, Grid, diff --git a/content/700-optimize/index.mdx b/content/700-optimize/index.mdx index eba5f3aa51..cd3c4a7e7c 100644 --- a/content/700-optimize/index.mdx +++ b/content/700-optimize/index.mdx @@ -10,7 +10,6 @@ pagination_next: 'optimize/getting-started' import { Bolt, - BorderBox, BoxTitle, Database, Grid, diff --git a/src/hooks/useUTMParams.ts b/src/hooks/useUTMParams.ts new file mode 100644 index 0000000000..24993503c1 --- /dev/null +++ b/src/hooks/useUTMParams.ts @@ -0,0 +1,15 @@ +import { useEffect, useState } from 'react'; + +export const useUTMParams = (): string => { + const [utmParams, setUTMParams] = useState(''); + + useEffect(() => { + // Check if we're on the client side + if (typeof window !== 'undefined') { + const storedParams = sessionStorage.getItem('utm_params'); + setUTMParams(storedParams || ''); + } + }, []); + + return utmParams; +}; diff --git a/src/theme/NavbarItem/NavbarNavLink.tsx b/src/theme/NavbarItem/NavbarNavLink.tsx index b8709c173c..49ae4f9fd6 100644 --- a/src/theme/NavbarItem/NavbarNavLink.tsx +++ b/src/theme/NavbarItem/NavbarNavLink.tsx @@ -6,6 +6,7 @@ import {isRegexpStringMatch} from '@docusaurus/theme-common'; import IconExternalLink from '@theme/Icon/ExternalLink'; import type {Props} from '@theme/NavbarItem/NavbarNavLink'; import { Icon } from '@site/src/components/Icon'; +import { useUTMParams } from '@site/src/hooks/useUTMParams'; type CustomProps = Props & { @@ -31,6 +32,28 @@ export default function NavbarNavLink({ const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true}); const isExternalLink = label && href && !isInternalUrl(href); + // Get UTM parameters from sessionStorage using custom hook + const utmParams = useUTMParams(); + + // Helper function to append UTM params to URL + const appendUtmParams = (url: string): string => { + if (!utmParams) { + console.log('NavbarNavLink: No UTM params for URL:', url); + return url; + } + + const [baseUrl, existingQuery] = url.split('?'); + if (existingQuery) { + const result = `${baseUrl}?${existingQuery}&${utmParams}`; + console.log('NavbarNavLink: Adding UTM params to existing query:', url, '->', result); + return result; + } else { + const result = `${baseUrl}?${utmParams}`; + console.log('NavbarNavLink: Adding UTM params to URL:', url, '->', result); + return result; + } + }; + // Link content is set through html XOR label const linkContentProps = html ? {dangerouslySetInnerHTML: {__html: html}} @@ -54,18 +77,35 @@ export default function NavbarNavLink({ }; if (href) { + // For external links, return as-is + if (isExternalLink) { + return ( + + ); + } + + // For internal links, append UTM parameters if available + const finalHref = prependBaseUrlToHref ? normalizedHref : href; + const urlWithUtms = appendUtmParams(finalHref); + return ( ); } + const urlWithUtms = appendUtmParams(toUrl); + return ( From 80a6667ab6e029e6c04b5c51599c7536622e9d64 Mon Sep 17 00:00:00 2001 From: Carla Goncalves Date: Mon, 15 Dec 2025 10:23:23 +0000 Subject: [PATCH 2/5] Update utm params internally for docs --- src/hooks/useUTMParams.ts | 36 ++++++++++-- src/theme/Logo/index.tsx | 88 ++++++++++++++++++++++++++++++ src/theme/Navbar/Content/index.tsx | 11 +++- src/utils/useUTMPersistenceDocs.ts | 3 +- 4 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 src/theme/Logo/index.tsx diff --git a/src/hooks/useUTMParams.ts b/src/hooks/useUTMParams.ts index 24993503c1..5381fdf0ed 100644 --- a/src/hooks/useUTMParams.ts +++ b/src/hooks/useUTMParams.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useState, useEffect } from 'react'; export const useUTMParams = (): string => { const [utmParams, setUTMParams] = useState(''); @@ -6,10 +6,38 @@ export const useUTMParams = (): string => { useEffect(() => { // Check if we're on the client side if (typeof window !== 'undefined') { - const storedParams = sessionStorage.getItem('utm_params'); - setUTMParams(storedParams || ''); + const updateUTMParams = () => { + const storedParams = sessionStorage.getItem('utm_params'); + console.log('useUTMParams - stored params from sessionStorage:', storedParams); + setUTMParams(storedParams || ''); + }; + + // Initial load + updateUTMParams(); + + // Listen for storage changes (in case UTM params are set after initial load) + const handleStorageChange = (e: StorageEvent) => { + if (e.key === 'utm_params') { + updateUTMParams(); + } + }; + + window.addEventListener('storage', handleStorageChange); + + // Also check periodically in case the storage was updated in the same tab + const interval = setInterval(updateUTMParams, 100); + + // Clean up after a short time to avoid infinite checking + setTimeout(() => { + clearInterval(interval); + }, 2000); + + return () => { + window.removeEventListener('storage', handleStorageChange); + clearInterval(interval); + }; } }, []); return utmParams; -}; +}; \ No newline at end of file diff --git a/src/theme/Logo/index.tsx b/src/theme/Logo/index.tsx new file mode 100644 index 0000000000..2891eae90b --- /dev/null +++ b/src/theme/Logo/index.tsx @@ -0,0 +1,88 @@ +import React, {type ReactNode} from 'react'; +import Link from '@docusaurus/Link'; +import useBaseUrl from '@docusaurus/useBaseUrl'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import {useThemeConfig, type NavbarLogo} from '@docusaurus/theme-common'; +import ThemedImage from '@theme/ThemedImage'; +import type {Props} from '@theme/Logo'; +import { useUTMParams } from '@site/src/hooks/useUTMParams'; + +function LogoThemedImage({ + logo, + alt, + imageClassName, +}: { + logo: NavbarLogo; + alt: string; + imageClassName?: string; +}) { + const sources = { + light: useBaseUrl(logo.src), + dark: useBaseUrl(logo.srcDark || logo.src), + }; + const themedImage = ( + + ); + + // Is this extra div really necessary? + // introduced in https://github.com/facebook/docusaurus/pull/5666 + return imageClassName ? ( +
{themedImage}
+ ) : ( + themedImage + ); +} + +export default function Logo(props: Props): ReactNode { + const { + siteConfig: {title}, + } = useDocusaurusContext(); + const { + navbar: {title: navbarTitle, logo}, + } = useThemeConfig(); + + const {imageClassName, titleClassName, ...propsRest} = props; + const logoLink = useBaseUrl(logo?.href || '/'); + const utmParams = useUTMParams(); + + // Helper function to append UTM params to URL + const appendUtmParams = (url: string): string => { + if (!utmParams) { + return url; + } + const separator = url.includes('?') ? '&' : '?'; + const result = `${url}${separator}${utmParams}`; + return result; + }; + + // If visible title is shown, fallback alt text should be + // an empty string to mark the logo as decorative. + const fallbackAlt = navbarTitle ? '' : title; + + // Use logo alt text if provided (including empty string), + // and provide a sensible fallback otherwise. + const alt = logo?.alt ?? fallbackAlt; + + return ( + + {logo && ( + + )} + {navbarTitle != null && {navbarTitle}} + + ); +} diff --git a/src/theme/Navbar/Content/index.tsx b/src/theme/Navbar/Content/index.tsx index 84dd491c34..6e951e21a0 100644 --- a/src/theme/Navbar/Content/index.tsx +++ b/src/theme/Navbar/Content/index.tsx @@ -11,6 +11,7 @@ import React, { type ReactNode } from 'react'; import styles from './styles.module.css'; import Link from '@docusaurus/Link'; import useBaseUrl from '@docusaurus/useBaseUrl'; +import { useUTMParams } from '@site/src/hooks/useUTMParams'; function useNavbarItems() { // TODO temporary casting until ThemeConfig type is improved @@ -58,12 +59,20 @@ function NavbarContentLayout({ export default function NavbarContent(): ReactNode { const mobileSidebar = useNavbarMobileSidebar(); + const utmParams = useUTMParams(); const items = useNavbarItems(); const [leftItems, rightItems] = splitNavbarItems(items); const searchBarItem = items.find((item) => item.type === 'search'); const baseUrl = useBaseUrl("/"); + + // Helper function to append UTM params to URL + const appendUtmParams = (url: string): string => { + if (!utmParams) return url; + const separator = url.includes('?') ? '&' : '?'; + return `${url}${separator}${utmParams}`; + }; return ( } / - docs + docs } middle={ diff --git a/src/utils/useUTMPersistenceDocs.ts b/src/utils/useUTMPersistenceDocs.ts index 3adecc5625..8640a65f0d 100644 --- a/src/utils/useUTMPersistenceDocs.ts +++ b/src/utils/useUTMPersistenceDocs.ts @@ -27,7 +27,8 @@ export const useUTMPersistenceDocs = () => { if (previousSearch.current === '') { previousSearch.current = location.search; if (hasUTMParams(location.search)) { - sessionStorage.setItem('utm_params', getUTMParams(location.search)); + const utms = getUTMParams(location.search); + sessionStorage.setItem('utm_params', utms); } return; } From 1eaa4b2acfc3f4f0a35c1561c37d7edd6de1e3ba Mon Sep 17 00:00:00 2001 From: Carla Goncalves Date: Mon, 15 Dec 2025 10:26:16 +0000 Subject: [PATCH 3/5] remove console logs --- functions/_middleware.ts | 1 - src/hooks/useUTMParams.ts | 1 - src/theme/NavbarItem/NavbarNavLink.tsx | 3 --- src/utils/useUTMPersistenceDocs.ts | 1 - 4 files changed, 6 deletions(-) diff --git a/functions/_middleware.ts b/functions/_middleware.ts index cfd258bc87..9054f840db 100644 --- a/functions/_middleware.ts +++ b/functions/_middleware.ts @@ -95,7 +95,6 @@ export const onRequest: PagesFunction = async (context) => { if (response.ok) { // Check what content type we actually got const actualContentType = response.headers.get('content-type'); - console.log(`Fetched ${markdownPath}, got content-type: ${actualContentType}`); return new Response(response.body, { status: 200, diff --git a/src/hooks/useUTMParams.ts b/src/hooks/useUTMParams.ts index 5381fdf0ed..595e7d5cd3 100644 --- a/src/hooks/useUTMParams.ts +++ b/src/hooks/useUTMParams.ts @@ -8,7 +8,6 @@ export const useUTMParams = (): string => { if (typeof window !== 'undefined') { const updateUTMParams = () => { const storedParams = sessionStorage.getItem('utm_params'); - console.log('useUTMParams - stored params from sessionStorage:', storedParams); setUTMParams(storedParams || ''); }; diff --git a/src/theme/NavbarItem/NavbarNavLink.tsx b/src/theme/NavbarItem/NavbarNavLink.tsx index 49ae4f9fd6..709de26723 100644 --- a/src/theme/NavbarItem/NavbarNavLink.tsx +++ b/src/theme/NavbarItem/NavbarNavLink.tsx @@ -38,18 +38,15 @@ export default function NavbarNavLink({ // Helper function to append UTM params to URL const appendUtmParams = (url: string): string => { if (!utmParams) { - console.log('NavbarNavLink: No UTM params for URL:', url); return url; } const [baseUrl, existingQuery] = url.split('?'); if (existingQuery) { const result = `${baseUrl}?${existingQuery}&${utmParams}`; - console.log('NavbarNavLink: Adding UTM params to existing query:', url, '->', result); return result; } else { const result = `${baseUrl}?${utmParams}`; - console.log('NavbarNavLink: Adding UTM params to URL:', url, '->', result); return result; } }; diff --git a/src/utils/useUTMPersistenceDocs.ts b/src/utils/useUTMPersistenceDocs.ts index 8640a65f0d..9b0f67bbe1 100644 --- a/src/utils/useUTMPersistenceDocs.ts +++ b/src/utils/useUTMPersistenceDocs.ts @@ -40,7 +40,6 @@ export const useUTMPersistenceDocs = () => { if (hadUTMs && !hasUTMs && location.pathname === previousSearch.current.split('?')[0]) { isManualRemoval.current = true; sessionStorage.removeItem('utm_params'); - console.log('Manual removal detected - UTMs cleared'); } // Save new UTMs if they exist else if (hasUTMs) { From 76c4fc7eb7c9ab0b8460aa2fe1b97eefc2436b37 Mon Sep 17 00:00:00 2001 From: Carla Goncalves Date: Wed, 17 Dec 2025 16:58:51 +0000 Subject: [PATCH 4/5] Another try --- src/hooks/useUTMParams.ts | 12 +----- src/theme/Logo/index.tsx | 8 ---- src/theme/NavbarItem/NavbarNavLink.tsx | 5 --- src/utils/useUTMPersistenceDocs.ts | 54 ++++++++++++++++++++++---- 4 files changed, 48 insertions(+), 31 deletions(-) diff --git a/src/hooks/useUTMParams.ts b/src/hooks/useUTMParams.ts index 595e7d5cd3..a2a0c12917 100644 --- a/src/hooks/useUTMParams.ts +++ b/src/hooks/useUTMParams.ts @@ -1,10 +1,9 @@ -import { useState, useEffect } from 'react'; +import { useEffect, useState } from 'react'; export const useUTMParams = (): string => { const [utmParams, setUTMParams] = useState(''); useEffect(() => { - // Check if we're on the client side if (typeof window !== 'undefined') { const updateUTMParams = () => { const storedParams = sessionStorage.getItem('utm_params'); @@ -14,7 +13,6 @@ export const useUTMParams = (): string => { // Initial load updateUTMParams(); - // Listen for storage changes (in case UTM params are set after initial load) const handleStorageChange = (e: StorageEvent) => { if (e.key === 'utm_params') { updateUTMParams(); @@ -23,13 +21,7 @@ export const useUTMParams = (): string => { window.addEventListener('storage', handleStorageChange); - // Also check periodically in case the storage was updated in the same tab - const interval = setInterval(updateUTMParams, 100); - - // Clean up after a short time to avoid infinite checking - setTimeout(() => { - clearInterval(interval); - }, 2000); + const interval = setInterval(updateUTMParams, 500); return () => { window.removeEventListener('storage', handleStorageChange); diff --git a/src/theme/Logo/index.tsx b/src/theme/Logo/index.tsx index 2891eae90b..d441327f26 100644 --- a/src/theme/Logo/index.tsx +++ b/src/theme/Logo/index.tsx @@ -31,8 +31,6 @@ function LogoThemedImage({ /> ); - // Is this extra div really necessary? - // introduced in https://github.com/facebook/docusaurus/pull/5666 return imageClassName ? (
{themedImage}
) : ( @@ -52,7 +50,6 @@ export default function Logo(props: Props): ReactNode { const logoLink = useBaseUrl(logo?.href || '/'); const utmParams = useUTMParams(); - // Helper function to append UTM params to URL const appendUtmParams = (url: string): string => { if (!utmParams) { return url; @@ -61,13 +58,8 @@ export default function Logo(props: Props): ReactNode { const result = `${url}${separator}${utmParams}`; return result; }; - - // If visible title is shown, fallback alt text should be - // an empty string to mark the logo as decorative. const fallbackAlt = navbarTitle ? '' : title; - // Use logo alt text if provided (including empty string), - // and provide a sensible fallback otherwise. const alt = logo?.alt ?? fallbackAlt; return ( diff --git a/src/theme/NavbarItem/NavbarNavLink.tsx b/src/theme/NavbarItem/NavbarNavLink.tsx index 709de26723..32c3d81a5b 100644 --- a/src/theme/NavbarItem/NavbarNavLink.tsx +++ b/src/theme/NavbarItem/NavbarNavLink.tsx @@ -32,10 +32,8 @@ export default function NavbarNavLink({ const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true}); const isExternalLink = label && href && !isInternalUrl(href); - // Get UTM parameters from sessionStorage using custom hook const utmParams = useUTMParams(); - // Helper function to append UTM params to URL const appendUtmParams = (url: string): string => { if (!utmParams) { return url; @@ -51,7 +49,6 @@ export default function NavbarNavLink({ } }; - // Link content is set through html XOR label const linkContentProps = html ? {dangerouslySetInnerHTML: {__html: html}} : { @@ -74,7 +71,6 @@ export default function NavbarNavLink({ }; if (href) { - // For external links, return as-is if (isExternalLink) { return ( { }; useEffect(() => { - // Skip initial render if (previousSearch.current === '') { previousSearch.current = location.search; if (hasUTMParams(location.search)) { - const utms = getUTMParams(location.search); - sessionStorage.setItem('utm_params', utms); + sessionStorage.setItem('utm_params', getUTMParams(location.search)); } return; } @@ -36,21 +34,18 @@ export const useUTMPersistenceDocs = () => { const hadUTMs = hasUTMParams(previousSearch.current); const hasUTMs = hasUTMParams(location.search); - // Detect manual removal - if (hadUTMs && !hasUTMs && location.pathname === previousSearch.current.split('?')[0]) { + if (hadUTMs && !hasUTMs) { isManualRemoval.current = true; sessionStorage.removeItem('utm_params'); } - // Save new UTMs if they exist else if (hasUTMs) { isManualRemoval.current = false; sessionStorage.setItem('utm_params', getUTMParams(location.search)); } - // Restore UTMs if they're missing and weren't manually removed else if (!isManualRemoval.current) { const storedParams = sessionStorage.getItem('utm_params'); if (storedParams) { - const newSearch = storedParams ? `?${storedParams}` : ''; + const newSearch = `?${storedParams}`; if (location.search !== newSearch) { history.replace({ pathname: location.pathname, @@ -62,4 +57,47 @@ export const useUTMPersistenceDocs = () => { previousSearch.current = location.search; }, [location, history]); + + useEffect(() => { + const handlePopState = () => { + setTimeout(() => { + const currentHasUTMs = hasUTMParams(window.location.search); + const storedParams = sessionStorage.getItem('utm_params'); + + if (!currentHasUTMs && storedParams) { + sessionStorage.removeItem('utm_params'); + isManualRemoval.current = true; + } + }, 50); + }; + + const handleHashChange = () => { + const currentHasUTMs = hasUTMParams(window.location.search); + const storedParams = sessionStorage.getItem('utm_params'); + + if (!currentHasUTMs && storedParams) { + sessionStorage.removeItem('utm_params'); + isManualRemoval.current = true; + } + }; + + window.addEventListener('popstate', handlePopState); + window.addEventListener('hashchange', handleHashChange); + + const intervalId = setInterval(() => { + const currentHasUTMs = hasUTMParams(window.location.search); + const storedParams = sessionStorage.getItem('utm_params'); + + if (!currentHasUTMs && storedParams && !isManualRemoval.current) { + sessionStorage.removeItem('utm_params'); + isManualRemoval.current = true; + } + }, 1000); + + return () => { + window.removeEventListener('popstate', handlePopState); + window.removeEventListener('hashchange', handleHashChange); + clearInterval(intervalId); + }; + }, []); }; From fc8bf26ce72f8c7f67e8bdc5261c605e8d8bf881 Mon Sep 17 00:00:00 2001 From: Carla Goncalves Date: Fri, 19 Dec 2025 11:17:02 +0000 Subject: [PATCH 5/5] update for removal + simplification --- src/theme/Layout/index.tsx | 4 - src/utils/useUTMPersistenceDocs.ts | 116 +++++++---------------------- 2 files changed, 27 insertions(+), 93 deletions(-) diff --git a/src/theme/Layout/index.tsx b/src/theme/Layout/index.tsx index 8f25b99533..c719cf8ce6 100644 --- a/src/theme/Layout/index.tsx +++ b/src/theme/Layout/index.tsx @@ -22,7 +22,6 @@ export default function Layout(props: Props): ReactNode { children, noFooter, wrapperClassName, - // Not really layout-related, but kept for convenience/retro-compatibility title, description, } = props; @@ -43,15 +42,12 @@ export default function Layout(props: Props): ReactNode { new URLSearchParams(utms).forEach((v, k) => url.searchParams.set(k, v)); a.setAttribute('href', url.toString()); } catch (e) { - // Handle invalid URLs } }); }; - // Initial update updateLinks(document.querySelectorAll('a[href*="console.prisma.io"]')); - // Watch for new links const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { diff --git a/src/utils/useUTMPersistenceDocs.ts b/src/utils/useUTMPersistenceDocs.ts index 6d7f4f9e8f..1330cf442a 100644 --- a/src/utils/useUTMPersistenceDocs.ts +++ b/src/utils/useUTMPersistenceDocs.ts @@ -1,103 +1,41 @@ import { useHistory, useLocation } from '@docusaurus/router'; import { useEffect, useRef } from 'react'; -const hasUTMParams = (search: string) => { +const UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign'] as const; +const STORAGE_KEY = 'utm_params'; + +const extractUTMParams = (search: string): string => { const params = new URLSearchParams(search); - return ['utm_source', 'utm_medium', 'utm_campaign'].some(p => params.has(p)); + const utmParams = new URLSearchParams(); + UTM_KEYS.forEach(key => { + const value = params.get(key); + if (value) utmParams.set(key, value); + }); + return utmParams.toString(); }; export const useUTMPersistenceDocs = () => { const location = useLocation(); const history = useHistory(); - const isManualRemoval = useRef(false); - const previousSearch = useRef(''); - - const getUTMParams = (search: string) => { - const params = new URLSearchParams(search); - const utmParams = new URLSearchParams(); - ['utm_source', 'utm_medium', 'utm_campaign'].forEach(param => { - const value = params.get(param); - if (value) utmParams.set(param, value); - }); - return utmParams.toString(); - }; + const prevPathname = useRef(location.pathname); useEffect(() => { - if (previousSearch.current === '') { - previousSearch.current = location.search; - if (hasUTMParams(location.search)) { - sessionStorage.setItem('utm_params', getUTMParams(location.search)); - } - return; - } - - const hadUTMs = hasUTMParams(previousSearch.current); - const hasUTMs = hasUTMParams(location.search); - - if (hadUTMs && !hasUTMs) { - isManualRemoval.current = true; - sessionStorage.removeItem('utm_params'); - } - else if (hasUTMs) { - isManualRemoval.current = false; - sessionStorage.setItem('utm_params', getUTMParams(location.search)); + const currentUTMs = extractUTMParams(location.search); + const storedUTMs = sessionStorage.getItem(STORAGE_KEY); + const isNavigation = prevPathname.current !== location.pathname; + + if (currentUTMs) { + sessionStorage.setItem(STORAGE_KEY, currentUTMs); + } else if (storedUTMs && isNavigation) { + history.replace({ + pathname: location.pathname, + search: `?${storedUTMs}`, + hash: location.hash, + }); + } else if (!currentUTMs && storedUTMs && !isNavigation) { + sessionStorage.removeItem(STORAGE_KEY); } - else if (!isManualRemoval.current) { - const storedParams = sessionStorage.getItem('utm_params'); - if (storedParams) { - const newSearch = `?${storedParams}`; - if (location.search !== newSearch) { - history.replace({ - pathname: location.pathname, - search: newSearch, - }); - } - } - } - - previousSearch.current = location.search; - }, [location, history]); - - useEffect(() => { - const handlePopState = () => { - setTimeout(() => { - const currentHasUTMs = hasUTMParams(window.location.search); - const storedParams = sessionStorage.getItem('utm_params'); - - if (!currentHasUTMs && storedParams) { - sessionStorage.removeItem('utm_params'); - isManualRemoval.current = true; - } - }, 50); - }; - - const handleHashChange = () => { - const currentHasUTMs = hasUTMParams(window.location.search); - const storedParams = sessionStorage.getItem('utm_params'); - - if (!currentHasUTMs && storedParams) { - sessionStorage.removeItem('utm_params'); - isManualRemoval.current = true; - } - }; - - window.addEventListener('popstate', handlePopState); - window.addEventListener('hashchange', handleHashChange); - - const intervalId = setInterval(() => { - const currentHasUTMs = hasUTMParams(window.location.search); - const storedParams = sessionStorage.getItem('utm_params'); - - if (!currentHasUTMs && storedParams && !isManualRemoval.current) { - sessionStorage.removeItem('utm_params'); - isManualRemoval.current = true; - } - }, 1000); - return () => { - window.removeEventListener('popstate', handlePopState); - window.removeEventListener('hashchange', handleHashChange); - clearInterval(intervalId); - }; - }, []); + prevPathname.current = location.pathname; + }, [location.pathname, location.search, location.hash]); };