UX: Improvements to user tips (#26480)
- Add a "Skip tips" button to first notification tip - Add a "Skip tips" button to the admin guide tip - Fixes the timeline tip showing when no timeline was present - Fixes post menu tip showing when no "..." button is present - Adds system tests - Marks each tip as seen as soon as it is displayed so that refreshing, clicking outside, etc. won't show it again - Change just above means we no longer need a MessageBus track Co-authored-by: Bianca Nenciu <nbianca@users.noreply.github.com>
This commit is contained in:
parent
3d4faf3272
commit
c4e8221d7e
|
@ -11,6 +11,7 @@
|
||||||
@priority={{900}}
|
@priority={{900}}
|
||||||
@titleText={{i18n "user_tips.admin_guide.title"}}
|
@titleText={{i18n "user_tips.admin_guide.title"}}
|
||||||
@contentHtml={{this.userTipContent}}
|
@contentHtml={{this.userTipContent}}
|
||||||
|
@showSkipButton={{true}}
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</DButton>
|
</DButton>
|
||||||
|
|
|
@ -54,6 +54,7 @@ export default class Notifications extends Component {
|
||||||
@placement="bottom-end"
|
@placement="bottom-end"
|
||||||
@titleText={{i18n "user_tips.first_notification.title"}}
|
@titleText={{i18n "user_tips.first_notification.title"}}
|
||||||
@contentText={{i18n "user_tips.first_notification.content"}}
|
@contentText={{i18n "user_tips.first_notification.content"}}
|
||||||
|
@showSkipButton={{true}}
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,3 @@
|
||||||
<UserTip
|
|
||||||
@id="topic_timeline"
|
|
||||||
@titleText={{i18n "user_tips.topic_timeline.title"}}
|
|
||||||
@contentText={{i18n "user_tips.topic_timeline.content"}}
|
|
||||||
@placement="left"
|
|
||||||
@triggerSelector=".timeline-scrollarea-wrapper"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class={{concat-class "timeline-container" this.classes}}
|
class={{concat-class "timeline-container" this.classes}}
|
||||||
{{did-insert this.addShowClass}}
|
{{did-insert this.addShowClass}}
|
||||||
|
|
|
@ -61,6 +61,14 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if this.displayTimeLineScrollArea}}
|
{{#if this.displayTimeLineScrollArea}}
|
||||||
|
<UserTip
|
||||||
|
@id="topic_timeline"
|
||||||
|
@titleText={{i18n "user_tips.topic_timeline.title"}}
|
||||||
|
@contentText={{i18n "user_tips.topic_timeline.content"}}
|
||||||
|
@placement="left"
|
||||||
|
@triggerSelector=".timeline-scrollarea-wrapper"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="timeline-scrollarea-wrapper">
|
<div class="timeline-scrollarea-wrapper">
|
||||||
<div class="timeline-date-wrapper">
|
<div class="timeline-date-wrapper">
|
||||||
<a
|
<a
|
||||||
|
|
|
@ -11,6 +11,10 @@ export default class UserTipContainer extends Component {
|
||||||
return htmlSafe(this.args.data.contentHtml);
|
return htmlSafe(this.args.data.contentHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get showSkipButton() {
|
||||||
|
return this.args.data.showSkipButton;
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
handleDismiss(_, event) {
|
handleDismiss(_, event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -18,6 +22,13 @@ export default class UserTipContainer extends Component {
|
||||||
this.userTips.hideUserTipForever(this.args.data.id);
|
this.userTips.hideUserTipForever(this.args.data.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
handleSkip(_, event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.args.close();
|
||||||
|
this.userTips.skipTips();
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="user-tip__container">
|
<div class="user-tip__container">
|
||||||
<div class="user-tip__title">{{@data.titleText}}</div>
|
<div class="user-tip__title">{{@data.titleText}}</div>
|
||||||
|
@ -28,7 +39,6 @@ export default class UserTipContainer extends Component {
|
||||||
{{@data.contentText}}
|
{{@data.contentText}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{#if @data.onDismiss}}
|
|
||||||
<div class="user-tip__buttons">
|
<div class="user-tip__buttons">
|
||||||
<DButton
|
<DButton
|
||||||
class="btn-primary"
|
class="btn-primary"
|
||||||
|
@ -36,8 +46,16 @@ export default class UserTipContainer extends Component {
|
||||||
@action={{this.handleDismiss}}
|
@action={{this.handleDismiss}}
|
||||||
@forwardEvent={{true}}
|
@forwardEvent={{true}}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
|
{{#if this.showSkipButton}}
|
||||||
|
<DButton
|
||||||
|
class="btn-flat btn-text"
|
||||||
|
@translatedLabel={{@data.buttonSkipText}}
|
||||||
|
@action={{this.handleSkip}}
|
||||||
|
@forwardEvent={{true}}
|
||||||
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,14 +55,19 @@ export default class UserTip extends Component {
|
||||||
contentText: this.args.contentText
|
contentText: this.args.contentText
|
||||||
? escape(this.args.contentText)
|
? escape(this.args.contentText)
|
||||||
: null,
|
: null,
|
||||||
onDismiss: () => {
|
|
||||||
this.userTips.hideUserTipForever(this.args.id);
|
|
||||||
},
|
|
||||||
buttonText,
|
buttonText,
|
||||||
|
buttonSkipText: I18n.t("user_tips.skip"),
|
||||||
|
showSkipButton: this.args.showSkipButton,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.tooltip.show(instance);
|
this.tooltip.show(instance);
|
||||||
|
|
||||||
|
if (this.shouldRenderTip) {
|
||||||
|
// mark tooltip directly as seen so that
|
||||||
|
// refreshing, clicking outside, etc. won't show it again
|
||||||
|
this.userTips.markAsSeen(this.args.id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
import { bind } from "discourse-common/utils/decorators";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
after: "message-bus",
|
|
||||||
|
|
||||||
initialize(owner) {
|
|
||||||
this.currentUser = owner.lookup("service:current-user");
|
|
||||||
if (!this.currentUser) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.userTips = owner.lookup("service:user-tips");
|
|
||||||
this.messageBus = owner.lookup("service:message-bus");
|
|
||||||
this.site = owner.lookup("service:site");
|
|
||||||
|
|
||||||
this.messageBus.subscribe(
|
|
||||||
`/user-tips/${this.currentUser.id}`,
|
|
||||||
this.onMessage
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
teardown() {
|
|
||||||
if (this.currentUser) {
|
|
||||||
this.messageBus?.unsubscribe(
|
|
||||||
`/user-tips/${this.currentUser.id}`,
|
|
||||||
this.onMessage
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
@bind
|
|
||||||
onMessage(seenUserTips) {
|
|
||||||
if (!this.site.user_tips) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.currentUser.user_option) {
|
|
||||||
this.currentUser.set("user_option", {});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.currentUser.set("user_option.seen_popups", seenUserTips);
|
|
||||||
|
|
||||||
(seenUserTips || []).forEach((userTipId) => {
|
|
||||||
this.userTips.hideUserTipForever(
|
|
||||||
Object.keys(this.site.user_tips).find(
|
|
||||||
(id) => this.site.user_tips[id] === userTipId
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -39,9 +39,11 @@ export default class UserTips extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
addAvailableTip(tip) {
|
addAvailableTip(tip) {
|
||||||
|
if (this.canSeeUserTip(tip.id) && !this._findAvailableTipById(tip.id)) {
|
||||||
this.#availableTips.add(tip);
|
this.#availableTips.add(tip);
|
||||||
this.#updateRenderedId();
|
this.#updateRenderedId();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
removeAvailableTip(tip) {
|
removeAvailableTip(tip) {
|
||||||
this.#availableTips.delete(tip);
|
this.#availableTips.delete(tip);
|
||||||
|
@ -84,7 +86,6 @@ export default class UserTips extends Service {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty tipId means all user tips.
|
|
||||||
if (!userTips[tipId]) {
|
if (!userTips[tipId]) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.warn("Cannot hide user tip with id", tipId);
|
console.warn("Cannot hide user tip with id", tipId);
|
||||||
|
@ -94,6 +95,23 @@ export default class UserTips extends Service {
|
||||||
const tipObj = [...this.#availableTips].find((t) => t.id === tipId);
|
const tipObj = [...this.#availableTips].find((t) => t.id === tipId);
|
||||||
this.removeAvailableTip(tipObj);
|
this.removeAvailableTip(tipObj);
|
||||||
|
|
||||||
|
await this.markAsSeen(tipId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async markAsSeen(tipId) {
|
||||||
|
if (!this.currentUser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tipId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userTips = this.site.user_tips;
|
||||||
|
if (!userTips || this.currentUser.user_option?.skip_new_user_tips) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Update list of seen user tips.
|
// Update list of seen user tips.
|
||||||
let seenUserTips = this.currentUser.user_option?.seen_popups || [];
|
let seenUserTips = this.currentUser.user_option?.seen_popups || [];
|
||||||
if (seenUserTips.includes(userTips[tipId])) {
|
if (seenUserTips.includes(userTips[tipId])) {
|
||||||
|
@ -108,4 +126,25 @@ export default class UserTips extends Service {
|
||||||
this.currentUser.set("user_option.seen_popups", seenUserTips);
|
this.currentUser.set("user_option.seen_popups", seenUserTips);
|
||||||
await this.currentUser.save(["seen_popups"]);
|
await this.currentUser.save(["seen_popups"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async skipTips() {
|
||||||
|
if (!this.currentUser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#availableTips.clear();
|
||||||
|
this.#shouldRenderSet.clear();
|
||||||
|
|
||||||
|
this.currentUser.set("user_option.skip_new_user_tips", true);
|
||||||
|
await this.currentUser.save(["skip_new_user_tips"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_findAvailableTipById(id) {
|
||||||
|
for (let item of this.#availableTips) {
|
||||||
|
if (item.id === id) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ import { registerWidgetShim } from "discourse/widgets/render-glimmer";
|
||||||
registerWidgetShim(
|
registerWidgetShim(
|
||||||
"header-user-tip-shim",
|
"header-user-tip-shim",
|
||||||
"div.header-user-tip-shim",
|
"div.header-user-tip-shim",
|
||||||
hbs`<UserTip @id="first_notification" @triggerSelector=".header-dropdown-toggle.current-user" @placement="bottom-end" @titleText={{i18n "user_tips.first_notification.title"}} @contentText={{i18n "user_tips.first_notification.content"}} />`
|
hbs`<UserTip @id="first_notification" @triggerSelector=".header-dropdown-toggle.current-user" @placement="bottom-end" @titleText={{i18n "user_tips.first_notification.title"}} @contentText={{i18n "user_tips.first_notification.content"}} @showSkipButton={{true}} />`
|
||||||
);
|
);
|
||||||
|
|
|
@ -621,6 +621,7 @@ export default createWidget("post-menu", {
|
||||||
visibleButtons = allButtons;
|
visibleButtons = allButtons;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hasShowMoreButton = false;
|
||||||
// Only show ellipsis if there is more than one button hidden
|
// Only show ellipsis if there is more than one button hidden
|
||||||
// if there are no more buttons, we are not collapsed
|
// if there are no more buttons, we are not collapsed
|
||||||
if (!state.collapsed || allButtons.length <= visibleButtons.length + 1) {
|
if (!state.collapsed || allButtons.length <= visibleButtons.length + 1) {
|
||||||
|
@ -636,6 +637,7 @@ export default createWidget("post-menu", {
|
||||||
icon: "ellipsis-h",
|
icon: "ellipsis-h",
|
||||||
});
|
});
|
||||||
visibleButtons.splice(visibleButtons.length - 1, 0, showMore);
|
visibleButtons.splice(visibleButtons.length - 1, 0, showMore);
|
||||||
|
hasShowMoreButton = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.values(_extraButtons).forEach((builder) => {
|
Object.values(_extraButtons).forEach((builder) => {
|
||||||
|
@ -813,7 +815,9 @@ export default createWidget("post-menu", {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (hasShowMoreButton) {
|
||||||
|
contents.push(this.attach("post-user-tip-shim"));
|
||||||
|
}
|
||||||
return contents;
|
return contents;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1009,10 +1009,7 @@ export default createWidget("post", {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [this.attach("post-article", attrs)];
|
||||||
this.attach("post-user-tip-shim"),
|
|
||||||
this.attach("post-article", attrs),
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleLike() {
|
toggleLike() {
|
||||||
|
|
|
@ -29,10 +29,17 @@
|
||||||
|
|
||||||
.user-tip__buttons {
|
.user-tip__buttons {
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: var(--secondary);
|
background: var(--secondary);
|
||||||
color: var(--tertiary);
|
color: var(--tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-flat.btn-text {
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--secondary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,28 +64,34 @@
|
||||||
|
|
||||||
&[data-placement^="top"] {
|
&[data-placement^="top"] {
|
||||||
.arrow {
|
.arrow {
|
||||||
bottom: -9px;
|
bottom: -10px;
|
||||||
rotate: 180deg;
|
rotate: 180deg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&[data-placement^="top-start"] {
|
||||||
|
.arrow {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&[data-placement^="bottom"] {
|
&[data-placement^="bottom"] {
|
||||||
.arrow {
|
.arrow {
|
||||||
top: -9px;
|
top: -10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-placement^="right"] {
|
&[data-placement^="right"] {
|
||||||
.arrow {
|
.arrow {
|
||||||
rotate: -90deg;
|
rotate: -90deg;
|
||||||
left: -9px;
|
left: -10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-placement^="left"] {
|
&[data-placement^="left"] {
|
||||||
.arrow {
|
.arrow {
|
||||||
rotate: 90deg;
|
rotate: 90deg;
|
||||||
right: -9px;
|
right: -10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,13 +265,6 @@ class UserUpdater
|
||||||
user_notification_schedule.destroy_scheduled_timings
|
user_notification_schedule.destroy_scheduled_timings
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if attributes.key?(:seen_popups) || attributes.key?(:skip_new_user_tips)
|
|
||||||
MessageBus.publish(
|
|
||||||
"/user-tips/#{user.id}",
|
|
||||||
user.user_option.seen_popups,
|
|
||||||
user_ids: [user.id],
|
|
||||||
)
|
|
||||||
end
|
|
||||||
DiscourseEvent.trigger(:user_updated, user)
|
DiscourseEvent.trigger(:user_updated, user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1990,6 +1990,7 @@ en:
|
||||||
|
|
||||||
user_tips:
|
user_tips:
|
||||||
button: "Got it!"
|
button: "Got it!"
|
||||||
|
skip: "Skip tips"
|
||||||
|
|
||||||
first_notification:
|
first_notification:
|
||||||
title: "Your first notification!"
|
title: "Your first notification!"
|
||||||
|
|
|
@ -586,14 +586,10 @@ RSpec.describe UserUpdater do
|
||||||
|
|
||||||
context "when skip_new_user_tips is edited" do
|
context "when skip_new_user_tips is edited" do
|
||||||
it "updates seen_popups too" do
|
it "updates seen_popups too" do
|
||||||
messages =
|
|
||||||
MessageBus.track_publish("/user-tips/#{user.id}") do
|
|
||||||
UserUpdater.new(Discourse.system_user, user).update(skip_new_user_tips: true)
|
UserUpdater.new(Discourse.system_user, user).update(skip_new_user_tips: true)
|
||||||
end
|
|
||||||
|
|
||||||
expect(user.user_option.skip_new_user_tips).to eq(true)
|
expect(user.user_option.skip_new_user_tips).to eq(true)
|
||||||
expect(user.user_option.seen_popups).to eq([-1])
|
expect(user.user_option.seen_popups).to eq([-1])
|
||||||
expect(messages.map(&:data)).to contain_exactly([-1])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not reset seen_popups" do
|
it "does not reset seen_popups" do
|
||||||
|
@ -606,18 +602,6 @@ RSpec.describe UserUpdater do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when seen_popups is edited" do
|
|
||||||
it "publishes a message" do
|
|
||||||
messages =
|
|
||||||
MessageBus.track_publish("/user-tips/#{user.id}") do
|
|
||||||
UserUpdater.new(Discourse.system_user, user).update(seen_popups: [1])
|
|
||||||
end
|
|
||||||
|
|
||||||
expect(user.user_option.seen_popups).to eq([1])
|
|
||||||
expect(messages.map(&:data)).to contain_exactly([1])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "logs the action" do
|
it "logs the action" do
|
||||||
user = Fabricate(:user, name: "Billy Bob")
|
user = Fabricate(:user, name: "Billy Bob")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
describe "Homepage", type: :system do
|
||||||
|
fab!(:admin)
|
||||||
|
fab!(:user)
|
||||||
|
fab!(:topics) { Fabricate.times(2, :post).map(&:topic) }
|
||||||
|
fab!(:posts) { Fabricate.times(3, :post, topic: topics[0]) }
|
||||||
|
let(:discovery) { PageObjects::Pages::Discovery.new }
|
||||||
|
|
||||||
|
context "when user tips are disabled" do
|
||||||
|
before { SiteSetting.enable_user_tips = false }
|
||||||
|
|
||||||
|
it "does not show the 'first notification' tip to the user when disabled" do
|
||||||
|
sign_in user
|
||||||
|
visit "/"
|
||||||
|
|
||||||
|
expect(page).to have_no_css(".fk-d-tooltip .user-tip__title")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not show the boostrapping tip to an admin user" do
|
||||||
|
SiteSetting.bootstrap_mode_enabled = true
|
||||||
|
sign_in admin
|
||||||
|
visit "/"
|
||||||
|
|
||||||
|
expect(page).to have_no_css(".fk-d-tooltip .user-tip__title")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when user tips are enabled" do
|
||||||
|
before { SiteSetting.enable_user_tips = true }
|
||||||
|
|
||||||
|
it "shows the 'first notification' tip to the user when enabled" do
|
||||||
|
sign_in user
|
||||||
|
expect(user.user_option.seen_popups).to eq(nil)
|
||||||
|
|
||||||
|
visit "/"
|
||||||
|
|
||||||
|
expect(page).to have_css(".fk-d-tooltip .user-tip__title", text: "Your first notification!")
|
||||||
|
|
||||||
|
# refresh the page
|
||||||
|
visit "/"
|
||||||
|
# Tip is marked as seen when it is displayed
|
||||||
|
expect(user.reload.user_option.seen_popups).to include(User.user_tips[:first_notification])
|
||||||
|
expect(page).to have_no_css(
|
||||||
|
".fk-d-tooltip .user-tip__title",
|
||||||
|
text: "Your first notification!",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "shows the boostrapping tip to an admin user" do
|
||||||
|
SiteSetting.bootstrap_mode_enabled = true
|
||||||
|
expect(admin.user_option.seen_popups).to eq(nil)
|
||||||
|
sign_in admin
|
||||||
|
visit "/"
|
||||||
|
|
||||||
|
expect(page).to have_css(".fk-d-tooltip .user-tip__title", text: "Welcome to your new site!")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "shows a second notification once first is dismissed and user visits a topic" do
|
||||||
|
sign_in user
|
||||||
|
visit "/"
|
||||||
|
|
||||||
|
find(".fk-d-tooltip .user-tip__buttons .btn-primary").click
|
||||||
|
expect(page).to have_no_css(".fk-d-tooltip .user-tip__title")
|
||||||
|
|
||||||
|
discovery.topic_list.visit_topic(topics[0])
|
||||||
|
expect(page).to have_css(".fk-d-tooltip .user-tip__title", text: "Topic timeline")
|
||||||
|
|
||||||
|
find(".fk-d-tooltip .user-tip__buttons .btn-primary").click
|
||||||
|
expect(page).to have_css(".fk-d-tooltip .user-tip__title", text: "Keep reading!")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can skip all tips" do
|
||||||
|
sign_in user
|
||||||
|
visit "/"
|
||||||
|
|
||||||
|
find(".fk-d-tooltip .user-tip__buttons .btn", text: "Skip tips").click
|
||||||
|
expect(page).to have_no_css(".fk-d-tooltip .user-tip__title")
|
||||||
|
|
||||||
|
discovery.topic_list.visit_topic(topics[0])
|
||||||
|
expect(page).to have_no_css(".fk-d-tooltip .user-tip__title")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue