logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://hacktivis.me/git/pleroma-fe.git

notifications.js (7774B)


  1. import { computed } from 'vue'
  2. import { mapGetters } from 'vuex'
  3. import Notification from '../notification/notification.vue'
  4. import ExtraNotifications from '../extra_notifications/extra_notifications.vue'
  5. import NotificationFilters from './notification_filters.vue'
  6. import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js'
  7. import {
  8. notificationsFromStore,
  9. filteredNotificationsFromStore,
  10. unseenNotificationsFromStore,
  11. countExtraNotifications,
  12. ACTIONABLE_NOTIFICATION_TYPES
  13. } from '../../services/notification_utils/notification_utils.js'
  14. import FaviconService from '../../services/favicon_service/favicon_service.js'
  15. import { library } from '@fortawesome/fontawesome-svg-core'
  16. import { faCircleNotch, faArrowUp, faMinus } from '@fortawesome/free-solid-svg-icons'
  17. library.add(
  18. faCircleNotch,
  19. faArrowUp,
  20. faMinus
  21. )
  22. const DEFAULT_SEEN_TO_DISPLAY_COUNT = 30
  23. const Notifications = {
  24. components: {
  25. Notification,
  26. NotificationFilters,
  27. ExtraNotifications
  28. },
  29. props: {
  30. // Disables panel styles, unread mark, potentially other notification-related actions
  31. // meant for "Interactions" timeline
  32. minimalMode: Boolean,
  33. // Custom filter mode, an array of strings, possible values 'mention', 'status', 'repeat', 'like', 'follow', used to override global filter for use in "Interactions" timeline
  34. filterMode: Array,
  35. // Do not show extra notifications
  36. noExtra: {
  37. type: Boolean,
  38. default: false
  39. },
  40. // Disable teleporting (i.e. for /users/user/notifications)
  41. disableTeleport: Boolean
  42. },
  43. data () {
  44. return {
  45. showScrollTop: false,
  46. bottomedOut: false,
  47. // How many seen notifications to display in the list. The more there are,
  48. // the heavier the page becomes. This count is increased when loading
  49. // older notifications, and cut back to default whenever hitting "Read!".
  50. seenToDisplayCount: DEFAULT_SEEN_TO_DISPLAY_COUNT
  51. }
  52. },
  53. provide () {
  54. return {
  55. popoversZLayer: computed(() => this.popoversZLayer)
  56. }
  57. },
  58. computed: {
  59. mainClass () {
  60. return this.minimalMode ? '' : 'panel panel-default'
  61. },
  62. notifications () {
  63. return notificationsFromStore(this.$store)
  64. },
  65. error () {
  66. return this.$store.state.notifications.error
  67. },
  68. unseenNotifications () {
  69. return unseenNotificationsFromStore(this.$store)
  70. },
  71. filteredNotifications () {
  72. if (this.unseenAtTop) {
  73. return [
  74. ...filteredNotificationsFromStore(this.$store).filter(n => this.shouldShowUnseen(n)),
  75. ...filteredNotificationsFromStore(this.$store).filter(n => !this.shouldShowUnseen(n))
  76. ]
  77. } else {
  78. return filteredNotificationsFromStore(this.$store, this.filterMode)
  79. }
  80. },
  81. unseenCountBadgeText () {
  82. return `${this.unseenCount ? this.unseenCount : ''}${this.extraNotificationsCount ? '*' : ''}`
  83. },
  84. unseenCount () {
  85. return this.unseenNotifications.length
  86. },
  87. ignoreInactionableSeen () { return this.$store.getters.mergedConfig.ignoreInactionableSeen },
  88. extraNotificationsCount () {
  89. return countExtraNotifications(this.$store)
  90. },
  91. unseenCountTitle () {
  92. return this.unseenNotifications.length + (this.unreadChatCount) + this.unreadAnnouncementCount
  93. },
  94. loading () {
  95. return this.$store.state.notifications.loading
  96. },
  97. noHeading () {
  98. const { layoutType } = this.$store.state.interface
  99. return this.minimalMode || layoutType === 'mobile'
  100. },
  101. teleportTarget () {
  102. const { layoutType } = this.$store.state.interface
  103. const map = {
  104. wide: '#notifs-column',
  105. mobile: '#mobile-notifications'
  106. }
  107. return map[layoutType] || '#notifs-sidebar'
  108. },
  109. popoversZLayer () {
  110. const { layoutType } = this.$store.state.interface
  111. return layoutType === 'mobile' ? 'navbar' : null
  112. },
  113. notificationsToDisplay () {
  114. return this.filteredNotifications.slice(0, this.unseenCount + this.seenToDisplayCount)
  115. },
  116. noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders },
  117. unseenAtTop () { return this.$store.getters.mergedConfig.unseenAtTop },
  118. showExtraNotifications () {
  119. return !this.noExtra
  120. },
  121. ...mapGetters(['unreadChatCount', 'unreadAnnouncementCount'])
  122. },
  123. mounted () {
  124. this.scrollerRef = this.$refs.root.closest('.column.-scrollable')
  125. if (!this.scrollerRef) {
  126. this.scrollerRef = this.$refs.root.closest('.mobile-notifications')
  127. }
  128. if (!this.scrollerRef) {
  129. this.scrollerRef = this.$refs.root.closest('.column.main')
  130. }
  131. this.scrollerRef.addEventListener('scroll', this.updateScrollPosition)
  132. },
  133. unmounted () {
  134. if (!this.scrollerRef) return
  135. this.scrollerRef.removeEventListener('scroll', this.updateScrollPosition)
  136. },
  137. watch: {
  138. unseenCountTitle (count) {
  139. if (count > 0) {
  140. FaviconService.drawFaviconBadge()
  141. this.$store.dispatch('setPageTitle', `(${count})`)
  142. } else {
  143. FaviconService.clearFaviconBadge()
  144. this.$store.dispatch('setPageTitle', '')
  145. }
  146. },
  147. teleportTarget () {
  148. // handle scroller change
  149. this.$nextTick(() => {
  150. this.scrollerRef.removeEventListener('scroll', this.updateScrollPosition)
  151. this.scrollerRef = this.$refs.root.closest('.column.-scrollable')
  152. if (!this.scrollerRef) {
  153. this.scrollerRef = this.$refs.root.closest('.mobile-notifications')
  154. }
  155. this.scrollerRef.addEventListener('scroll', this.updateScrollPosition)
  156. this.updateScrollPosition()
  157. })
  158. }
  159. },
  160. methods: {
  161. scrollToTop () {
  162. const scrollable = this.scrollerRef
  163. scrollable.scrollTo({ top: this.$refs.root.offsetTop })
  164. },
  165. updateScrollPosition () {
  166. this.showScrollTop = this.$refs.root.offsetTop < this.scrollerRef.scrollTop
  167. },
  168. shouldShowUnseen (notification) {
  169. if (notification.seen) return false
  170. const actionable = ACTIONABLE_NOTIFICATION_TYPES.has(notification.type)
  171. return this.ignoreInactionableSeen ? actionable : true
  172. },
  173. /* "Interacted" really refers to "actionable" notifications that require user input,
  174. * everything else (likes/repeats/reacts) cannot be acted and therefore we just clear
  175. * the "seen" status upon any clicks on them
  176. */
  177. notificationClicked (notification) {
  178. const { id } = notification
  179. this.$store.dispatch('notificationClicked', { id })
  180. },
  181. notificationInteracted (notification) {
  182. const { id } = notification
  183. this.$store.dispatch('markSingleNotificationAsSeen', { id })
  184. },
  185. markAsSeen () {
  186. this.$store.dispatch('markNotificationsAsSeen')
  187. this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT
  188. },
  189. fetchOlderNotifications () {
  190. if (this.loading) {
  191. return
  192. }
  193. const seenCount = this.filteredNotifications.length - this.unseenCount
  194. if (this.seenToDisplayCount < seenCount) {
  195. this.seenToDisplayCount = Math.min(this.seenToDisplayCount + 20, seenCount)
  196. return
  197. } else if (this.seenToDisplayCount > seenCount) {
  198. this.seenToDisplayCount = seenCount
  199. }
  200. const store = this.$store
  201. const credentials = store.state.users.currentUser.credentials
  202. store.commit('setNotificationsLoading', { value: true })
  203. notificationsFetcher.fetchAndUpdate({
  204. store,
  205. credentials,
  206. older: true
  207. }).then(notifs => {
  208. store.commit('setNotificationsLoading', { value: false })
  209. if (notifs.length === 0) {
  210. this.bottomedOut = true
  211. }
  212. this.seenToDisplayCount += notifs.length
  213. })
  214. }
  215. }
  216. }
  217. export default Notifications