FEATURE: add update banner to the categories and latest topics view (#14403)

FEATURE: add update banner to the categories and latest topics view (#14403)

diff --git a/app/assets/javascripts/discourse/app/controllers/discovery/categories.js b/app/assets/javascripts/discourse/app/controllers/discovery/categories.js
index b286fd4..b834630 100644
--- a/app/assets/javascripts/discourse/app/controllers/discovery/categories.js
+++ b/app/assets/javascripts/discourse/app/controllers/discovery/categories.js
@@ -42,5 +42,13 @@ export default DiscoveryController.extend({
     refresh() {
       this.send("triggerRefresh");
     },
+    showInserted() {
+      const tracker = this.topicTrackingState;
+
+      // Move inserted into topics
+      this.model.loadBefore(tracker.get("newIncoming"), true);
+      tracker.resetTracking();
+      return false;
+    },
   },
 });
diff --git a/app/assets/javascripts/discourse/app/models/topic-tracking-state.js b/app/assets/javascripts/discourse/app/models/topic-tracking-state.js
index 3097cb5..96215c7 100644
--- a/app/assets/javascripts/discourse/app/models/topic-tracking-state.js
+++ b/app/assets/javascripts/discourse/app/models/topic-tracking-state.js
@@ -236,7 +236,10 @@ const TopicTrackingState = EmberObject.extend({
 
     // always add incoming if looking at the latest list and a latest channel
     // message comes through
-    if (filter === "latest" && data.message_type === "latest") {
+    if (
+      (filter === "latest" || filter === "categories") &&
+      data.message_type === "latest"
+    ) {
       this._addIncoming(data.topic_id);
     }
 
diff --git a/app/assets/javascripts/discourse/app/routes/discovery-categories.js b/app/assets/javascripts/discourse/app/routes/discovery-categories.js
index 96e241d..92081b7 100644
--- a/app/assets/javascripts/discourse/app/routes/discovery-categories.js
+++ b/app/assets/javascripts/discourse/app/routes/discovery-categories.js
@@ -11,6 +11,8 @@ import { defaultHomepage } from "discourse/lib/utilities";
 import { hash } from "rsvp";
 import { next } from "@ember/runloop";
 import showModal from "discourse/lib/show-modal";
+import getURL from "discourse-common/lib/get-url";
+import Session from "discourse/models/session";
 
 const DiscoveryCategoriesRoute = DiscourseRoute.extend(OpenComposer, {
   renderTemplate() {
@@ -56,11 +58,42 @@ const DiscoveryCategoriesRoute = DiscourseRoute.extend(OpenComposer, {
           Site.currentProp("top_tags", topicsList.topic_list.top_tags);
         }
 
+        let store = this.store;
+
         return EmberObject.create({
           categories: CategoryList.categoriesFrom(
             this.store,
             wrappedCategoriesList
           ),
+          loadBefore: function (topic_ids, storeInSession) {
+            // refresh dupes
+            this.topics.removeObjects(
+              this.topics.filter((topic) => topic_ids.indexOf(topic.id) >= 0)
+            );
+
+            const url = `${getURL("/")}latest.json?topic_ids=${topic_ids.join(
+              ","
+            )}`;
+
+            return ajax({ url, data: this.params }).then((result) => {
+              const topicIds = [];
+
+              this.topics.forEach((topic) => (topicIds[topic.id] = true));
+
+              let i = 0;
+              TopicList.topicsFrom(store, result).forEach((topic) => {
+                if (!topicIds[topic.id]) {
+                  topic.set("highlight", true);
+                  this.topics.insertAt(i, topic);
+                  i++;
+                }
+              });
+
+              if (storeInSession) {
+                Session.currentProp("topicList", this);
+              }
+            });
+          },
           topics: TopicList.topicsFrom(this.store, topicsList),
           can_create_category: categoriesList.can_create_category,
           can_create_topic: categoriesList.can_create_topic,
diff --git a/app/assets/javascripts/discourse/app/templates/discovery/categories.hbs b/app/assets/javascripts/discourse/app/templates/discovery/categories.hbs
index c50a673..92e3f0c 100644
--- a/app/assets/javascripts/discourse/app/templates/discovery/categories.hbs
+++ b/app/assets/javascripts/discourse/app/templates/discovery/categories.hbs
@@ -1,6 +1,14 @@
 {{plugin-outlet name="above-discovery-categories" tagName="" args=(hash categories=model.categories categoryPageStyle=categoryPageStyle topics=model.topics)}}
 
 {{#discovery-categories refresh=(action "refresh")}}
+  {{#if topicTrackingState.hasIncoming}}
+    <div class="show-more {{if hasTopics "has-topics"}}">
+      <div role="button" class="alert alert-info clickable" {{action "showInserted"}}>
+        {{count-i18n key="topic_count_" suffix=topicTrackingState.filter count=topicTrackingState.incomingCount}}
+      </div>
+    </div>
+  {{/if}}
+
   {{component categoryPageStyle
               categories=model.categories
               topics=model.topics}}
diff --git a/app/assets/javascripts/discourse/tests/unit/models/topic-tracking-state-test.js b/app/assets/javascripts/discourse/tests/unit/models/topic-tracking-state-test.js
index 56b94a8..b2ffb56 100644
--- a/app/assets/javascripts/discourse/tests/unit/models/topic-tracking-state-test.js
+++ b/app/assets/javascripts/discourse/tests/unit/models/topic-tracking-state-test.js
@@ -499,6 +499,26 @@ discourseModule("Unit | Model | topic-tracking-state", function (hooks) {
         );
       });
 
+      test("adds incoming in the categories latest topics list", function (assert) {
+        trackingState.trackIncoming("categories");
+        const unreadCategoriesLatestTopicsPayload = {
+          ...unreadTopicPayload,
+          message_type: "latest",
+        };
+
+        publishToMessageBus(`/latest`, unreadCategoriesLatestTopicsPayload);
+        assert.deepEqual(
+          trackingState.newIncoming,
+          [111],
+          "unread topic is incoming"
+        );
+        assert.equal(
+          trackingState.incomingCount,
+          1,
+          "incoming count is increased"
+        );
+      });
+
       test("dismisses new topic", function (assert) {
         trackingState.loadStates([
           {
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 9885897..bd9cb65 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -350,6 +350,10 @@ en:
         yes_value: "Discard"
         no_value: "Resume editing"
 
+    topic_count_categories:
+      one: "See %{count} new or updated topic"
+      other: "See %{count} new or updated topics"
+
     topic_count_latest:
       one: "See %{count} new or updated topic"
       other: "See %{count} new or updated topics"

GitHub sha: ed0b6a3660416c1fb9c0b541cdf43689980c23e9

This commit appears in #14403 which was approved by pmusaraj and CvX. It was merged by jmperez127.

This commit has been mentioned on Discourse Meta. There might be relevant details there: