diff --git a/app/assets/javascripts/discourse/app/components/user-card-contents.js b/app/assets/javascripts/discourse/app/components/user-card-contents.js index d755eaf5d12..51d653ddcdb 100644 --- a/app/assets/javascripts/discourse/app/components/user-card-contents.js +++ b/app/assets/javascripts/discourse/app/components/user-card-contents.js @@ -14,6 +14,7 @@ import { isEmpty } from "@ember/utils"; import { prioritizeNameInUx } from "discourse/lib/settings"; import { dasherize } from "@ember/string"; import { emojiUnescape } from "discourse/lib/text"; +import { escapeExpression } from "discourse/lib/utilities"; export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, { elementId: "user-card", @@ -55,10 +56,9 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, { return this.siteSettings.enable_user_status && this.user.status; }, - @discourseComputed("user.status") - userStatusEmoji() { - const emoji = this.user.status.emoji ?? "mega"; - return emojiUnescape(`:${emoji}:`); + @discourseComputed("user.status.emoji") + userStatusEmoji(emoji) { + return emojiUnescape(escapeExpression(`:${emoji}:`)); }, isSuspendedOrHasBio: or("user.suspend_reason", "user.bio_excerpt"), diff --git a/app/assets/javascripts/discourse/app/components/user-status-picker.js b/app/assets/javascripts/discourse/app/components/user-status-picker.js new file mode 100644 index 00000000000..691a4e683c3 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/user-status-picker.js @@ -0,0 +1,57 @@ +import Component from "@ember/component"; +import { action, computed } from "@ember/object"; +import { scheduleOnce } from "@ember/runloop"; +import { emojiUnescape } from "discourse/lib/text"; +import { escapeExpression } from "discourse/lib/utilities"; + +export default class UserStatusPicker extends Component { + tagName = ""; + isFocused = false; + emojiPickerIsActive = false; + emoji = null; + description = null; + + @computed("emoji") + get emojiHtml() { + const emoji = escapeExpression(`:${this.emoji}:`); + return emojiUnescape(emoji); + } + + @action + blur() { + this.set("isFocused", false); + } + + @action + emojiSelected(emoji) { + this.set("emoji", emoji); + this.set("emojiPickerIsActive", false); + + scheduleOnce("afterRender", () => { + document.querySelector(".btn-emoji")?.focus(); + }); + } + + @action + focus() { + this.set("isFocused", true); + } + + @action + onEmojiPickerOutsideClick() { + this.set("emojiPickerIsActive", false); + } + + @action + setDefaultEmoji() { + if (!this.emoji) { + this.set("emoji", "speech_balloon"); + } + } + + @action + toggleEmojiPicker(event) { + event.stopPropagation(); + this.set("emojiPickerIsActive", !this.emojiPickerIsActive); + } +} diff --git a/app/assets/javascripts/discourse/app/controllers/user-status.js b/app/assets/javascripts/discourse/app/controllers/user-status.js index b43309e9d13..20f025d379d 100644 --- a/app/assets/javascripts/discourse/app/controllers/user-status.js +++ b/app/assets/javascripts/discourse/app/controllers/user-status.js @@ -1,49 +1,49 @@ import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { action } from "@ember/object"; -import { notEmpty } from "@ember/object/computed"; import { inject as service } from "@ember/service"; import { popupAjaxError } from "discourse/lib/ajax-error"; import bootbox from "bootbox"; +import discourseComputed from "discourse-common/utils/decorators"; export default Controller.extend(ModalFunctionality, { userStatusService: service("user-status"), + emoji: null, description: null, - statusIsSet: notEmpty("description"), showDeleteButton: false, onShow() { - if (this.currentUser.status) { - this.setProperties({ - description: this.currentUser.status.description, - showDeleteButton: true, - }); - } + const status = this.currentUser.status; + this.setProperties({ + emoji: status?.emoji, + description: status?.description, + showDeleteButton: !!status, + }); + }, + + @discourseComputed("emoji", "description") + statusIsSet(emoji, description) { + return !!emoji && !!description; }, @action delete() { this.userStatusService .clear() - .then(() => { - this._resetModal(); - this.send("closeModal"); - }) + .then(() => this.send("closeModal")) .catch((e) => this._handleError(e)); }, @action saveAndClose() { - if (this.description) { - const status = { description: this.description }; - this.userStatusService - .set(status) - .then(() => { - this.send("closeModal"); - }) - .catch((e) => this._handleError(e)); - } + const status = { description: this.description, emoji: this.emoji }; + this.userStatusService + .set(status) + .then(() => { + this.send("closeModal"); + }) + .catch((e) => this._handleError(e)); }, _handleError(e) { @@ -53,9 +53,4 @@ export default Controller.extend(ModalFunctionality, { popupAjaxError(e); } }, - - _resetModal() { - this.set("description", null); - this.set("showDeleteButton", false); - }, }); diff --git a/app/assets/javascripts/discourse/app/services/user-status.js b/app/assets/javascripts/discourse/app/services/user-status.js index b152a556984..0b6835f15ee 100644 --- a/app/assets/javascripts/discourse/app/services/user-status.js +++ b/app/assets/javascripts/discourse/app/services/user-status.js @@ -8,7 +8,7 @@ export default class UserStatusService extends Service { await ajax({ url: "/user-status.json", type: "PUT", - data: { description: status.description }, + data: status, }); this.currentUser.set("status", status); diff --git a/app/assets/javascripts/discourse/app/templates/components/user-status-picker.hbs b/app/assets/javascripts/discourse/app/templates/components/user-status-picker.hbs new file mode 100644 index 00000000000..046feaf844a --- /dev/null +++ b/app/assets/javascripts/discourse/app/templates/components/user-status-picker.hbs @@ -0,0 +1,30 @@ +
+
+ + +
+
+{{emoji-picker + isActive=this.emojiPickerIsActive + emojiSelected=(action "emojiSelected") + onEmojiPickerClose=(action "onEmojiPickerOutsideClick") + placement="bottom" +}} diff --git a/app/assets/javascripts/discourse/app/templates/modal/user-status.hbs b/app/assets/javascripts/discourse/app/templates/modal/user-status.hbs index 8cbd63f50bf..4a3f263d19d 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/user-status.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/user-status.hbs @@ -1,10 +1,7 @@ {{#d-modal-body}} {{#conditional-loading-spinner condition=loading}} -
- {{input - class="user-status-description" - placeholder=(i18n "user_status.what_are_you_doing") - value=description}} +
+ {{user-status-picker emoji=emoji description=description}}