diff --git a/app/assets/javascripts/discourse/app/controllers/user-topics-list.js b/app/assets/javascripts/discourse/app/controllers/user-topics-list.js
index 195adb4fb00..6800f060d3c 100644
--- a/app/assets/javascripts/discourse/app/controllers/user-topics-list.js
+++ b/app/assets/javascripts/discourse/app/controllers/user-topics-list.js
@@ -19,6 +19,12 @@ export default Controller.extend(BulkTopicSelection, {
channel: null,
tagsForUser: null,
pmTopicTrackingState: null,
+ incomingCount: reads("pmTopicTrackingState.newIncoming.length"),
+
+ @discourseComputed("emptyState", "model.topics.length", "incomingCount")
+ showEmptyStatePlaceholder(emptyState, topicsLength, incomingCount) {
+ return emptyState && topicsLength === 0 && incomingCount === 0;
+ },
saveScrollPosition() {
this.session.set("topicListScrollPosition", $(window).scrollTop());
@@ -29,8 +35,6 @@ export default Controller.extend(BulkTopicSelection, {
this.set("application.showFooter", !this.get("model.canLoadMore"));
},
- incomingCount: reads("pmTopicTrackingState.newIncoming.length"),
-
@discourseComputed("filter", "model.topics.length")
showResetNew(filter, hasTopics) {
return filter === NEW_FILTER && hasTopics;
diff --git a/app/assets/javascripts/discourse/app/routes/build-private-messages-route.js b/app/assets/javascripts/discourse/app/routes/build-private-messages-route.js
index c2608d7606c..846408a7cc7 100644
--- a/app/assets/javascripts/discourse/app/routes/build-private-messages-route.js
+++ b/app/assets/javascripts/discourse/app/routes/build-private-messages-route.js
@@ -3,6 +3,8 @@ import UserAction from "discourse/models/user-action";
import UserTopicListRoute from "discourse/routes/user-topic-list";
import { findOrResetCachedTopicList } from "discourse/lib/cached-topic-list";
import { action } from "@ember/object";
+import { iconHTML } from "discourse-common/lib/icon-library";
+import getURL from "discourse-common/lib/get-url";
export const NEW_FILTER = "new";
export const UNREAD_FILTER = "unread";
@@ -61,6 +63,7 @@ export default (inboxType, path, filter) => {
inbox: inboxType,
pmTopicTrackingState:
userPrivateMessagesController.pmTopicTrackingState,
+ emptyState: this.emptyState(),
});
userTopicsListController.subscribe();
@@ -74,6 +77,15 @@ export default (inboxType, path, filter) => {
this.searchService.set("contextType", "private_messages");
},
+ emptyState() {
+ const title = I18n.t("user.no_messages_title");
+ const body = I18n.t("user.no_messages_body", {
+ aboutUrl: getURL("/about"),
+ icon: iconHTML("envelope"),
+ }).htmlSafe();
+ return { title, body };
+ },
+
deactivate() {
this.controllerFor("user-topics-list").unsubscribe();
diff --git a/app/assets/javascripts/discourse/app/templates/user-topics-list.hbs b/app/assets/javascripts/discourse/app/templates/user-topics-list.hbs
index 4e9d4d138e3..7096fec48c6 100644
--- a/app/assets/javascripts/discourse/app/templates/user-topics-list.hbs
+++ b/app/assets/javascripts/discourse/app/templates/user-topics-list.hbs
@@ -1,11 +1,19 @@
-{{#unless site.mobileView}}
- {{#if showToggleBulkSelect}}
- {{bulk-select-button canDoBulkActions=true selected=selected action=(route-action "refresh")}}
- {{/if}}
-{{/unless}}
+{{#if showEmptyStatePlaceholder}}
+
+
{{emptyState.title}}
+
+
+{{else}}
+ {{#unless site.mobileView}}
+ {{#if showToggleBulkSelect}}
+ {{bulk-select-button canDoBulkActions=true selected=selected action=(route-action "refresh")}}
+ {{/if}}
+ {{/unless}}
-{{#load-more class="paginated-topics-list" selector=".paginated-topics-list .topic-list tr" action=(action "loadMore")}}
- {{topic-dismiss-buttons
+ {{#load-more class="paginated-topics-list" selector=".paginated-topics-list .topic-list tr" action=(action "loadMore")}}
+ {{topic-dismiss-buttons
position="top"
selectedTopics=selected
model=model
@@ -13,27 +21,27 @@
showDismissRead=showDismissRead
resetNew=(action "resetNew")}}
- {{#if (gt incomingCount 0)}}
-
- {{/if}}
+ {{#if (gt incomingCount 0)}}
+
+ {{/if}}
- {{basic-topic-list topicList=model
- hideCategory=hideCategory
- showPosters=showPosters
- bulkSelectEnabled=bulkSelectEnabled
- selected=selected
- tagsForUser=tagsForUser
- onScroll=saveScrollPosition
- canBulkSelect=canBulkSelect
- scrollOnLoad=true
- toggleBulkSelect=(action "toggleBulkSelect")
- updateAutoAddTopicsToBulkSelect=(action "updateAutoAddTopicsToBulkSelect")}}
+ {{basic-topic-list topicList=model
+ hideCategory=hideCategory
+ showPosters=showPosters
+ bulkSelectEnabled=bulkSelectEnabled
+ selected=selected
+ tagsForUser=tagsForUser
+ onScroll=saveScrollPosition
+ canBulkSelect=canBulkSelect
+ scrollOnLoad=true
+ toggleBulkSelect=(action "toggleBulkSelect")
+ updateAutoAddTopicsToBulkSelect=(action "updateAutoAddTopicsToBulkSelect")}}
- {{topic-dismiss-buttons
+ {{topic-dismiss-buttons
position="bottom"
selectedTopics=selected
model=model
@@ -41,5 +49,6 @@
showDismissRead=showDismissRead
resetNew=(action "resetNew")}}
- {{conditional-loading-spinner condition=model.loadingMore}}
-{{/load-more}}
+ {{conditional-loading-spinner condition=model.loadingMore}}
+ {{/load-more}}
+{{/if}}
diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-private-messages-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-private-messages-test.js
index dac9e7d27be..d1891a8dead 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/user-private-messages-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/user-private-messages-test.js
@@ -546,3 +546,46 @@ acceptance(
});
}
);
+
+acceptance("User Private Messages - user with no messages", function (needs) {
+ needs.user();
+
+ needs.pretender((server, helper) => {
+ const emptyResponse = {
+ topic_list: {
+ topics: [],
+ },
+ };
+
+ const apiUrls = [
+ "/topics/private-messages-all/:username.json",
+ "/topics/private-messages-all-sent/:username.json",
+ "/topics/private-messages-all-new/:username.json",
+ "/topics/private-messages-all-unread/:username.json",
+ "/topics/private-messages-all-archive/:username.json",
+ ];
+
+ apiUrls.forEach((url) => {
+ server.get(url, () => {
+ return helper.response(emptyResponse);
+ });
+ });
+ });
+
+ test("It renders the empty state panel", async function (assert) {
+ await visit("/u/charlie/messages");
+ assert.ok(exists("div.empty-state"));
+
+ await visit("/u/charlie/messages/sent");
+ assert.ok(exists("div.empty-state"));
+
+ await visit("/u/charlie/messages/new");
+ assert.ok(exists("div.empty-state"));
+
+ await visit("/u/charlie/messages/unread");
+ assert.ok(exists("div.empty-state"));
+
+ await visit("/u/charlie/messages/archive");
+ assert.ok(exists("div.empty-state"));
+ });
+});