From 6b8d6359439bdb7badde1704181372b93d168b83 Mon Sep 17 00:00:00 2001 From: Osama Sayegh Date: Fri, 22 Jul 2022 05:07:32 +0300 Subject: [PATCH] DEV: Add implementations for various notification types for the new user menu (#17589) This commit is a subset of the changes proposed in https://github.com/discourse/discourse/pull/17379. --- .../bookmark-reminder-notification-item.js | 17 +++ .../user-menu/custom-notification-item.js | 15 +++ .../granted-badge-notification-item.js | 36 ++++++ .../group-mentioned-notification-item.js | 11 ++ ...group-message-summary-notification-item.js | 23 ++++ .../invitee-accepted-notification-item.js | 13 ++ .../liked-consolidated-notification-item.js | 21 ++++ .../user-menu/liked-notification-item.js | 38 ++++++ ...ship-request-accepted-notification-item.js | 23 ++++ ...-request-consolidated-notification-item.js | 26 ++++ .../user-menu/moved-post-notification-item.js | 8 ++ .../watching-first-post-notification-item.js | 8 ++ .../discourse/app/models/notification.js | 23 +++- ...ookmark-reminder-notification-item-test.js | 107 ++++++++++++++++ .../granted-badge-notification-item-test.js | 63 ++++++++++ .../group-mentioned-notification-item-test.js | 68 +++++++++++ ...-message-summary-notification-item-test.js | 55 +++++++++ ...ked-consolidated-notification-item-test.js | 71 +++++++++++ .../user-menu/liked-notification-item-test.js | 114 ++++++++++++++++++ config/locales/client.en.yml | 7 ++ 20 files changed, 746 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/bookmark-reminder-notification-item.js create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/custom-notification-item.js create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/granted-badge-notification-item.js create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/group-mentioned-notification-item.js create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/group-message-summary-notification-item.js create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/invitee-accepted-notification-item.js create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/liked-consolidated-notification-item.js create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/liked-notification-item.js create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/membership-request-accepted-notification-item.js create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/membership-request-consolidated-notification-item.js create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/moved-post-notification-item.js create mode 100644 app/assets/javascripts/discourse/app/components/user-menu/watching-first-post-notification-item.js create mode 100644 app/assets/javascripts/discourse/tests/integration/components/user-menu/bookmark-reminder-notification-item-test.js create mode 100644 app/assets/javascripts/discourse/tests/integration/components/user-menu/granted-badge-notification-item-test.js create mode 100644 app/assets/javascripts/discourse/tests/integration/components/user-menu/group-mentioned-notification-item-test.js create mode 100644 app/assets/javascripts/discourse/tests/integration/components/user-menu/group-message-summary-notification-item-test.js create mode 100644 app/assets/javascripts/discourse/tests/integration/components/user-menu/liked-consolidated-notification-item-test.js create mode 100644 app/assets/javascripts/discourse/tests/integration/components/user-menu/liked-notification-item-test.js diff --git a/app/assets/javascripts/discourse/app/components/user-menu/bookmark-reminder-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/bookmark-reminder-notification-item.js new file mode 100644 index 00000000000..519ef8ec0d0 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/bookmark-reminder-notification-item.js @@ -0,0 +1,17 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; +import I18n from "I18n"; + +export default class UserMenuBookmarkReminderNotificationItem extends UserMenuNotificationItem { + get linkTitle() { + if (this.notification.data.bookmark_name) { + return I18n.t("notifications.titles.bookmark_reminder_with_name", { + name: this.notification.data.bookmark_name, + }); + } + return super.linkTitle; + } + + get description() { + return super.description || this.notification.data.title; + } +} diff --git a/app/assets/javascripts/discourse/app/components/user-menu/custom-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/custom-notification-item.js new file mode 100644 index 00000000000..269664f2701 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/custom-notification-item.js @@ -0,0 +1,15 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; +import I18n from "I18n"; + +export default class UserMenuCustomNotificationItem extends UserMenuNotificationItem { + get linkTitle() { + if (this.notification.data.title) { + return I18n.t(this.notification.data.title); + } + return super.linkTitle; + } + + get icon() { + return `notification.${this.notification.data.message}`; + } +} diff --git a/app/assets/javascripts/discourse/app/components/user-menu/granted-badge-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/granted-badge-notification-item.js new file mode 100644 index 00000000000..5da5a681340 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/granted-badge-notification-item.js @@ -0,0 +1,36 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; +import getURL from "discourse-common/lib/get-url"; +import I18n from "I18n"; + +export default class UserMenuGrantedBadgeNotificationItem extends UserMenuNotificationItem { + get linkHref() { + const badgeId = this.notification.data.badge_id; + if (badgeId) { + let slug = this.notification.data.badge_slug; + if (!slug) { + slug = this.notification.data.badge_name + .replace(/[^A-Za-z0-9_]+/g, "-") + .toLowerCase(); + } + let username = this.notification.data.username; + username = username ? `?username=${username.toLowerCase()}` : ""; + return getURL(`/badges/${badgeId}/${slug}${username}`); + } else { + return super.url; + } + } + + get label() { + return I18n.t("notifications.granted_badge", { + description: this.notification.data.badge_name, + }); + } + + get wrapLabel() { + return false; + } + + get description() { + return null; + } +} diff --git a/app/assets/javascripts/discourse/app/components/user-menu/group-mentioned-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/group-mentioned-notification-item.js new file mode 100644 index 00000000000..217709f9d18 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/group-mentioned-notification-item.js @@ -0,0 +1,11 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; + +export default class UserMenuGroupMentionedNotificationItem extends UserMenuNotificationItem { + get label() { + return `${this.username} @${this.notification.data.group_name}`; + } + + get labelWrapperClasses() { + return "mention-group notify"; + } +} diff --git a/app/assets/javascripts/discourse/app/components/user-menu/group-message-summary-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/group-message-summary-notification-item.js new file mode 100644 index 00000000000..2f4eda9f5f5 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/group-message-summary-notification-item.js @@ -0,0 +1,23 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; +import I18n from "I18n"; + +export default class UserMenuGroupMessageSummaryNotificationItem extends UserMenuNotificationItem { + get inboxCount() { + return this.notification.data.inbox_count; + } + + get label() { + return I18n.t("notifications.group_message_summary", { + count: this.inboxCount, + group_name: this.notification.data.group_name, + }); + } + + get wrapLabel() { + return false; + } + + get description() { + return null; + } +} diff --git a/app/assets/javascripts/discourse/app/components/user-menu/invitee-accepted-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/invitee-accepted-notification-item.js new file mode 100644 index 00000000000..e4635f2e43e --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/invitee-accepted-notification-item.js @@ -0,0 +1,13 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; +import { userPath } from "discourse/lib/url"; +import I18n from "I18n"; + +export default class UserMenuInviteeAcceptedNotificationItem extends UserMenuNotificationItem { + get linkHref() { + return userPath(this.notification.data.display_username); + } + + get description() { + return I18n.t("notifications.invitee_accepted_your_invitation"); + } +} diff --git a/app/assets/javascripts/discourse/app/components/user-menu/liked-consolidated-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/liked-consolidated-notification-item.js new file mode 100644 index 00000000000..1591c4d6476 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/liked-consolidated-notification-item.js @@ -0,0 +1,21 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; +import { userPath } from "discourse/lib/url"; +import I18n from "I18n"; + +export default class UserMenuLikedConsolidatedNotificationItem extends UserMenuNotificationItem { + get linkHref() { + return userPath( + `${ + this.notification.username || this.currentUser.username + }/notifications/likes-received?acting_username=${ + this.notification.data.username + }` + ); + } + + get description() { + return I18n.t("notifications.liked_consolidated_description", { + count: this.notification.data.count, + }); + } +} diff --git a/app/assets/javascripts/discourse/app/components/user-menu/liked-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/liked-notification-item.js new file mode 100644 index 00000000000..e4f8b02ce67 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/liked-notification-item.js @@ -0,0 +1,38 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; +import { formatUsername } from "discourse/lib/utilities"; +import I18n from "I18n"; + +export default class UserMenuLikedNotificationItem extends UserMenuNotificationItem { + get count() { + return this.notification.data.count; + } + + get username2() { + return formatUsername(this.notification.data.username2); + } + + get label() { + if (this.count === 2) { + return I18n.t("notifications.liked_by_2_users", { + username: this.username, + username2: this.username2, + }); + } else if (this.count > 2) { + return I18n.t("notifications.liked_by_multiple_users", { + username: this.username, + username2: this.username2, + count: this.count - 2, + }); + } else { + return super.label; + } + } + + get labelWrapperClasses() { + if (this.count === 2) { + return "double-user"; + } else if (this.count > 2) { + return "multi-user"; + } + } +} diff --git a/app/assets/javascripts/discourse/app/components/user-menu/membership-request-accepted-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/membership-request-accepted-notification-item.js new file mode 100644 index 00000000000..850dc4c084c --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/membership-request-accepted-notification-item.js @@ -0,0 +1,23 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; +import { groupPath } from "discourse/lib/url"; +import I18n from "I18n"; + +export default class UserMenuMembershipRequestAcceptedNotificationItem extends UserMenuNotificationItem { + get linkHref() { + return groupPath(this.notification.data.group_name); + } + + get label() { + return I18n.t("notifications.membership_request_accepted", { + group_name: this.notification.data.group_name, + }); + } + + get wrapLabel() { + return false; + } + + get description() { + return null; + } +} diff --git a/app/assets/javascripts/discourse/app/components/user-menu/membership-request-consolidated-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/membership-request-consolidated-notification-item.js new file mode 100644 index 00000000000..0fe0faa7282 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/membership-request-consolidated-notification-item.js @@ -0,0 +1,26 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; +import { userPath } from "discourse/lib/url"; +import I18n from "I18n"; + +export default class UserMenuMembershipRequestConsolidatedNotificationItem extends UserMenuNotificationItem { + get linkHref() { + return userPath( + `${this.notification.username || this.currentUser.username}/messages` + ); + } + + get label() { + return I18n.t("notifications.membership_request_consolidated", { + group_name: this.notification.data.group_name, + count: this.notification.data.count, + }); + } + + get wrapLabel() { + return false; + } + + get description() { + return null; + } +} diff --git a/app/assets/javascripts/discourse/app/components/user-menu/moved-post-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/moved-post-notification-item.js new file mode 100644 index 00000000000..e4394918fae --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/moved-post-notification-item.js @@ -0,0 +1,8 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; +import I18n from "I18n"; + +export default class UserMenuMovedPostNotificationItem extends UserMenuNotificationItem { + get label() { + return I18n.t("notifications.user_moved_post", { username: this.username }); + } +} diff --git a/app/assets/javascripts/discourse/app/components/user-menu/watching-first-post-notification-item.js b/app/assets/javascripts/discourse/app/components/user-menu/watching-first-post-notification-item.js new file mode 100644 index 00000000000..7d917d2e74d --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-menu/watching-first-post-notification-item.js @@ -0,0 +1,8 @@ +import UserMenuNotificationItem from "discourse/components/user-menu/notification-item"; +import I18n from "I18n"; + +export default class UserMenuWatchingFirstPostNotificationItem extends UserMenuNotificationItem { + get label() { + return I18n.t("notifications.watching_first_post_label"); + } +} diff --git a/app/assets/javascripts/discourse/app/models/notification.js b/app/assets/javascripts/discourse/app/models/notification.js index 8994d66a89a..4ef83473c81 100644 --- a/app/assets/javascripts/discourse/app/models/notification.js +++ b/app/assets/javascripts/discourse/app/models/notification.js @@ -2,7 +2,28 @@ import RestModel from "discourse/models/rest"; import { tracked } from "@glimmer/tracking"; const DEFAULT_ITEM = "user-menu/notification-item"; -const _componentForType = {}; + +function defaultComponentForType() { + return { + bookmark_reminder: "user-menu/bookmark-reminder-notification-item", + custom: "user-menu/custom-notification-item", + granted_badge: "user-menu/granted-badge-notification-item", + group_mentioned: "user-menu/group-mentioned-notification-item", + group_message_summary: "user-menu/group-message-summary-notification-item", + invitee_accepted: "user-menu/invitee-accepted-notification-item", + liked: "user-menu/liked-notification-item", + liked_consolidated: "user-menu/liked-consolidated-notification-item", + membership_request_accepted: + "user-menu/membership-request-accepted-notification-item", + membership_request_consolidated: + "user-menu/membership-request-consolidated-notification-item", + moved_post: "user-menu/moved-post-notification-item", + watching_first_post: "user-menu/watching-first-post-notification-item", + }; +} + +let _componentForType = defaultComponentForType(); +// TODO(osama): add plugin API export default class Notification extends RestModel { @tracked read; diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-menu/bookmark-reminder-notification-item-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-menu/bookmark-reminder-notification-item-test.js new file mode 100644 index 00000000000..531c1b8429d --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/user-menu/bookmark-reminder-notification-item-test.js @@ -0,0 +1,107 @@ +import { module, test } from "qunit"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { query } from "discourse/tests/helpers/qunit-helpers"; +import { deepMerge } from "discourse-common/lib/object"; +import { NOTIFICATION_TYPES } from "discourse/tests/fixtures/concerns/notification-types"; +import { render } from "@ember/test-helpers"; +import Notification from "discourse/models/notification"; +import { hbs } from "ember-cli-htmlbars"; +import I18n from "I18n"; + +function getNotification(overrides = {}) { + return Notification.create( + deepMerge( + { + id: 11, + user_id: 1, + notification_type: NOTIFICATION_TYPES.bookmark_reminder, + read: false, + high_priority: true, + created_at: "2022-07-01T06:00:32.173Z", + post_number: 113, + topic_id: 449, + fancy_title: "This is fancy title <a>!", + slug: "this-is-fancy-title", + data: { + title: "this is unsafe bookmark title !", + display_username: "osama", + bookmark_name: null, + bookmarkable_url: "/t/sometopic/3232", + }, + }, + overrides + ) + ); +} + +module( + "Integration | Component | user-menu | bookmark-reminder-notification-item", + function (hooks) { + setupRenderingTest(hooks); + + const template = hbs``; + + test("when the bookmark has a name", async function (assert) { + this.set( + "notification", + getNotification({ data: { bookmark_name: "MY BOOKMARK" } }) + ); + await render(template); + const link = query("li a"); + assert.strictEqual( + link.title, + I18n.t("notifications.titles.bookmark_reminder_with_name", { + name: "MY BOOKMARK", + }), + "the notification has a title that includes the bookmark name" + ); + }); + + test("when the bookmark doesn't have a name", async function (assert) { + this.set( + "notification", + getNotification({ data: { bookmark_name: null } }) + ); + await render(template); + const link = query("li a"); + assert.strictEqual( + link.title, + I18n.t("notifications.titles.bookmark_reminder"), + "the notification has a generic title" + ); + }); + + test("when the bookmark reminder doesn't originate from a topic and has a title", async function (assert) { + this.set( + "notification", + getNotification({ + post_number: null, + topic_id: null, + fancy_title: null, + data: { + title: "this is unsafe bookmark title !", + bookmarkable_url: "/chat/channel/33", + }, + }) + ); + await render(template); + const description = query("li .notification-description"); + assert.strictEqual( + description.textContent.trim(), + "this is unsafe bookmark title !", + "the title is rendered safely as description" + ); + }); + + test("when the bookmark reminder originates from a topic", async function (assert) { + this.set("notification", getNotification()); + await render(template); + const description = query("li .notification-description"); + assert.strictEqual( + description.textContent.trim(), + "This is fancy title !", + "fancy_title is safe and rendered correctly" + ); + }); + } +); diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-menu/granted-badge-notification-item-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-menu/granted-badge-notification-item-test.js new file mode 100644 index 00000000000..abbe3a6fda4 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/user-menu/granted-badge-notification-item-test.js @@ -0,0 +1,63 @@ +import { module, test } from "qunit"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { exists, query } from "discourse/tests/helpers/qunit-helpers"; +import { deepMerge } from "discourse-common/lib/object"; +import { NOTIFICATION_TYPES } from "discourse/tests/fixtures/concerns/notification-types"; +import { render } from "@ember/test-helpers"; +import Notification from "discourse/models/notification"; +import { hbs } from "ember-cli-htmlbars"; +import I18n from "I18n"; + +function getNotification(overrides = {}) { + return Notification.create( + deepMerge( + { + id: 11, + user_id: 1, + notification_type: NOTIFICATION_TYPES.granted_badge, + read: false, + high_priority: false, + created_at: "2022-07-01T06:00:32.173Z", + data: { + badge_id: 12, + badge_name: "Tough Guy ", + badge_slug: "tough-guy", + username: "ossa", + badge_title: false, + }, + }, + overrides + ) + ); +} + +module( + "Integration | Component | user-menu | granted-badge-notification-item", + function (hooks) { + setupRenderingTest(hooks); + + const template = hbs``; + + test("links to the badge page and filters by the username", async function (assert) { + this.set("notification", getNotification()); + await render(template); + const link = query("li a"); + assert.ok(link.href.endsWith("/badges/12/tough-guy?username=ossa")); + }); + + test("displays the right notification content", async function (assert) { + this.set("notification", getNotification()); + await render(template); + const div = query("li div"); + assert.strictEqual( + div.textContent.trim(), + I18n.t("notifications.granted_badge", { + description: "Tough Guy ", + }), + "label is rendered safely" + ); + assert.ok(!exists("li .notification-label")); + assert.ok(!exists("li .notification-description")); + }); + } +); diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-menu/group-mentioned-notification-item-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-menu/group-mentioned-notification-item-test.js new file mode 100644 index 00000000000..18b8ed3e0ad --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/user-menu/group-mentioned-notification-item-test.js @@ -0,0 +1,68 @@ +import { module, test } from "qunit"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { query } from "discourse/tests/helpers/qunit-helpers"; +import { deepMerge } from "discourse-common/lib/object"; +import { render } from "@ember/test-helpers"; +import { NOTIFICATION_TYPES } from "discourse/tests/fixtures/concerns/notification-types"; +import Notification from "discourse/models/notification"; +import { hbs } from "ember-cli-htmlbars"; + +function getNotification(overrides = {}) { + return Notification.create( + deepMerge( + { + id: 11, + user_id: 1, + notification_type: NOTIFICATION_TYPES.group_mentioned, + read: false, + high_priority: false, + created_at: "2022-07-01T06:00:32.173Z", + post_number: 113, + topic_id: 449, + fancy_title: "This is fancy title <a>!", + slug: "this-is-fancy-title", + data: { + topic_title: "this is title before it becomes fancy !", + original_post_id: 112, + original_post_type: 1, + original_username: "kolary", + display_username: "osama", + group_id: 333, + group_name: "hikers", + }, + }, + overrides + ) + ); +} + +module( + "Integration | Component | user-menu | group-mentioned-notification-item", + function (hooks) { + setupRenderingTest(hooks); + + const template = hbs``; + + test("notification label displays the user who mentioned and the mentioned group", async function (assert) { + this.set("notification", getNotification()); + await render(template); + const label = query("li .notification-label"); + assert.strictEqual(label.textContent.trim(), "osama @hikers"); + assert.ok( + label.classList.contains("mention-group"), + "label has mention-group class" + ); + assert.ok(label.classList.contains("notify"), "label has notify class"); + }); + + test("notification description displays the topic title", async function (assert) { + this.set("notification", getNotification()); + await render(template); + const description = query("li .notification-description"); + assert.strictEqual( + description.textContent.trim(), + "This is fancy title !" + ); + }); + } +); diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-menu/group-message-summary-notification-item-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-menu/group-message-summary-notification-item-test.js new file mode 100644 index 00000000000..9b5a2989fd5 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/user-menu/group-message-summary-notification-item-test.js @@ -0,0 +1,55 @@ +import { module, test } from "qunit"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { exists, query } from "discourse/tests/helpers/qunit-helpers"; +import { render } from "@ember/test-helpers"; +import { deepMerge } from "discourse-common/lib/object"; +import { NOTIFICATION_TYPES } from "discourse/tests/fixtures/concerns/notification-types"; +import Notification from "discourse/models/notification"; +import { hbs } from "ember-cli-htmlbars"; +import I18n from "I18n"; + +function getNotification(overrides = {}) { + return Notification.create( + deepMerge( + { + id: 11, + user_id: 1, + notification_type: NOTIFICATION_TYPES.group_message_summary, + read: false, + high_priority: false, + created_at: "2022-07-01T06:00:32.173Z", + data: { + group_id: 321, + group_name: "drummers", + inbox_count: 13, + username: "drummers.boss", + }, + }, + overrides + ) + ); +} + +module( + "Integration | Component | user-menu | group-message-summary-notification-item", + function (hooks) { + setupRenderingTest(hooks); + + const template = hbs``; + + test("the notification displays the right content", async function (assert) { + this.set("notification", getNotification()); + await render(template); + const notification = query("li"); + assert.strictEqual( + notification.textContent.trim(), + I18n.t("notifications.group_message_summary", { + count: 13, + group_name: "drummers", + }) + ); + assert.ok(!exists("li .notification-label")); + assert.ok(!exists("li .notification-description")); + }); + } +); diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-menu/liked-consolidated-notification-item-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-menu/liked-consolidated-notification-item-test.js new file mode 100644 index 00000000000..0af3a813a07 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/user-menu/liked-consolidated-notification-item-test.js @@ -0,0 +1,71 @@ +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 { deepMerge } from "discourse-common/lib/object"; +import { NOTIFICATION_TYPES } from "discourse/tests/fixtures/concerns/notification-types"; +import Notification from "discourse/models/notification"; +import { hbs } from "ember-cli-htmlbars"; +import I18n from "I18n"; + +function getNotification(overrides = {}) { + return Notification.create( + deepMerge( + { + id: 11, + user_id: 1, + notification_type: NOTIFICATION_TYPES.liked_consolidated, + read: false, + high_priority: false, + created_at: "2022-07-01T06:00:32.173Z", + data: { + topic_title: "this is some topic and it's irrelevant", + original_post_id: 3294, + original_post_type: 1, + original_username: "liker439", + display_username: "liker439", + username: "liker439", + count: 44, + }, + }, + overrides + ) + ); +} + +module( + "Integration | Component | user-menu | liked-consolidated-notification-item", + function (hooks) { + setupRenderingTest(hooks); + + const template = hbs``; + + test("the notification links to the likes received notifications page of the user", async function (assert) { + this.set("notification", getNotification()); + await render(template); + const link = query("li a"); + assert.ok( + link.href.endsWith( + "/u/eviltrout/notifications/likes-received?acting_username=liker439" + ) + ); + }); + + test("the notification label displays the user who liked", async function (assert) { + this.set("notification", getNotification()); + await render(template); + const label = query("li .notification-label"); + assert.strictEqual(label.textContent.trim(), "liker439"); + }); + + test("the notification description displays the number of likes", async function (assert) { + this.set("notification", getNotification()); + await render(template); + const description = query("li .notification-description"); + assert.strictEqual( + description.textContent.trim(), + I18n.t("notifications.liked_consolidated_description", { count: 44 }) + ); + }); + } +); diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-menu/liked-notification-item-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-menu/liked-notification-item-test.js new file mode 100644 index 00000000000..679e21b1081 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/user-menu/liked-notification-item-test.js @@ -0,0 +1,114 @@ +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 { deepMerge } from "discourse-common/lib/object"; +import { NOTIFICATION_TYPES } from "discourse/tests/fixtures/concerns/notification-types"; +import Notification from "discourse/models/notification"; +import { hbs } from "ember-cli-htmlbars"; +import I18n from "I18n"; + +function getNotification(overrides = {}) { + return Notification.create( + deepMerge( + { + id: 11, + user_id: 1, + notification_type: NOTIFICATION_TYPES.liked, + read: false, + high_priority: false, + created_at: "2022-07-01T06:00:32.173Z", + post_number: 113, + topic_id: 449, + fancy_title: "This is fancy title <a>!", + slug: "this-is-fancy-title", + data: { + topic_title: "this is title before it becomes fancy !", + username: "osama", + display_username: "osama", + username2: "shrek", + count: 2, + }, + }, + overrides + ) + ); +} + +module( + "Integration | Component | user-menu | liked-notification-item", + function (hooks) { + setupRenderingTest(hooks); + + const template = hbs``; + + test("when the likes count is 2", async function (assert) { + this.set("notification", getNotification({ data: { count: 2 } })); + await render(template); + + const label = query("li .notification-label"); + const description = query("li .notification-description"); + assert.strictEqual( + label.textContent.trim(), + "osama, shrek", + "the label displays both usernames comma-concatenated" + ); + assert.ok( + label.classList.contains("double-user"), + "label has double-user class" + ); + assert.strictEqual( + description.textContent.trim(), + "This is fancy title !", + "the description displays the topic title" + ); + }); + + test("when the likes count is more than 2", async function (assert) { + this.set("notification", getNotification({ data: { count: 3 } })); + await render(template); + + const label = query("li .notification-label"); + const description = query("li .notification-description"); + assert.strictEqual( + label.textContent.trim(), + I18n.t("notifications.liked_by_multiple_users", { + username: "osama", + username2: "shrek", + count: 1, + }), + "the label displays the first 2 usernames comma-concatenated with the count of remaining users" + ); + assert.ok( + label.classList.contains("multi-user"), + "label has multi-user class" + ); + assert.strictEqual( + description.textContent.trim(), + "This is fancy title !", + "the description displays the topic title" + ); + }); + + test("when the likes count is 1", async function (assert) { + this.set( + "notification", + getNotification({ data: { count: 1, username2: null } }) + ); + await render(template); + + const label = query("li .notification-label"); + const description = query("li .notification-description"); + assert.strictEqual( + label.textContent.trim(), + "osama", + "the label displays the username" + ); + assert.strictEqual( + description.textContent.trim(), + "This is fancy title !", + "the description displays the topic title" + ); + }); + } +); diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 19478b4cf7e..c37c917c9dc 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -2322,6 +2322,8 @@ en: empty: "No notifications found." post_approved: "Your post was approved" reviewable_items: "items requiring review" + watching_first_post_label: "New Topic" + user_moved_post: "%{username} moved" mentioned: "%{username} %{description}" group_mentioned: "%{username} %{description}" quoted: "%{username} %{description}" @@ -2334,6 +2336,10 @@ en: liked_many: one: "%{username}, %{username2} and %{count} other %{description}" other: "%{username}, %{username2} and %{count} others %{description}" + liked_by_2_users: "%{username}, %{username2}" + liked_by_multiple_users: + one: "%{username}, %{username2} and %{count} other" + other: "%{username}, %{username2} and %{count} others" liked_consolidated_description: one: "liked %{count} of your posts" other: "liked %{count} of your posts" @@ -2342,6 +2348,7 @@ en: invited_to_private_message: "

%{username} %{description}" invited_to_topic: "%{username} %{description}" invitee_accepted: "%{username} accepted your invitation" + invitee_accepted_your_invitation: "accepted your invitation" moved_post: "%{username} moved %{description}" linked: "%{username} %{description}" granted_badge: "Earned '%{description}'"