FEATURE: Display new/unread count for tracked categories in exp sidebar (#17046)
This commit is contained in:
parent
cd8c97debc
commit
946f8a65fd
|
@ -1,10 +1,20 @@
|
|||
import { cached } from "@glimmer/tracking";
|
||||
|
||||
import GlimmerComponent from "discourse/components/glimmer";
|
||||
import CategorySectionLink from "discourse/lib/sidebar/categories-section/category-section-link";
|
||||
|
||||
export default class SidebarCategoriesSection extends GlimmerComponent {
|
||||
@cached
|
||||
get sectionLinks() {
|
||||
return this.site.trackedCategoriesList.map((trackedCategory) => {
|
||||
return new CategorySectionLink({ category: trackedCategory });
|
||||
return new CategorySectionLink({
|
||||
category: trackedCategory,
|
||||
topicTrackingState: this.topicTrackingState,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
willDestroy() {
|
||||
this.sectionLinks.forEach((sectionLink) => sectionLink.teardown());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,42 @@
|
|||
import I18n from "I18n";
|
||||
|
||||
import { htmlSafe } from "@ember/template";
|
||||
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
import { categoryBadgeHTML } from "discourse/helpers/category-link";
|
||||
import Category from "discourse/models/category";
|
||||
|
||||
export default class CategorySectionLink {
|
||||
constructor({ category }) {
|
||||
@tracked totalUnread = 0;
|
||||
@tracked totalNew = 0;
|
||||
|
||||
constructor({ category, topicTrackingState }) {
|
||||
this.category = category;
|
||||
this.topicTrackingState = topicTrackingState;
|
||||
|
||||
this.callbackId = this.topicTrackingState.onStateChange(
|
||||
this._refreshCounts
|
||||
);
|
||||
|
||||
this._refreshCounts();
|
||||
}
|
||||
|
||||
teardown() {
|
||||
this.topicTrackingState.offStateChange(this.callbackId);
|
||||
}
|
||||
|
||||
@bind
|
||||
_refreshCounts() {
|
||||
this.totalUnread = this.topicTrackingState.countUnread({
|
||||
categoryId: this.category.id,
|
||||
});
|
||||
|
||||
if (this.totalUnread === 0) {
|
||||
this.totalNew = this.topicTrackingState.countNew({
|
||||
categoryId: this.category.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get name() {
|
||||
|
@ -31,4 +62,26 @@ export default class CategorySectionLink {
|
|||
get text() {
|
||||
return htmlSafe(categoryBadgeHTML(this.category, { link: false }));
|
||||
}
|
||||
|
||||
get badgeText() {
|
||||
if (this.totalUnread > 0) {
|
||||
return I18n.t("sidebar.unread_count", {
|
||||
count: this.totalUnread,
|
||||
});
|
||||
} else if (this.totalNew > 0) {
|
||||
return I18n.t("sidebar.new_count", {
|
||||
count: this.totalNew,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get route() {
|
||||
if (this.totalUnread > 0) {
|
||||
return "discovery.unreadCategory";
|
||||
} else if (this.totalNew > 0) {
|
||||
return "discovery.newCategory";
|
||||
} else {
|
||||
return "discovery.latestCategory";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,12 @@ const Site = RestModel.extend({
|
|||
|
||||
for (const category of categories) {
|
||||
if (category.isTracked) {
|
||||
trackedCategories.push(category);
|
||||
if (
|
||||
!this.siteSettings.suppress_uncategorized_badge ||
|
||||
category.id !== this.uncategorized_category_id
|
||||
) {
|
||||
trackedCategories.push(category);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
@title={{sectionLink.title}}
|
||||
@content={{sectionLink.text}}
|
||||
@currentWhen={{sectionLink.currentWhen}}
|
||||
@model={{sectionLink.model}}>
|
||||
@model={{sectionLink.model}}
|
||||
@badgeText={{sectionLink.badgeText}} >
|
||||
</Sidebar::SectionLink>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import I18n from "I18n";
|
||||
|
||||
import { click, currentURL, visit } from "@ember/test-helpers";
|
||||
import { click, currentURL, settled, visit } from "@ember/test-helpers";
|
||||
|
||||
import {
|
||||
acceptance,
|
||||
conditionalTest,
|
||||
exists,
|
||||
publishToMessageBus,
|
||||
query,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
|
@ -17,9 +18,57 @@ import discoveryFixture from "discourse/tests/fixtures/discovery-fixtures";
|
|||
import categoryFixture from "discourse/tests/fixtures/category-fixtures";
|
||||
import { cloneJSON } from "discourse-common/lib/object";
|
||||
|
||||
acceptance(
|
||||
"Sidebar - Categories Section - suppress_uncategorized_badge enabled",
|
||||
function (needs) {
|
||||
needs.settings({
|
||||
suppress_uncategorized_badge: true,
|
||||
});
|
||||
|
||||
needs.user({ experimental_sidebar_enabled: true });
|
||||
|
||||
conditionalTest(
|
||||
"uncategorized category is not shown",
|
||||
!isLegacyEmber(),
|
||||
async function (assert) {
|
||||
const categories = Site.current().categories;
|
||||
const category1 = categories[0];
|
||||
|
||||
const uncategorizedCategory = categories.find((category) => {
|
||||
return category.id === Site.current().uncategorized_category_id;
|
||||
});
|
||||
|
||||
category1.set("notification_level", NotificationLevels.TRACKING);
|
||||
|
||||
uncategorizedCategory.set(
|
||||
"notification_level",
|
||||
NotificationLevels.TRACKING
|
||||
);
|
||||
|
||||
await visit("/");
|
||||
|
||||
assert.strictEqual(
|
||||
queryAll(".sidebar-section-categories .sidebar-section-link").length,
|
||||
1,
|
||||
"there should only be one section link under the section"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(`.sidebar-section-link-${category1.slug}`),
|
||||
`only the ${category1.slug} section link is shown`
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
acceptance("Sidebar - Categories Section", function (needs) {
|
||||
needs.user({ experimental_sidebar_enabled: true });
|
||||
|
||||
needs.settings({
|
||||
suppress_uncategorized_badge: false,
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
["latest", "top", "new", "unread"].forEach((type) => {
|
||||
server.get(`/c/:categorySlug/:categoryId/l/${type}.json`, () => {
|
||||
|
@ -77,6 +126,30 @@ acceptance("Sidebar - Categories Section", function (needs) {
|
|||
}
|
||||
);
|
||||
|
||||
conditionalTest(
|
||||
"uncategorized category is shown when tracked",
|
||||
!isLegacyEmber(),
|
||||
async function (assert) {
|
||||
const categories = Site.current().categories;
|
||||
|
||||
const uncategorizedCategory = categories.find((category) => {
|
||||
return category.id === Site.current().uncategorized_category_id;
|
||||
});
|
||||
|
||||
uncategorizedCategory.set(
|
||||
"notification_level",
|
||||
NotificationLevels.TRACKING
|
||||
);
|
||||
|
||||
await visit("/");
|
||||
|
||||
assert.ok(
|
||||
exists(`.sidebar-section-link-${uncategorizedCategory.slug}`),
|
||||
`displays the section link for ${uncategorizedCategory.slug} category`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
conditionalTest(
|
||||
"category section links for tracked categories",
|
||||
!isLegacyEmber(),
|
||||
|
@ -263,4 +336,159 @@ acceptance("Sidebar - Categories Section", function (needs) {
|
|||
);
|
||||
}
|
||||
);
|
||||
|
||||
conditionalTest(
|
||||
"new and unread count for categories link",
|
||||
!isLegacyEmber(),
|
||||
async function (assert) {
|
||||
const { category1, category2 } = setupTrackedCategories();
|
||||
|
||||
this.container.lookup("topic-tracking-state:main").loadStates([
|
||||
{
|
||||
topic_id: 1,
|
||||
highest_post_number: 1,
|
||||
last_read_post_number: null,
|
||||
created_at: "2022-05-11T03:09:31.959Z",
|
||||
category_id: category1.id,
|
||||
notification_level: null,
|
||||
created_in_new_period: true,
|
||||
unread_not_too_old: true,
|
||||
treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z",
|
||||
},
|
||||
{
|
||||
topic_id: 2,
|
||||
highest_post_number: 12,
|
||||
last_read_post_number: 11,
|
||||
created_at: "2020-02-09T09:40:02.672Z",
|
||||
category_id: category1.id,
|
||||
notification_level: 2,
|
||||
created_in_new_period: false,
|
||||
unread_not_too_old: true,
|
||||
treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z",
|
||||
},
|
||||
{
|
||||
topic_id: 3,
|
||||
highest_post_number: 15,
|
||||
last_read_post_number: 14,
|
||||
created_at: "2021-06-14T12:41:02.477Z",
|
||||
category_id: category2.id,
|
||||
notification_level: 2,
|
||||
created_in_new_period: false,
|
||||
unread_not_too_old: true,
|
||||
treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z",
|
||||
},
|
||||
{
|
||||
topic_id: 4,
|
||||
highest_post_number: 17,
|
||||
last_read_post_number: 16,
|
||||
created_at: "2020-10-31T03:41:42.257Z",
|
||||
category_id: category2.id,
|
||||
notification_level: 2,
|
||||
created_in_new_period: false,
|
||||
unread_not_too_old: true,
|
||||
treat_as_new_topic_start_date: "2022-05-09T03:17:34.286Z",
|
||||
},
|
||||
]);
|
||||
|
||||
await visit("/");
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
`.sidebar-section-link-${category1.slug} .sidebar-section-link-content-badge`
|
||||
).textContent.trim(),
|
||||
I18n.t("sidebar.unread_count", { count: 1 }),
|
||||
`displays 1 unread count for ${category1.slug} section link`
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
`.sidebar-section-link-${category2.slug} .sidebar-section-link-content-badge`
|
||||
).textContent.trim(),
|
||||
I18n.t("sidebar.unread_count", { count: 2 }),
|
||||
`displays 2 unread count for ${category2.slug} section link`
|
||||
);
|
||||
|
||||
publishToMessageBus("/unread", {
|
||||
topic_id: 2,
|
||||
message_type: "read",
|
||||
payload: {
|
||||
last_read_post_number: 12,
|
||||
highest_post_number: 12,
|
||||
},
|
||||
});
|
||||
|
||||
await settled();
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
`.sidebar-section-link-${category1.slug} .sidebar-section-link-content-badge`
|
||||
).textContent.trim(),
|
||||
I18n.t("sidebar.new_count", { count: 1 }),
|
||||
`displays 1 new count for ${category1.slug} section link`
|
||||
);
|
||||
|
||||
publishToMessageBus("/unread", {
|
||||
topic_id: 1,
|
||||
message_type: "read",
|
||||
payload: {
|
||||
last_read_post_number: 1,
|
||||
highest_post_number: 1,
|
||||
},
|
||||
});
|
||||
|
||||
await settled();
|
||||
|
||||
assert.ok(
|
||||
!exists(
|
||||
`.sidebar-section-link-${category1.slug} .sidebar-section-link-content-badge`
|
||||
),
|
||||
`does not display any badge ${category1.slug} section link`
|
||||
);
|
||||
|
||||
publishToMessageBus("/unread", {
|
||||
topic_id: 3,
|
||||
message_type: "read",
|
||||
payload: {
|
||||
last_read_post_number: 15,
|
||||
highest_post_number: 15,
|
||||
},
|
||||
});
|
||||
|
||||
await settled();
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
`.sidebar-section-link-${category2.slug} .sidebar-section-link-content-badge`
|
||||
).textContent.trim(),
|
||||
I18n.t("sidebar.unread_count", { count: 1 }),
|
||||
`displays 1 unread count for ${category2.slug} section link`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
conditionalTest(
|
||||
"clean up topic tracking state state changed callbacks when section is destroyed",
|
||||
!isLegacyEmber(),
|
||||
async function (assert) {
|
||||
setupTrackedCategories();
|
||||
|
||||
await visit("/");
|
||||
|
||||
const topicTrackingState = this.container.lookup(
|
||||
"topic-tracking-state:main"
|
||||
);
|
||||
|
||||
const initialCallbackCount = Object.keys(
|
||||
topicTrackingState.stateChangeCallbacks
|
||||
).length;
|
||||
|
||||
await click(".header-sidebar-toggle .btn");
|
||||
await click(".header-sidebar-toggle .btn");
|
||||
|
||||
assert.strictEqual(
|
||||
Object.keys(topicTrackingState.stateChangeCallbacks).length,
|
||||
initialCallbackCount
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue