From d086ad89aebba7e767046afe39aa0bc68417c6ea Mon Sep 17 00:00:00 2001 From: Omar Alshaker Date: Mon, 9 Dec 2024 23:21:27 +0100 Subject: [PATCH] Persist scroll position in the Help Center --- .../src/components/help-center-content.tsx | 14 +++++++- .../src/hooks/use-scroll-position.ts | 34 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 packages/help-center/src/hooks/use-scroll-position.ts diff --git a/packages/help-center/src/components/help-center-content.tsx b/packages/help-center/src/components/help-center-content.tsx index 05dae66c88bb9..e02f6e30d2ab9 100644 --- a/packages/help-center/src/components/help-center-content.tsx +++ b/packages/help-center/src/components/help-center-content.tsx @@ -16,6 +16,7 @@ import { v4 as uuidv4 } from 'uuid'; */ import { useHelpCenterContext } from '../contexts/HelpCenterContext'; import { useSupportStatus } from '../data/use-support-status'; +import { useArticleScrollPosition } from '../hooks/use-scroll-position'; import { HELP_CENTER_STORE } from '../stores'; import { HelpCenterArticle } from './help-center-article'; import { HelpCenterChat } from './help-center-chat'; @@ -58,6 +59,10 @@ const HelpCenterContent: React.FC< { isRelative?: boolean; currentRoute?: string const { data: openSupportInteraction, isLoading: isLoadingOpenSupportInteractions } = useGetSupportInteractions( 'help-center' ); const isUserEligibleForPaidSupport = data?.eligibility.is_user_eligible ?? false; + const scrollPosition = useArticleScrollPosition( + containerRef, + location.pathname.includes( '/post' ) + ); useEffect( () => { recordTracksEvent( 'calypso_helpcenter_page_open', { @@ -108,8 +113,15 @@ const HelpCenterContent: React.FC< { isRelative?: boolean; currentRoute?: string useEffect( () => { if ( containerRef.current && ! location.hash && ! location.pathname.includes( '/odie' ) ) { - containerRef.current.scrollTo( 0, 0 ); + if ( location.pathname.includes( '/post' ) && scrollPosition > 0 ) { + containerRef.current.style.scrollBehavior = 'unset'; + containerRef.current.scrollTo( 0, scrollPosition ); + containerRef.current.style.scrollBehavior = 'smooth'; + } else { + containerRef.current.scrollTo( 0, 0 ); + } } + // eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to run this on scroll }, [ location ] ); return ( diff --git a/packages/help-center/src/hooks/use-scroll-position.ts b/packages/help-center/src/hooks/use-scroll-position.ts new file mode 100644 index 0000000000000..c20884b53824f --- /dev/null +++ b/packages/help-center/src/hooks/use-scroll-position.ts @@ -0,0 +1,34 @@ +import { useEffect, useState } from '@wordpress/element'; + +/** + * Persist the value in memory so when the element is unmounted it doesn't get lost. + */ +let cachedScrollPosition = 0; + +/** + * Persists the scroll position of an element in memory and returns it. + * @param ref the HTML element to track the scroll position of. + * @param enabled to only enable for article pages. + * @returns the current or last recorded scroll position. + */ +export function useArticleScrollPosition( ref: React.RefObject< HTMLElement >, enabled: boolean ) { + const [ scrollPosition, setScrollPosition ] = useState( cachedScrollPosition ); + + useEffect( () => { + const element = ref?.current; + + const handleScroll = () => { + if ( element ) { + setScrollPosition( ( cachedScrollPosition = ref.current.scrollTop ) ); + } + }; + if ( enabled ) { + element?.addEventListener( 'scroll', handleScroll ); + } + return () => { + element?.removeEventListener( 'scroll', handleScroll ); + }; + }, [ ref, enabled ] ); + + return scrollPosition; +}