diff --git a/about.json b/about.json index 8e13740..fe00ca6 100644 --- a/about.json +++ b/about.json @@ -8,5 +8,8 @@ }, "color_schemes": { }, - "component": true + "component": true, + "modifiers": { + "svg_icons": ["id-card", "th-list"] + } } diff --git a/javascripts/discourse/components/user-card-directory-toggle.js b/javascripts/discourse/components/user-card-directory-toggle.js new file mode 100644 index 0000000..ed94faf --- /dev/null +++ b/javascripts/discourse/components/user-card-directory-toggle.js @@ -0,0 +1,20 @@ +import Component from "@ember/component"; +import { inject as service } from "@ember/service"; +import discourseComputed from "discourse-common/utils/decorators"; + +export default Component.extend({ + router: service("router"), + tagName: "", + + @discourseComputed("router.currentRoute.queryParams.cards") + showingCards(cardsParam) { + return cardsParam === "yes"; + }, + + actions: { + toggleCards() { + const newValue = this.showingCards ? "no" : "yes"; + this.router.transitionTo({ queryParams: { cards: newValue } }); + }, + }, +}); diff --git a/javascripts/discourse/initializers/user-card-directory.js.es6 b/javascripts/discourse/initializers/user-card-directory.js.es6 index 6100e42..bf37e2d 100644 --- a/javascripts/discourse/initializers/user-card-directory.js.es6 +++ b/javascripts/discourse/initializers/user-card-directory.js.es6 @@ -7,18 +7,44 @@ import { ajax } from "discourse/lib/ajax"; export default { name: "user-card-directory", initialize(container) { - // This component provides a responsive template - // Delete the core mobile one - delete Ember.TEMPLATES["mobile/users"]; - - withPluginApi("0.8.7", api => { + withPluginApi("0.8.7", (api) => { api.modifyClass("route:users", { resetController(controller, isExiting) { this._super(...arguments); if (isExiting) { controller.set("cachedUserCardInfo", {}); } - } + }, + }); + + api.modifyClass("route:users", { + queryParams: { + cards: { refreshModel: true }, + }, + + beforeModel(transition) { + this._super(transition); + if ( + settings.default_view === "cards" && + !transition.to.queryParams.cards + ) { + this.transitionTo({ queryParams: { cards: "yes" } }); + } + }, + + model(params) { + return this._super(params).then((model) => { + model.showAsCards = params["cards"] === "yes"; + return model; + }); + }, + + renderTemplate(controller, model) { + if (model.showAsCards) { + return this.render("users-as-card-directory"); + } + return this._super(); + }, }); api.modifyClass("controller:users", { diff --git a/javascripts/discourse/templates/components/user-card-directory-toggle.hbs b/javascripts/discourse/templates/components/user-card-directory-toggle.hbs new file mode 100644 index 0000000..057f6a8 --- /dev/null +++ b/javascripts/discourse/templates/components/user-card-directory-toggle.hbs @@ -0,0 +1,6 @@ +{{d-button + icon=(if showingCards "th-list" "id-card") + action=(action "toggleCards") + title=(theme-prefix (if showingCards "show_table" "show_cards")) + class="btn-default open-edit-columns-btn toggle-cards-button" +}} diff --git a/javascripts/discourse/templates/connectors/users-directory-controls/user-card-directory-toggle.hbs b/javascripts/discourse/templates/connectors/users-directory-controls/user-card-directory-toggle.hbs new file mode 100644 index 0000000..1e24d4b --- /dev/null +++ b/javascripts/discourse/templates/connectors/users-directory-controls/user-card-directory-toggle.hbs @@ -0,0 +1 @@ +{{user-card-directory-toggle}} diff --git a/javascripts/discourse/templates/users.hbs b/javascripts/discourse/templates/users-as-card-directory.hbs similarity index 96% rename from javascripts/discourse/templates/users.hbs rename to javascripts/discourse/templates/users-as-card-directory.hbs index 3ba2129..8f02367 100644 --- a/javascripts/discourse/templates/users.hbs +++ b/javascripts/discourse/templates/users-as-card-directory.hbs @@ -41,6 +41,7 @@ class="btn-default open-edit-columns-btn" }} {{/if}} + {{plugin-outlet name="users-directory-controls" connectorTagName="" tagName="" args=(hash model=model)}} diff --git a/locales/en.yml b/locales/en.yml index 2bdb2ee..2c1574c 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -4,4 +4,5 @@ en: settings: hide_current_user: Always hide the current user from the grid show_stats: Show statistics under each user card - filter_by_group: filter by group + show_cards: Show as cards + show_table: Show as table diff --git a/settings.yml b/settings.yml index 7fb3489..886411b 100644 --- a/settings.yml +++ b/settings.yml @@ -1,2 +1,8 @@ hide_current_user: false show_stats: true +default_view: + type: enum + default: "cards" + choices: + - "cards" + - "table" diff --git a/test/acceptance/users-test.js b/test/acceptance/users-test.js new file mode 100644 index 0000000..3f2b306 --- /dev/null +++ b/test/acceptance/users-test.js @@ -0,0 +1,156 @@ +import { + acceptance, + exists, + count, +} from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; +import { click, visit } from "@ember/test-helpers"; + +acceptance("User Card Directory", function (needs) { + needs.pretender((server, helper) => { + server.get("/directory_items", () => { + return helper.response({ + directory_items: [ + { + id: 1, + likes_received: 0, + likes_given: 0, + topics_entered: 0, + topic_count: 0, + post_count: 0, + posts_read: 0, + days_visited: 1, + user: { + id: 1, + username: "foo", + name: "Foo", + avatar_template: + "/letter_avatar_proxy/v4/letter/f/3be4f8/{size}.png", + }, + }, + { + id: 2, + likes_received: 0, + likes_given: 0, + topics_entered: 0, + topic_count: 0, + post_count: 0, + posts_read: 0, + days_visited: 1, + user: { + id: 2, + username: "bar", + name: "Bar", + avatar_template: + "/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png", + }, + }, + ], + meta: { + last_updated_at: "2020-01-01T12:00:00.000Z", + total_rows_directory_items: 2, + load_more_directory_items: + "/directory_items?order=likes_received&page=1&period=weekly", + }, + }); + }); + + server.get("/user-cards.json", () => { + return helper.response({ + user_badges: [], + badges: [], + badge_types: [], + users: [ + { + id: 1, + username: "foo", + name: "Foo", + avatar_template: + "/letter_avatar_proxy/v4/letter/m/9fc348/{size}.png", + last_posted_at: null, + last_seen_at: "2018-11-26T11:49:48.721Z", + created_at: "2018-09-20T11:14:39.341Z", + ignored: false, + muted: false, + can_ignore_user: true, + can_mute_user: true, + can_send_private_messages: true, + can_send_private_message_to_user: true, + trust_level: 1, + moderator: false, + admin: false, + title: null, + badge_count: 1, + user_fields: {}, + custom_fields: {}, + time_read: 0, + recent_time_read: 0, + primary_group_id: null, + primary_group_name: null, + primary_group_flair_url: null, + primary_group_flair_bg_color: null, + primary_group_flair_color: null, + featured_topic: null, + staged: false, + date_of_birth: null, + featured_user_badge_ids: [], + }, + { + id: 2, + username: "bar", + name: "Bar", + avatar_template: + "/letter_avatar_proxy/v4/letter/m/9fc348/{size}.png", + last_posted_at: null, + last_seen_at: "2018-11-26T11:49:48.721Z", + created_at: "2018-09-20T11:14:39.341Z", + ignored: false, + muted: false, + can_ignore_user: true, + can_mute_user: true, + can_send_private_messages: true, + can_send_private_message_to_user: true, + trust_level: 1, + moderator: false, + admin: false, + title: null, + badge_count: 1, + user_fields: {}, + custom_fields: {}, + time_read: 0, + recent_time_read: 0, + primary_group_id: null, + primary_group_name: null, + primary_group_flair_url: null, + primary_group_flair_bg_color: null, + primary_group_flair_color: null, + featured_topic: null, + staged: false, + date_of_birth: null, + featured_user_badge_ids: [], + }, + ], + }); + }); + }); + + test("Displays table when cards=no", async function (assert) { + await visit("/u?cards=no"); + assert.ok($("body.users-page").length, "has the body class"); + assert.equal(count(".directory table tr"), 2, "has a list of users"); + }); + + test("Displays cards when cards=yes", async function (assert) { + await visit("/u?cards=yes"); + assert.equal(count(".user-card-avatar"), 2, "has two cards showing"); + }); + + test("Can toggle between views", async function (assert) { + await visit("/u?cards=no"); + assert.equal(count(".directory table tr"), 2, "has two table rows"); + await click(".toggle-cards-button"); + assert.equal(count(".user-card-avatar"), 2, "has two cards"); + await click(".toggle-cards-button"); + assert.equal(count(".directory table tr"), 2, "has two table rows"); + }); +});