From e30e7afce7a0d85f374c4d293d4180b3fae23b41 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Wed, 16 Jul 2025 16:04:27 +0200 Subject: [PATCH] fix(useGetMessages): introduce composable, extract shared data Signed-off-by: Maksim Sukharev --- src/App.vue | 3 + src/PublicShareAuthSidebar.vue | 2 + src/PublicShareSidebar.vue | 2 + src/components/MessagesList/MessagesList.vue | 61 ++++++---------- src/composables/useGetMessages.ts | 73 ++++++++++++++++++++ src/views/FilesSidebarChatView.vue | 3 + 6 files changed, 106 insertions(+), 38 deletions(-) create mode 100644 src/composables/useGetMessages.ts diff --git a/src/App.vue b/src/App.vue index 0163b7a06c..917b6a5fbc 100644 --- a/src/App.vue +++ b/src/App.vue @@ -40,6 +40,7 @@ import SettingsDialog from './components/SettingsDialog/SettingsDialog.vue' import ConfirmDialog from './components/UIShared/ConfirmDialog.vue' import { useActiveSession } from './composables/useActiveSession.js' import { useDocumentTitle } from './composables/useDocumentTitle.ts' +import { useGetMessagesProvider } from './composables/useGetMessages.ts' import { useGetToken } from './composables/useGetToken.ts' import { useHashCheck } from './composables/useHashCheck.js' import { useIsInCall } from './composables/useIsInCall.js' @@ -72,6 +73,8 @@ export default { setup() { useDocumentTitle() + // Provide context for MessagesList mounted in different places + useGetMessagesProvider() // Add provided value to check if we're in the main app or plugin provide('Talk:isMainApp', true) diff --git a/src/PublicShareAuthSidebar.vue b/src/PublicShareAuthSidebar.vue index 29febd7cf6..029bebd1d5 100644 --- a/src/PublicShareAuthSidebar.vue +++ b/src/PublicShareAuthSidebar.vue @@ -36,6 +36,7 @@ import PollViewer from './components/PollViewer/PollViewer.vue' import InternalSignalingHint from './components/RightSidebar/InternalSignalingHint.vue' import TopBar from './components/TopBar/TopBar.vue' import TransitionWrapper from './components/UIShared/TransitionWrapper.vue' +import { useGetMessagesProvider } from './composables/useGetMessages.ts' import { useGetToken } from './composables/useGetToken.ts' import { useHashCheck } from './composables/useHashCheck.js' import { useSessionIssueHandler } from './composables/useSessionIssueHandler.ts' @@ -65,6 +66,7 @@ export default { setup() { useHashCheck() + useGetMessagesProvider() return { isLeavingAfterSessionIssue: useSessionIssueHandler(), diff --git a/src/PublicShareSidebar.vue b/src/PublicShareSidebar.vue index 974074acc9..233bd61c68 100644 --- a/src/PublicShareSidebar.vue +++ b/src/PublicShareSidebar.vue @@ -50,6 +50,7 @@ import InternalSignalingHint from './components/RightSidebar/InternalSignalingHi import CallButton from './components/TopBar/CallButton.vue' import TopBar from './components/TopBar/TopBar.vue' import TransitionWrapper from './components/UIShared/TransitionWrapper.vue' +import { useGetMessagesProvider } from './composables/useGetMessages.ts' import { useGetToken } from './composables/useGetToken.ts' import { useHashCheck } from './composables/useHashCheck.js' import { useIsInCall } from './composables/useIsInCall.js' @@ -96,6 +97,7 @@ export default { setup() { useHashCheck() + useGetMessagesProvider() return { isInCall: useIsInCall(), diff --git a/src/components/MessagesList/MessagesList.vue b/src/components/MessagesList/MessagesList.vue index 249c66392f..3c3c055739 100644 --- a/src/components/MessagesList/MessagesList.vue +++ b/src/components/MessagesList/MessagesList.vue @@ -82,6 +82,7 @@ import TransitionWrapper from '../UIShared/TransitionWrapper.vue' import MessagesGroup from './MessagesGroup/MessagesGroup.vue' import MessagesSystemGroup from './MessagesGroup/MessagesSystemGroup.vue' import { useDocumentVisibility } from '../../composables/useDocumentVisibility.ts' +import { useGetMessages } from '../../composables/useGetMessages.ts' import { useGetThreadId } from '../../composables/useGetThreadId.ts' import { useIsInCall } from '../../composables/useIsInCall.js' import { ATTENDEE, CHAT, CONVERSATION, MESSAGE } from '../../constants.ts' @@ -133,6 +134,18 @@ export default { emits: ['update:isChatScrolledToBottom'], setup(props) { + const { + pollingErrorTimeout, + loadingOldMessages, + isInitialisingMessages, + destroying, + stopFetchingOldMessages, + isParticipant, + isInLobby, + chatIdentifier, + isChatBeginningReached, + } = useGetMessages() + const isDocumentVisible = useDocumentVisibility() const isChatVisible = computed(() => isDocumentVisible.value && props.isVisible) const threadId = useGetThreadId() @@ -142,6 +155,16 @@ export default { chatExtrasStore: useChatExtrasStore(), isChatVisible, threadId, + + pollingErrorTimeout, + loadingOldMessages, + isInitialisingMessages, + destroying, + stopFetchingOldMessages, + isParticipant, + isInLobby, + chatIdentifier, + isChatBeginningReached, } }, @@ -163,24 +186,14 @@ export default { */ previousScrollTopValue: null, - pollingErrorTimeout: 1, - - loadingOldMessages: false, - - isInitialisingMessages: false, - isFocusingMessage: false, - destroying: false, - expirationInterval: null, debounceUpdateReadMarkerPosition: () => {}, debounceHandleScroll: () => {}, - stopFetchingOldMessages: false, - isScrolling: null, stickyDate: null, @@ -242,41 +255,13 @@ export default { return this.$store.getters.hasMoreMessagesToLoad(this.token) }, - /** - * Returns whether the current participant is a participant of the - * current conversation or not. - * - * @return {boolean} true if it is already a participant, false - * otherwise. - */ - isParticipant() { - if (!this.conversation) { - return false - } - - return !!this.$store.getters.findParticipant(this.token, this.conversation)?.attendeeId - }, - - isInLobby() { - return this.$store.getters.isInLobby - }, - conversation() { return this.$store.getters.conversation(this.token) }, - chatIdentifier() { - return this.token + ':' + this.isParticipant - }, - currentDay() { return convertToUnix(new Date().setHours(0, 0, 0, 0)) }, - - isChatBeginningReached() { - return this.stopFetchingOldMessages || (this.messagesList?.[0]?.messageType === MESSAGE.TYPE.SYSTEM - && ['conversation_created', 'history_cleared'].includes(this.messagesList[0].systemMessage)) - }, }, watch: { diff --git a/src/composables/useGetMessages.ts b/src/composables/useGetMessages.ts new file mode 100644 index 0000000000..576a0fbbba --- /dev/null +++ b/src/composables/useGetMessages.ts @@ -0,0 +1,73 @@ +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import type { + ChatMessage, + Conversation, +} from '../types/index.ts' + +import { computed, ref } from 'vue' +import { useStore } from 'vuex' +import { MESSAGE } from '../constants.ts' +import { useGetToken } from './useGetToken.ts' + +/** + * Composable to provide control logic for fetching messages list + */ +export function useGetMessagesProvider() { + const store = useStore() + const currentToken = useGetToken() + const conversation = computed(() => store.getters.conversation(currentToken.value)) + const isInLobby = computed(() => store.getters.isInLobby) + + const pollingErrorTimeout = ref(1) + const destroying = ref(false) + + const loadingOldMessages = ref(false) + const isInitialisingMessages = ref(false) + const stopFetchingOldMessages = ref(false) + + /** + * Returns whether the current participant is a participant of current conversation. + */ + const isParticipant = computed(() => { + if (!conversation.value) { + return false + } + + return !!store.getters.findParticipant(currentToken.value, conversation.value)?.attendeeId + }) + + const chatIdentifier = computed(() => currentToken.value + ':' + isParticipant.value) + + const firstKnownMessage = computed(() => { + return store.getters.message(currentToken.value, store.getters.getFirstKnownMessageId(currentToken.value)) + }) + const isChatBeginningReached = computed(() => { + return stopFetchingOldMessages.value || (!!firstKnownMessage.value + && firstKnownMessage.value.messageType === MESSAGE.TYPE.SYSTEM + && ['conversation_created', 'history_cleared'].includes(firstKnownMessage.value.systemMessage)) + }) + + return { + pollingErrorTimeout, + loadingOldMessages, + isInitialisingMessages, + destroying, + stopFetchingOldMessages, + isParticipant, + isInLobby, + chatIdentifier, + isChatBeginningReached, + } +} + +/** + * Composable to inject control logic for fetching messages list in the component + */ +export function useGetMessages() { + // FIXME + return useGetMessagesProvider() +} diff --git a/src/views/FilesSidebarChatView.vue b/src/views/FilesSidebarChatView.vue index 0cdd67cf1b..1de748a4bc 100644 --- a/src/views/FilesSidebarChatView.vue +++ b/src/views/FilesSidebarChatView.vue @@ -24,6 +24,7 @@ import PollManager from '../components/PollViewer/PollManager.vue' import PollViewer from '../components/PollViewer/PollViewer.vue' import InternalSignalingHint from '../components/RightSidebar/InternalSignalingHint.vue' import CallButton from '../components/TopBar/CallButton.vue' +import { useGetMessagesProvider } from '../composables/useGetMessages.ts' import { useGetToken } from '../composables/useGetToken.ts' import { useIsInCall } from '../composables/useIsInCall.js' @@ -42,6 +43,8 @@ export default { }, setup() { + useGetMessagesProvider() + return { isInCall: useIsInCall(), token: useGetToken(),