From e067783a30be41644abe1aecca631ef31cf476a8 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Thu, 17 Mar 2022 12:59:10 -0400
Subject: Add announcement display with placeholder messages

---
 src/components/side_drawer/side_drawer.vue | 13 +++++++++++++
 1 file changed, 13 insertions(+)

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

diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index cbeafdd2..dccb8ab7 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -191,6 +191,19 @@
             /> {{ $t("nav.administration") }}
           </a>
         </li>
+        <li
+          @click="toggleDrawer"
+        >
+          <router-link
+            :to="{ name: 'announcements' }"
+          >
+            <FAIcon
+              fixed-width
+              class="fa-scale-110 fa-old-padding"
+              icon="bullhorn"
+            /> {{ $t("nav.announcements") }}
+          </router-link>
+        </li>
         <li
           v-if="currentUser"
           @click="toggleDrawer"
-- 
cgit v1.2.3-70-g09d2


From b4a7e58bec86205e23adda2b0625d237acd5aa91 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Thu, 17 Mar 2022 17:51:39 -0400
Subject: Show badges for unread announcements

---
 src/components/mobile_nav/mobile_nav.js       | 2 +-
 src/components/mobile_nav/mobile_nav.vue      | 2 +-
 src/components/nav_panel/nav_panel.js         | 2 +-
 src/components/navigation/navigation.js       | 3 ++-
 src/components/notifications/notifications.js | 4 ++--
 src/components/side_drawer/side_drawer.js     | 2 +-
 src/components/side_drawer/side_drawer.vue    | 6 ++++++
 src/modules/announcements.js                  | 9 +++++++++
 8 files changed, 23 insertions(+), 7 deletions(-)

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

diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js
index fb8ffa30..cdbbb812 100644
--- a/src/components/mobile_nav/mobile_nav.js
+++ b/src/components/mobile_nav/mobile_nav.js
@@ -54,7 +54,7 @@ const MobileNav = {
     isChat () {
       return this.$route.name === 'chat'
     },
-    ...mapGetters(['unreadChatCount']),
+    ...mapGetters(['unreadChatCount', 'unreadAnnouncementCount']),
     chatsPinned () {
       return new Set(this.$store.state.serverSideStorage.prefsStorage.collections.pinnedNavItems).has('chats')
     }
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index d642008b..0f1fe621 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -19,7 +19,7 @@
             icon="bars"
           />
           <div
-            v-if="unreadChatCount && !chatsPinned"
+            v-if="(unreadChatCount && !chatsPinned) || unreadAnnouncementCount"
             class="alert-dot"
           />
         </button>
diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js
index 66c8a4cd..438615da 100644
--- a/src/components/nav_panel/nav_panel.js
+++ b/src/components/nav_panel/nav_panel.js
@@ -117,7 +117,7 @@ const NavPanel = {
         }
       )
     },
-    ...mapGetters(['unreadChatCount'])
+    ...mapGetters(['unreadChatCount', 'unreadAnnouncementCount'])
   }
 }
 
diff --git a/src/components/navigation/navigation.js b/src/components/navigation/navigation.js
index 4541e60b..40100f97 100644
--- a/src/components/navigation/navigation.js
+++ b/src/components/navigation/navigation.js
@@ -75,6 +75,7 @@ export const ROOT_ITEMS = {
   announcements: {
     route: 'announcements',
     icon: 'bullhorn',
-    label: 'nav.announcements'
+    label: 'nav.announcements',
+    badgeGetter: 'unreadAnnouncementCount'
   }
 }
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index c3acd9e0..dde9c93e 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -69,7 +69,7 @@ const Notifications = {
       return this.unseenNotifications.length
     },
     unseenCountTitle () {
-      return this.unseenCount + (this.unreadChatCount)
+      return this.unseenCount + (this.unreadChatCount) + this.unreadAnnouncementCount
     },
     loading () {
       return this.$store.state.statuses.notifications.loading
@@ -94,7 +94,7 @@ const Notifications = {
       return this.filteredNotifications.slice(0, this.unseenCount + this.seenToDisplayCount)
     },
     noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders },
-    ...mapGetters(['unreadChatCount'])
+    ...mapGetters(['unreadChatCount', 'unreadAnnouncementCount'])
   },
   mounted () {
     this.scrollerRef = this.$refs.root.closest('.column.-scrollable')
diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js
index bb22446b..680216dd 100644
--- a/src/components/side_drawer/side_drawer.js
+++ b/src/components/side_drawer/side_drawer.js
@@ -97,7 +97,7 @@ const SideDrawer = {
     ...mapState({
       pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable
     }),
-    ...mapGetters(['unreadChatCount'])
+    ...mapGetters(['unreadChatCount', 'unreadAnnouncementCount'])
   },
   methods: {
     toggleDrawer () {
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index dccb8ab7..4101cb03 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -202,6 +202,12 @@
               class="fa-scale-110 fa-old-padding"
               icon="bullhorn"
             /> {{ $t("nav.announcements") }}
+            <span
+              v-if="unreadAnnouncementCount"
+              class="badge badge-notification"
+            >
+              {{ unreadAnnouncementCount }}
+            </span>
           </router-link>
         </li>
         <li
diff --git a/src/modules/announcements.js b/src/modules/announcements.js
index 8470fb2a..f04ba50e 100644
--- a/src/modules/announcements.js
+++ b/src/modules/announcements.js
@@ -25,9 +25,18 @@ export const mutations = {
   }
 }
 
+export const getters = {
+  unreadAnnouncementCount (state) {
+    return state.announcements.reduce((acc, cur) => {
+      return (!cur.inactive && !cur.read) ? acc + 1 : acc
+    }, 0)
+  }
+}
+
 const announcements = {
   state: defaultState,
   mutations,
+  getters,
   actions: {
     fetchAnnouncements (store) {
       const currentUser = store.rootState.users.currentUser
-- 
cgit v1.2.3-70-g09d2


From d74d5a8ce29311bc4b5c79527558f84c59965932 Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Thu, 24 Nov 2022 18:39:42 -0500
Subject: Detect backend support for announcements

---
 src/components/nav_panel/nav_panel.js      |  2 ++
 src/components/navigation/filter.js        |  3 ++-
 src/components/navigation/navigation.js    |  3 ++-
 src/components/side_drawer/side_drawer.js  |  3 ++-
 src/components/side_drawer/side_drawer.vue |  1 +
 src/modules/announcements.js               | 17 +++++++++++++++++
 6 files changed, 26 insertions(+), 3 deletions(-)

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

diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js
index 438615da..28fafed8 100644
--- a/src/components/nav_panel/nav_panel.js
+++ b/src/components/nav_panel/nav_panel.js
@@ -88,6 +88,7 @@ const NavPanel = {
       privateMode: state => state.instance.private,
       federating: state => state.instance.federating,
       pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable,
+      supportsAnnouncements: state => state.announcements.supportsAnnouncements,
       pinnedItems: state => new Set(state.serverSideStorage.prefsStorage.collections.pinnedNavItems),
       collapsed: state => state.serverSideStorage.prefsStorage.simple.collapseNav
     }),
@@ -98,6 +99,7 @@ const NavPanel = {
           .map(([k, v]) => ({ ...v, name: k })),
         {
           hasChats: this.pleromaChatMessagesAvailable,
+          hasAnnouncements: this.supportsAnnouncements,
           isFederating: this.federating,
           isPrivate: this.privateMode,
           currentUser: this.currentUser
diff --git a/src/components/navigation/filter.js b/src/components/navigation/filter.js
index 31b55486..5474a8ac 100644
--- a/src/components/navigation/filter.js
+++ b/src/components/navigation/filter.js
@@ -1,4 +1,4 @@
-export const filterNavigation = (list = [], { hasChats, isFederating, isPrivate, currentUser }) => {
+export const filterNavigation = (list = [], { hasChats, hasAnnouncements, isFederating, isPrivate, currentUser }) => {
   return list.filter(({ criteria, anon, anonRoute }) => {
     const set = new Set(criteria || [])
     if (!isFederating && set.has('federating')) return false
@@ -6,6 +6,7 @@ export const filterNavigation = (list = [], { hasChats, isFederating, isPrivate,
     if (!currentUser && !(anon || anonRoute)) return false
     if ((!currentUser || !currentUser.locked) && set.has('lockedUser')) return false
     if (!hasChats && set.has('chats')) return false
+    if (!hasAnnouncements && set.has('announcements')) return false
     return true
   })
 }
diff --git a/src/components/navigation/navigation.js b/src/components/navigation/navigation.js
index 40100f97..7f096316 100644
--- a/src/components/navigation/navigation.js
+++ b/src/components/navigation/navigation.js
@@ -76,6 +76,7 @@ export const ROOT_ITEMS = {
     route: 'announcements',
     icon: 'bullhorn',
     label: 'nav.announcements',
-    badgeGetter: 'unreadAnnouncementCount'
+    badgeGetter: 'unreadAnnouncementCount',
+    criteria: ['announcements']
   }
 }
diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js
index 680216dd..27019577 100644
--- a/src/components/side_drawer/side_drawer.js
+++ b/src/components/side_drawer/side_drawer.js
@@ -95,7 +95,8 @@ const SideDrawer = {
       }
     },
     ...mapState({
-      pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable
+      pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable,
+      supportsAnnouncements: state => state.announcements.supportsAnnouncements
     }),
     ...mapGetters(['unreadChatCount', 'unreadAnnouncementCount'])
   },
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index 4101cb03..887596f8 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -192,6 +192,7 @@
           </a>
         </li>
         <li
+          v-if="currentUser && supportsAnnouncements"
           @click="toggleDrawer"
         >
           <router-link
diff --git a/src/modules/announcements.js b/src/modules/announcements.js
index 0f8b6d09..e4d2d2b0 100644
--- a/src/modules/announcements.js
+++ b/src/modules/announcements.js
@@ -2,6 +2,7 @@ const FETCH_ANNOUNCEMENT_INTERVAL_MS = 1000 * 60 * 5
 
 export const defaultState = {
   announcements: [],
+  supportsAnnouncements: true,
   fetchAnnouncementsTimer: undefined
 }
 
@@ -20,6 +21,9 @@ export const mutations = {
   },
   setFetchAnnouncementsTimer (state, timer) {
     state.fetchAnnouncementsTimer = timer
+  },
+  setSupportsAnnouncements (state, supportsAnnouncements) {
+    state.supportsAnnouncements = supportsAnnouncements
   }
 }
 
@@ -40,6 +44,10 @@ const announcements = {
   getters,
   actions: {
     fetchAnnouncements (store) {
+      if (!store.state.supportsAnnouncements) {
+        return Promise.resolve()
+      }
+
       const currentUser = store.rootState.users.currentUser
       const isAdmin = currentUser && currentUser.role === 'admin'
 
@@ -72,6 +80,15 @@ const announcements = {
         .then(announcements => {
           store.commit('setAnnouncements', announcements)
         })
+        .catch(error => {
+          // If and only if backend does not support announcements, it would return 404.
+          // In this case, silently ignores it.
+          if (error && error.statusCode === 404) {
+            store.commit('setSupportsAnnouncements', false)
+          } else {
+            throw error
+          }
+        })
     },
     markAnnouncementAsRead (store, id) {
       return store.rootState.api.backendInteractor.dismissAnnouncement({ id })
-- 
cgit v1.2.3-70-g09d2

