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

Implement new users micro survey for project dashboard page on react and non-react version (#11347)

* Implement new users micro survey for project dashboard page on react and non-react version

* Add 'new-users-micro-survey-click' and 'new-users-micro-survey-prompt' new event for the analytics

GitOrigin-RevId: 9aabe931987638b38995d404aa90ac4d40b2f3b5
M Fahru 3 лет назад
Родитель
Сommit
8227199dcb

+ 32 - 0
services/web/app/src/Features/Project/ProjectController.js

@@ -556,6 +556,26 @@ const ProjectController = {
             }
           )
         },
+        newUsersMicroSurveyAssignment(cb) {
+          SplitTestHandler.getAssignment(
+            req,
+            res,
+            'new-users-micro-survey',
+            (err, assignment) => {
+              if (err) {
+                logger.error(
+                  { err },
+                  'failed to get "new-users-micro-survey" split test assignment'
+                )
+
+                const defaultAssignment = { variant: 'default' }
+                cb(null, defaultAssignment)
+              } else {
+                cb(null, assignment)
+              }
+            }
+          )
+        },
         survey(cb) {
           SurveyHandler.getSurvey(userId, (err, survey) => {
             if (err) {
@@ -578,6 +598,7 @@ const ProjectController = {
           user,
           userEmailsData,
           groupsAndEnterpriseBannerAssignment,
+          newUsersMicroSurveyAssignment,
           userIsMemberOfGroupSubscription,
         } = results
 
@@ -718,6 +739,16 @@ const ProjectController = {
           !userIsMemberOfGroupSubscription &&
           !hasPaidAffiliation
 
+        const SEVEN_DAYS = 1000 * 60 * 60 * 24 * 7
+
+        const isUserLessThanSevenDaysOld =
+          user.signUpDate && Date.now() - user.signUpDate.getTime() < SEVEN_DAYS
+
+        const showNewUsersMicroSurvey =
+          Features.hasFeature('saas') &&
+          newUsersMicroSurveyAssignment.variant === 'enabled' &&
+          isUserLessThanSevenDaysOld
+
         ProjectController._injectProjectUsers(projects, (error, projects) => {
           if (error != null) {
             return next(error)
@@ -745,6 +776,7 @@ const ProjectController = {
             showGroupsAndEnterpriseBanner,
             groupsAndEnterpriseBannerVariant:
               groupsAndEnterpriseBannerAssignment.variant,
+            showNewUsersMicroSurvey,
           }
 
           const paidUser =

+ 27 - 0
services/web/app/src/Features/Project/ProjectListController.js

@@ -312,6 +312,32 @@ async function projectListReactPage(req, res, next) {
     !userIsMemberOfGroupSubscription &&
     !hasPaidAffiliation
 
+  let newUsersMicroSurveyAssignment
+
+  try {
+    newUsersMicroSurveyAssignment =
+      await SplitTestHandler.promises.getAssignment(
+        req,
+        res,
+        'new-users-micro-survey'
+      )
+  } catch (error) {
+    logger.error(
+      { err: error },
+      'failed to get "new-users-micro-survey" split test assignment'
+    )
+  }
+
+  const SEVEN_DAYS = 1000 * 60 * 60 * 24 * 7
+
+  const isUserLessThanSevenDaysOld =
+    user.signUpDate && Date.now() - user.signUpDate.getTime() < SEVEN_DAYS
+
+  const showNewUsersMicroSurvey =
+    Features.hasFeature('saas') &&
+    (newUsersMicroSurveyAssignment?.variant ?? 'default') === 'enabled' &&
+    isUserLessThanSevenDaysOld
+
   res.render('project/list-react', {
     title: 'your_projects',
     usersBestSubscription,
@@ -329,6 +355,7 @@ async function projectListReactPage(req, res, next) {
     showGroupsAndEnterpriseBanner,
     groupsAndEnterpriseBannerVariant:
       groupsAndEnterpriseBannerAssignment?.variant ?? 'default',
+    showNewUsersMicroSurvey,
   })
 }
 

+ 1 - 0
services/web/app/views/project/list-react.pug

@@ -27,6 +27,7 @@ block append meta
 	meta(name="ol-currentUrl" data-type="string" content=currentUrl)
 	meta(name="ol-showGroupsAndEnterpriseBanner" data-type="boolean" content=showGroupsAndEnterpriseBanner)
 	meta(name="ol-groupsAndEnterpriseBannerVariant" data-type="string" content=groupsAndEnterpriseBannerVariant)
+	meta(name="ol-showNewUsersMicroSurvey" data-type="boolean" content=showNewUsersMicroSurvey)
 
 block content
 	main.content.content-alt.project-list-react#project-list-root

+ 30 - 0
services/web/app/views/project/list/notifications.pug

@@ -283,3 +283,33 @@ include ../../_mixins/reconfirm_affiliation
 						button(ng-click="dismiss()").close.pull-right
 							span(aria-hidden="true") &times;
 							span.sr-only #{translate("close")}
+
+	if showNewUsersMicroSurvey
+		ul.list-unstyled(
+			ng-controller="NewUsersMicroSurveyController",
+			ng-cloak
+		)
+			li.notification-entry(
+				ng-if="!hasDismissedNewUsersMicroSurvey"
+				event-tracking="new-users-micro-survey-prompt"
+				event-tracking-mb="true"
+				event-tracking-trigger="load"
+				event-segmentation='{"project-dashboard-react": "default"}'
+			)
+				.alert.alert-info
+					.notification-body
+						| !{translate("help_us_improve_overleaf_by_answering_a_two_question_survey", {}, ['strong'])}
+					.notification-action
+						a.pull-right.btn.btn-sm.btn-info(
+							ng-click="dismiss()"
+							href="https://docs.google.com/forms/d/e/1FAIpQLSdN23eSbaGkl96-LkNiIW1QCVdhAQEnSGrEhbuuZgNQ5-Qvog/viewform?usp=sf_link"
+							target="_blank"
+							event-tracking="new-users-micro-survey-click"
+							event-tracking-mb="true"
+							event-tracking-trigger="click"
+							event-segmentation='{"project-dashboard-react": "default"}'
+						) #{translate("take_survey")}
+					.notification-close
+						button(ng-click="dismiss()").close.pull-right
+							span(aria-hidden="true") &times;
+							span.sr-only #{translate("close")}

+ 2 - 0
services/web/frontend/extracted-translations.json

@@ -291,6 +291,7 @@
   "have_an_extra_backup": "",
   "headers": "",
   "help": "",
+  "help_us_improve_overleaf_by_answering_a_two_question_survey": "",
   "hide_outline": "",
   "history": "",
   "hotkey_add_a_comment": "",
@@ -668,6 +669,7 @@
   "tags": "",
   "tags_slash_folders": "",
   "take_short_survey": "",
+  "take_survey": "",
   "template_approved_by_publisher": "",
   "templates": "",
   "terminated": "",

+ 72 - 0
services/web/frontend/js/features/project-list/components/notifications/new-users-micro-survey.tsx

@@ -0,0 +1,72 @@
+import { useCallback, useEffect, useState } from 'react'
+import Notification from './notification'
+import { sendMB } from '../../../../infrastructure/event-tracking'
+import getMeta from '../../../../utils/meta'
+import customLocalStorage from '../../../../infrastructure/local-storage'
+import { Trans, useTranslation } from 'react-i18next'
+
+export default function NewUsersMicroSurvey() {
+  const { t } = useTranslation()
+
+  const showNewUsersMicroSurvey = getMeta(
+    'ol-showNewUsersMicroSurvey'
+  ) as boolean
+
+  const hasDismissedNewUsersMicroSurvey = customLocalStorage.getItem(
+    'has_dismissed_new_users_micro_survey'
+  )
+
+  // need extra state to close the survey when user clicking the main button
+  const [show, setShow] = useState(!hasDismissedNewUsersMicroSurvey)
+
+  const handleClose = useCallback(() => {
+    customLocalStorage.setItem('has_dismissed_new_users_micro_survey', true)
+  }, [])
+
+  const handleClickTakeSurvey = useCallback(() => {
+    customLocalStorage.setItem('has_dismissed_new_users_micro_survey', true)
+
+    setShow(false)
+
+    sendMB('new-users-micro-survey-click', {
+      'project-dashboard-react': 'enabled',
+    })
+  }, [])
+
+  useEffect(() => {
+    sendMB('new-users-micro-survey-prompt', {
+      'project-dashboard-react': 'enabled',
+    })
+  }, [])
+
+  if (hasDismissedNewUsersMicroSurvey || !showNewUsersMicroSurvey || !show) {
+    return null
+  }
+
+  return (
+    <Notification bsStyle="info" onDismiss={handleClose}>
+      <Notification.Body>
+        <span>
+          <Trans
+            i18nKey="help_us_improve_overleaf_by_answering_a_two_question_survey"
+            components={
+              /* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
+              [<strong />]
+            }
+          />
+        </span>
+      </Notification.Body>
+      <Notification.Action>
+        <a
+          className="pull-right btn btn-info btn-sm"
+          href="https://docs.google.com/forms/d/e/1FAIpQLSdN23eSbaGkl96-LkNiIW1QCVdhAQEnSGrEhbuuZgNQ5-Qvog/viewform?usp=sf_link"
+          rel="noreferrer"
+          target="_blank"
+          onClick={handleClickTakeSurvey}
+        >
+          {t('take_survey')}
+        </a>
+      </Notification.Action>
+    </Notification>
+  )
+}

+ 2 - 0
services/web/frontend/js/features/project-list/components/notifications/user-notifications.tsx

@@ -3,6 +3,7 @@ import Institution from './groups/institution'
 import ConfirmEmail from './groups/confirm-email'
 import ReconfirmationInfo from './groups/affiliation/reconfirmation-info'
 import GroupsAndEnterpriseBanner from './groups-and-enterprise-banner'
+import NewUsersMicroSurvey from './new-users-micro-survey'
 
 function UserNotifications() {
   return (
@@ -13,6 +14,7 @@ function UserNotifications() {
         <ConfirmEmail />
         <ReconfirmationInfo />
         <GroupsAndEnterpriseBanner />
+        <NewUsersMicroSurvey />
       </ul>
     </div>
   )

+ 16 - 0
services/web/frontend/js/main/project-list/notifications-controller.js

@@ -47,6 +47,22 @@ App.controller(
   }
 )
 
+App.controller(
+  'NewUsersMicroSurveyController',
+  function ($scope, localStorage) {
+    $scope.hasDismissedNewUsersMicroSurvey = localStorage(
+      'has_dismissed_new_users_micro_survey'
+    )
+
+    $scope.dismiss = () => {
+      localStorage('has_dismissed_new_users_micro_survey', true)
+      $scope.hasDismissedNewUsersMicroSurvey = true
+    }
+
+    $scope.newUsersMicroSurveyVariant = getMeta('ol-newUsersMicroSurvey')
+  }
+)
+
 App.controller('ProjectInviteNotificationController', function ($scope, $http) {
   // Shortcuts for translation keys
   $scope.projectName = $scope.notification.messageOpts.projectName

+ 2 - 0
services/web/locales/en.json

@@ -632,6 +632,7 @@
   "help": "Help",
   "help_articles_matching": "Help articles matching your subject",
   "help_improve_overleaf_fill_out_this_survey": "If you would like to help us improve Overleaf, please take a moment to fill out <0>this survey</0>.",
+  "help_us_improve_overleaf_by_answering_a_two_question_survey": "Help us improve __appName__ by answering a <0>two question survey</0>.",
   "help_us_spread_word": "Help us spread the word about __appName__",
   "hide_outline": "Hide File outline",
   "history": "History",
@@ -1415,6 +1416,7 @@
   "tags_slash_folders": "Tags/Folders",
   "take_me_home": "Take me home!",
   "take_short_survey": "Take a short survey",
+  "take_survey": "Take Survey",
   "tc_everyone": "Everyone",
   "tc_guests": "Guests",
   "tc_switch_everyone_tip": "Toggle track-changes for everyone",