Просмотр исходного кода

Implement "switch away survey" when users switching back to ace from cm6 (#10201)

Implement legacy source editor survey:

* Force user to switch to cm6 if they haven't seen switch away survey

* Only show user switch away survey if they open ace from another editor

* We need to wait 3 seconds until the survey is being shown

* Add comment to explain the reasoning of not showing cm6 switch away survey for rich text users

* Use localstorage `editor.has_seen_cm6_switch_away_survey` setter to not show the survey if user has seen the survey

* the `editor.has_seen_cm6_switch_away_survey` will have the value `true` even if user is not interacting with it, so update comment to reflect that

* Add `once: true` option to keydown event to avoid unnecessary callback invocation upon key presses

GitOrigin-RevId: c26be2bb39efac2dff112c821fca893e5993dcbf
M Fahru 4 лет назад
Родитель
Сommit
19dd2f67e2

+ 2 - 0
services/web/app/views/project/editor/editor.pug

@@ -12,6 +12,8 @@ div.full-size(
 	custom-toggler-msg-when-open=hasFeature('custom-togglers') ? translate("tooltip_hide_pdf") : false
 	custom-toggler-msg-when-open=hasFeature('custom-togglers') ? translate("tooltip_hide_pdf") : false
 	custom-toggler-msg-when-closed=hasFeature('custom-togglers') ? translate("tooltip_show_pdf") : false
 	custom-toggler-msg-when-closed=hasFeature('custom-togglers') ? translate("tooltip_show_pdf") : false
 )
 )
+	cm6-switch-away-survey()
+
 	include ./editor-pane
 	include ./editor-pane
 
 
 	.ui-layout-east
 	.ui-layout-east

+ 98 - 0
services/web/frontend/js/features/source-editor/components/cm6-switch-away-survey.tsx

@@ -0,0 +1,98 @@
+import { useCallback, useEffect, useRef, useState } from 'react'
+import { Button } from 'react-bootstrap'
+import customLocalStorage from '../../../infrastructure/local-storage'
+import useScopeValue from '../../../shared/hooks/use-scope-value'
+
+type CM6SwitchAwaySurveyState = 'disabled' | 'enabled' | 'shown'
+
+export default function CM6SwitchAwaySurvey() {
+  const [state, setState] = useState<CM6SwitchAwaySurveyState>('disabled')
+  const [newSourceEditor] = useScopeValue('editor.newSourceEditor')
+  const [richText] = useScopeValue('editor.showRichText')
+  const initialRichTextPreference = useRef<boolean>(richText)
+
+  useEffect(() => {
+    // If the user has previously seen the survey, then don't show it again
+    const hasSeenCM6SwitchAwaySurvey = customLocalStorage.getItem(
+      'editor.has_seen_cm6_switch_away_survey'
+    )
+    if (hasSeenCM6SwitchAwaySurvey) return
+
+    if (initialRichTextPreference.current) {
+      if (!richText && newSourceEditor) {
+        // If user change from rich text to cm6, we remove the rich text preference
+        // so if user use rich text -> cm6 -> ace, we will show the survey
+        initialRichTextPreference.current = false
+      }
+
+      // If the user loaded rich text initially, then don't show the survey
+      // (we are assuming that they will not have used CM6 as much)
+      return
+    }
+
+    if (!newSourceEditor) {
+      setState('enabled')
+    }
+  }, [newSourceEditor, richText])
+
+  useEffect(() => {
+    if (state === 'enabled') {
+      const handleKeyDown = () => {
+        const TIME_FOR_SURVEY_TO_APPEAR = 3000
+
+        setTimeout(() => {
+          setState('shown')
+          customLocalStorage.setItem(
+            'editor.has_seen_cm6_switch_away_survey',
+            true
+          )
+        }, TIME_FOR_SURVEY_TO_APPEAR)
+      }
+
+      // can't access the ace editor directly, so add the keydown event
+      // to window
+      window?.addEventListener('keydown', handleKeyDown, { once: true })
+    }
+  }, [state])
+
+  const handleClose = useCallback(() => {
+    setState('disabled')
+  }, [])
+
+  if (state !== 'shown') {
+    return null
+  }
+
+  return (
+    <div className="alert alert-success cm6-switch-away-survey" role="alert">
+      <Button
+        className="close"
+        data-dismiss="alert"
+        aria-label="Close"
+        onClick={handleClose}
+      >
+        <span aria-hidden="true">&times;</span>
+      </Button>
+      <div className="warning-content">
+        <div>
+          <div className="warning-text">
+            We noticed that you're still using the{' '}
+            <strong>Source (legacy)</strong> editor.
+          </div>
+          <div className="warning-text">Could you let us know why?</div>
+        </div>
+        <div style={{ display: 'inline-flex' }}>
+          <a
+            href="https://forms.gle/aW5tMRASpQ7Snds6A"
+            className="btn btn-sm btn-info"
+            target="_blank"
+            rel="noreferrer"
+            onClick={handleClose}
+          >
+            Take survey
+          </a>
+        </div>
+      </div>
+    </div>
+  )
+}

+ 9 - 0
services/web/frontend/js/features/source-editor/controllers/cm6-switch-away-survey-controller.js

@@ -0,0 +1,9 @@
+import App from '../../../base'
+import { react2angular } from 'react2angular'
+import { rootContext } from '../../../shared/context/root-context'
+import CM6SwitchAwaySurvey from '../components/cm6-switch-away-survey'
+
+App.component(
+  'cm6SwitchAwaySurvey',
+  react2angular(rootContext.use(CM6SwitchAwaySurvey))
+)

+ 1 - 0
services/web/frontend/js/ide.js

@@ -64,6 +64,7 @@ import './features/editor-navigation-toolbar/controllers/editor-navigation-toolb
 import './features/pdf-preview/controllers/pdf-preview-controller'
 import './features/pdf-preview/controllers/pdf-preview-controller'
 import './features/share-project-modal/controllers/react-share-project-modal-controller'
 import './features/share-project-modal/controllers/react-share-project-modal-controller'
 import './features/source-editor/controllers/editor-switch-controller'
 import './features/source-editor/controllers/editor-switch-controller'
+import './features/source-editor/controllers/cm6-switch-away-survey-controller'
 import { cleanupServiceWorker } from './utils/service-worker-cleanup'
 import { cleanupServiceWorker } from './utils/service-worker-cleanup'
 import { reportCM6Perf } from './infrastructure/cm6-performance'
 import { reportCM6Perf } from './infrastructure/cm6-performance'
 
 

+ 12 - 3
services/web/frontend/js/ide/editor/EditorManager.js

@@ -176,11 +176,20 @@ export default EditorManager = (function () {
         return false
         return false
       }
       }
 
 
-      const sourceEditor = this.localStorage(
-        `editor.source_editor.${this.$scope.project_id}`
+      const hasSeenCM6SwitchAwaySurvey = this.localStorage(
+        'editor.has_seen_cm6_switch_away_survey'
       )
       )
 
 
-      return sourceEditor === 'cm6' || sourceEditor == null
+      if (hasSeenCM6SwitchAwaySurvey) {
+        const sourceEditor = this.localStorage(
+          `editor.source_editor.${this.$scope.project_id}`
+        )
+
+        return sourceEditor === 'cm6' || sourceEditor == null
+      } else {
+        // force user to switch to cm6 if they haven't seen the switch away survey
+        return true
+      }
     }
     }
 
 
     autoOpenDoc() {
     autoOpenDoc() {

+ 28 - 0
services/web/frontend/stylesheets/app/editor.less

@@ -799,3 +799,31 @@ CodeMirror
     }
     }
   }
   }
 }
 }
+
+.cm6-switch-away-survey {
+  padding: @padding-sm;
+  box-shadow: 5px 5px 6px rgba(0, 0, 0, 0.3);
+  background-color: @ol-blue;
+  width: 530px;
+  position: absolute;
+  right: @margin-sm;
+  bottom: @margin-xl;
+  z-index: @zindex-popover;
+
+  .btn.close {
+    background-color: @ol-blue;
+  }
+
+  .warning-content {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-right: 32px;
+  }
+
+  .warning-text {
+    padding-right: @alert-padding;
+    display: inline-block;
+    font-size: @font-size-small;
+  }
+}