From 470ad36218d309a66edcbed354878a7fcc5268e8 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 9 Nov 2017 14:28:11 +0000 Subject: [PATCH] Add onboarding popup for link-sharing --- .../Features/Project/ProjectController.coffee | 20 +++++++ services/web/app/views/project/editor.pug | 1 + .../web/app/views/project/editor/editor.pug | 14 +++++ .../web/app/views/project/editor/header.pug | 2 +- services/web/public/coffee/ide.coffee | 2 + .../LinkSharingOnboardingController.coffee | 24 ++++++++ .../onboarding/linksharing/link-sharing.png | Bin 0 -> 2965 bytes .../app/editor/feature-onboarding.less | 56 ++++++++++++++++++ 8 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 services/web/public/coffee/ide/LinkSharingOnboardingController.coffee create mode 100644 services/web/public/img/onboarding/linksharing/link-sharing.png diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index bbfb47d6a1..bb08f49de5 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -290,6 +290,23 @@ module.exports = ProjectController = else logger.log { user_id, event }, "autocompile onboarding not shown yet to this user" return cb(null, { enabled: true, showOnboarding: true }) + couldShowLinkSharingOnboarding: (cb) -> + cb = underscore.once(cb) + if !user_id? + return cb() + # Extract data from user's ObjectId + timestamp = parseInt(user_id.toString().substring(0, 8), 16) + userSignupDate = new Date(timestamp * 1000) + if userSignupDate > new Date("2017-11-10") + # Don't show for users who registered after it was released + return cb(null, false) + timeout = setTimeout cb, 500 + AnalyticsManager.getLastOccurance user_id, "shown-linksharing-onboarding", (error, event) -> + clearTimeout timeout + if error? || event? + return cb(null, false) + else + return cb(null, true) }, (err, results)-> if err? logger.err err:err, "error getting details for project page" @@ -304,7 +321,9 @@ module.exports = ProjectController = token = TokenAccessHandler.getRequestToken(req, project_id) isTokenMember = results.isTokenMember + # Roll out token-access based on Project owner enableTokenAccessUI = ProjectController._isInPercentageRollout(project.owner_ref, 0) + showLinkSharingOnboarding = enableTokenAccessUI && results.couldShowLinkSharingOnboarding AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, token, (error, privilegeLevel)-> return next(error) if error? if !privilegeLevel? or privilegeLevel == PrivilegeLevels.NONE @@ -356,6 +375,7 @@ module.exports = ProjectController = themes: THEME_LIST maxDocLength: Settings.max_doc_length enableTokenAccessUI: enableTokenAccessUI + showLinkSharingOnboarding: showLinkSharingOnboarding timer.done() _buildProjectList: (allProjects)-> diff --git a/services/web/app/views/project/editor.pug b/services/web/app/views/project/editor.pug index 5bb7f98354..b89fb28e94 100644 --- a/services/web/app/views/project/editor.pug +++ b/services/web/app/views/project/editor.pug @@ -126,6 +126,7 @@ block requirejs window.showPerUserTCNotice = #{!!showPerUserTCNotice}; window.autoCompileEnabled = #{!!autoCompileEnabled}; window.showAutoCompileOnboarding = #{!!showAutoCompileOnboarding} + window.showLinkSharingOnboarding = #{!!showLinkSharingOnboarding} window.wikiEnabled = #{!!(settings.apis.wiki && settings.apis.wiki.url)}; window.enableTokenAccessUI = #{enableTokenAccessUI} window.requirejs = { diff --git a/services/web/app/views/project/editor/editor.pug b/services/web/app/views/project/editor/editor.pug index 86cc63a5e5..76d2998eab 100644 --- a/services/web/app/views/project/editor/editor.pug +++ b/services/web/app/views/project/editor/editor.pug @@ -108,3 +108,17 @@ div.full-size( p #{translate("auto_compile_onboarding_description")} button.btn.btn-default.btn-block(ng-click="dismiss()") | #{translate("got_it")} + +#onboarding-linksharing.onboarding-popover.popover( + ng-controller="LinkSharingOnboardingController" + ng-if="onboarding.linkSharing == 'unseen'" + ng-class="placement" +) + .popover-inner + h3.popover-title #{translate("link_sharing")} + .popover-content + p #{translate("try_out_link_sharing")} + img(src="/img/onboarding/linksharing/link-sharing.png" width="100%") + p #{translate("try_link_sharing_description")} + button.btn.btn-default.btn-block(ng-click="dismiss()") + | #{translate("got_it")} diff --git a/services/web/app/views/project/editor/header.pug b/services/web/app/views/project/editor/header.pug index 8bd37f707c..49361b5a2e 100644 --- a/services/web/app/views/project/editor/header.pug +++ b/services/web/app/views/project/editor/header.pug @@ -99,7 +99,7 @@ header.toolbar.toolbar-header.toolbar-with-labels( i.review-icon p.toolbar-label | #{translate("review")} - a.btn.btn-full-height( + a.btn.btn-full-height#shareButton( href, ng-if="permissions.admin", ng-click="openShareProjectModal();", diff --git a/services/web/public/coffee/ide.coffee b/services/web/public/coffee/ide.coffee index 93d14c78e9..d5023f96d0 100644 --- a/services/web/public/coffee/ide.coffee +++ b/services/web/public/coffee/ide.coffee @@ -14,6 +14,7 @@ define [ "ide/SafariScrollPatcher" "ide/FeatureOnboardingController", "ide/AutoCompileOnboardingController", + "ide/LinkSharingOnboardingController", "ide/settings/index" "ide/share/index" "ide/chat/index" @@ -79,6 +80,7 @@ define [ } $scope.onboarding = { autoCompile: if window.showAutoCompileOnboarding then 'unseen' else 'dismissed' + linkSharing: if window.showLinkSharingOnboarding then 'unseen' else 'dismissed' } $scope.user = window.user $scope.__enableTokenAccessUI = window.enableTokenAccessUI == true diff --git a/services/web/public/coffee/ide/LinkSharingOnboardingController.coffee b/services/web/public/coffee/ide/LinkSharingOnboardingController.coffee new file mode 100644 index 0000000000..7b54328bd9 --- /dev/null +++ b/services/web/public/coffee/ide/LinkSharingOnboardingController.coffee @@ -0,0 +1,24 @@ +define [ + "base" +], (App) -> + App.controller "LinkSharingOnboardingController", ($scope, $timeout, event_tracking) -> + $scope._shown = false + + popover = angular.element('#onboarding-linksharing') + popover.hide() + + $scope.dismiss = () -> + $scope.onboarding.linkSharing = 'dismissed' + event_tracking.sendMB "shown-linksharing-onboarding" + + $scope.$on 'doc:opened', () -> + return if $scope._shown + shareBtn = angular.element('#shareButton') + offset = shareBtn.offset() + popover.show() + $scope.placement = 'bottom' + popover.offset({ + top: offset.top + 8 + shareBtn.height(), + left: offset.left + }) + $scope.shown = true diff --git a/services/web/public/img/onboarding/linksharing/link-sharing.png b/services/web/public/img/onboarding/linksharing/link-sharing.png new file mode 100644 index 0000000000000000000000000000000000000000..a86fe18ce58213d3e2cf9f8c1c946b5607155e8b GIT binary patch literal 2965 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 literal 0 HcmV?d00001 diff --git a/services/web/public/stylesheets/app/editor/feature-onboarding.less b/services/web/public/stylesheets/app/editor/feature-onboarding.less index 475658f885..26cbb3cf4d 100644 --- a/services/web/public/stylesheets/app/editor/feature-onboarding.less +++ b/services/web/public/stylesheets/app/editor/feature-onboarding.less @@ -143,3 +143,59 @@ a.feat-onboard-dismiss { right: -9.5px; } } +.onboarding-popover { + display: block; + top: 10px; + + img { + margin-bottom: 10px; + border: 1px solid @gray-lighter; + } + + &::before, &::after { + content: ''; + border-width: 11px; + border-style: solid; + border-color: transparent; + top: 7px; + display: block; + position: absolute; + } + + &.right::before { + border-left-width: 0; + border-right-color: rgba(0, 0, 0, .3); + left: -11px; + } + + &.right::after { + border-left-width: 0; + border-right-color: #f7f7f7; + left: -9.5px; + } + + &.left::before { + border-right-width: 0; + border-left-color: rgba(0, 0, 0, .3); + right: -11px + } + + &.left::after { + border-right-width: 0; + border-left-color: #f7f7f7; + right: -9.5px; + } + + &.bottom::before { + border-top-width: 0; + border-bottom-color: rgba(0, 0, 0, .3); + top: -11px + } + + &.bottom::after { + border-top-width: 0; + border-bottom-color: #f7f7f7; + top: -9.5px; + } + +}