mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: Add messages tab to the new user menu (#17850)
Some of the changes in this PR are extracted from https://github.com/discourse/discourse/pull/17379. Similar to the bookmarks tab in the new user menu, the messages tab also displays a mix of notifications and messages. When there are unread message notifications, the tab displays all of these notifications at the top and fills the remaining space in the menu with a list of the user's messages. The bubble/badge count on the messages tab indicates how many unread message notifications there are.
This commit is contained in:
@@ -70,6 +70,30 @@ const CORE_TOP_TABS = [
|
||||
}
|
||||
},
|
||||
|
||||
class extends UserMenuTab {
|
||||
get id() {
|
||||
return "messages";
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return "notification.private_message";
|
||||
}
|
||||
|
||||
get panelComponent() {
|
||||
return "user-menu/messages-list";
|
||||
}
|
||||
|
||||
get count() {
|
||||
return this.getUnreadCountForType("private_message");
|
||||
}
|
||||
|
||||
get shouldDisplay() {
|
||||
return (
|
||||
this.siteSettings.enable_personal_messages || this.currentUser.staff
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
class extends UserMenuTab {
|
||||
get id() {
|
||||
return "bookmarks";
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import UserMenuItem from "discourse/components/user-menu/menu-item";
|
||||
import { postUrl } from "discourse/lib/utilities";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default class UserMenuMessageItem extends UserMenuItem {
|
||||
get className() {
|
||||
return "message";
|
||||
}
|
||||
|
||||
get linkHref() {
|
||||
const nextUnreadPostNumber = Math.min(
|
||||
(this.message.last_read_post_number || 0) + 1,
|
||||
this.message.highest_post_number
|
||||
);
|
||||
return postUrl(this.message.slug, this.message.id, nextUnreadPostNumber);
|
||||
}
|
||||
|
||||
get linkTitle() {
|
||||
return I18n.t("user.private_message");
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return "notification.private_message";
|
||||
}
|
||||
|
||||
get label() {
|
||||
return this.message.last_poster_username;
|
||||
}
|
||||
|
||||
get description() {
|
||||
return htmlSafe(this.message.fancy_title);
|
||||
}
|
||||
|
||||
get topicId() {
|
||||
return this.message.id;
|
||||
}
|
||||
|
||||
get message() {
|
||||
return this.args.item;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{component this.component item=@item}}
|
||||
@@ -0,0 +1,12 @@
|
||||
import GlimmerComponent from "discourse/components/glimmer";
|
||||
import Notification from "discourse/models/notification";
|
||||
|
||||
export default class UserMenuMessageNotificationItem extends GlimmerComponent {
|
||||
get component() {
|
||||
if (this.args.item.constructor === Notification) {
|
||||
return "user-menu/notification-item";
|
||||
} else {
|
||||
return "user-menu/message-item";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<div class="empty-state">
|
||||
<span class="empty-state-title">
|
||||
{{i18n "user.no_messages_title"}}
|
||||
</span>
|
||||
<div class="empty-state-body">
|
||||
<p>
|
||||
{{html-safe (i18n "user.no_messages_body" icon=(d-icon "envelope") aboutUrl=(get-url "/about"))}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,72 @@
|
||||
import UserMenuNotificationsList from "discourse/components/user-menu/notifications-list";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import Notification from "discourse/models/notification";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default class UserMenuMessagesList extends UserMenuNotificationsList {
|
||||
get dismissTypes() {
|
||||
return ["private_message"];
|
||||
}
|
||||
|
||||
get showAllHref() {
|
||||
return `${this.currentUser.path}/messages`;
|
||||
}
|
||||
|
||||
get showAllTitle() {
|
||||
return I18n.t("user_menu.view_all_messages");
|
||||
}
|
||||
|
||||
get showDismiss() {
|
||||
return this.#unreadMessaagesNotifications > 0;
|
||||
}
|
||||
|
||||
get dismissTitle() {
|
||||
return I18n.t("user.dismiss_messages_tooltip");
|
||||
}
|
||||
|
||||
get itemsCacheKey() {
|
||||
return "user-menu-messages-tab";
|
||||
}
|
||||
|
||||
get itemComponent() {
|
||||
return "user-menu/message-notification-item";
|
||||
}
|
||||
|
||||
get emptyStateComponent() {
|
||||
return "user-menu/messages-list-empty-state";
|
||||
}
|
||||
|
||||
get #unreadMessaagesNotifications() {
|
||||
const key = `grouped_unread_high_priority_notifications.${this.site.notification_types.private_message}`;
|
||||
// we're retrieving the value with get() so that Ember tracks the property
|
||||
// and re-renders the UI when it changes.
|
||||
// we can stop using `get()` when the User model is refactored into native
|
||||
// class with @tracked properties.
|
||||
return this.currentUser.get(key) || 0;
|
||||
}
|
||||
|
||||
fetchItems() {
|
||||
return ajax(
|
||||
`/u/${this.currentUser.username}/user-menu-private-messages`
|
||||
).then((data) => {
|
||||
const content = [];
|
||||
data.notifications.forEach((notification) => {
|
||||
content.push(Notification.create(notification));
|
||||
});
|
||||
content.push(...data.topics);
|
||||
return content;
|
||||
});
|
||||
}
|
||||
|
||||
dismissWarningModal() {
|
||||
const modalController = showModal("dismiss-notification-confirmation");
|
||||
modalController.set(
|
||||
"confirmationMessage",
|
||||
I18n.t("notifications.dismiss_confirmation.body.messages", {
|
||||
count: this.#unreadMessaagesNotifications,
|
||||
})
|
||||
);
|
||||
return modalController;
|
||||
}
|
||||
}
|
||||
@@ -93,6 +93,28 @@ export default class UserMenuNotificationsList extends UserMenuItemsList {
|
||||
const modalController = this.dismissWarningModal();
|
||||
const modalCallback = () => {
|
||||
ajax("/notifications/mark-read", opts).then(() => {
|
||||
if (dismissTypes) {
|
||||
const unreadNotificationCountsHash = {
|
||||
...this.currentUser.grouped_unread_high_priority_notifications,
|
||||
};
|
||||
dismissTypes.forEach((type) => {
|
||||
const typeId = this.site.notification_types[type];
|
||||
if (typeId) {
|
||||
delete unreadNotificationCountsHash[typeId];
|
||||
}
|
||||
});
|
||||
this.currentUser.set(
|
||||
"grouped_unread_high_priority_notifications",
|
||||
unreadNotificationCountsHash
|
||||
);
|
||||
} else {
|
||||
this.currentUser.set("all_unread_notifications_count", 0);
|
||||
this.currentUser.set("unread_high_priority_notifications", 0);
|
||||
this.currentUser.set(
|
||||
"grouped_unread_high_priority_notifications",
|
||||
{}
|
||||
);
|
||||
}
|
||||
this.refreshList();
|
||||
postRNWebviewMessage("markRead", "1");
|
||||
});
|
||||
|
||||
@@ -2,8 +2,6 @@ import { click, visit } from "@ember/test-helpers";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
loggedInUser,
|
||||
publishToMessageBus,
|
||||
query,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
@@ -184,6 +182,7 @@ acceptance("User menu - Dismiss button", function (needs) {
|
||||
unread_high_priority_notifications: 10,
|
||||
grouped_unread_high_priority_notifications: {
|
||||
[NOTIFICATION_TYPES.bookmark_reminder]: 103,
|
||||
[NOTIFICATION_TYPES.private_message]: 89,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -210,6 +209,20 @@ acceptance("User menu - Dismiss button", function (needs) {
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
server.get("/u/eviltrout/user-menu-private-messages", () => {
|
||||
if (markRead) {
|
||||
const copy = cloneJSON(
|
||||
UserMenuFixtures["/u/:username/user-menu-private-messages"]
|
||||
);
|
||||
copy.notifications = [];
|
||||
return helper.response(copy);
|
||||
} else {
|
||||
return helper.response(
|
||||
UserMenuFixtures["/u/:username/user-menu-private-messages"]
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
needs.hooks.afterEach(() => {
|
||||
@@ -227,18 +240,13 @@ acceptance("User menu - Dismiss button", function (needs) {
|
||||
I18n.t("notifications.dismiss_confirmation.body.default", { count: 10 }),
|
||||
"confirmation modal is shown when there are unread high pri notifications"
|
||||
);
|
||||
assert.notOk(markRead, "mark-read request isn't sent");
|
||||
|
||||
await click(".modal-footer .btn-default"); // click cancel on the dismiss modal
|
||||
assert.notOk(markRead, "mark-read request isn't sent");
|
||||
|
||||
await publishToMessageBus(`/notification/${loggedInUser().id}`, {
|
||||
unread_high_priority_notifications: 0,
|
||||
});
|
||||
await click(".user-menu .notifications-dismiss");
|
||||
assert.ok(
|
||||
markRead,
|
||||
"mark-read request is sent without a confirmation modal when there are no unread high pri notifications"
|
||||
);
|
||||
await click(".modal-footer .btn-primary"); // click confirm on the dismiss modal
|
||||
assert.ok(markRead, "mark-read request is sent");
|
||||
});
|
||||
|
||||
test("shows confirmation modal for the bookmarks list", async function (assert) {
|
||||
@@ -273,9 +281,6 @@ acceptance("User menu - Dismiss button", function (needs) {
|
||||
assert.notOk(markRead, "mark-read request isn't sent");
|
||||
|
||||
await click(".modal-footer .btn-primary"); // confirm dismiss on the dismiss modal
|
||||
await publishToMessageBus(`/notification/${loggedInUser().id}`, {
|
||||
grouped_unread_high_priority_notifications: {},
|
||||
});
|
||||
|
||||
assert.notOk(
|
||||
exists("#quick-access-bookmarks ul li.notification"),
|
||||
@@ -298,6 +303,60 @@ acceptance("User menu - Dismiss button", function (needs) {
|
||||
assert.notOk(exists(".user-menu .notifications-dismiss"));
|
||||
});
|
||||
|
||||
test("shows confirmation modal for the messages list", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
|
||||
assert.strictEqual(
|
||||
query("#user-menu-button-messages .badge-notification").textContent,
|
||||
"89",
|
||||
"messages tab has bubble with count"
|
||||
);
|
||||
|
||||
await click("#user-menu-button-messages");
|
||||
assert.ok(
|
||||
exists("#quick-access-messages ul li.notification"),
|
||||
"messages notifications are visible"
|
||||
);
|
||||
assert.ok(
|
||||
exists("#quick-access-messages ul li.message"),
|
||||
"messages are visible"
|
||||
);
|
||||
|
||||
await click(".user-menu .notifications-dismiss");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".dismiss-notification-confirmation").textContent.trim(),
|
||||
I18n.t("notifications.dismiss_confirmation.body.messages", {
|
||||
count: 89,
|
||||
}),
|
||||
"confirmation modal is shown when there are unread messages notifications"
|
||||
);
|
||||
assert.notOk(markRead, "mark-read request isn't sent");
|
||||
|
||||
await click(".modal-footer .btn-primary"); // confirm dismiss on the dismiss modal
|
||||
|
||||
assert.notOk(
|
||||
exists("#quick-access-messages ul li.notification"),
|
||||
"messages notifications are gone"
|
||||
);
|
||||
assert.ok(
|
||||
exists("#quick-access-messages ul li.message"),
|
||||
"messages are still visible"
|
||||
);
|
||||
assert.notOk(
|
||||
exists("#user-menu-button-messages .badge-notification"),
|
||||
"messages tab no longer has bubble"
|
||||
);
|
||||
assert.ok(markRead, "mark-read request is sent");
|
||||
assert.strictEqual(
|
||||
markReadRequestBody,
|
||||
"dismiss_types=private_message",
|
||||
"mark-read request specifies private_message types"
|
||||
);
|
||||
assert.notOk(exists(".user-menu .notifications-dismiss"));
|
||||
});
|
||||
|
||||
test("doesn't show confirmation modal for the likes notifications list", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
|
||||
@@ -62,5 +62,127 @@ export default {
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
"/u/:username/user-menu-private-messages": {
|
||||
notifications: [
|
||||
{
|
||||
id: 8315,
|
||||
user_id: 1,
|
||||
notification_type: 6,
|
||||
read: false,
|
||||
high_priority: true,
|
||||
created_at: "2022-08-05T17:27:24.873Z",
|
||||
post_number: 1,
|
||||
topic_id: 249,
|
||||
fancy_title: "Very secret message!",
|
||||
slug: "very-secret-message",
|
||||
data: {
|
||||
topic_title: "very secret message!",
|
||||
original_post_id: 1043,
|
||||
original_post_type: 1,
|
||||
original_username: "osama",
|
||||
revision_number: null,
|
||||
display_username: "osama"
|
||||
},
|
||||
},
|
||||
],
|
||||
topics: [
|
||||
{
|
||||
id: 8092,
|
||||
title: "BUG: Can not render emoji properly :/",
|
||||
fancy_title: "BUG: Can not render emoji properly :confused:",
|
||||
slug: "bug-can-not-render-emoji-properly",
|
||||
posts_count: 1,
|
||||
reply_count: 0,
|
||||
highest_post_number: 2,
|
||||
image_url: null,
|
||||
created_at: "2019-07-26T01:29:24.008Z",
|
||||
last_posted_at: "2019-07-26T01:29:24.177Z",
|
||||
bumped: true,
|
||||
bumped_at: "2019-07-26T01:29:24.177Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 2,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
closed: false,
|
||||
archived: false,
|
||||
notification_level: 3,
|
||||
bookmarked: false,
|
||||
bookmarks: [],
|
||||
liked: false,
|
||||
views: 5,
|
||||
like_count: 0,
|
||||
has_summary: false,
|
||||
archetype: "private_message",
|
||||
last_poster_username: "mixtape",
|
||||
category_id: null,
|
||||
pinned_globally: false,
|
||||
featured_link: null,
|
||||
posters: [
|
||||
{
|
||||
extras: "latest single",
|
||||
description: "Original Poster, Most Recent Poster",
|
||||
user_id: 13,
|
||||
primary_group_id: null,
|
||||
},
|
||||
],
|
||||
participants: [
|
||||
{
|
||||
extras: "latest",
|
||||
description: null,
|
||||
user_id: 13,
|
||||
primary_group_id: null,
|
||||
},
|
||||
],
|
||||
fancy_title: "BUG: Can not render emoji properly :confused:",
|
||||
slug: "bug-can-not-render-emoji-properly",
|
||||
posts_count: 1,
|
||||
reply_count: 0,
|
||||
highest_post_number: 2,
|
||||
image_url: null,
|
||||
created_at: "2019-07-26T01:29:24.008Z",
|
||||
last_posted_at: "2019-07-26T01:29:24.177Z",
|
||||
bumped: true,
|
||||
bumped_at: "2019-07-26T01:29:24.177Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 2,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
closed: false,
|
||||
archived: false,
|
||||
notification_level: 3,
|
||||
bookmarked: false,
|
||||
bookmarks: [],
|
||||
liked: false,
|
||||
views: 5,
|
||||
like_count: 0,
|
||||
has_summary: false,
|
||||
archetype: "private_message",
|
||||
last_poster_username: "mixtape",
|
||||
category_id: null,
|
||||
pinned_globally: false,
|
||||
featured_link: null,
|
||||
posters: [
|
||||
{
|
||||
extras: "latest single",
|
||||
description: "Original Poster, Most Recent Poster",
|
||||
user_id: 13,
|
||||
primary_group_id: null,
|
||||
},
|
||||
],
|
||||
participants: [
|
||||
{
|
||||
extras: "latest",
|
||||
description: null,
|
||||
user_id: 13,
|
||||
primary_group_id: null,
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,51 +3,48 @@ import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { render } from "@ember/test-helpers";
|
||||
import { deepMerge } from "discourse-common/lib/object";
|
||||
import Notification from "discourse/models/notification";
|
||||
import { hbs } from "ember-cli-htmlbars";
|
||||
|
||||
function getBookmark(overrides = {}) {
|
||||
return Notification.create(
|
||||
deepMerge(
|
||||
{
|
||||
id: 6,
|
||||
created_at: "2022-08-05T06:09:39.559Z",
|
||||
updated_at: "2022-08-05T06:11:27.246Z",
|
||||
name: "",
|
||||
reminder_at: "2022-08-05T06:10:42.223Z",
|
||||
reminder_at_ics_start: "20220805T061042Z",
|
||||
reminder_at_ics_end: "20220805T071042Z",
|
||||
pinned: false,
|
||||
title: "Test poll topic hello world",
|
||||
fancy_title: "Test poll topic hello world",
|
||||
excerpt: "poll",
|
||||
bookmarkable_id: 1009,
|
||||
bookmarkable_type: "Post",
|
||||
bookmarkable_url: "http://localhost:4200/t/this-bookmarkable-url/227/1",
|
||||
tags: [],
|
||||
tags_descriptions: {},
|
||||
truncated: true,
|
||||
topic_id: 227,
|
||||
linked_post_number: 1,
|
||||
deleted: false,
|
||||
hidden: false,
|
||||
category_id: 1,
|
||||
closed: false,
|
||||
archived: false,
|
||||
archetype: "regular",
|
||||
highest_post_number: 45,
|
||||
last_read_post_number: 31,
|
||||
bumped_at: "2022-04-21T15:14:37.359Z",
|
||||
slug: "test-poll-topic-hello-world",
|
||||
user: {
|
||||
id: 1,
|
||||
username: "somebody",
|
||||
name: "Mr. Somebody",
|
||||
avatar_template: "/letter_avatar_proxy/v4/letter/o/f05b48/{size}.png",
|
||||
},
|
||||
return deepMerge(
|
||||
{
|
||||
id: 6,
|
||||
created_at: "2022-08-05T06:09:39.559Z",
|
||||
updated_at: "2022-08-05T06:11:27.246Z",
|
||||
name: "",
|
||||
reminder_at: "2022-08-05T06:10:42.223Z",
|
||||
reminder_at_ics_start: "20220805T061042Z",
|
||||
reminder_at_ics_end: "20220805T071042Z",
|
||||
pinned: false,
|
||||
title: "Test poll topic hello world",
|
||||
fancy_title: "Test poll topic hello world",
|
||||
excerpt: "poll",
|
||||
bookmarkable_id: 1009,
|
||||
bookmarkable_type: "Post",
|
||||
bookmarkable_url: "http://localhost:4200/t/this-bookmarkable-url/227/1",
|
||||
tags: [],
|
||||
tags_descriptions: {},
|
||||
truncated: true,
|
||||
topic_id: 227,
|
||||
linked_post_number: 1,
|
||||
deleted: false,
|
||||
hidden: false,
|
||||
category_id: 1,
|
||||
closed: false,
|
||||
archived: false,
|
||||
archetype: "regular",
|
||||
highest_post_number: 45,
|
||||
last_read_post_number: 31,
|
||||
bumped_at: "2022-04-21T15:14:37.359Z",
|
||||
slug: "test-poll-topic-hello-world",
|
||||
user: {
|
||||
id: 1,
|
||||
username: "somebody",
|
||||
name: "Mr. Somebody",
|
||||
avatar_template: "/letter_avatar_proxy/v4/letter/o/f05b48/{size}.png",
|
||||
},
|
||||
overrides
|
||||
)
|
||||
},
|
||||
overrides
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,17 +48,22 @@ module("Integration | Component | user-menu", function (hooks) {
|
||||
test("the menu has a group of tabs at the top", async function (assert) {
|
||||
await render(template);
|
||||
const tabs = queryAll(".top-tabs.tabs-list .btn");
|
||||
assert.strictEqual(tabs.length, 5);
|
||||
["all-notifications", "replies", "mentions", "likes"].forEach(
|
||||
(tab, index) => {
|
||||
assert.strictEqual(tabs[index].id, `user-menu-button-${tab}`);
|
||||
assert.strictEqual(tabs[index].dataset.tabNumber, index.toString());
|
||||
assert.strictEqual(
|
||||
tabs[index].getAttribute("aria-controls"),
|
||||
`quick-access-${tab}`
|
||||
);
|
||||
}
|
||||
);
|
||||
assert.strictEqual(tabs.length, 6);
|
||||
[
|
||||
"all-notifications",
|
||||
"replies",
|
||||
"mentions",
|
||||
"likes",
|
||||
"messages",
|
||||
"bookmarks",
|
||||
].forEach((tab, index) => {
|
||||
assert.strictEqual(tabs[index].id, `user-menu-button-${tab}`);
|
||||
assert.strictEqual(tabs[index].dataset.tabNumber, index.toString());
|
||||
assert.strictEqual(
|
||||
tabs[index].getAttribute("aria-controls"),
|
||||
`quick-access-${tab}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("the menu has a group of tabs at the bottom", async function (assert) {
|
||||
@@ -67,7 +72,7 @@ module("Integration | Component | user-menu", function (hooks) {
|
||||
assert.strictEqual(tabs.length, 1);
|
||||
const preferencesTab = tabs[0];
|
||||
assert.ok(preferencesTab.href.endsWith("/u/eviltrout/preferences"));
|
||||
assert.strictEqual(preferencesTab.dataset.tabNumber, "5");
|
||||
assert.strictEqual(preferencesTab.dataset.tabNumber, "6");
|
||||
assert.strictEqual(preferencesTab.getAttribute("tabindex"), "-1");
|
||||
});
|
||||
|
||||
@@ -77,11 +82,11 @@ module("Integration | Component | user-menu", function (hooks) {
|
||||
assert.ok(!exists("#user-menu-button-likes"));
|
||||
|
||||
const tabs = Array.from(queryAll(".tabs-list .btn")); // top and bottom tabs
|
||||
assert.strictEqual(tabs.length, 5);
|
||||
assert.strictEqual(tabs.length, 6);
|
||||
|
||||
assert.deepEqual(
|
||||
tabs.map((t) => t.dataset.tabNumber),
|
||||
["0", "1", "2", "3", "4"],
|
||||
["0", "1", "2", "3", "4", "5"],
|
||||
"data-tab-number of the tabs has no gaps when the likes tab is hidden"
|
||||
);
|
||||
});
|
||||
@@ -90,18 +95,47 @@ module("Integration | Component | user-menu", function (hooks) {
|
||||
this.currentUser.set("can_review", true);
|
||||
await render(template);
|
||||
const tab = query("#user-menu-button-review-queue");
|
||||
assert.strictEqual(tab.dataset.tabNumber, "5");
|
||||
assert.strictEqual(tab.dataset.tabNumber, "6");
|
||||
|
||||
const tabs = Array.from(queryAll(".tabs-list .btn")); // top and bottom tabs
|
||||
assert.strictEqual(tabs.length, 7);
|
||||
assert.strictEqual(tabs.length, 8);
|
||||
|
||||
assert.deepEqual(
|
||||
tabs.map((t) => t.dataset.tabNumber),
|
||||
["0", "1", "2", "3", "4", "5", "6"],
|
||||
["0", "1", "2", "3", "4", "5", "6", "7"],
|
||||
"data-tab-number of the tabs has no gaps when the reviewables tab is show"
|
||||
);
|
||||
});
|
||||
|
||||
test("messages tab isn't shown if current user isn't staff and enable_personal_messages setting is disabled", async function (assert) {
|
||||
this.currentUser.set("moderator", false);
|
||||
this.currentUser.set("admin", false);
|
||||
this.siteSettings.enable_personal_messages = false;
|
||||
|
||||
await render(template);
|
||||
|
||||
assert.ok(!exists("#user-menu-button-messages"));
|
||||
|
||||
const tabs = Array.from(queryAll(".tabs-list .btn")); // top and bottom tabs
|
||||
assert.strictEqual(tabs.length, 6);
|
||||
|
||||
assert.deepEqual(
|
||||
tabs.map((t) => t.dataset.tabNumber),
|
||||
["0", "1", "2", "3", "4", "5"],
|
||||
"data-tab-number of the tabs has no gaps when the messages tab is hidden"
|
||||
);
|
||||
});
|
||||
|
||||
test("messages tab is shown if current user is staff even if enable_personal_messages setting is disabled", async function (assert) {
|
||||
this.currentUser.set("moderator", true);
|
||||
this.currentUser.set("admin", false);
|
||||
this.siteSettings.enable_personal_messages = false;
|
||||
|
||||
await render(template);
|
||||
|
||||
assert.ok(exists("#user-menu-button-messages"));
|
||||
});
|
||||
|
||||
test("reviewables count is shown on the reviewables tab", async function (assert) {
|
||||
this.currentUser.set("can_review", true);
|
||||
this.currentUser.set("reviewable_count", 4);
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { render } from "@ember/test-helpers";
|
||||
import { cloneJSON, deepMerge } from "discourse-common/lib/object";
|
||||
import { hbs } from "ember-cli-htmlbars";
|
||||
import PrivateMessagesFixture from "discourse/tests/fixtures/private-messages-fixtures";
|
||||
|
||||
function getMessage(overrides = {}) {
|
||||
const data = cloneJSON(
|
||||
PrivateMessagesFixture["/topics/private-messages/eviltrout.json"].topic_list
|
||||
.topics[0]
|
||||
);
|
||||
return deepMerge(data, overrides);
|
||||
}
|
||||
|
||||
module("Integration | Component | user-menu | message-item", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
const template = hbs`<UserMenu::MessageItem @item={{this.message}}/>`;
|
||||
|
||||
test("item description is the fancy title of the message", async function (assert) {
|
||||
this.set(
|
||||
"message",
|
||||
getMessage({ fancy_title: "This is a <b>safe</b> title!" })
|
||||
);
|
||||
await render(template);
|
||||
assert.strictEqual(
|
||||
query("li.message .item-description").textContent.trim(),
|
||||
"This is a safe title!"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query("li.message .item-description b").textContent.trim(),
|
||||
"safe",
|
||||
"fancy title is not escaped"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { exists, query, queryAll } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { render, settled } from "@ember/test-helpers";
|
||||
import { NOTIFICATION_TYPES } from "discourse/tests/fixtures/concerns/notification-types";
|
||||
import { hbs } from "ember-cli-htmlbars";
|
||||
import pretender, { response } from "discourse/tests/helpers/create-pretender";
|
||||
import I18n from "I18n";
|
||||
|
||||
module("Integration | Component | user-menu | messages-list", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
const template = hbs`<UserMenu::MessagesList/>`;
|
||||
|
||||
test("renders notifications on top and messages on bottom", async function (assert) {
|
||||
await render(template);
|
||||
const items = queryAll("ul li");
|
||||
|
||||
assert.strictEqual(items.length, 2);
|
||||
|
||||
assert.ok(items[0].classList.contains("notification"));
|
||||
assert.ok(items[0].classList.contains("unread"));
|
||||
assert.ok(items[0].classList.contains("private-message"));
|
||||
|
||||
assert.ok(items[1].classList.contains("message"));
|
||||
});
|
||||
|
||||
test("show all link", async function (assert) {
|
||||
await render(template);
|
||||
const link = query(".panel-body-bottom .show-all");
|
||||
assert.ok(
|
||||
link.href.endsWith("/u/eviltrout/messages"),
|
||||
"links to the user's messages page"
|
||||
);
|
||||
assert.strictEqual(
|
||||
link.title,
|
||||
I18n.t("user_menu.view_all_messages"),
|
||||
"has a title"
|
||||
);
|
||||
});
|
||||
|
||||
test("dismiss button", async function (assert) {
|
||||
this.currentUser.set("grouped_unread_high_priority_notifications", {
|
||||
[NOTIFICATION_TYPES.private_message]: 72,
|
||||
});
|
||||
await render(template);
|
||||
const dismiss = query(".panel-body-bottom .notifications-dismiss");
|
||||
assert.ok(
|
||||
dismiss,
|
||||
"dismiss button is shown if the user has unread private_message notifications"
|
||||
);
|
||||
assert.strictEqual(
|
||||
dismiss.title,
|
||||
I18n.t("user.dismiss_messages_tooltip"),
|
||||
"dismiss button has a title"
|
||||
);
|
||||
|
||||
this.currentUser.set("grouped_unread_high_priority_notifications", {});
|
||||
await settled();
|
||||
|
||||
assert.notOk(
|
||||
exists(".panel-body-bottom .notifications-dismiss"),
|
||||
"dismiss button is not shown if the user no unread private_message notifications"
|
||||
);
|
||||
});
|
||||
|
||||
test("empty state (aka blank page syndrome)", async function (assert) {
|
||||
pretender.get("/u/eviltrout/user-menu-private-messages", () => {
|
||||
return response({ notifications: [], topics: [] });
|
||||
});
|
||||
await render(template);
|
||||
assert.strictEqual(
|
||||
query(".empty-state-title").textContent.trim(),
|
||||
I18n.t("user.no_messages_title"),
|
||||
"empty state title is shown"
|
||||
);
|
||||
assert.ok(
|
||||
exists(".empty-state-body svg.d-icon-envelope"),
|
||||
"icon is correctly rendered in the empty state body"
|
||||
);
|
||||
const emptyStateBodyLink = query(".empty-state-body a");
|
||||
assert.ok(
|
||||
emptyStateBodyLink.href.endsWith("/about"),
|
||||
"link inside empty state body is rendered"
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user