From 562180dd9a2f1b3251463791b608339d7b23bccd Mon Sep 17 00:00:00 2001 From: Vinoth Kannan Date: Tue, 18 Aug 2020 13:43:40 +0530 Subject: [PATCH] FEATURE: add option to skip new user tips in first notification. (#10462) --- .../app/templates/preferences/interface.hbs | 2 +- .../discourse/app/widgets/header.js | 37 +++++++++++++++---- .../stylesheets/common/base/discourse.scss | 6 +++ app/models/user.rb | 3 +- app/services/badge_granter.rb | 1 + config/locales/client.en.yml | 5 ++- .../config/locales/server.en.yml | 1 + plugins/discourse-narrative-bot/plugin.rb | 23 ++++++++++++ .../discourse-narrative-bot/spec/user_spec.rb | 15 ++++++++ spec/models/user_spec.rb | 8 ++++ spec/services/badge_granter_spec.rb | 9 +++++ 11 files changed, 100 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/discourse/app/templates/preferences/interface.hbs b/app/assets/javascripts/discourse/app/templates/preferences/interface.hbs index af40097a8dd..d4cd222b96f 100644 --- a/app/assets/javascripts/discourse/app/templates/preferences/interface.hbs +++ b/app/assets/javascripts/discourse/app/templates/preferences/interface.hbs @@ -103,7 +103,7 @@ onChange=(action (mut model.user_option.title_count_mode)) }} - {{preference-checkbox labelKey="user.skip_new_user_tips" checked=model.user_option.skip_new_user_tips class="pref-new-user-tips"}} + {{preference-checkbox labelKey="user.skip_new_user_tips.description" checked=model.user_option.skip_new_user_tips class="pref-new-user-tips"}} {{plugin-outlet name="user-preferences-interface" args=(hash model=model save=(action "save"))}} diff --git a/app/assets/javascripts/discourse/app/widgets/header.js b/app/assets/javascripts/discourse/app/widgets/header.js index ba945ccd647..d2d4d59f26c 100644 --- a/app/assets/javascripts/discourse/app/widgets/header.js +++ b/app/assets/javascripts/discourse/app/widgets/header.js @@ -5,7 +5,7 @@ import { schedule } from "@ember/runloop"; import { createWidget } from "discourse/widgets/widget"; import { iconNode } from "discourse-common/lib/icon-library"; import { avatarImg } from "discourse/widgets/post"; -import DiscourseURL from "discourse/lib/url"; +import DiscourseURL, { userPath } from "discourse/lib/url"; import { wantsNewWindow } from "discourse/lib/intercept-click"; import { applySearchAutocomplete } from "discourse/lib/search"; import { ajax } from "discourse/lib/ajax"; @@ -85,18 +85,29 @@ createWidget("header-notifications", { !user.get("read_first_notification") && !user.get("enforcedSecondFactor") ) { - contents.push(h("span.ring")); if (!attrs.active && attrs.ringBackdrop) { + contents.push(h("span.ring")); contents.push(h("span.ring-backdrop-spotlight")); contents.push( h( "span.ring-backdrop", {}, - h( - "h1.ring-first-notification", - {}, - I18n.t("user.first_notification") - ) + h("h1.ring-first-notification", {}, [ + h("span", {}, I18n.t("user.first_notification")), + h("br"), + h("br"), + h("span", {}, [ + I18n.t("user.skip_new_user_tips.not_first_time"), + " ", + this.attach("link", { + action: "skipNewUserTips", + className: "skip-new-user-tips", + label: "user.skip_new_user_tips.skip_link", + title: "user.skip_new_user_tips.description", + omitSpan: true + }) + ]) + ]) ) ); } @@ -579,6 +590,18 @@ export default createWidget("header", { this.scheduleRerender(); }, + skipNewUserTips() { + this.headerDismissFirstNotificationMask(); + ajax(userPath(this.currentUser.username_lower), { + type: "PUT", + data: { + skip_new_user_tips: true + } + }).then(() => { + this.currentUser.set("skip_new_user_tips", true); + }); + }, + headerKeyboardTrigger(msg) { switch (msg.type) { case "search": diff --git a/app/assets/stylesheets/common/base/discourse.scss b/app/assets/stylesheets/common/base/discourse.scss index 6360f2fcfdf..37d5ce67572 100644 --- a/app/assets/stylesheets/common/base/discourse.scss +++ b/app/assets/stylesheets/common/base/discourse.scss @@ -443,6 +443,12 @@ table { top: 60px; width: 230px; line-height: $line-height-medium; + + .skip-new-user-tips { + font-size: $font-down-1; + color: var(--secondary); + text-decoration: underline; + } } .ring { diff --git a/app/models/user.rb b/app/models/user.rb index 91f2070770d..440ed6519d8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -568,7 +568,8 @@ class User < ActiveRecord::Base def read_first_notification? if (trust_level > TrustLevel[1] || - (first_seen_at.present? && first_seen_at < TRACK_FIRST_NOTIFICATION_READ_DURATION.seconds.ago)) + (first_seen_at.present? && first_seen_at < TRACK_FIRST_NOTIFICATION_READ_DURATION.seconds.ago) || + user_option.skip_new_user_tips) return true end diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index a5027c53030..dc21f5bb4a4 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -45,6 +45,7 @@ class BadgeGranter def grant return if @granted_by && !Guardian.new(@granted_by).can_grant_badges?(@user) return unless @badge.enabled? + return if @badge.badge_grouping_id == BadgeGrouping::GettingStarted && @user.user_option.skip_new_user_tips find_by = { badge_id: @badge.id, user_id: @user.id } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 1fd701bacd7..0168e342682 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -930,7 +930,10 @@ en: dismiss_notifications_tooltip: "Mark all unread notifications as read" first_notification: "Your first notification! Select it to begin." dynamic_favicon: "Show counts on browser icon" - skip_new_user_tips: "Skip new user onboarding tips and badges" + skip_new_user_tips: + description: "Skip new user onboarding tips and badges" + not_first_time: "Not your first time?" + skip_link: "Skip these tips" theme_default_on_all_devices: "Make this the default theme on all my devices" dark_mode: "Dark Mode" dark_mode_enable: "Enable automatic dark mode color scheme" diff --git a/plugins/discourse-narrative-bot/config/locales/server.en.yml b/plugins/discourse-narrative-bot/config/locales/server.en.yml index 33bd9b72ea7..6bd0bb2250e 100644 --- a/plugins/discourse-narrative-bot/config/locales/server.en.yml +++ b/plugins/discourse-narrative-bot/config/locales/server.en.yml @@ -156,6 +156,7 @@ en: reset_trigger: "tutorial" title: "New user tutorial completion certificate" cert_title: "In recognition of successful completion of the new user tutorial" + delete_reason: "User skipped the new user tips" hello: title: "Greetings!" diff --git a/plugins/discourse-narrative-bot/plugin.rb b/plugins/discourse-narrative-bot/plugin.rb index 55e765522fc..1a42183ece5 100644 --- a/plugins/discourse-narrative-bot/plugin.rb +++ b/plugins/discourse-narrative-bot/plugin.rb @@ -150,6 +150,12 @@ after_initialize do user.enqueue_bot_welcome_post end + self.add_model_callback(UserOption, :after_save) do + if saved_change_to_skip_new_user_tips? && self.skip_new_user_tips + user.delete_bot_welcome_post + end + end + self.add_to_class(:user, :enqueue_bot_welcome_post) do return if SiteSetting.disable_discourse_narrative_bot_welcome_post @@ -173,9 +179,26 @@ after_initialize do self.human? && !self.anonymous? && !self.staged && + !user_option.skip_new_user_tips && !SiteSetting.discourse_narrative_bot_ignored_usernames.split('|'.freeze).include?(self.username) end + self.add_to_class(:user, :delete_bot_welcome_post) do + data = DiscourseNarrativeBot::Store.get(self.id) || {} + topic_id = data[:topic_id] + return if topic_id.blank? || data[:track] != DiscourseNarrativeBot::NewUserNarrative.to_s + + topic_user = topic_users.find_by(topic_id: topic_id) + return if topic_user.present? && (topic_user.last_read_post_number.present? || topic_user.highest_seen_post_number.present?) + + topic = Topic.find_by(id: topic_id) + return if topic.blank? + + first_post = topic.ordered_posts.first + PostDestroyer.new(Discourse.system_user, first_post, context: I18n.t('discourse_narrative_bot.new_user_narrative.delete_reason')).destroy + DiscourseNarrativeBot::Store.remove(self.id) + end + self.on(:post_created) do |post, options| user = post.user diff --git a/plugins/discourse-narrative-bot/spec/user_spec.rb b/plugins/discourse-narrative-bot/spec/user_spec.rb index f73c291f410..bf09a0f7339 100644 --- a/plugins/discourse-narrative-bot/spec/user_spec.rb +++ b/plugins/discourse-narrative-bot/spec/user_spec.rb @@ -108,6 +108,21 @@ describe User do end end + context 'when user skipped the new user tips' do + let(:user) { Fabricate(:user) } + + it 'should not initiate the bot' do + SiteSetting.default_other_skip_new_user_tips = true + expect { user }.to_not change { Post.count } + end + + it 'should delete the existing PM' do + user.user_option.skip_new_user_tips = true + + expect { user.user_option.save! }.to change { Topic.count }.by(-1) + end + end + context 'when user is anonymous?' do before do SiteSetting.allow_anonymous_posting = true diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 52f38a0e925..cea4a75126a 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1763,6 +1763,14 @@ describe User do expect(user.read_first_notification?).to eq(true) end end + + describe 'when user skipped new user tips' do + it 'should return the right value' do + user.user_option.update!(skip_new_user_tips: true) + + expect(user.read_first_notification?).to eq(true) + end + end end describe "#featured_user_badges" do diff --git a/spec/services/badge_granter_spec.rb b/spec/services/badge_granter_spec.rb index b2fa73c9e0c..f36f93b02bc 100644 --- a/spec/services/badge_granter_spec.rb +++ b/spec/services/badge_granter_spec.rb @@ -155,6 +155,15 @@ describe BadgeGranter do expect(user_badge).to eq(nil) end + it "doesn't grant 'getting started' badges when user skipped new user tips" do + freeze_time + user.user_option.update!(skip_new_user_tips: true) + badge = Fabricate(:badge, badge_grouping_id: BadgeGrouping::GettingStarted) + + user_badge = BadgeGranter.grant(badge, user, created_at: 1.year.ago) + expect(user_badge).to eq(nil) + end + it 'grants multiple badges' do badge = Fabricate(:badge, multiple_grant: true) user_badge = BadgeGranter.grant(badge, user)