notifications migrated to pinia

This commit is contained in:
Henry Jameson 2026-08-10 17:43:24 +03:00
commit a196ed88e8
11 changed files with 122 additions and 146 deletions

View file

@ -1,9 +1,9 @@
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import { notificationsFromStore } from '../../services/notification_utils/notification_utils.js'
import BasicUserCard from '../basic_user_card/basic_user_card.vue' import BasicUserCard from '../basic_user_card/basic_user_card.vue'
import { useMergedConfigStore } from 'src/stores/merged_config.js' import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useNotificationsStore } from 'src/stores/notifications.js'
import { useOAuthStore } from 'src/stores/oauth.js' import { useOAuthStore } from 'src/stores/oauth.js'
import { approveUser, denyUser } from 'src/api/user.js' import { approveUser, denyUser } from 'src/api/user.js'
@ -24,7 +24,7 @@ const FollowRequestCard = {
}, },
methods: { methods: {
findFollowRequestNotificationId() { findFollowRequestNotificationId() {
const notif = notificationsFromStore(this.$store).find( const notif = useNotificationsStore().data.find(
(notif) => (notif) =>
notif.from_profile.id === this.user.id && notif.from_profile.id === this.user.id &&
notif.type === 'follow_request', notif.type === 'follow_request',

View file

@ -5,7 +5,7 @@ import NavigationPins from 'src/components/navigation/navigation_pins.vue'
import GestureService from '../../services/gesture_service/gesture_service' import GestureService from '../../services/gesture_service/gesture_service'
import { import {
countExtraNotifications, countExtraNotifications,
unseenNotificationsFromStore, unseenNotifications,
} from '../../services/notification_utils/notification_utils' } from '../../services/notification_utils/notification_utils'
import { useAnnouncementsStore } from 'src/stores/announcements.js' import { useAnnouncementsStore } from 'src/stores/announcements.js'
@ -57,8 +57,7 @@ const MobileNav = {
return useUsersStore().currentUser return useUsersStore().currentUser
}, },
unseenNotifications() { unseenNotifications() {
return unseenNotificationsFromStore( return unseenNotifications(
this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility, useMergedConfigStore().mergedConfig.notificationVisibility,
useMergedConfigStore().mergedConfig.ignoreInactionableSeen, useMergedConfigStore().mergedConfig.ignoreInactionableSeen,
) )

View file

@ -7,9 +7,8 @@ import FaviconService from '../../services/favicon_service/favicon_service.js'
import { import {
ACTIONABLE_NOTIFICATION_TYPES, ACTIONABLE_NOTIFICATION_TYPES,
countExtraNotifications, countExtraNotifications,
filteredNotificationsFromStore, filteredNotifications,
notificationsFromStore, unseenNotifications,
unseenNotificationsFromStore,
} from '../../services/notification_utils/notification_utils.js' } from '../../services/notification_utils/notification_utils.js'
import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js' import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js'
import NotificationFilters from './notification_filters.vue' import NotificationFilters from './notification_filters.vue'
@ -18,6 +17,7 @@ import { useAnnouncementsStore } from 'src/stores/announcements.js'
import { useChatsStore } from 'src/stores/chats.js' import { useChatsStore } from 'src/stores/chats.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js' import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useNotificationsStore } from 'src/stores/notifications.js'
import { useUsersStore } from 'src/stores/users.js' import { useUsersStore } from 'src/stores/users.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -71,14 +71,13 @@ const Notifications = {
return this.minimalMode ? '' : 'panel panel-default' return this.minimalMode ? '' : 'panel panel-default'
}, },
notifications() { notifications() {
return notificationsFromStore(this.$store) return useNotificationsStore().data
}, },
error() { error() {
return this.$store.state.notifications.error return useNotificationsStore().error
}, },
unseenNotifications() { unseenNotifications() {
return unseenNotificationsFromStore( return unseenNotifications(
this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility, useMergedConfigStore().mergedConfig.notificationVisibility,
useMergedConfigStore().mergedConfig.ignoreInactionableSeen, useMergedConfigStore().mergedConfig.ignoreInactionableSeen,
) )
@ -86,18 +85,15 @@ const Notifications = {
filteredNotifications() { filteredNotifications() {
if (this.unseenAtTop) { if (this.unseenAtTop) {
return [ return [
...filteredNotificationsFromStore( ...filteredNotifications(
this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility, useMergedConfigStore().mergedConfig.notificationVisibility,
).filter((n) => this.shouldShowUnseen(n)), ).filter((n) => this.shouldShowUnseen(n)),
...filteredNotificationsFromStore( ...filteredNotifications(
this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility, useMergedConfigStore().mergedConfig.notificationVisibility,
).filter((n) => !this.shouldShowUnseen(n)), ).filter((n) => !this.shouldShowUnseen(n)),
] ]
} else { } else {
return filteredNotificationsFromStore( return filteredNotifications(
this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility, useMergedConfigStore().mergedConfig.notificationVisibility,
this.filterMode, this.filterMode,
) )
@ -128,7 +124,7 @@ const Notifications = {
) )
}, },
loading() { loading() {
return this.$store.state.notifications.loading return useNotificationsStore().loading
}, },
noHeading() { noHeading() {
const { layoutType } = useInterfaceStore() const { layoutType } = useInterfaceStore()
@ -225,14 +221,14 @@ const Notifications = {
*/ */
notificationClicked(notification) { notificationClicked(notification) {
const { id } = notification const { id } = notification
this.$store.dispatch('notificationClicked', { id }) useNotificationsStore().notificationClicked(id)
}, },
notificationInteracted(notification) { notificationInteracted(notification) {
const { id } = notification const { id } = notification
this.$store.dispatch('markSingleNotificationAsSeen', { id }) useNotificationsStore().markSingleNotificationAsSeen(id)
}, },
markAsSeen() { markAsSeen() {
this.$store.dispatch('markNotificationsAsSeen') useNotificationsStore().markNotificationsAsSeen()
this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT
}, },
fetchOlderNotifications() { fetchOlderNotifications() {
@ -253,7 +249,7 @@ const Notifications = {
const store = this.$store const store = this.$store
const credentials = useUsersStore().currentUser.credentials const credentials = useUsersStore().currentUser.credentials
store.commit('setNotificationsLoading', { value: true }) useNotificationsStore().setNotificationsLoading(true)
notificationsFetcher notificationsFetcher
.fetchAndUpdate({ .fetchAndUpdate({
store, store,
@ -261,7 +257,7 @@ const Notifications = {
older: true, older: true,
}) })
.then((notifs) => { .then((notifs) => {
store.commit('setNotificationsLoading', { value: false }) useNotificationsStore().setNotificationsLoading(false)
if (notifs.length === 0) { if (notifs.length === 0) {
this.bottomedOut = true this.bottomedOut = true
} }

View file

@ -4,7 +4,7 @@ import { mapGetters } from 'vuex'
import { USERNAME_ROUTES } from 'src/components/navigation/navigation.js' import { USERNAME_ROUTES } from 'src/components/navigation/navigation.js'
import UserCard from 'src/components/user_card/user_card.vue' import UserCard from 'src/components/user_card/user_card.vue'
import GestureService from '../../services/gesture_service/gesture_service' import GestureService from '../../services/gesture_service/gesture_service'
import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils' import { unseenNotifications } from '../../services/notification_utils/notification_utils'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements'
import { useChatsStore } from 'src/stores/chats.js' import { useChatsStore } from 'src/stores/chats.js'
@ -77,8 +77,7 @@ const SideDrawer = {
return useShoutStore().joined return useShoutStore().joined
}, },
unseenNotifications() { unseenNotifications() {
return unseenNotificationsFromStore( return unseenNotifications(
this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility, useMergedConfigStore().mergedConfig.notificationVisibility,
useMergedConfigStore().mergedConfig.ignoreInactionableSeen, useMergedConfigStore().mergedConfig.ignoreInactionableSeen,
) )

View file

@ -5,6 +5,7 @@ import { maybeShowChatNotification } from '../services/chat_utils/chat_utils.js'
import { useChatsStore } from 'src/stores/chats.js' import { useChatsStore } from 'src/stores/chats.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useNotificationsStore } from 'src/stores/notifications.js'
import { useOAuthStore } from 'src/stores/oauth.js' import { useOAuthStore } from 'src/stores/oauth.js'
import { useShoutStore } from 'src/stores/shout.js' import { useShoutStore } from 'src/stores/shout.js'
@ -117,9 +118,9 @@ const api = {
({ detail: message }) => { ({ detail: message }) => {
if (!message) return // pings if (!message) return // pings
if (message.event === 'notification') { if (message.event === 'notification') {
dispatch('addNewNotifications', { useNotificationsStore().addNewNotifications({
notifications: [message.notification], timestamp: Date.now(),
older: false, data: message.notification,
}) })
} else if (message.event === 'update') { } else if (message.event === 'update') {
dispatch('addNewStatuses', { dispatch('addNewStatuses', {
@ -212,7 +213,6 @@ const api = {
if (state.mastoUserSocketStatus !== WSConnectionStatus.ERROR) { if (state.mastoUserSocketStatus !== WSConnectionStatus.ERROR) {
dispatch('startFetchingTimeline', { timeline: 'friends' }) dispatch('startFetchingTimeline', { timeline: 'friends' })
dispatch('startFetchingNotifications') dispatch('startFetchingNotifications')
dispatch('startFetchingChats')
useInterfaceStore().pushGlobalNotice({ useInterfaceStore().pushGlobalNotice({
level: 'error', level: 'error',
messageKey: 'timeline.socket_broke', messageKey: 'timeline.socket_broke',
@ -234,7 +234,6 @@ const api = {
stopMastoUserSocket({ state, dispatch }) { stopMastoUserSocket({ state, dispatch }) {
dispatch('startFetchingTimeline', { timeline: 'friends' }) dispatch('startFetchingTimeline', { timeline: 'friends' })
dispatch('startFetchingNotifications') dispatch('startFetchingNotifications')
dispatch('startFetchingChats')
state.mastoUserSocket.close() state.mastoUserSocket.close()
}, },
@ -289,7 +288,6 @@ const api = {
startFetchingNotifications(store) { startFetchingNotifications(store) {
if (store.state.fetchers.notifications) return if (store.state.fetchers.notifications) return
const fetcher = notificationsFetcher.startFetching({ const fetcher = notificationsFetcher.startFetching({
store,
credentials: useOAuthStore().token, credentials: useOAuthStore().token,
}) })
store.commit('addFetcher', { fetcherName: 'notifications', fetcher }) store.commit('addFetcher', { fetcherName: 'notifications', fetcher })

View file

@ -1,12 +1,10 @@
import api from './api.js' import api from './api.js'
import drafts from './drafts.js' import drafts from './drafts.js'
import notifications from './notifications.js'
import profileConfig from './profileConfig.js' import profileConfig from './profileConfig.js'
import statuses from './statuses.js' import statuses from './statuses.js'
export default { export default {
statuses, statuses,
notifications,
api, api,
profileConfig, profileConfig,
drafts, drafts,

View file

@ -4,14 +4,16 @@ import {
showDesktopNotification as swDesktopNotification, showDesktopNotification as swDesktopNotification,
} from '../sw/sw.js' } from '../sw/sw.js'
import { useNotificationsStore } from 'src/stores/notifications.js'
const state = { failCreateNotif: false } const state = { failCreateNotif: false }
export const showDesktopNotification = (rootState, desktopNotificationOpts) => { export const showDesktopNotification = (desktopNotificationOpts) => {
if ( if (
!('Notification' in window && window.Notification.permission === 'granted') !('Notification' in window && window.Notification.permission === 'granted')
) )
return return
if (rootState.notifications.desktopNotificationSilence) { if (useNotificationsStore().desktopNotificationSilence) {
return return
} }
@ -30,7 +32,7 @@ export const showDesktopNotification = (rootState, desktopNotificationOpts) => {
} }
} }
export const closeDesktopNotification = (rootState, { id }) => { export const closeDesktopNotification = (id) => {
if ( if (
!('Notification' in window && window.Notification.permission === 'granted') !('Notification' in window && window.Notification.permission === 'granted')
) )

View file

@ -1,6 +1,8 @@
import { showDesktopNotification } from '../desktop_notification_utils/desktop_notification_utils.js' import { showDesktopNotification } from '../desktop_notification_utils/desktop_notification_utils.js'
import { muteFilterHits } from '../status_parser/status_parser.js' import { muteFilterHits } from '../status_parser/status_parser.js'
import { useNotificationsStore } from 'src/stores/notifications.js'
import FaviconService from 'src/services/favicon_service/favicon_service.js' import FaviconService from 'src/services/favicon_service/favicon_service.js'
export const ACTIONABLE_NOTIFICATION_TYPES = new Set([ export const ACTIONABLE_NOTIFICATION_TYPES = new Set([
@ -11,8 +13,6 @@ export const ACTIONABLE_NOTIFICATION_TYPES = new Set([
let cachedBadgeUrl = null let cachedBadgeUrl = null
export const notificationsFromStore = (store) => store.state.notifications.data
const visibleTypes = (notificationVisibility) => { const visibleTypes = (notificationVisibility) => {
return [ return [
notificationVisibility.likes && 'like', notificationVisibility.likes && 'like',
@ -69,14 +69,11 @@ const isMutedNotification = (muteFilters, notification) => {
} }
export const maybeShowNotification = ( export const maybeShowNotification = (
store,
notificationVisibility, notificationVisibility,
muteFilters, muteFilters,
notification, notification,
i18n, i18n,
) => { ) => {
const rootState = store.rootState || store.state
if (notification.seen) return if (notification.seen) return
if (!visibleTypes(notificationVisibility).includes(notification.type)) return if (!visibleTypes(notificationVisibility).includes(notification.type)) return
if ( if (
@ -86,28 +83,23 @@ export const maybeShowNotification = (
return return
const notificationObject = prepareNotificationObject(notification, i18n) const notificationObject = prepareNotificationObject(notification, i18n)
showDesktopNotification(rootState, notificationObject) showDesktopNotification(notificationObject)
} }
export const filteredNotificationsFromStore = ( export const filteredNotifications = (notificationVisibility, types) => {
store,
notificationVisibility,
types,
) => {
// map is just to clone the array since sort mutates it and it causes some issues // map is just to clone the array since sort mutates it and it causes some issues
const sortedNotifications = notificationsFromStore(store).sort(sortById) const sortedNotifications = useNotificationsStore().data.sort(sortById)
// TODO implement sorting elsewhere and make it optional // TODO implement sorting elsewhere and make it optional
return sortedNotifications.filter((notification) => return sortedNotifications.filter((notification) =>
(types || visibleTypes(notificationVisibility)).includes(notification.type), (types || visibleTypes(notificationVisibility)).includes(notification.type),
) )
} }
export const unseenNotificationsFromStore = ( export const unseenNotifications = (
store,
notificationVisibility, notificationVisibility,
ignoreInactionableSeen, ignoreInactionableSeen,
) => { ) => {
return filteredNotificationsFromStore(store, notificationVisibility).filter( return filteredNotifications(notificationVisibility).filter(
({ seen, type }) => { ({ seen, type }) => {
if (!ignoreInactionableSeen) return !seen if (!ignoreInactionableSeen) return !seen
if (seen) return false if (seen) return false

View file

@ -3,12 +3,10 @@ import { promiseInterval } from '../promise_interval/promise_interval.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js' import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useNotificationsStore } from 'src/stores/notifications.js'
import { fetchTimeline } from 'src/api/timelines.js' import { fetchTimeline } from 'src/api/timelines.js'
const update = ({ store, notifications, older }) => {
store.dispatch('addNewNotifications', { notifications, older })
}
// //
// For using include_types when fetching notifications. // For using include_types when fetching notifications.
// Note: chat_mention excluded as pleroma-fe polls them separately // Note: chat_mention excluded as pleroma-fe polls them separately
@ -25,10 +23,9 @@ const mastoApiNotificationTypes = new Set([
'pleroma:report', 'pleroma:report',
]) ])
const fetchAndUpdate = ({ store, credentials, older = false, sinceId }) => { const fetchAndUpdate = ({ credentials, older = false, sinceId }) => {
const args = { credentials } const args = { credentials }
const rootState = store.rootState || store.state const timelineData = useNotificationsStore()
const timelineData = rootState.notifications
const hideMutedPosts = useMergedConfigStore().mergedConfig.hideMutedPosts const hideMutedPosts = useMergedConfigStore().mergedConfig.hideMutedPosts
if (useInstanceCapabilitiesStore().pleromaChatMessagesAvailable) { if (useInstanceCapabilitiesStore().pleromaChatMessagesAvailable) {
@ -43,7 +40,7 @@ const fetchAndUpdate = ({ store, credentials, older = false, sinceId }) => {
if (timelineData.minId !== Number.POSITIVE_INFINITY) { if (timelineData.minId !== Number.POSITIVE_INFINITY) {
args.maxId = timelineData.minId args.maxId = timelineData.minId
} }
return fetchNotifications({ store, args, older }) return fetchNotifications({ args, older })
} else { } else {
// fetch new notifications // fetch new notifications
if ( if (
@ -54,7 +51,7 @@ const fetchAndUpdate = ({ store, credentials, older = false, sinceId }) => {
} else if (sinceId !== null) { } else if (sinceId !== null) {
args.sinceId = sinceId args.sinceId = sinceId
} }
const result = fetchNotifications({ store, args, older }) const result = fetchNotifications({ args, older })
// If there's any unread notifications, try fetch notifications since // If there's any unread notifications, try fetch notifications since
// the newest read notification to check if any of the unread notifs // the newest read notification to check if any of the unread notifs
@ -72,7 +69,7 @@ const fetchAndUpdate = ({ store, credentials, older = false, sinceId }) => {
if (minId !== Infinity) { if (minId !== Infinity) {
args.sinceId = null // Don't use since_id since it sorta conflicts with min_id args.sinceId = null // Don't use since_id since it sorta conflicts with min_id
args.minId = minId - 1 // go beyond args.minId = minId - 1 // go beyond
fetchNotifications({ store, args, older }) fetchNotifications({ args, older })
} }
} }
@ -80,11 +77,13 @@ const fetchAndUpdate = ({ store, credentials, older = false, sinceId }) => {
} }
} }
const fetchNotifications = ({ store, args, older }) => { const fetchNotifications = ({ args, older }) => {
return fetchTimeline(args) return fetchTimeline(args)
.then((response) => { .then((response) => {
const notifications = response.data const notifications = response.data
update({ store, notifications, older })
useNotificationsStore().addNewNotifications(response)
return notifications return notifications
}) })
.catch((error) => { .catch((error) => {
@ -97,7 +96,7 @@ const fetchNotifications = ({ store, args, older }) => {
.toArray() .toArray()
.map((x) => x[1]) .map((x) => x[1])
.forEach((x) => mastoApiNotificationTypes.delete(x)) .forEach((x) => mastoApiNotificationTypes.delete(x))
return fetchNotifications({ store, args, older }) return fetchNotifications({ args, older })
} }
useInterfaceStore().pushGlobalNotice({ useInterfaceStore().pushGlobalNotice({
@ -114,7 +113,7 @@ const startFetching = ({ credentials, store }) => {
// Initially there's set flag to silence all desktop notifications so // Initially there's set flag to silence all desktop notifications so
// that there won't spam of them when user just opened up the FE we // that there won't spam of them when user just opened up the FE we
// reset that flag after a while to show new notifications once again. // reset that flag after a while to show new notifications once again.
setTimeout(() => store.dispatch('setNotificationsSilence', false), 10000) setTimeout(() => useNotificationsStore().setNotificationsSilence(false), 10000)
const boundFetchAndUpdate = () => fetchAndUpdate({ credentials, store }) const boundFetchAndUpdate = () => fetchAndUpdate({ credentials, store })
boundFetchAndUpdate() boundFetchAndUpdate()
return promiseInterval(boundFetchAndUpdate, 10000) return promiseInterval(boundFetchAndUpdate, 10000)

View file

@ -1,3 +1,5 @@
import { defineStore } from 'pinia'
import { import {
closeAllDesktopNotifications, closeAllDesktopNotifications,
closeDesktopNotification, closeDesktopNotification,
@ -17,70 +19,56 @@ import { useUsersStore } from 'src/stores/users.js'
import { dismissNotification, markNotificationsAsSeen } from 'src/api/user.js' import { dismissNotification, markNotificationsAsSeen } from 'src/api/user.js'
const emptyNotifications = () => ({ export const defaultState = () => ({
desktopNotificationSilence: true, desktopNotificationSilence: true,
maxId: 0, maxId: 0,
minId: Number.POSITIVE_INFINITY, minId: Number.POSITIVE_INFINITY,
data: [], data: [],
idStore: {}, statusNotificationRelations: new WeakMap(),
idStore: new Map(),
loading: false, loading: false,
}) })
export const defaultState = () => ({ export const useNotificationsStore = defineStore('notifications', {
...emptyNotifications(), state: defaultState,
}) actions: {
clearNotifications() {
export const notifications = {
state: defaultState(),
mutations: {
addNewNotifications(state, { notifications }) {
notifications.forEach((notification) => {
state.data.push(notification)
state.idStore[notification.id] = notification
})
},
clearNotifications(state) {
const blankState = defaultState() const blankState = defaultState()
Object.keys(state).forEach((k) => {
state[k] = blankState[k] Object.keys(defaultState()).forEach((k) => {
this[k] = blankState[k]
}) })
}, },
updateNotificationsMinMaxId(state, id) { updateNotificationsMinMaxId(id) {
state.maxId = id > state.maxId ? id : state.maxId this.maxId = id > this.maxId ? id : this.maxId
state.minId = id < state.minId ? id : state.minId this.minId = id < this.minId ? id : this.minId
}, },
setNotificationsLoading(state, { value }) { setNotificationsLoading(value) {
state.loading = value this.loading = value
}, },
setNotificationsSilence(state, { value }) { setNotificationsSilence(value) {
state.desktopNotificationSilence = value this.desktopNotificationSilence = value
}, },
markNotificationsAsSeen(state) { updateNotification({ id, updater }) {
state.data.forEach((notification) => { const notification = this.idStore.get(id)
notification.seen = true
})
},
markSingleNotificationAsSeen(state, { id }) {
const notification = state.idStore[id]
if (notification) notification.seen = true
},
dismissNotification(state, { id }) {
state.data = state.data.filter((n) => n.id !== id)
delete state.idStore[id]
},
updateNotification(state, { id, updater }) {
const notification = state.idStore[id]
notification && updater(notification) notification && updater(notification)
}, },
}, addNewNotifications(result) {
actions: { const { timestamp, data: notifications } = result
addNewNotifications(store, { notifications }) {
const { commit, dispatch, state, rootState } = store useUsersStore().addNewUsers({
timestamp,
data: notifications.map((n) => n.from_profile),
})
notifications.forEach(
(n) => (n.from_profile = useUsersStore().findUser(n.from_profile.id)),
)
const validNotifications = notifications.filter((notification) => { const validNotifications = notifications.filter((notification) => {
// If invalid notification, update ids but don't add it to store // If invalid notification, update ids but don't add it to store
if (!isValidNotification(notification)) { if (!isValidNotification(notification)) {
console.error('Invalid notification:', notification) console.error('Invalid notification:', notification)
commit('updateNotificationsMinMaxId', notification.id) this.updateNotificationsMinMaxId(notification.id)
return false return false
} }
return true return true
@ -92,7 +80,8 @@ export const notifications = {
) )
// Synchronous commit to add all the statuses // Synchronous commit to add all the statuses
commit('addNewStatuses', { window.vuex.commit('addNewStatuses', {
timestamp,
statuses: statusNotifications.map( statuses: statusNotifications.map(
(notification) => notification.status, (notification) => notification.status,
), ),
@ -101,7 +90,7 @@ export const notifications = {
// Update references to statuses in notifications to ones in the store // Update references to statuses in notifications to ones in the store
statusNotifications.forEach((notification) => { statusNotifications.forEach((notification) => {
const id = notification.status.id const id = notification.status.id
const referenceStatus = rootState.statuses.allStatusesObject[id] const referenceStatus = window.vuex.state.statuses.allStatusesObject[id]
if (referenceStatus) { if (referenceStatus) {
notification.status = referenceStatus notification.status = referenceStatus
@ -114,28 +103,36 @@ export const notifications = {
} }
if (notification.type === 'pleroma:emoji_reaction') { if (notification.type === 'pleroma:emoji_reaction') {
dispatch('fetchEmojiReactionsBy', notification.status.id) window.vuex.dispatch('fetchEmojiReactionsBy', notification.status.id)
} }
// Only add a new notification if we don't have one for the same action // Only add a new notification if we don't have one for the same action
if (!Object.hasOwn(state.idStore, notification.id)) { if (!this.idStore.has(notification.id)) {
commit('updateNotificationsMinMaxId', notification.id) this.updateNotificationsMinMaxId(notification.id)
commit('addNewNotifications', { notifications: [notification] })
notifications.forEach((notification) => {
this.data.push(notification)
this.idStore.set(notification.id, notification)
})
this.statusNotificationRelations.set(
notification.status,
this.idStore.get(notification.id),
)
maybeShowNotification( maybeShowNotification(
store,
useMergedConfigStore().mergedConfig.notificationVisibility, useMergedConfigStore().mergedConfig.notificationVisibility,
Object.values(useSyncConfigStore().prefsStorage.simple.muteFilters), Object.values(useSyncConfigStore().prefsStorage.simple.muteFilters),
notification, notification,
useI18nStore().i18n, useI18nStore().i18n,
) )
} else if (notification.seen) { } else if (notification.seen) {
state.idStore[notification.id].seen = true this.idStore.get(notification.id).seen = true
} }
}) })
}, },
notificationClicked({ state, dispatch }, { id }) { notificationClicked(id) {
const notification = state.idStore[id] const notification = this.idStore.get(id)
const { type, seen } = notification const { type, seen } = notification
if (!seen) { if (!seen) {
@ -145,49 +142,45 @@ export const notifications = {
case 'follow_request': case 'follow_request':
break break
default: default:
dispatch('markSingleNotificationAsSeen', { id }) this.markSingleNotificationAsSeen({ id })
} }
} }
}, },
setNotificationsLoading({ commit }, { value }) { markNotificationsAsSeen() {
commit('setNotificationsLoading', { value }) this.data.forEach((notification) => {
}, notification.seen = true
setNotificationsSilence({ commit }, { value }) { })
commit('setNotificationsSilence', { value })
},
markNotificationsAsSeen({ rootState, state, commit }) {
commit('markNotificationsAsSeen')
markNotificationsAsSeen({ markNotificationsAsSeen({
id: state.maxId, id: this.maxId,
credentials: useUsersStore().currentUser.credentials, credentials: useUsersStore().currentUser.credentials,
}).then(() => { }).then(() => {
closeAllDesktopNotifications(rootState) closeAllDesktopNotifications()
}) })
}, },
markSingleNotificationAsSeen({ rootState, commit }, { id }) { markSingleNotificationAsSeen({ id }) {
commit('markSingleNotificationAsSeen', { id }) const notification = this.idStore.get(id)
if (notification) notification.seen = true
markNotificationsAsSeen({ markNotificationsAsSeen({
single: true, single: true,
id, id,
credentials: useUsersStore().currentUser.credentials, credentials: useUsersStore().currentUser.credentials,
}).then(() => { }).then(() => {
closeDesktopNotification(rootState, { id }) closeDesktopNotification(id)
}) })
}, },
dismissNotificationLocal({ commit }, { id }) { dismissNotificationLocal(id) {
commit('dismissNotification', { id }) this.data = this.data.filter((n) => n.id !== id)
delete this.idStore.delete(id)
}, },
dismissNotification({ rootState, commit }, { id }) { dismissNotification(id) {
commit('dismissNotification', { id }) this.dismissNotificationLocal(id)
dismissNotification({ dismissNotification({
id, id,
credentials: useOAuthStore().token, credentials: useOAuthStore().token,
}) })
}, },
updateNotification({ commit }, { id, updater }) {
commit('updateNotification', { id, updater })
},
}, },
} })
export default notifications

View file

@ -697,7 +697,7 @@ export const useUsersStore = defineStore('users', {
.then(() => { .then(() => {
dispatch('fetchChats', { latest: true }) dispatch('fetchChats', { latest: true })
setTimeout( setTimeout(
() => dispatch('setNotificationsSilence', false), () => useNotificationsStore().setNotificationsSilence(false),
10000, 10000,
) )
}) })