From 04fbb6d93d6217812dc1b594b65f237bcee692a7 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Thu, 17 Mar 2022 16:51:32 -0400
Subject: Show announcement dates

---
 .../announcement_editor/announcement_editor.vue    | 52 ++++++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 src/components/announcement_editor/announcement_editor.vue

(limited to 'src/components/announcement_editor/announcement_editor.vue')

diff --git a/src/components/announcement_editor/announcement_editor.vue b/src/components/announcement_editor/announcement_editor.vue
new file mode 100644
index 00000000..e2418b8d
--- /dev/null
+++ b/src/components/announcement_editor/announcement_editor.vue
@@ -0,0 +1,52 @@
+<template>
+  <div class="announcement-editor">
+    <textarea
+      ref="textarea"
+      v-model="announcement.content"
+      class="post-textarea"
+      rows="1"
+      cols="1"
+      :placeholder="$t('announcements.post_placeholder')"
+      :disabled="disabled"
+    />
+    <span class="announcement-metadata">
+      <label for="announcement-start-time">{{ $t('announcements.start_time_prompt') }}</label>
+      <input
+        id="announcement-start-time"
+        v-model="announcement.startsAt"
+        :type="announcement.allDay ? 'date' : 'datetime-local'"
+        :disabled="disabled"
+      >
+    </span>
+    <span class="announcement-metadata">
+      <label for="announcement-end-time">{{ $t('announcements.end_time_prompt') }}</label>
+      <input
+        id="announcement-end-time"
+        v-model="announcement.endsAt"
+        :type="announcement.allDay ? 'date' : 'datetime-local'"
+        :disabled="disabled"
+      >
+    </span>
+    <span class="announcement-metadata">
+      <Checkbox
+        id="announcement-all-day"
+        v-model="announcement.allDay"
+        :disabled="disabled"
+      />
+      <label for="announcement-all-day">{{ $t('announcements.all_day_prompt') }}</label>
+    </span>
+  </div>
+</template>
+
+<script src="./announcement_editor.js"></script>
+
+<style lang="scss">
+    .announcement-editor {
+      display: flex;
+      align-items: stretch;
+      flex-direction: column;
+      .announcement-metadata {
+        margin-top: 0.5em;
+      }
+    }
+</style>
-- 
cgit v1.2.3-70-g09d2


From 89c49b6fb46e607aee07afd5bc436e8f2f605bfe Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Thu, 17 Mar 2022 17:11:53 -0400
Subject: Allow editing announcements

---
 src/components/announcement/announcement.js        | 31 +++++++++++++-
 src/components/announcement/announcement.vue       | 50 +++++++++++++++++++++-
 .../announcement_editor/announcement_editor.vue    | 24 +++++++----
 .../announcements_page/announcements_page.vue      |  7 ---
 src/modules/announcements.js                       |  6 +++
 src/services/api/api.service.js                    | 23 ++++++++--
 6 files changed, 118 insertions(+), 23 deletions(-)

(limited to 'src/components/announcement_editor/announcement_editor.vue')

diff --git a/src/components/announcement/announcement.js b/src/components/announcement/announcement.js
index 309eecea..253e2bb2 100644
--- a/src/components/announcement/announcement.js
+++ b/src/components/announcement/announcement.js
@@ -12,8 +12,10 @@ const Announcement = {
       newAnnouncement: {
         content: '',
         startsAt: undefined,
-        endsAt: undefined
-      }
+        endsAt: undefined,
+        allDay: undefined
+      },
+      editError: ''
     }
   },
   props: {
@@ -58,6 +60,31 @@ const Announcement = {
     formatTimeOrDate (time, locale) {
       const d = new Date(time)
       return this.announcement['all_day'] ? d.toLocaleDateString(locale) : d.toLocaleString(locale)
+    },
+    enterEditMode () {
+      this.newAnnouncement.content = this.announcement.pleroma['raw_content']
+      this.newAnnouncement.startsAt = this.announcement['starts_at']
+      this.newAnnouncement.endsAt = this.announcement['ends_at']
+      this.newAnnouncement.allDay = this.announcement['all_day']
+      this.editing = true
+    },
+    submitEdit () {
+      this.$store.dispatch('editAnnouncement', {
+        id: this.announcement.id,
+        ...this.newAnnouncement
+      })
+        .then(() => {
+          this.editing = false
+        })
+        .catch(error => {
+          this.editError = error.error
+        })
+    },
+    cancelEdit () {
+      this.editing = false
+    },
+    clearError () {
+      this.editError = undefined
     }
   }
 }
diff --git a/src/components/announcement/announcement.vue b/src/components/announcement/announcement.vue
index 5ddeebf5..1e4edcca 100644
--- a/src/components/announcement/announcement.vue
+++ b/src/components/announcement/announcement.vue
@@ -16,7 +16,10 @@
       />
     </div>
     <div class="footer">
-      <div class="times">
+      <div
+        v-if="!editing"
+        class="times"
+      >
         <span v-if="startsAt">
           {{ $t('announcements.start_time_display', { time: startsAt }) }}
         </span>
@@ -24,7 +27,10 @@
           {{ $t('announcements.end_time_display', { time: endsAt }) }}
         </span>
       </div>
-      <div class="actions">
+      <div
+        v-if="!editing"
+        class="actions"
+      >
         <button
           v-if="currentUser"
           class="btn button-default"
@@ -33,6 +39,13 @@
         >
           {{ $t('announcements.mark_as_read_action') }}
         </button>
+        <button
+          v-if="currentUser && currentUser.role === 'admin'"
+          class="btn button-default"
+          @click="enterEditMode"
+        >
+          {{ $t('announcements.edit_action') }}
+        </button>
         <button
           v-if="currentUser && currentUser.role === 'admin'"
           class="btn button-default"
@@ -41,6 +54,39 @@
           {{ $t('announcements.delete_action') }}
         </button>
       </div>
+      <div
+        v-else
+        class="actions"
+      >
+        <button
+          class="btn button-default"
+          @click="submitEdit"
+        >
+          {{ $t('announcements.submit_edit_action') }}
+        </button>
+        <button
+          class="btn button-default"
+          @click="cancelEdit"
+        >
+          {{ $t('announcements.cancel_edit_action') }}
+        </button>
+        <div
+          v-if="editing && editError"
+          class="alert error"
+        >
+          {{ $t('announcements.edit_error', { error }) }}
+          <button
+            class="button-unstyled"
+            @click="clearError"
+          >
+            <FAIcon
+              class="fa-scale-110 fa-old-padding"
+              icon="times"
+              :title="$t('announcements.close_error')"
+            />
+          </button>
+        </div>
+      </div>
     </div>
   </div>
 </template>
diff --git a/src/components/announcement_editor/announcement_editor.vue b/src/components/announcement_editor/announcement_editor.vue
index e2418b8d..0f29f9f7 100644
--- a/src/components/announcement_editor/announcement_editor.vue
+++ b/src/components/announcement_editor/announcement_editor.vue
@@ -41,12 +41,20 @@
 <script src="./announcement_editor.js"></script>
 
 <style lang="scss">
-    .announcement-editor {
-      display: flex;
-      align-items: stretch;
-      flex-direction: column;
-      .announcement-metadata {
-        margin-top: 0.5em;
-      }
-    }
+.announcement-editor {
+  display: flex;
+  align-items: stretch;
+  flex-direction: column;
+
+  .announcement-metadata {
+    margin-top: 0.5em;
+  }
+
+  .post-textarea {
+    resize: vertical;
+    height: 10em;
+    overflow: none;
+    box-sizing: content-box;
+  }
+}
 </style>
diff --git a/src/components/announcements_page/announcements_page.vue b/src/components/announcements_page/announcements_page.vue
index 54307c4d..b1489dec 100644
--- a/src/components/announcements_page/announcements_page.vue
+++ b/src/components/announcements_page/announcements_page.vue
@@ -71,13 +71,6 @@
       margin-bottom: var(--status-margin, $status-margin);
     }
 
-    .post-textarea {
-      resize: vertical;
-      height: 10em;
-      overflow: none;
-      box-sizing: content-box;
-    }
-
     .post-button {
       min-width: 10em;
     }
diff --git a/src/modules/announcements.js b/src/modules/announcements.js
index a42acf93..1d97c67c 100644
--- a/src/modules/announcements.js
+++ b/src/modules/announcements.js
@@ -65,6 +65,12 @@ const announcements = {
           return store.dispatch('fetchAnnouncements')
         })
     },
+    editAnnouncement (store, { id, content, startsAt, endsAt, allDay }) {
+      return store.rootState.api.backendInteractor.editAnnouncement({ id, content, startsAt, endsAt, allDay })
+        .then(() => {
+          return store.dispatch('fetchAnnouncements')
+        })
+    },
     deleteAnnouncement (store, id) {
       return store.rootState.api.backendInteractor.deleteAnnouncement({ id })
         .then(() => {
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index c2bfe8cc..0d4c674a 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -104,6 +104,7 @@ const PLEROMA_ADMIN_REPORTS = '/api/pleroma/admin/reports'
 const PLEROMA_BACKUP_URL = '/api/v1/pleroma/backups'
 const PLEROMA_ANNOUNCEMENTS_URL = '/api/v1/pleroma/admin/announcements'
 const PLEROMA_POST_ANNOUNCEMENT_URL = '/api/v1/pleroma/admin/announcements'
+const PLEROMA_EDIT_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
 const PLEROMA_DELETE_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
 
 const oldfetch = window.fetch
@@ -1382,26 +1383,39 @@ const dismissAnnouncement = ({ id, credentials }) => {
   })
 }
 
-const postAnnouncement = ({ credentials, content, startsAt, endsAt, allDay }) => {
+const announcementToPayload = ({ content, startsAt, endsAt, allDay }) => {
   const payload = { content }
 
   if (typeof startsAt !== 'undefined') {
-    payload['starts_at'] = new Date(startsAt).toISOString()
+    payload['starts_at'] = startsAt ? new Date(startsAt).toISOString() : null
   }
 
   if (typeof endsAt !== 'undefined') {
-    payload['ends_at'] = new Date(endsAt).toISOString()
+    payload['ends_at'] = endsAt ? new Date(endsAt).toISOString() : null
   }
 
   if (typeof allDay !== 'undefined') {
     payload['all_day'] = allDay
   }
 
+  return payload
+}
+
+const postAnnouncement = ({ credentials, content, startsAt, endsAt, allDay }) => {
   return promisedRequest({
     url: PLEROMA_POST_ANNOUNCEMENT_URL,
     credentials,
     method: 'POST',
-    payload
+    payload: announcementToPayload({ content, startsAt, endsAt, allDay })
+  })
+}
+
+const editAnnouncement = ({ id, credentials, content, startsAt, endsAt, allDay }) => {
+  return promisedRequest({
+    url: PLEROMA_EDIT_ANNOUNCEMENT_URL(id),
+    credentials,
+    method: 'PATCH',
+    payload: announcementToPayload({ content, startsAt, endsAt, allDay })
   })
 }
 
@@ -1743,6 +1757,7 @@ const apiService = {
   fetchAnnouncements,
   dismissAnnouncement,
   postAnnouncement,
+  editAnnouncement,
   deleteAnnouncement,
   adminFetchAnnouncements
 }
-- 
cgit v1.2.3-70-g09d2

