diff --git a/app/assets/javascripts/discourse/app/components/user-notifications-large.js b/app/assets/javascripts/discourse/app/components/user-notifications-large.js index 3d2a2112b5..35cdf06a20 100644 --- a/app/assets/javascripts/discourse/app/components/user-notifications-large.js +++ b/app/assets/javascripts/discourse/app/components/user-notifications-large.js @@ -6,11 +6,15 @@ export default MountWidget.extend({ init() { this._super(...arguments); - this.args = { notifications: this.notifications }; + this.args = { notifications: this.notifications, filter: this.filter }; }, - @observes("notifications.length", "notifications.@each.read") + @observes("notifications.length", "notifications.@each.read", "filter") _triggerRefresh() { + this.set("args", { + notifications: this.notifications, + filter: this.filter + }); this.queueRerender(); } }); diff --git a/app/assets/javascripts/discourse/app/controllers/user-notifications.js b/app/assets/javascripts/discourse/app/controllers/user-notifications.js index dc9147105e..e821b68364 100644 --- a/app/assets/javascripts/discourse/app/controllers/user-notifications.js +++ b/app/assets/javascripts/discourse/app/controllers/user-notifications.js @@ -8,14 +8,20 @@ export default Controller.extend({ application: controller(), router: service(), currentPath: readOnly("router._router.currentPath"), + filter: "all", @observes("model.canLoadMore") _showFooter() { this.set("application.showFooter", !this.get("model.canLoadMore")); }, - @discourseComputed("model.content.length") - hasNotifications(length) { + @discourseComputed("model.content.length", "filter") + hasNotifications(length, filter) { + if (filter === "read") { + return this.model.filterBy("read", true).length > 0; + } else if (filter === "unread") { + return this.model.filterBy("read", false).length > 0; + } return length > 0; }, @@ -35,6 +41,10 @@ export default Controller.extend({ loadMore() { this.model.loadMore(); + }, + + filterNotifications(value) { + this.set("filter", value); } } }); diff --git a/app/assets/javascripts/discourse/app/templates/user/notifications-index.hbs b/app/assets/javascripts/discourse/app/templates/user/notifications-index.hbs index a44a96e8d9..578f376348 100644 --- a/app/assets/javascripts/discourse/app/templates/user/notifications-index.hbs +++ b/app/assets/javascripts/discourse/app/templates/user/notifications-index.hbs @@ -8,8 +8,11 @@ {{/if}} +{{notifications-filter value=filter onChange=(action "filterNotifications")}} + + {{#if hasNotifications}} - {{user-notifications-large notifications=model}} + {{user-notifications-large notifications=model filter=filter}} {{conditional-loading-spinner condition=loading}} {{else}}
{{i18n "notifications.empty"}}
diff --git a/app/assets/javascripts/discourse/app/widgets/user-notifications-large.js b/app/assets/javascripts/discourse/app/widgets/user-notifications-large.js index 76bf1da687..53a4d3ad52 100644 --- a/app/assets/javascripts/discourse/app/widgets/user-notifications-large.js +++ b/app/assets/javascripts/discourse/app/widgets/user-notifications-large.js @@ -30,9 +30,13 @@ createWidget("large-notification-item", { export default createWidget("user-notifications-large", { html(attrs) { - const notifications = attrs.notifications; + let notifications = attrs.notifications; const username = notifications.findArgs.username; - + if (attrs.filter === "read") { + notifications = notifications.filterBy("read", true); + } else if (attrs.filter === "unread") { + notifications = notifications.filterBy("read", false); + } return notifications.map(n => { n.username = username; return this.attach("large-notification-item", n); diff --git a/app/assets/javascripts/select-kit/components/notifications-filter.js b/app/assets/javascripts/select-kit/components/notifications-filter.js new file mode 100644 index 0000000000..3432f49e7a --- /dev/null +++ b/app/assets/javascripts/select-kit/components/notifications-filter.js @@ -0,0 +1,25 @@ +import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box"; +import { computed } from "@ember/object"; + +export default DropdownSelectBoxComponent.extend({ + classNames: ["notifications-filter"], + content: computed(function() { + return [ + { + id: "all", + label: I18n.t("user.user_notifications.filters.all") + }, + { + id: "read", + label: I18n.t("user.user_notifications.filters.read") + }, + { + id: "unread", + label: I18n.t("user.user_notifications.filters.unread") + } + ]; + }), + selectKitOptions: { + headerComponent: "notifications-filter/notifications-filter-header" + } +}); diff --git a/app/assets/javascripts/select-kit/components/notifications-filter/notifications-filter-header.js b/app/assets/javascripts/select-kit/components/notifications-filter/notifications-filter-header.js new file mode 100644 index 0000000000..b615470433 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/notifications-filter/notifications-filter-header.js @@ -0,0 +1,18 @@ +import DropdownSelectBoxHeaderComponent from "select-kit/components/dropdown-select-box/dropdown-select-box-header"; +import discourseComputed from "discourse-common/utils/decorators"; + +export default DropdownSelectBoxHeaderComponent.extend({ + layoutName: + "select-kit/templates/components/notifications-filter/notifications-filter-header", + classNames: ["notifications-filter-header"], + + @discourseComputed("value") + label(value) { + return `user.user_notifications.filters.${value}`; + }, + + @discourseComputed("selectKit.isExpanded") + caretIcon(isExpanded) { + return isExpanded ? "caret-up" : "caret-down"; + } +}); diff --git a/app/assets/javascripts/select-kit/templates/components/notifications-filter/notifications-filter-header.hbs b/app/assets/javascripts/select-kit/templates/components/notifications-filter/notifications-filter-header.hbs new file mode 100644 index 0000000000..21cee39d91 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/notifications-filter/notifications-filter-header.hbs @@ -0,0 +1,7 @@ + + +{{d-icon caretIcon class="caret-icon"}} diff --git a/app/assets/stylesheets/common/base/user.scss b/app/assets/stylesheets/common/base/user.scss index 805b6bc8d0..869635a250 100644 --- a/app/assets/stylesheets/common/base/user.scss +++ b/app/assets/stylesheets/common/base/user.scss @@ -64,6 +64,12 @@ .d-icon-heart { color: $love; } + + .user-notifications-filter-separator { + display: block; + width: 100%; + border: 0.5px solid $primary-low; + } } .user-main { diff --git a/app/assets/stylesheets/common/select-kit/notifications-filter.scss b/app/assets/stylesheets/common/select-kit/notifications-filter.scss new file mode 100644 index 0000000000..680622f8aa --- /dev/null +++ b/app/assets/stylesheets/common/select-kit/notifications-filter.scss @@ -0,0 +1,43 @@ +.select-kit { + &.dropdown-select-box { + &.notifications-filter { + display: inline-flex; + position: relative; + + .select-kit-collection { + padding: 5px; + } + + .notifications-filter-header { + padding: 0 0.5em 0 0.5em; + background: none; + border: none; + justify-content: flex-start; + width: auto; + height: auto; + label.filter-text { + margin-right: 15px; + color: $primary-medium; + } + + label.header-text { + color: dark-light-choose($tertiary, $tertiary); + } + + .d-icon { + color: $primary-medium; + opacity: 1; + margin: 5px 0 10px 5px; + font-size: $font-up-3; + } + + &.is-focused, + &:hover { + background: none; + border: none; + outline: none; + } + } + } + } +} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 1b8fb7c65a..5c3211a53b 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -835,6 +835,11 @@ en: private_message: "Message" private_messages: "Messages" user_notifications: + filters: + filter_by: "Filter By" + all: "All" + read: "Read" + unread: "Unread" ignore_duration_title: "Ignore Timer" ignore_duration_username: "Username" ignore_duration_when: "Duration:"