FEATURE: Let staff add custom post notices. (#7377)

FEATURE: Let staff add custom post notices. (#7377)

diff --git a/app/assets/javascripts/discourse/controllers/add-post-notice.js.es6 b/app/assets/javascripts/discourse/controllers/add-post-notice.js.es6
new file mode 100644
index 0000000..971a71a
--- /dev/null
+++ b/app/assets/javascripts/discourse/controllers/add-post-notice.js.es6
@@ -0,0 +1,59 @@
+import ModalFunctionality from "discourse/mixins/modal-functionality";
+import computed from "ember-addons/ember-computed-decorators";
+
+export default Ember.Controller.extend(ModalFunctionality, {
+  post: null,
+  resolve: null,
+  reject: null,
+
+  notice: null,
+  saving: false,
+
+  @computed("saving", "notice")
+  disabled(saving, notice) {
+    return saving || Ember.isEmpty(notice);
+  },
+
+  onShow() {
+    this.setProperties({
+      notice: "",
+      saving: false
+    });
+  },
+
+  onClose() {
+    const reject = this.get("reject");
+    if (reject) {
+      reject();
+    }
+  },
+
+  actions: {
+    setNotice() {
+      this.set("saving", true);
+
+      const post = this.get("post");
+      const resolve = this.get("resolve");
+      const reject = this.get("reject");
+      const notice = this.get("notice");
+
+      // Let `updatePostField` handle state.
+      this.setProperties({ resolve: null, reject: null });
+
+      post
+        .updatePostField("notice", notice)
+        .then(() => {
+          post.setProperties({
+            notice_type: "custom",
+            notice_args: notice
+          });
+          resolve();
+          this.send("closeModal");
+        })
+        .catch(() => {
+          reject();
+          this.send("closeModal");
+        });
+    }
+  }
+});
diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6
index 7c0ba8b..61b9a52 100644
--- a/app/assets/javascripts/discourse/controllers/topic.js.es6
+++ b/app/assets/javascripts/discourse/controllers/topic.js.es6
@@ -750,6 +750,22 @@ export default Ember.Controller.extend(bufferedProperty("model"), {
       this.send("showGrantBadgeModal");
     },
 
+    addNotice(post) {
+      return new Ember.RSVP.Promise(function(resolve, reject) {
+        const controller = showModal("add-post-notice");
+        controller.setProperties({ post, resolve, reject });
+      });
+    },
+
+    removeNotice(post) {
+      return post.updatePostField("notice", null).then(() =>
+        post.setProperties({
+          notice_type: null,
+          notice_args: null
+        })
+      );
+    },
+
     toggleParticipant(user) {
       this.get("model.postStream")
         .toggleParticipant(user.get("username"))
diff --git a/app/assets/javascripts/discourse/lib/transform-post.js.es6 b/app/assets/javascripts/discourse/lib/transform-post.js.es6
index 7579e30..43aa804 100644
--- a/app/assets/javascripts/discourse/lib/transform-post.js.es6
+++ b/app/assets/javascripts/discourse/lib/transform-post.js.es6
@@ -133,10 +133,12 @@ export default function transformPost(
   postAtts.topicUrl = topic.get("url");
   postAtts.isSaving = post.isSaving;
 
-  if (post.post_notice_type) {
-    postAtts.postNoticeType = post.post_notice_type;
-    if (postAtts.postNoticeType === "returning") {
-      postAtts.postNoticeTime = new Date(post.post_notice_time);
+  if (post.notice_type) {
+    postAtts.noticeType = post.notice_type;
+    if (postAtts.noticeType === "custom") {
+      postAtts.noticeMessage = post.notice_args;
+    } else if (postAtts.noticeType === "returning_user") {
+      postAtts.noticeTime = new Date(post.notice_args);
     }
   }
 
diff --git a/app/assets/javascripts/discourse/templates/modal/add-post-notice.hbs b/app/assets/javascripts/discourse/templates/modal/add-post-notice.hbs
new file mode 100644
index 0000000..244287d
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/modal/add-post-notice.hbs
@@ -0,0 +1,12 @@
+{{#d-modal-body title="post.controls.add_post_notice"}}
+  <form>{{textarea value=notice}}</form>
+{{/d-modal-body}}
+
+<div class="modal-footer">
+  {{d-button
+    class="btn-primary"
+    action=(action "setNotice")
+    disabled=disabled
+    label=(if saving "saving" "save")}}
+  {{d-modal-cancel close=(route-action "closeModal")}}
+</div>
diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs
index ae8c8e58..1a4f1e0 100644
--- a/app/assets/javascripts/discourse/templates/topic.hbs
+++ b/app/assets/javascripts/discourse/templates/topic.hbs
@@ -184,6 +184,8 @@
                 rebakePost=(action "rebakePost")
                 changePostOwner=(action "changePostOwner")
                 grantBadge=(action "grantBadge")
+                addNotice=(action "addNotice")
+                removeNotice=(action "removeNotice")
                 lockPost=(action "lockPost")
                 unlockPost=(action "unlockPost")
                 unhidePost=(action "unhidePost")
diff --git a/app/assets/javascripts/discourse/widgets/post-admin-menu.js.es6 b/app/assets/javascripts/discourse/widgets/post-admin-menu.js.es6
index 718730e..2cb9388 100644
--- a/app/assets/javascripts/discourse/widgets/post-admin-menu.js.es6
+++ b/app/assets/javascripts/discourse/widgets/post-admin-menu.js.es6
@@ -74,14 +74,23 @@ export function buildManageButtons(attrs, currentUser, siteSettings) {
       });
     }
 
-    const action = attrs.locked ? "unlock" : "lock";
-    contents.push({
-      icon: action,
-      label: `post.controls.${action}_post`,
-      action: `${action}Post`,
-      title: `post.controls.${action}_post_description`,
-      className: `btn-default ${action}-post`
-    });
+    if (attrs.locked) {
+      contents.push({
+        icon: "unlock",
+        label: "post.controls.unlock_post",
+        action: "unlockPost",
+        title: "post.controls.unlock_post_description",
+        className: "btn-default unlock-post"
+      });
+    } else {
+      contents.push({
+        icon: "lock",
+        label: "post.controls.lock_post",
+        action: "lockPost",
+        title: "post.controls.lock_post_description",
+        className: "btn-default lock-post"
+      });
+    }
   }
 
   if (attrs.canManage || attrs.canWiki) {
@@ -102,6 +111,24 @@ export function buildManageButtons(attrs, currentUser, siteSettings) {
     }
   }
 
+  if (currentUser.staff) {
+    if (attrs.noticeType) {
+      contents.push({
+        icon: "asterisk",
+        label: "post.controls.remove_post_notice",
+        action: "removeNotice",
+        className: "btn-default remove-notice"
+      });
+    } else {
+      contents.push({
+        icon: "asterisk",
+        label: "post.controls.add_post_notice",
+        action: "addNotice",
+        className: "btn-default add-notice"
+      });
+    }
+  }
+
   return contents;
 }
 
diff --git a/app/assets/javascripts/discourse/widgets/post.js.es6 b/app/assets/javascripts/discourse/widgets/post.js.es6
index 94c921c..65f17c1 100644
--- a/app/assets/javascripts/discourse/widgets/post.js.es6
+++ b/app/assets/javascripts/discourse/widgets/post.js.es6
@@ -434,13 +434,7 @@ createWidget("post-notice", {
   tagName: "div.post-notice",
 
   buildClasses(attrs) {
-    const classes = [];
-
-    if (attrs.postNoticeType === "first") {
-      classes.push("new-user");
-    } else if (attrs.postNoticeType === "returning") {
-      classes.push("returning-user");
-    }
+    const classes = [attrs.noticeType.replace(/_/g, "-")];
 
     if (
       new Date() - new Date(attrs.created_at) >
@@ -458,13 +452,16 @@ createWidget("post-notice", {
         ? attrs.username
         : attrs.name;
     let text, icon;
-    if (attrs.postNoticeType === "first") {
+    if (attrs.noticeType === "custom") {
+      icon = "asterisk";
+      text = attrs.noticeMessage;
+    } else if (attrs.noticeType === "new_user") {
       icon = "hands-helping";
-      text = I18n.t("post.notice.first", { user });
-    } else if (attrs.postNoticeType === "returning") {
+      text = I18n.t("post.notice.new_user", { user });

[... diff too long, it was truncated ...]

GitHub sha: 57d1dea8

2 Likes