diff options
Diffstat (limited to 'src/components/notifications/notifications.js')
| -rw-r--r-- | src/components/notifications/notifications.js | 60 |
1 files changed, 52 insertions, 8 deletions
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index d499d3d6..85d3662e 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -1,12 +1,15 @@ import { computed } from 'vue' import { mapGetters } from 'vuex' import Notification from '../notification/notification.vue' +import ExtraNotifications from '../extra_notifications/extra_notifications.vue' import NotificationFilters from './notification_filters.vue' import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js' import { notificationsFromStore, filteredNotificationsFromStore, - unseenNotificationsFromStore + unseenNotificationsFromStore, + countExtraNotifications, + ACTIONABLE_NOTIFICATION_TYPES } from '../../services/notification_utils/notification_utils.js' import FaviconService from '../../services/favicon_service/favicon_service.js' import { library } from '@fortawesome/fontawesome-svg-core' @@ -23,14 +26,20 @@ const DEFAULT_SEEN_TO_DISPLAY_COUNT = 30 const Notifications = { components: { Notification, - NotificationFilters + NotificationFilters, + ExtraNotifications }, props: { // Disables panel styles, unread mark, potentially other notification-related actions // meant for "Interactions" timeline minimalMode: Boolean, - // Custom filter mode, an array of strings, possible values 'mention', 'repeat', 'like', 'follow', used to override global filter for use in "Interactions" timeline + // Custom filter mode, an array of strings, possible values 'mention', 'status', 'repeat', 'like', 'follow', used to override global filter for use in "Interactions" timeline filterMode: Array, + // Do not show extra notifications + noExtra: { + type: Boolean, + default: false + }, // Disable teleporting (i.e. for /users/user/notifications) disableTeleport: Boolean }, @@ -57,22 +66,36 @@ const Notifications = { return notificationsFromStore(this.$store) }, error () { - return this.$store.state.statuses.notifications.error + return this.$store.state.notifications.error }, unseenNotifications () { return unseenNotificationsFromStore(this.$store) }, filteredNotifications () { - return filteredNotificationsFromStore(this.$store, this.filterMode) + if (this.unseenAtTop) { + return [ + ...filteredNotificationsFromStore(this.$store).filter(n => this.shouldShowUnseen(n)), + ...filteredNotificationsFromStore(this.$store).filter(n => !this.shouldShowUnseen(n)) + ] + } else { + return filteredNotificationsFromStore(this.$store, this.filterMode) + } + }, + unseenCountBadgeText () { + return `${this.unseenCount ? this.unseenCount : ''}${this.extraNotificationsCount ? '*' : ''}` }, unseenCount () { return this.unseenNotifications.length }, + ignoreInactionableSeen () { return this.$store.getters.mergedConfig.ignoreInactionableSeen }, + extraNotificationsCount () { + return countExtraNotifications(this.$store) + }, unseenCountTitle () { - return this.unseenCount + (this.unreadChatCount) + this.unreadAnnouncementCount + return this.unseenNotifications.length + (this.unreadChatCount) + this.unreadAnnouncementCount }, loading () { - return this.$store.state.statuses.notifications.loading + return this.$store.state.notifications.loading }, noHeading () { const { layoutType } = this.$store.state.interface @@ -94,6 +117,10 @@ const Notifications = { return this.filteredNotifications.slice(0, this.unseenCount + this.seenToDisplayCount) }, noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders }, + unseenAtTop () { return this.$store.getters.mergedConfig.unseenAtTop }, + showExtraNotifications () { + return !this.noExtra + }, ...mapGetters(['unreadChatCount', 'unreadAnnouncementCount']) }, mounted () { @@ -137,11 +164,28 @@ const Notifications = { scrollToTop () { const scrollable = this.scrollerRef scrollable.scrollTo({ top: this.$refs.root.offsetTop }) - // this.$refs.root.scrollIntoView({ behavior: 'smooth', block: 'start' }) }, updateScrollPosition () { this.showScrollTop = this.$refs.root.offsetTop < this.scrollerRef.scrollTop }, + shouldShowUnseen (notification) { + if (notification.seen) return false + + const actionable = ACTIONABLE_NOTIFICATION_TYPES.has(notification.type) + return this.ignoreInactionableSeen ? actionable : true + }, + /* "Interacted" really refers to "actionable" notifications that require user input, + * everything else (likes/repeats/reacts) cannot be acted and therefore we just clear + * the "seen" status upon any clicks on them + */ + notificationClicked (notification) { + const { id } = notification + this.$store.dispatch('notificationClicked', { id }) + }, + notificationInteracted (notification) { + const { id } = notification + this.$store.dispatch('markSingleNotificationAsSeen', { id }) + }, markAsSeen () { this.$store.dispatch('markNotificationsAsSeen') this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT |
