From daa5c87485b137164be5bb704d342e8c3169d9d0 Mon Sep 17 00:00:00 2001 From: Alasdair Smith Date: Wed, 30 Aug 2023 14:37:07 +0100 Subject: [PATCH] Merge pull request #14577 from overleaf/as-fix-popover Fix history UI tutorial so that it is correctly dismissed GitOrigin-RevId: f5792db1531759815fd22c07d253649bedcf3dbd --- .../web/frontend/extracted-translations.json | 1 - .../change-list/all-history-list.tsx | 25 ++++++----- .../change-list/history-version.tsx | 44 ++++++++++++------- .../js/shared/context/editor-context.js | 19 ++++++++ services/web/locales/en.json | 3 +- 5 files changed, 63 insertions(+), 29 deletions(-) diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index eeecf87e52..6a4109770c 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -799,7 +799,6 @@ "raw_logs": "", "raw_logs_description": "", "react_history_tutorial_content": "", - "react_history_tutorial_learn_more": "", "react_history_tutorial_title": "", "reactivate_subscription": "", "read_only": "", diff --git a/services/web/frontend/js/features/history/components/change-list/all-history-list.tsx b/services/web/frontend/js/features/history/components/change-list/all-history-list.tsx index 807155cfb4..b1cc9e9681 100644 --- a/services/web/frontend/js/features/history/components/change-list/all-history-list.tsx +++ b/services/web/frontend/js/features/history/components/change-list/all-history-list.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'react' +import { useCallback, useEffect, useRef, useState } from 'react' import HistoryVersion from './history-version' import LoadingSpinner from '../../../../shared/components/loading-spinner' import { OwnerPaywallPrompt } from './owner-paywall-prompt' @@ -10,11 +10,15 @@ import { import { useUserContext } from '../../../../shared/context/user-context' import useDropdownActiveItem from '../../hooks/use-dropdown-active-item' import { useHistoryContext } from '../../context/history-context' -import getMeta from '../../../../utils/meta' +import { useEditorContext } from '../../../../shared/context/editor-context' type CompletedTutorials = { 'react-history-buttons-tutorial': Date } +type EditorTutorials = { + completedTutorials: CompletedTutorials + setCompletedTutorial: (key: string) => void +} const unselectedStates: ItemSelectionState[] = [ 'aboveSelected', @@ -97,14 +101,15 @@ function AllHistoryList() { } }, [updatesLoadingState]) - const completedTutorials: CompletedTutorials = getMeta( - 'ol-completedTutorials' - ) + const { completedTutorials, setCompletedTutorial }: EditorTutorials = + useEditorContext() // only show tutorial popover if they havent dismissed ("completed") it yet - const hasCompletedHistTutorial = Boolean( - completedTutorials?.['react-history-buttons-tutorial'] - ) + const showTutorial = !completedTutorials?.['react-history-buttons-tutorial'] + + const completeTutorial = useCallback(() => { + setCompletedTutorial('react-history-buttons-tutorial') + }, [setCompletedTutorial]) // only show tutorial popover on the first icon const firstUnselectedIndex = visibleUpdates.findIndex(update => { @@ -116,8 +121,6 @@ function AllHistoryList() { return unselectedStates.includes(selectionState) }) - const [showTutorial, setShowTutorial] = useState(!hasCompletedHistTutorial) - return (
@@ -167,7 +170,7 @@ function AllHistoryList() { } dropdownActive={dropdownActive} hasTutorialOverlay={hasTutorialOverlay} - setShowTutorial={setShowTutorial} + completeTutorial={completeTutorial} /> ) })} diff --git a/services/web/frontend/js/features/history/components/change-list/history-version.tsx b/services/web/frontend/js/features/history/components/change-list/history-version.tsx index 8f3fd1ccaf..26f7cc258b 100644 --- a/services/web/frontend/js/features/history/components/change-list/history-version.tsx +++ b/services/web/frontend/js/features/history/components/change-list/history-version.tsx @@ -49,7 +49,7 @@ type HistoryVersionProps = { setActiveDropdownItem: ActiveDropdown['setActiveDropdownItem'] closeDropdownForItem: ActiveDropdown['closeDropdownForItem'] hasTutorialOverlay?: boolean - setShowTutorial: (show: boolean) => void + completeTutorial: () => void } function HistoryVersion({ @@ -68,7 +68,7 @@ function HistoryVersion({ setActiveDropdownItem, closeDropdownForItem, hasTutorialOverlay = false, - setShowTutorial, + completeTutorial, }: HistoryVersionProps) { const orderedLabels = orderBy(update.labels, ['created_at'], ['desc']) const iconRef = useRef(null) @@ -81,10 +81,16 @@ function HistoryVersion({ // wait for the layout to settle before showing popover, to avoid a flash/ instant move const [layoutSettled, setLayoutSettled] = useState(false) + const [resizing, setResizing] = useState(false) + + // Determine whether the tutorial popover should be shown or not. + // This is a slightly unusual pattern, as in theory we could control this via + // the `show` prop. However we were concerned about the perf impact of every + // history version having a (hidden) popover that won't ever be triggered. useEffect(() => { - if (iconRef.current && hasTutorialOverlay && layoutSettled) { + if (iconRef.current && hasTutorialOverlay && layoutSettled && !resizing) { const dismissModal = () => { - setShowTutorial(false) + completeTutorial() runAsync(completeHistoryTutorial()).catch(console.error) } @@ -98,7 +104,7 @@ function HistoryVersion({ setPopover( @@ -114,17 +120,25 @@ function HistoryVersion({ > , // eslint-disable-line jsx-a11y/anchor-has-content, react/jsx-key + ]} /> - - {' '} - {t('react_history_tutorial_learn_more')} - ) + } else { + setPopover(null) } - }, [hasTutorialOverlay, runAsync, setShowTutorial, t, layoutSettled]) + }, [ + hasTutorialOverlay, + runAsync, + t, + layoutSettled, + completeTutorial, + resizing, + ]) // give the components time to position before showing popover so we dont get a instant position change useEffect(() => { @@ -144,11 +158,11 @@ function HistoryVersion({ if (timer) { window.clearTimeout(timer) } else { - setShowTutorial(false) + setResizing(true) } timer = window.setTimeout(() => { timer = null - setShowTutorial(true) + setResizing(false) }, 500) } @@ -157,7 +171,7 @@ function HistoryVersion({ window.addEventListener('resize', handleResize) return () => window.removeEventListener('resize', handleResize) } - }, [hasTutorialOverlay, setShowTutorial]) + }, [hasTutorialOverlay]) const closeDropdown = useCallback(() => { closeDropdownForItem(update, 'moreOptions') @@ -167,7 +181,7 @@ function HistoryVersion({ return ( <> - {hasTutorialOverlay && popover} + {popover} {showDivider ? (
+ getMeta('ol-completedTutorials') + ) + + const setCompletedTutorial = useCallback( + tutorialKey => { + setCompletedTutorials({ + ...completedTutorials, + [tutorialKey]: new Date(), + }) + }, + [completedTutorials] + ) + useEffect(() => { if (ide?.socket) { ide.socket.on('projectNameUpdated', setProjectName) @@ -151,6 +166,8 @@ export function EditorProvider({ children, settings }) { showSymbolPalette, toggleSymbolPalette, insertSymbol, + completedTutorials, + setCompletedTutorial, }), [ cobranding, @@ -163,6 +180,8 @@ export function EditorProvider({ children, settings }) { showSymbolPalette, toggleSymbolPalette, insertSymbol, + completedTutorials, + setCompletedTutorial, ] ) diff --git a/services/web/locales/en.json b/services/web/locales/en.json index deee3ad602..c65771fc0a 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -1299,8 +1299,7 @@ "quoted_text_in": "Quoted text in", "raw_logs": "Raw logs", "raw_logs_description": "Raw logs from the LaTeX compiler", - "react_history_tutorial_content": "To compare a range of versions, use the <0> on the versions you want at the start and end of the range. To add a label or to download a version use the options in the three-dot menu. Learn more about using Overleaf History.", - "react_history_tutorial_learn_more": "Learn more about using Overleaf History.", + "react_history_tutorial_content": "To compare a range of versions, use the <0> on the versions you want at the start and end of the range. To add a label or to download a version use the options in the three-dot menu. <1>Learn more about using Overleaf History.", "react_history_tutorial_title": "History actions have a new home", "reactivate_subscription": "Reactivate your subscription", "read_only": "Read Only",