mirror of
https://github.com/discourse/discourse.git
synced 2025-03-22 07:35:38 +08:00
FEATURE: add option to skip new user tips in first notification. (#10462)
This commit is contained in:
parent
2a7490149c
commit
562180dd9a
@ -103,7 +103,7 @@
|
|||||||
onChange=(action (mut model.user_option.title_count_mode))
|
onChange=(action (mut model.user_option.title_count_mode))
|
||||||
}}
|
}}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
|
|
||||||
{{plugin-outlet name="user-preferences-interface" args=(hash model=model save=(action "save"))}}
|
{{plugin-outlet name="user-preferences-interface" args=(hash model=model save=(action "save"))}}
|
||||||
|
@ -5,7 +5,7 @@ import { schedule } from "@ember/runloop";
|
|||||||
import { createWidget } from "discourse/widgets/widget";
|
import { createWidget } from "discourse/widgets/widget";
|
||||||
import { iconNode } from "discourse-common/lib/icon-library";
|
import { iconNode } from "discourse-common/lib/icon-library";
|
||||||
import { avatarImg } from "discourse/widgets/post";
|
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 { wantsNewWindow } from "discourse/lib/intercept-click";
|
||||||
import { applySearchAutocomplete } from "discourse/lib/search";
|
import { applySearchAutocomplete } from "discourse/lib/search";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
@ -85,18 +85,29 @@ createWidget("header-notifications", {
|
|||||||
!user.get("read_first_notification") &&
|
!user.get("read_first_notification") &&
|
||||||
!user.get("enforcedSecondFactor")
|
!user.get("enforcedSecondFactor")
|
||||||
) {
|
) {
|
||||||
contents.push(h("span.ring"));
|
|
||||||
if (!attrs.active && attrs.ringBackdrop) {
|
if (!attrs.active && attrs.ringBackdrop) {
|
||||||
|
contents.push(h("span.ring"));
|
||||||
contents.push(h("span.ring-backdrop-spotlight"));
|
contents.push(h("span.ring-backdrop-spotlight"));
|
||||||
contents.push(
|
contents.push(
|
||||||
h(
|
h(
|
||||||
"span.ring-backdrop",
|
"span.ring-backdrop",
|
||||||
{},
|
{},
|
||||||
h(
|
h("h1.ring-first-notification", {}, [
|
||||||
"h1.ring-first-notification",
|
h("span", {}, I18n.t("user.first_notification")),
|
||||||
{},
|
h("br"),
|
||||||
I18n.t("user.first_notification")
|
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();
|
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) {
|
headerKeyboardTrigger(msg) {
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case "search":
|
case "search":
|
||||||
|
@ -443,6 +443,12 @@ table {
|
|||||||
top: 60px;
|
top: 60px;
|
||||||
width: 230px;
|
width: 230px;
|
||||||
line-height: $line-height-medium;
|
line-height: $line-height-medium;
|
||||||
|
|
||||||
|
.skip-new-user-tips {
|
||||||
|
font-size: $font-down-1;
|
||||||
|
color: var(--secondary);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ring {
|
.ring {
|
||||||
|
@ -568,7 +568,8 @@ class User < ActiveRecord::Base
|
|||||||
|
|
||||||
def read_first_notification?
|
def read_first_notification?
|
||||||
if (trust_level > TrustLevel[1] ||
|
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
|
return true
|
||||||
end
|
end
|
||||||
|
@ -45,6 +45,7 @@ class BadgeGranter
|
|||||||
def grant
|
def grant
|
||||||
return if @granted_by && !Guardian.new(@granted_by).can_grant_badges?(@user)
|
return if @granted_by && !Guardian.new(@granted_by).can_grant_badges?(@user)
|
||||||
return unless @badge.enabled?
|
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 }
|
find_by = { badge_id: @badge.id, user_id: @user.id }
|
||||||
|
|
||||||
|
@ -930,7 +930,10 @@ en:
|
|||||||
dismiss_notifications_tooltip: "Mark all unread notifications as read"
|
dismiss_notifications_tooltip: "Mark all unread notifications as read"
|
||||||
first_notification: "Your first notification! Select it to begin."
|
first_notification: "Your first notification! Select it to begin."
|
||||||
dynamic_favicon: "Show counts on browser icon"
|
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"
|
theme_default_on_all_devices: "Make this the default theme on all my devices"
|
||||||
dark_mode: "Dark Mode"
|
dark_mode: "Dark Mode"
|
||||||
dark_mode_enable: "Enable automatic dark mode color scheme"
|
dark_mode_enable: "Enable automatic dark mode color scheme"
|
||||||
|
@ -156,6 +156,7 @@ en:
|
|||||||
reset_trigger: "tutorial"
|
reset_trigger: "tutorial"
|
||||||
title: "New user tutorial completion certificate"
|
title: "New user tutorial completion certificate"
|
||||||
cert_title: "In recognition of successful completion of the new user tutorial"
|
cert_title: "In recognition of successful completion of the new user tutorial"
|
||||||
|
delete_reason: "User skipped the new user tips"
|
||||||
|
|
||||||
hello:
|
hello:
|
||||||
title: "Greetings!"
|
title: "Greetings!"
|
||||||
|
@ -150,6 +150,12 @@ after_initialize do
|
|||||||
user.enqueue_bot_welcome_post
|
user.enqueue_bot_welcome_post
|
||||||
end
|
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
|
self.add_to_class(:user, :enqueue_bot_welcome_post) do
|
||||||
return if SiteSetting.disable_discourse_narrative_bot_welcome_post
|
return if SiteSetting.disable_discourse_narrative_bot_welcome_post
|
||||||
|
|
||||||
@ -173,9 +179,26 @@ after_initialize do
|
|||||||
self.human? &&
|
self.human? &&
|
||||||
!self.anonymous? &&
|
!self.anonymous? &&
|
||||||
!self.staged &&
|
!self.staged &&
|
||||||
|
!user_option.skip_new_user_tips &&
|
||||||
!SiteSetting.discourse_narrative_bot_ignored_usernames.split('|'.freeze).include?(self.username)
|
!SiteSetting.discourse_narrative_bot_ignored_usernames.split('|'.freeze).include?(self.username)
|
||||||
end
|
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|
|
self.on(:post_created) do |post, options|
|
||||||
user = post.user
|
user = post.user
|
||||||
|
|
||||||
|
@ -108,6 +108,21 @@ describe User do
|
|||||||
end
|
end
|
||||||
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
|
context 'when user is anonymous?' do
|
||||||
before do
|
before do
|
||||||
SiteSetting.allow_anonymous_posting = true
|
SiteSetting.allow_anonymous_posting = true
|
||||||
|
@ -1763,6 +1763,14 @@ describe User do
|
|||||||
expect(user.read_first_notification?).to eq(true)
|
expect(user.read_first_notification?).to eq(true)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
describe "#featured_user_badges" do
|
describe "#featured_user_badges" do
|
||||||
|
@ -155,6 +155,15 @@ describe BadgeGranter do
|
|||||||
expect(user_badge).to eq(nil)
|
expect(user_badge).to eq(nil)
|
||||||
end
|
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
|
it 'grants multiple badges' do
|
||||||
badge = Fabricate(:badge, multiple_grant: true)
|
badge = Fabricate(:badge, multiple_grant: true)
|
||||||
user_badge = BadgeGranter.grant(badge, user)
|
user_badge = BadgeGranter.grant(badge, user)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user