FEATURE: add option to skip new user tips in first notification. (#10462)

FEATURE: add option to skip new user tips in first notification. (#10462)

diff --git a/app/assets/javascripts/discourse/app/templates/preferences/interface.hbs b/app/assets/javascripts/discourse/app/templates/preferences/interface.hbs
index af40097..d4cd222 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))
     }}
   </div>
-  {{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"}}
 </div>
 
 {{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 ba945cc..d2d4d59 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 6360f2f..37d5ce6 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 91f2070..440ed65 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 a5027c5..dc21f5b 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 1fd701b..0168e34 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 33bd9b7..6bd0bb2 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 55e7655..1a42183 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

[... diff too long, it was truncated ...]

GitHub sha: 562180dd

This commit appears in #10462 which was merged by vinothkannans.