diff --git a/services/web/app/src/Features/Project/ProjectController.js b/services/web/app/src/Features/Project/ProjectController.js index 6744fb8d78..8104681b36 100644 --- a/services/web/app/src/Features/Project/ProjectController.js +++ b/services/web/app/src/Features/Project/ProjectController.js @@ -354,6 +354,7 @@ const _ProjectController = { 'word-count-client', 'editor-popup-ux-survey', 'new-editor-error-logs-redesign', + 'ide-redesign-experiment-nudge', ].filter(Boolean) const getUserValues = async userId => diff --git a/services/web/app/src/Features/Tutorial/TutorialController.mjs b/services/web/app/src/Features/Tutorial/TutorialController.mjs index b4ab3f6727..4606f662bf 100644 --- a/services/web/app/src/Features/Tutorial/TutorialController.mjs +++ b/services/web/app/src/Features/Tutorial/TutorialController.mjs @@ -16,6 +16,7 @@ const VALID_KEYS = [ 'wf-features-moved', 'review-mode', 'new-error-logs-promo', + 'try-redesign-again-nudge-promo', ] async function completeTutorial(req, res, next) { diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index cb1da29d7a..309ce4021b 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -442,6 +442,7 @@ "doing_this_will_verify_affiliation_and_allow_log_in_2": "", "done": "", "dont_forget_you_currently_have": "", + "dont_miss_out_on_the_updated_editor": "", "dont_reload_or_close_this_tab": "", "double_clicking_on_the_pdf_shows": "", "download": "", @@ -2081,6 +2082,7 @@ "were_performing_maintenance": "", "were_redesigning_our_editor_to_make_it_easier_to_use": "", "were_reducing_compile_timeout": "", + "weve_been_making_changes_and_improvements_why_not_give_it_a_try": "", "what_did_you_find_most_helpful": "", "what_do_you_need_help_with": "", "what_does_this_mean": "", diff --git a/services/web/frontend/js/features/editor-navigation-toolbar/try-new-editor-button.tsx b/services/web/frontend/js/features/editor-navigation-toolbar/try-new-editor-button.tsx index 6fc3bc80a3..8afe6104e1 100644 --- a/services/web/frontend/js/features/editor-navigation-toolbar/try-new-editor-button.tsx +++ b/services/web/frontend/js/features/editor-navigation-toolbar/try-new-editor-button.tsx @@ -1,12 +1,21 @@ -import { useCallback } from 'react' +import { useCallback, useRef } from 'react' import OLButton from '../ui/components/ol/ol-button' import { useIdeRedesignSwitcherContext } from '../ide-react/context/ide-redesign-switcher-context' import MaterialIcon from '@/shared/components/material-icon' import { useTranslation } from 'react-i18next' +import TooltipPromotion from '../ide-redesign/components/tooltip-promo' +import { useFeatureFlag } from '@/shared/context/split-test-context' + +const TUTORIAL_KEY = 'try-redesign-again-nudge-promo' +const EVENT_DATA = { name: 'try-redesign-again-nudge-promotion' } const TryNewEditorButton = () => { const { t } = useTranslation() const { setShowSwitcherModal } = useIdeRedesignSwitcherContext() + const showNudge = useFeatureFlag('ide-redesign-experiment-nudge') + + const switcherButtonRef = useRef(null) + const onClick = useCallback(() => { setShowSwitcherModal(true) }, [setShowSwitcherModal]) @@ -18,9 +27,22 @@ const TryNewEditorButton = () => { size="sm" leadingIcon={} variant="secondary" + ref={switcherButtonRef} > {t('try_the_new_editor')} + {showNudge && ( + + )} ) } diff --git a/services/web/frontend/js/features/ide-redesign/components/error-logs/new-error-logs-promo.tsx b/services/web/frontend/js/features/ide-redesign/components/error-logs/new-error-logs-promo.tsx index 1589fa819d..144a1acdb9 100644 --- a/services/web/frontend/js/features/ide-redesign/components/error-logs/new-error-logs-promo.tsx +++ b/services/web/frontend/js/features/ide-redesign/components/error-logs/new-error-logs-promo.tsx @@ -1,9 +1,5 @@ -import Close from '@/shared/components/close' -import { useEditorContext } from '@/shared/context/editor-context' -import useTutorial from '@/shared/hooks/promotions/use-tutorial' -import { useCallback, useEffect } from 'react' -import { Overlay, Popover } from 'react-bootstrap' import { useTranslation } from 'react-i18next' +import TooltipPromotion from '../tooltip-promo' const TUTORIAL_KEY = 'new-error-logs-promo' const EVENT_DATA = { name: 'new-error-logs-promotion' } @@ -14,46 +10,18 @@ export default function NewErrorLogsPromo({ target: HTMLElement | null }) { const { t } = useTranslation() - - const { inactiveTutorials } = useEditorContext() - const { showPopup, tryShowingPopup, hideUntilReload, completeTutorial } = - useTutorial(TUTORIAL_KEY, EVENT_DATA) - - useEffect(() => { - if (!inactiveTutorials.includes(TUTORIAL_KEY)) { - tryShowingPopup() - } - }, [tryShowingPopup, inactiveTutorials]) - - const onHide = useCallback(() => { - hideUntilReload() - }, [hideUntilReload]) - - const onClose = useCallback(() => { - completeTutorial({ - action: 'complete', - event: 'promo-dismiss', - }) - }, [completeTutorial]) - if (!target) { return null } return ( - - - - {t('error_logs_have_had_an_update')} - - - - + tutorialKey={TUTORIAL_KEY} + eventData={EVENT_DATA} + className="new-error-logs-promo" + content={t('error_logs_have_had_an_update')} + placement="right" + /> ) } diff --git a/services/web/frontend/js/features/ide-redesign/components/tooltip-promo.tsx b/services/web/frontend/js/features/ide-redesign/components/tooltip-promo.tsx new file mode 100644 index 0000000000..4359f42dd3 --- /dev/null +++ b/services/web/frontend/js/features/ide-redesign/components/tooltip-promo.tsx @@ -0,0 +1,66 @@ +import Close from '@/shared/components/close' +import { useEditorContext } from '@/shared/context/editor-context' +import useTutorial from '@/shared/hooks/promotions/use-tutorial' +import classNames from 'classnames' +import { useCallback, useEffect } from 'react' +import { Overlay, OverlayProps, Popover } from 'react-bootstrap' + +export default function TooltipPromotion({ + target, + tutorialKey, + eventData, + className, + content, + header, + placement = 'bottom', +}: { + target: HTMLElement | null + tutorialKey: string + eventData: Record + className?: string + content: string + header?: string + placement?: OverlayProps['placement'] +}) { + const { inactiveTutorials } = useEditorContext() + const { showPopup, tryShowingPopup, hideUntilReload, dismissTutorial } = + useTutorial(tutorialKey, eventData) + + useEffect(() => { + if (!inactiveTutorials.includes(tutorialKey)) { + tryShowingPopup() + } + }, [tryShowingPopup, inactiveTutorials, tutorialKey]) + + const onHide = useCallback(() => { + hideUntilReload() + }, [hideUntilReload]) + + if (!target) { + return null + } + + return ( + + + {header && ( + + {header} + + + )} + + + {content} + {!header && } + + + + ) +} diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 8aa1abd506..7e7d42c184 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -576,6 +576,7 @@ "done": "Done", "dont_forget_you_currently_have": "Don’t forget, you currently have:", "dont_have_account": "Don’t have an account?", + "dont_miss_out_on_the_updated_editor": "Don’t miss out on the updated editor", "dont_reload_or_close_this_tab": "Don’t reload or close this tab.", "double_clicking_on_the_pdf_shows": "Double clicking on the PDF shows the corresponding location in code. Added word count (7 May 2025)", "download": "Download", @@ -2633,6 +2634,7 @@ "were_performing_maintenance": "We’re performing maintenance on Overleaf and you need to wait a moment. Sorry for any inconvenience. The editor will refresh automatically in __seconds__ seconds.", "were_redesigning_our_editor_to_make_it_easier_to_use": "We’re redesigning our editor to make it easier to use and ensure it’s future ready. Try it out and give us your feedback to help us get this right. (Some features are still in the works, so you can switch back at any time.)", "were_reducing_compile_timeout": "We’re in the process of <0>reducing the compile timeout limit on our free plan, which may affect your project in future.", + "weve_been_making_changes_and_improvements_why_not_give_it_a_try": "We’ve been making changes and improvements. Why not give it a try?", "what_did_you_find_most_helpful": "What did you find most helpful?", "what_do_you_need": "What do you need?", "what_do_you_need_help_with": "What do you need help with?",