diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index de404b440d936efc966716ff886769441c6a0a47..07c0371bd48ee7be8223787fef724cbde766bbc4 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -15,6 +15,9 @@ Fixed
 * Progress page didn't work properly.
 * About page failed to load for apps with an unknown licence.
 * Some pages couldn't be scrolled when a task progress popup was open.
+* Notification query failed on admin users without persons.
+* Querying for notification caused unnecessary database requests.
+* Loading bar didn't disappear on some pages after loading was finished.
 
 `3.1`_ - 2022-05-30
 -------------------
diff --git a/aleksis/core/frontend/components/LegacyBaseTemplate.vue b/aleksis/core/frontend/components/LegacyBaseTemplate.vue
index 790fc10c592bac5acc1e3bbadabcae63e065804f..0105952fd08792c2cb4a472465d435a1f94a0eb3 100644
--- a/aleksis/core/frontend/components/LegacyBaseTemplate.vue
+++ b/aleksis/core/frontend/components/LegacyBaseTemplate.vue
@@ -71,7 +71,9 @@ export default {
 
       // Show loader if iframe starts to change its content, even if the $route stays the same
       this.$refs.contentIFrame.contentWindow.onpagehide = () => {
-        this.$root.contentLoading = true;
+        if (this.$root.isLegacyBaseTemplate) {
+          this.$root.contentLoading = true;
+        }
       };
 
       // Write title of iframe to SPA window
diff --git a/aleksis/core/frontend/components/notifications/NotificationList.vue b/aleksis/core/frontend/components/notifications/NotificationList.vue
index 1c51c00661816fe3e244e6d511a0e70c747dbca6..08914210eefc7ecd2f52ea24342abf1d1467e5c9 100644
--- a/aleksis/core/frontend/components/notifications/NotificationList.vue
+++ b/aleksis/core/frontend/components/notifications/NotificationList.vue
@@ -20,7 +20,7 @@
           v-if="
             myNotifications &&
             myNotifications.person &&
-            myNotifications.person.unreadNotificationsCount > 0
+            myNotifications.person.notifications.length > 0
           "
         >
           mdi-bell-badge-outline
@@ -38,7 +38,7 @@
         v-if="
           myNotifications.person &&
           myNotifications.person.notifications &&
-          myNotifications.person.notifications.length
+          unreadNotifications.length
         "
       >
         <v-subheader>{{ $t("notifications.notifications") }}</v-subheader>
@@ -86,5 +86,10 @@ export default {
       pollInterval: 30000,
     },
   },
+  computed: {
+    unreadNotifications() {
+      return this.myNotifications.filter(n => !n.read);
+    },
+  },
 };
 </script>
diff --git a/aleksis/core/frontend/components/notifications/myNotifications.graphql b/aleksis/core/frontend/components/notifications/myNotifications.graphql
index b8287ea2f50664f556d82bdb58e4b508c7ece1d4..89e91562086607e6c9e7649fa1295d234d189bd3 100644
--- a/aleksis/core/frontend/components/notifications/myNotifications.graphql
+++ b/aleksis/core/frontend/components/notifications/myNotifications.graphql
@@ -1,7 +1,6 @@
 {
   myNotifications: whoAmI {
     person {
-      unreadNotificationsCount
       notifications {
         id
         title
diff --git a/aleksis/core/schema/person.py b/aleksis/core/schema/person.py
index 6eed201487348034b2d9b1cba616046b1794dbf2..bf2229545850b088409defde34ced90bc658f7c1 100644
--- a/aleksis/core/schema/person.py
+++ b/aleksis/core/schema/person.py
@@ -62,7 +62,7 @@ class PersonType(DjangoObjectType):
     secondary_image_url = graphene.String()
 
     notifications = graphene.List(NotificationType)
-    unread_notifications_count = graphene.Int()
+    unread_notifications_count = graphene.Int(required=False)
 
     is_dummy = graphene.Boolean()
     preferences = graphene.Field(PersonPreferencesType)
@@ -150,7 +150,11 @@ class PersonType(DjangoObjectType):
         return root.user.id if root.user else None
 
     def resolve_unread_notifications_count(root, info, **kwargs):  # noqa
-        return root.unread_notifications_count
+        if root.pk and has_person(info.context) and root == info.context.user.person:
+            return root.unread_notifications_count
+        elif root.pk:
+            return 0
+        return None
 
     def resolve_photo(root, info, **kwargs):
         if info.context.user.has_perm("core.view_photo_rule", root):
@@ -199,11 +203,11 @@ class PersonType(DjangoObjectType):
         return root.is_dummy if hasattr(root, "is_dummy") else False
 
     def resolve_notifications(root: Person, info, **kwargs):
-        if has_person(info.context.user) and info.context.user.person == root:
+        if root.pk and has_person(info.context) and root == info.context.user.person:
             return root.notifications.filter(send_at__lte=timezone.now()).order_by(
                 "read", "-created"
             )
-        raise PermissionDenied()
+        return []
 
     def resolve_can_edit_person(root, info, **kwargs):  # noqa
         return info.context.user.has_perm("core.edit_person_rule", root)