2022-06-21 23:30:10 +02:00
import { computed } from 'vue'
2020-05-07 15:10:53 +02:00
import { mapGetters } from 'vuex'
2018-04-09 19:44:37 +02:00
import Notification from '../notification/notification.vue'
2021-03-01 15:21:35 +01:00
import NotificationFilters from './notification_filters.vue'
2018-08-12 13:14:34 +02:00
import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js'
2018-12-28 20:39:54 +01:00
import {
notificationsFromStore ,
2020-01-14 14:28:57 +01:00
filteredNotificationsFromStore ,
2018-12-28 20:39:54 +01:00
unseenNotificationsFromStore
} from '../../services/notification_utils/notification_utils.js'
2020-11-02 14:46:49 +01:00
import FaviconService from '../../services/favicon_service/favicon_service.js'
2020-10-19 21:35:46 +02:00
import { library } from '@fortawesome/fontawesome-svg-core'
2022-08-24 21:31:48 +02:00
import { faCircleNotch , faArrowUp , faMinus } from '@fortawesome/free-solid-svg-icons'
2020-10-19 21:35:46 +02:00
library . add (
2022-08-17 19:49:20 +02:00
faCircleNotch ,
2022-08-24 21:31:48 +02:00
faArrowUp ,
faMinus
2020-10-19 21:35:46 +02:00
)
2016-11-27 19:44:56 +01:00
2020-01-14 14:28:57 +01:00
const DEFAULT _SEEN _TO _DISPLAY _COUNT = 30
2016-11-27 19:44:56 +01:00
const Notifications = {
2021-03-01 15:21:35 +01:00
components : {
Notification ,
NotificationFilters
} ,
2019-05-15 19:44:35 +02:00
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
2022-06-07 15:52:03 +02:00
filterMode : Array ,
// Disable teleporting (i.e. for /users/user/notifications)
disableTeleport : Boolean
2019-05-15 19:49:46 +02:00
} ,
2019-01-29 20:04:52 +01:00
data ( ) {
return {
2022-08-17 19:49:20 +02:00
showScrollTop : false ,
2020-01-14 14:28:57 +01:00
bottomedOut : false ,
// How many seen notifications to display in the list. The more there are,
// the heavier the page becomes. This count is increased when loading
// older notifications, and cut back to default whenever hitting "Read!".
seenToDisplayCount : DEFAULT _SEEN _TO _DISPLAY _COUNT
2019-01-29 20:04:52 +01:00
}
} ,
2022-06-21 23:30:10 +02:00
provide ( ) {
return {
popoversZLayer : computed ( ( ) => this . popoversZLayer )
}
} ,
2016-11-27 19:44:56 +01:00
computed : {
2019-05-14 21:38:16 +02:00
mainClass ( ) {
return this . minimalMode ? '' : 'panel panel-default'
} ,
2017-02-18 20:42:00 +01:00
notifications ( ) {
2018-12-28 20:39:54 +01:00
return notificationsFromStore ( this . $store )
2017-02-18 20:42:00 +01:00
} ,
2018-08-20 19:45:54 +02:00
error ( ) {
return this . $store . state . statuses . notifications . error
} ,
2017-02-18 20:42:00 +01:00
unseenNotifications ( ) {
2018-12-28 20:39:54 +01:00
return unseenNotificationsFromStore ( this . $store )
2017-02-18 20:42:00 +01:00
} ,
2020-01-14 14:28:57 +01:00
filteredNotifications ( ) {
return filteredNotificationsFromStore ( this . $store , this . filterMode )
2017-02-18 20:42:00 +01:00
} ,
unseenCount ( ) {
return this . unseenNotifications . length
2019-01-29 20:04:52 +01:00
} ,
2020-05-07 15:10:53 +02:00
unseenCountTitle ( ) {
2022-03-17 22:51:39 +01:00
return this . unseenCount + ( this . unreadChatCount ) + this . unreadAnnouncementCount
2020-05-07 15:10:53 +02:00
} ,
2019-01-29 20:04:52 +01:00
loading ( ) {
return this . $store . state . statuses . notifications . loading
2020-01-14 14:28:57 +01:00
} ,
2022-04-05 18:22:15 +02:00
noHeading ( ) {
const { layoutType } = this . $store . state . interface
2022-04-07 13:37:16 +02:00
return this . minimalMode || layoutType === 'mobile'
2022-04-05 18:22:15 +02:00
} ,
teleportTarget ( ) {
const { layoutType } = this . $store . state . interface
const map = {
wide : '#notifs-column' ,
mobile : '#mobile-notifications'
}
return map [ layoutType ] || '#notifs-sidebar'
} ,
2022-06-21 23:30:10 +02:00
popoversZLayer ( ) {
const { layoutType } = this . $store . state . interface
return layoutType === 'mobile' ? 'navbar' : null
} ,
2020-01-14 14:28:57 +01:00
notificationsToDisplay ( ) {
return this . filteredNotifications . slice ( 0 , this . unseenCount + this . seenToDisplayCount )
2020-05-07 15:10:53 +02:00
} ,
2022-08-17 19:49:20 +02:00
noSticky ( ) { return this . $store . getters . mergedConfig . disableStickyHeaders } ,
2022-03-17 22:51:39 +01:00
... mapGetters ( [ 'unreadChatCount' , 'unreadAnnouncementCount' ] )
2017-02-18 20:42:00 +01:00
} ,
2022-08-17 19:49:20 +02:00
mounted ( ) {
this . scrollerRef = this . $refs . root . closest ( '.column.-scrollable' )
2022-08-24 21:37:07 +02:00
if ( ! this . scrollerRef ) {
this . scrollerRef = this . $refs . root . closest ( '.mobile-notifications' )
}
2022-08-17 19:49:20 +02:00
this . scrollerRef . addEventListener ( 'scroll' , this . updateScrollPosition )
} ,
unmounted ( ) {
2022-08-24 21:37:07 +02:00
if ( ! this . scrollerRef ) return
2022-08-17 19:49:20 +02:00
this . scrollerRef . removeEventListener ( 'scroll' , this . updateScrollPosition )
} ,
2017-02-18 20:42:00 +01:00
watch : {
2020-05-07 15:10:53 +02:00
unseenCountTitle ( count ) {
2017-02-19 12:19:47 +01:00
if ( count > 0 ) {
2020-11-02 14:46:49 +01:00
FaviconService . drawFaviconBadge ( )
2017-02-19 12:19:47 +01:00
this . $store . dispatch ( 'setPageTitle' , ` ( ${ count } ) ` )
} else {
2020-11-02 14:46:49 +01:00
FaviconService . clearFaviconBadge ( )
2017-02-19 12:19:47 +01:00
this . $store . dispatch ( 'setPageTitle' , '' )
}
2022-08-24 21:37:07 +02:00
} ,
teleportTarget ( ) {
// handle scroller change
2022-09-28 20:23:27 +02:00
this . $nextTick ( ( ) => {
this . scrollerRef . removeEventListener ( 'scroll' , this . updateScrollPosition )
this . scrollerRef = this . $refs . root . closest ( '.column.-scrollable' )
if ( ! this . scrollerRef ) {
this . scrollerRef = this . $refs . root . closest ( '.mobile-notifications' )
}
this . scrollerRef . addEventListener ( 'scroll' , this . updateScrollPosition )
this . updateScrollPosition ( )
} )
2017-02-18 20:42:00 +01:00
}
} ,
methods : {
2022-08-17 19:49:20 +02:00
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
} ,
2017-02-18 20:42:00 +01:00
markAsSeen ( ) {
2019-03-12 22:16:57 +01:00
this . $store . dispatch ( 'markNotificationsAsSeen' )
2020-01-14 14:28:57 +01:00
this . seenToDisplayCount = DEFAULT _SEEN _TO _DISPLAY _COUNT
2019-03-12 22:16:57 +01:00
} ,
2018-08-12 13:14:34 +02:00
fetchOlderNotifications ( ) {
2019-05-03 13:52:22 +02:00
if ( this . loading ) {
return
}
2020-01-14 14:28:57 +01:00
const seenCount = this . filteredNotifications . length - this . unseenCount
if ( this . seenToDisplayCount < seenCount ) {
this . seenToDisplayCount = Math . min ( this . seenToDisplayCount + 20 , seenCount )
return
} else if ( this . seenToDisplayCount > seenCount ) {
this . seenToDisplayCount = seenCount
}
2018-08-12 13:14:34 +02:00
const store = this . $store
const credentials = store . state . users . currentUser . credentials
2019-01-29 20:04:52 +01:00
store . commit ( 'setNotificationsLoading' , { value : true } )
2018-08-12 13:14:34 +02:00
notificationsFetcher . fetchAndUpdate ( {
store ,
credentials ,
older : true
2019-01-29 20:04:52 +01:00
} ) . then ( notifs => {
store . commit ( 'setNotificationsLoading' , { value : false } )
if ( notifs . length === 0 ) {
this . bottomedOut = true
}
2020-01-14 14:28:57 +01:00
this . seenToDisplayCount += notifs . length
2018-08-12 13:14:34 +02:00
} )
2016-11-27 19:44:56 +01:00
}
}
}
export default Notifications