FEATURE: adds a filter for all/unread/read on user's notifications page (#9535)

FEATURE: adds a filter for all/unread/read on user’s notifications page (#9535)

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 3d2a211..35cdf06 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 dc91471..e821b68 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 a44a96e..578f376 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 @@
   </div>
 {{/if}}
 
+{{notifications-filter value=filter onChange=(action "filterNotifications")}}
+<span class="user-notifications-filter-separator"></span>
+
 {{#if hasNotifications}}
-  {{user-notifications-large notifications=model}}
+  {{user-notifications-large notifications=model filter=filter}}
   {{conditional-loading-spinner condition=loading}}
 {{else}}
   <div class="alert alert-info">{{i18n "notifications.empty"}}</div>
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 76bf1da..53a4d3a 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 0000000..3432f49
--- /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 0000000..b615470
--- /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 0000000..21cee39
--- /dev/null
+++ b/app/assets/javascripts/select-kit/templates/components/notifications-filter/notifications-filter-header.hbs
@@ -0,0 +1,7 @@
+<label class="filter-text">
+  {{i18n "user.user_notifications.filters.filter_by"}}
+</label>
+<label class="header-text">
+  {{i18n label}}
+</label>
+{{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 805b6bc..869635a 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 0000000..680622f
--- /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 {

[... diff too long, it was truncated ...]

GitHub sha: 99abdf51

This commit appears in #9535 which was merged by jjaffeux.