diff --git a/src/api/chats.js b/src/api/chats.js
index 001f00f26..5d766dec4 100644
--- a/src/api/chats.js
+++ b/src/api/chats.js
@@ -1,6 +1,9 @@
import { paramsString, promisedRequest } from './helpers.js'
-import { parseChat, parseChatMessage } from 'src/services/entity_normalizer/entity_normalizer.service.js'
+import {
+ parseChat,
+ parseChatMessage,
+} from 'src/services/entity_normalizer/entity_normalizer.service.js'
const PLEROMA_CHATS_URL = '/api/v1/pleroma/chats'
const PLEROMA_CHAT_URL = (id) => `/api/v1/pleroma/chats/by-account-id/${id}`
diff --git a/src/components/chat_list/chat_list.js b/src/components/chat_list/chat_list.js
index 597fcc709..446ccb70a 100644
--- a/src/components/chat_list/chat_list.js
+++ b/src/components/chat_list/chat_list.js
@@ -1,9 +1,12 @@
-import { mapGetters, mapState } from 'vuex'
+import { mapState as mapPiniaState } from 'pinia'
+import { mapState } from 'vuex'
import ChatListItem from 'src/components/chat_list_item/chat_list_item.vue'
import ChatNew from 'src/components/chat_new/chat_new.vue'
import List from 'src/components/list/list.vue'
+import { useChatsStore } from 'src/stores/chats.js'
+
const ChatList = {
components: {
ChatListItem,
@@ -14,7 +17,7 @@ const ChatList = {
...mapState({
currentUser: (state) => state.users.currentUser,
}),
- ...mapGetters(['sortedChatList']),
+ ...mapPiniaState(useChatsStore, ['sortedChatList']),
},
data() {
return {
@@ -22,12 +25,12 @@ const ChatList = {
}
},
created() {
- this.$store.dispatch('fetchChats', { latest: true })
+ useChatsStore().fetchChats()
},
methods: {
cancelNewChat() {
this.isNew = false
- this.$store.dispatch('fetchChats', { latest: true })
+ useChatsStore().fetchChats()
},
newChat() {
this.isNew = true
diff --git a/src/components/chat_message/chat_message.js b/src/components/chat_message/chat_message.js
index 9ec73dc44..bacfd3e94 100644
--- a/src/components/chat_message/chat_message.js
+++ b/src/components/chat_message/chat_message.js
@@ -15,7 +15,11 @@ import { useInterfaceStore } from 'src/stores/interface'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core'
-import { faEllipsisH, faTimes, faCircleNotch } from '@fortawesome/free-solid-svg-icons'
+import {
+ faCircleNotch,
+ faEllipsisH,
+ faTimes,
+} from '@fortawesome/free-solid-svg-icons'
library.add(faTimes, faEllipsisH, faCircleNotch)
diff --git a/src/components/chat_message_list/chat_message_list.js b/src/components/chat_message_list/chat_message_list.js
index 71199608d..1f709d0a1 100644
--- a/src/components/chat_message_list/chat_message_list.js
+++ b/src/components/chat_message_list/chat_message_list.js
@@ -1,6 +1,4 @@
-import { orderBy, throttle, uniqueId } from 'lodash'
-import { mapState as mapPiniaState } from 'pinia'
-import { mapGetters, mapState } from 'vuex'
+import { orderBy, uniqueId } from 'lodash'
import ChatMessage from 'src/components/chat_message/chat_message.vue'
@@ -34,7 +32,6 @@ const ChatMessageList = {
const date = new Date(message.created_at)
const olderMessage = messages[index - 1]
- const newerMessage = messages[index + 1]
const newerItem = acc[acc.length - 1]
const diff = olderMessage
diff --git a/src/components/chat_view/chat_view.js b/src/components/chat_view/chat_view.js
index 2df1a0c5e..8cdb3535f 100644
--- a/src/components/chat_view/chat_view.js
+++ b/src/components/chat_view/chat_view.js
@@ -1,7 +1,7 @@
-import { throttle } from 'lodash'
-import { nextTick } from 'vue'
+import { maxBy, minBy, sortBy, throttle } from 'lodash'
import { mapState as mapPiniaState } from 'pinia'
-import { mapGetters, mapState } from 'vuex'
+import { nextTick } from 'vue'
+import { mapState } from 'vuex'
import ChatMessageList from 'src/components/chat_message_list/chat_message_list.vue'
import ChatTitle from 'src/components/chat_title/chat_title.vue'
@@ -15,16 +15,17 @@ import {
isScrollable,
} from './chat_layout_utils.js'
+import { useChatsStore } from 'src/stores/chats.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useOAuthStore } from 'src/stores/oauth.js'
import {
chatMessages,
+ deleteChatMessage,
getOrCreateChat,
readChat,
sendChatMessage,
- deleteChatMessage,
} from 'src/api/chats.js'
import { WSConnectionStatus } from 'src/api/websocket.js'
@@ -215,7 +216,7 @@ const Chat = {
credentials: useOAuthStore().token,
})
- this.$store.commit('readChat', { id: this.chat.id, lastId: lastReadId })
+ useChatsStore().readChat(this.chat.id)
},
bottomedOut(offset) {
return isBottomedOut(offset)
@@ -378,7 +379,10 @@ const Chat = {
// Sanity check
if (message.chat_id !== this.chat.id) {
- console.warn(`Chat message doesn't belong to current chat (id: ${this.chat.id})!!`, message)
+ console.warn(
+ `Chat message doesn't belong to current chat (id: ${this.chat.id})!!`,
+ message,
+ )
return
}
@@ -386,7 +390,10 @@ const Chat = {
if (message.idempotency_key) {
if (this.pendingMessagesIndex[message.idempotencyKeyIndex]) {
delete this.pendingMessagesIndex[message.idempotencyKeyIndex]
- this.pendingMessages = this.pendingMessages.filter(({ idempotency_key }) => idempotency_key !== message.idempotency_key)
+ this.pendingMessages = this.pendingMessages.filter(
+ ({ idempotency_key }) =>
+ idempotency_key !== message.idempotency_key,
+ )
}
}
@@ -445,7 +452,7 @@ const Chat = {
retriesLeft: MAX_RETRIES,
})
},
- async doSendMessage({ params, pendingId, retriesLeft = MAX_RETRIES }) {
+ async doSendMessage({ params, retriesLeft = MAX_RETRIES }) {
if (retriesLeft <= 0) return
try {
@@ -458,7 +465,11 @@ const Chat = {
messages: [{ ...data }],
})
} catch (error) {
- if (error.name !== 'StatusCodeError' || error.message === 'Failed to fetch') throw error
+ if (
+ error.name !== 'StatusCodeError' ||
+ error.message === 'Failed to fetch'
+ )
+ throw error
console.error('Error sending message', error)
this.handleMessageError({
@@ -471,11 +482,10 @@ const Chat = {
(error.statusCode >= 500 && error.statusCode < 600) ||
error.message === 'Failed to fetch'
) {
- this.messageRetriers[fakeMessage.id] = setTimeout(
+ this.messageRetriers[params.idempotencyKey] = setTimeout(
() => {
this.doSendMessage({
params,
- fakeMessage,
retriesLeft: retriesLeft - 1,
})
},
@@ -484,7 +494,7 @@ const Chat = {
}
}
},
- handleMessageError(idempotencyKey, isRetry) {
+ handleMessageError(idempotencyKey, isRetry) {
const fakeMessage = this.pendingMessagesIndex[idempotencyKey]
if (fakeMessage) {
diff --git a/src/components/extra_notifications/extra_notifications.js b/src/components/extra_notifications/extra_notifications.js
index 31ca57aaa..24ed074af 100644
--- a/src/components/extra_notifications/extra_notifications.js
+++ b/src/components/extra_notifications/extra_notifications.js
@@ -1,7 +1,8 @@
-import { mapState as mapPiniaState } from 'pinia'
+import { mapState } from 'pinia'
import { mapGetters } from 'vuex'
import { useAnnouncementsStore } from 'src/stores/announcements.js'
+import { useChatsStore } from 'src/stores/chats.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
@@ -21,7 +22,7 @@ const ExtraNotifications = {
return (
this.mergedConfig.showExtraNotifications &&
this.mergedConfig.showChatsInExtraNotifications &&
- this.unreadChatCount
+ this.unreadChatsCount
)
},
shouldShowAnnouncements() {
@@ -53,11 +54,12 @@ const ExtraNotifications = {
currentUser() {
return this.$store.state.users.currentUser
},
- ...mapGetters(['unreadChatCount', 'followRequestCount']),
- ...mapPiniaState(useAnnouncementsStore, {
+ ...mapGetters(['followRequestCount']),
+ ...mapState(useAnnouncementsStore, {
unreadAnnouncementCount: 'unreadAnnouncementCount',
}),
- ...mapPiniaState(useMergedConfigStore, ['mergedConfig']),
+ ...mapState(useMergedConfigStore, ['mergedConfig']),
+ ...mapState(useChatsStore, ['unreadChatsCount']),
},
methods: {
openNotificationSettings() {
diff --git a/src/components/extra_notifications/extra_notifications.vue b/src/components/extra_notifications/extra_notifications.vue
index 5728dc98f..fc2516815 100644
--- a/src/components/extra_notifications/extra_notifications.vue
+++ b/src/components/extra_notifications/extra_notifications.vue
@@ -14,7 +14,7 @@
class="fa-scale-110 icon"
icon="comments"
/>
- {{ $t('notifications.unread_chats', { num: unreadChatCount }, unreadChatCount) }}
+ {{ $t('notifications.unread_chats', { num: unreadChatsCount }, unreadChatsCount) }}
- new Set(store.prefsStorage.collections.pinnedNavItems).has('chats'),
- }),
shouldConfirmLogout() {
return useMergedConfigStore().mergedConfig.modalOnLogout
},
closingDrawerMarksAsSeen() {
return useMergedConfigStore().mergedConfig.closingDrawerMarksAsSeen
},
- ...mapGetters(['unreadChatCount']),
+ ...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']),
+ ...mapState(useMergedConfigStore, {
+ pinnedItems: (store) =>
+ new Set(store.prefsStorage.collections.pinnedNavItems).has('chats'),
+ }),
+ ...mapState(useChatsStore, ['unreadChatsCount']),
},
methods: {
toggleMobileSidebar() {
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index 743b7deb0..8cdb70a1a 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -19,7 +19,7 @@
icon="bars"
/>
diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js
index ae6264217..5a4a78ec4 100644
--- a/src/components/nav_panel/nav_panel.js
+++ b/src/components/nav_panel/nav_panel.js
@@ -1,5 +1,5 @@
import { mapState as mapPiniaState } from 'pinia'
-import { mapGetters, mapState } from 'vuex'
+import { mapState } from 'vuex'
import BookmarkFoldersMenuContent from 'src/components/bookmark_folders_menu/bookmark_folders_menu_content.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue'
@@ -10,6 +10,7 @@ import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
import NavigationPins from 'src/components/navigation/navigation_pins.vue'
import { useAnnouncementsStore } from 'src/stores/announcements'
+import { useChatsStore } from 'src/stores/chats.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
@@ -131,6 +132,7 @@ const NavPanel = {
currentUser: (state) => state.users.currentUser,
followRequestCount: (state) => state.api.followRequests.length,
}),
+ ...mapPiniaState(useChatsStore, ['unreadChatsCount']),
timelinesItems() {
return filterNavigation(
Object.entries({ ...TIMELINES })
@@ -162,7 +164,6 @@ const NavPanel = {
},
)
},
- ...mapGetters(['unreadChatCount']),
},
}
diff --git a/src/components/navigation/navigation.js b/src/components/navigation/navigation.js
index 66fb0d347..39fa2c993 100644
--- a/src/components/navigation/navigation.js
+++ b/src/components/navigation/navigation.js
@@ -76,7 +76,7 @@ export const ROOT_ITEMS = {
icon: 'comments',
label: 'nav.chats',
badgeStyle: 'notification',
- badgeGetter: 'unreadChatCount',
+ badgeGetter: 'unreadChatsCount',
criteria: ['chats'],
},
friendRequests: {
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index 49349b127..393aef639 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -1,6 +1,5 @@
import { mapState } from 'pinia'
import { computed } from 'vue'
-import { mapGetters } from 'vuex'
import ExtraNotifications from 'src/components/extra_notifications/extra_notifications.vue'
import Notification from 'src/components/notification/notification.vue'
@@ -16,6 +15,7 @@ import notificationsFetcher from '../../services/notifications_fetcher/notificat
import NotificationFilters from './notification_filters.vue'
import { useAnnouncementsStore } from 'src/stores/announcements.js'
+import { useChatsStore } from 'src/stores/chats.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
@@ -115,13 +115,14 @@ const Notifications = {
return countExtraNotifications(
this.$store,
useMergedConfigStore().mergedConfig,
+ useChatsStore().unreadChatsCount,
useAnnouncementsStore().unreadAnnouncementCount,
)
},
unseenCountTitle() {
return (
this.unseenNotifications.length +
- this.unreadChatCount +
+ this.unreadChatsCount +
this.unreadAnnouncementCount
)
},
@@ -160,7 +161,7 @@ const Notifications = {
return !this.noExtra
},
...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']),
- ...mapGetters(['unreadChatCount']),
+ ...mapState(useChatsStore, ['unreadChatsCount']),
},
mounted() {
this.scrollerRef = this.$refs.root.closest('.column.-scrollable')
diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js
index 27e9a5249..2098b3dff 100644
--- a/src/components/side_drawer/side_drawer.js
+++ b/src/components/side_drawer/side_drawer.js
@@ -12,6 +12,7 @@ import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.j
import { useInterfaceStore } from 'src/stores/interface'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useShoutStore } from 'src/stores/shout'
+import { useChatsStore } from 'src/stores/chats.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
@@ -113,7 +114,8 @@ const SideDrawer = {
sitename: (store) => store.instanceIdentity.name,
hideSitename: (store) => store.instanceIdentity.hideSitename,
}),
- ...mapGetters(['unreadChatCount', 'draftCount']),
+ ...mapState(useChatsStore, ['unreadChatsCount']),
+ ...mapGetters(['draftCount']),
},
methods: {
toggleDrawer() {
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index c034edf91..e0b7331c6 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -106,10 +106,10 @@
icon="comments"
/> {{ $t("nav.chats") }}
- {{ unreadChatCount }}
+ {{ unreadChatsCount }}
diff --git a/src/modules/api.js b/src/modules/api.js
index 232d1776d..e26336c05 100644
--- a/src/modules/api.js
+++ b/src/modules/api.js
@@ -2,6 +2,7 @@ import { Socket } from 'phoenix'
import { maybeShowChatNotification } from '../services/chat_utils/chat_utils.js'
+import { useChatsStore } from 'src/stores/chats.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useOAuthStore } from 'src/stores/oauth.js'
@@ -174,7 +175,7 @@ const api = {
) {
dispatch('stopFetchingTimeline', { timeline: 'friends' })
dispatch('stopFetchingNotifications')
- dispatch('stopFetchingChats')
+ useChatsStore().stopFetchingChats()
}
commit('resetRetryMultiplier')
commit('setMastoUserSocketStatus', WSConnectionStatus.JOINED)
diff --git a/src/modules/chats.js b/src/modules/chats.js
deleted file mode 100644
index 1b03a85c5..000000000
--- a/src/modules/chats.js
+++ /dev/null
@@ -1,141 +0,0 @@
-import { find, omitBy, orderBy, sumBy } from 'lodash'
-import { reactive } from 'vue'
-
-import { maybeShowChatNotification } from '../services/chat_utils/chat_utils.js'
-import { promiseInterval } from '../services/promise_interval/promise_interval.js'
-
-import { useOAuthStore } from 'src/stores/oauth.js'
-
-import { chats, deleteChatMessage } from 'src/api/chats.js'
-
-const emptyChatList = () => ({
- data: [],
- idStore: {},
-})
-
-const defaultState = {
- chatList: emptyChatList(),
- chatListFetcher: null,
-}
-
-const getChatById = (state, id) => {
- return find(state.chatList.data, { id })
-}
-
-const sortedChatList = (state) => {
- return orderBy(state.chatList.data, ['updated_at'], ['desc'])
-}
-
-const unreadChatCount = (state) => {
- return sumBy(state.chatList.data, 'unread')
-}
-
-const chatsModule = {
- state: { ...defaultState },
- getters: {
- sortedChatList,
- unreadChatCount,
- },
- actions: {
- // Chat list
- startFetchingChats({ dispatch, commit }) {
- const fetcher = () => dispatch('fetchChats', { latest: true })
- commit('setChatListFetcher', {
- fetcher: () => promiseInterval(fetcher, 5000),
- })
- },
- stopFetchingChats({ commit }) {
- commit('setChatListFetcher', { fetcher: undefined })
- },
- fetchChats({ dispatch, rootState }) {
- return chats({
- credentials: useOAuthStore().token,
- }).then(({ data }) => {
- dispatch('addNewChats', { chats: data })
- return chats
- })
- },
- addNewChats(store, { chats }) {
- const { commit, dispatch, rootGetters } = store
- const newChatMessageSideEffects = (chat) => {
- maybeShowChatNotification(store, chat)
- }
- commit(
- 'addNewUsers',
- chats.map((k) => k.account).filter((k) => k),
- )
- commit('addNewChats', {
- dispatch,
- chats,
- rootGetters,
- newChatMessageSideEffects,
- })
- },
- },
- mutations: {
- setChatListFetcher(state, { fetcher }) {
- const prevFetcher = state.chatListFetcher
- if (prevFetcher) {
- prevFetcher.stop()
- }
- state.chatListFetcher = fetcher && fetcher()
- },
- addNewChats(state, { chats, newChatMessageSideEffects }) {
- chats.forEach((updatedChat) => {
- const chat = getChatById(state, updatedChat.id)
-
- if (chat) {
- const isNewMessage =
- (chat.lastMessage && chat.lastMessage.id) !==
- (updatedChat.lastMessage && updatedChat.lastMessage.id)
- chat.lastMessage = updatedChat.lastMessage
- chat.unread = updatedChat.unread
- chat.updated_at = updatedChat.updated_at
- if (isNewMessage && chat.unread) {
- newChatMessageSideEffects(updatedChat)
- }
- } else {
- state.chatList.data.push(updatedChat)
- state.chatList.idStore[updatedChat.id] = updatedChat
- }
- })
- },
- updateChat(state, { chat: updatedChat }) {
- const chat = getChatById(state, updatedChat.id)
- if (chat) {
- chat.lastMessage = updatedChat.lastMessage
- chat.unread = updatedChat.unread
- chat.updated_at = updatedChat.updated_at
- }
- if (!chat) {
- state.chatList.data.unshift(updatedChat)
- }
- state.chatList.idStore[updatedChat.id] = updatedChat
- },
- deleteChat(state, { id }) {
- state.chats.data = state.chats.data.filter(
- (conversation) => conversation.last_status.id !== id,
- )
- state.chats.idStore = omitBy(
- state.chats.idStore,
- (conversation) => conversation.last_status.id === id,
- )
- },
- resetChats(state, { commit }) {
- state.chatList = emptyChatList()
- state.currentChatId = null
- commit('setChatListFetcher', { fetcher: undefined })
- },
- setChatsLoading(state, { value }) {
- state.chats.loading = value
- },
- readChat(state, { id, lastReadId }) {
- const chat = getChatById(state, id)
- if (chat) {
- chat.unread = 0
- }
- },
- },
-}
-
-export default chatsModule
diff --git a/src/modules/index.js b/src/modules/index.js
index e42260c06..c8f3dce39 100644
--- a/src/modules/index.js
+++ b/src/modules/index.js
@@ -1,5 +1,4 @@
import api from './api.js'
-import chats from './chats.js'
import drafts from './drafts.js'
import notifications from './notifications.js'
import profileConfig from './profileConfig.js'
@@ -13,5 +12,4 @@ export default {
api,
profileConfig,
drafts,
- chats,
}
diff --git a/src/modules/users.js b/src/modules/users.js
index d6b1adaaa..db3811827 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -21,6 +21,7 @@ import {
import { useAnnouncementsStore } from 'src/stores/announcements.js'
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js'
+import { useChatsStore } from 'src/stores/chats.js'
import { useEmojiStore } from 'src/stores/emoji.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
@@ -725,7 +726,7 @@ const users = {
store.dispatch('stopFetchingFollowRequests')
store.commit('clearNotifications')
store.commit('resetStatuses')
- store.dispatch('resetChats')
+ useChatsStore().resetChats()
oauth.clearToken()
Cookies.remove('__Host-pleroma_key', { path: '/' })
useInterfaceStore().setLastTimeline('public-timeline')
diff --git a/src/services/chat_utils/chat_utils.js b/src/services/chat_utils/chat_utils.js
index 6d3181dd1..ccf91e85c 100644
--- a/src/services/chat_utils/chat_utils.js
+++ b/src/services/chat_utils/chat_utils.js
@@ -1,10 +1,8 @@
import { showDesktopNotification } from '../desktop_notification_utils/desktop_notification_utils.js'
-export const maybeShowChatNotification = (store, chat) => {
+export const maybeShowChatNotification = (chat) => {
if (!chat.lastMessage) return
- if (store.rootState.chats.currentChatId === chat.id && !document.hidden)
- return
- if (store.rootState.users.currentUser.id === chat.lastMessage.account_id)
+ if (window.vuex.state.users.currentUser.id === chat.lastMessage.account_id)
return
const opts = {
@@ -21,7 +19,7 @@ export const maybeShowChatNotification = (store, chat) => {
opts.image = chat.lastMessage.attachment.preview_url
}
- showDesktopNotification(store.rootState, opts)
+ showDesktopNotification(window.vuex.state, opts)
}
export const buildFakeMessage = ({
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
index 37e5e95ad..6cb3dbc19 100644
--- a/src/services/notification_utils/notification_utils.js
+++ b/src/services/notification_utils/notification_utils.js
@@ -191,6 +191,7 @@ export const prepareNotificationObject = (notification, i18n) => {
export const countExtraNotifications = (
store,
mergedConfig,
+ unreadChatsCount,
unreadAnnouncementCount,
) => {
const rootGetters = store.rootGetters || store.getters
@@ -200,9 +201,7 @@ export const countExtraNotifications = (
}
return [
- mergedConfig.showChatsInExtraNotifications
- ? rootGetters.unreadChatCount
- : 0,
+ mergedConfig.showChatsInExtraNotifications ? unreadChatsCount : 0,
mergedConfig.showAnnouncementsInExtraNotifications
? unreadAnnouncementCount
: 0,
diff --git a/src/stores/chats.js b/src/stores/chats.js
new file mode 100644
index 000000000..bc5b7f101
--- /dev/null
+++ b/src/stores/chats.js
@@ -0,0 +1,114 @@
+import { find, omitBy, orderBy, sumBy } from 'lodash'
+import { defineStore } from 'pinia'
+
+import { maybeShowChatNotification } from '../services/chat_utils/chat_utils.js'
+import { promiseInterval } from '../services/promise_interval/promise_interval.js'
+
+import { useOAuthStore } from 'src/stores/oauth.js'
+
+import { chats } from 'src/api/chats.js'
+
+const emptyChatList = () => ({
+ data: [],
+ idStore: {},
+})
+
+const defaultState = {
+ chatList: emptyChatList(),
+ chatListFetcher: null,
+}
+
+const getChatById = (state, id) => {
+ return find(state.chatList.data, { id })
+}
+
+export const useChatsStore = defineStore('chats', {
+ state: () => ({ ...defaultState }),
+ getters: {
+ sortedChatList(state) {
+ return orderBy(state.chatList.data, ['updated_at'], ['desc'])
+ },
+ unreadChatsCount(state) {
+ return sumBy(state.chatList.data, 'unread')
+ },
+ },
+ actions: {
+ startFetchingChats() {
+ const fetcher = () => this.fetchChats()
+ this.setChatListFetcher(() => promiseInterval(fetcher, 5000))
+ },
+ stopFetchingChats() {
+ this.setChatListFetcher(null)
+ },
+ async fetchChats() {
+ const { data } = await chats({
+ credentials: useOAuthStore().token,
+ })
+
+ this.addNewChats(data)
+ },
+ setChatListFetcher(fetcher) {
+ const prevFetcher = this.chatListFetcher
+ if (prevFetcher) {
+ prevFetcher.stop()
+ }
+ this.chatListFetcher = fetcher?.()
+ },
+ resetChats() {
+ this.chatList = emptyChatList()
+ this.setChatListFetcher(null)
+ },
+ addNewChats(chats) {
+ window.vuex.commit(
+ 'addNewUsers',
+ chats.map((k) => k.account).filter((k) => k),
+ )
+
+ chats.forEach((updatedChat) => {
+ const chat = getChatById(this, updatedChat.id)
+
+ if (chat) {
+ const isNewMessage =
+ (chat.lastMessage && chat.lastMessage.id) !==
+ (updatedChat.lastMessage && updatedChat.lastMessage.id)
+ chat.lastMessage = updatedChat.lastMessage
+ chat.unread = updatedChat.unread
+ chat.updated_at = updatedChat.updated_at
+ if (isNewMessage && chat.unread) {
+ maybeShowChatNotification(chat)
+ }
+ } else {
+ this.chatList.data.push(updatedChat)
+ this.chatList.idStore[updatedChat.id] = updatedChat
+ }
+ })
+ },
+ readChat(id) {
+ const chat = getChatById(this, id)
+ if (chat) {
+ chat.unread = 0
+ }
+ },
+ updateChat({ chat: updatedChat }) {
+ const chat = getChatById(this, updatedChat.id)
+ if (chat) {
+ chat.lastMessage = updatedChat.lastMessage
+ chat.unread = updatedChat.unread
+ chat.updated_at = updatedChat.updated_at
+ }
+ if (!chat) {
+ this.chatList.data.unshift(updatedChat)
+ }
+ this.chatList.idStore[updatedChat.id] = updatedChat
+ },
+ deleteChat(id) {
+ this.chats.data = this.chats.data.filter(
+ (conversation) => conversation.last_status.id !== id,
+ )
+ this.chats.idStore = omitBy(
+ this.chats.idStore,
+ (conversation) => conversation.last_status.id === id,
+ )
+ },
+ },
+})