From 55917125a89e4647fd942ed735015f4f8c9a32ed Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 7 Jul 2026 20:44:13 +0300 Subject: [PATCH] refactored chat into separate chat_view and chat_message_list --- src/boot/routes.js | 2 +- src/components/chat_message/chat_message.js | 20 +++-- src/components/chat_message/chat_message.vue | 6 +- .../chat_message_list/chat_message_list.js | 76 +++++++++++++++++++ .../chat_message_list/chat_message_list.scss | 7 ++ .../chat_message_list/chat_message_list.vue | 14 ++++ .../{chat => chat_view}/chat_layout_utils.js | 0 .../{chat/chat.js => chat_view/chat_view.js} | 17 +++-- .../chat.scss => chat_view/chat_view.scss} | 0 .../chat_view.style.js} | 2 +- .../chat.vue => chat_view/chat_view.vue} | 28 +------ src/services/chat_service/chat_service.js | 51 ------------- 12 files changed, 127 insertions(+), 96 deletions(-) create mode 100644 src/components/chat_message_list/chat_message_list.js create mode 100644 src/components/chat_message_list/chat_message_list.scss create mode 100644 src/components/chat_message_list/chat_message_list.vue rename src/components/{chat => chat_view}/chat_layout_utils.js (100%) rename src/components/{chat/chat.js => chat_view/chat_view.js} (97%) rename src/components/{chat/chat.scss => chat_view/chat_view.scss} (100%) rename src/components/{chat/chat.style.js => chat_view/chat_view.style.js} (86%) rename src/components/{chat/chat.vue => chat_view/chat_view.vue} (71%) diff --git a/src/boot/routes.js b/src/boot/routes.js index 9b00a8004..4f21246e5 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -294,7 +294,7 @@ export default (store) => { name: 'chat', path: '/users/:username/chats/:recipient_id', component: defineAsyncComponent( - () => import('src/components/chat/chat.vue'), + () => import('src/components/chat_view/chat_view.vue'), ), meta: { dontScroll: false }, beforeEnter: validateAuthenticatedRoute, diff --git a/src/components/chat_message/chat_message.js b/src/components/chat_message/chat_message.js index 2066a8194..e5a798fef 100644 --- a/src/components/chat_message/chat_message.js +++ b/src/components/chat_message/chat_message.js @@ -22,10 +22,9 @@ library.add(faTimes, faEllipsisH) const ChatMessage = { name: 'ChatMessage', props: [ - 'author', 'edited', 'noHeading', - 'chatViewItem', + 'chatItem', 'hoveredMessageChain', ], emits: ['hover'], @@ -42,21 +41,26 @@ const ChatMessage = { computed: { // Returns HH:MM (hours and minutes) in local time. createdAt() { - const time = this.chatViewItem.data.created_at + const time = this.chatItem.data.created_at return time.toLocaleTimeString('en', { hour: '2-digit', minute: '2-digit', hour12: false, }) }, + author() { + return this.$store.getters.findUser( + this.chatItem.data.account_id + ) + }, isCurrentUser() { return this.message.account_id === this.currentUser.id }, message() { - return this.chatViewItem.data + return this.chatItem.data }, isMessage() { - return this.chatViewItem.type === 'message' + return this.chatItem.type === 'message' }, messageForStatusContent() { return { @@ -96,15 +100,15 @@ const ChatMessage = { onHover(bool) { this.$emit('hover', { isHovered: bool, - messageChainId: this.chatViewItem.messageChainId, + messageChainId: this.chatItem.messageChainId, }) }, async deleteMessage() { const confirmed = window.confirm(this.$t('chats.delete_confirm')) if (confirmed) { await this.$store.dispatch('deleteChatMessage', { - messageId: this.chatViewItem.data.id, - chatId: this.chatViewItem.data.chat_id, + messageId: this.chatItem.data.id, + chatId: this.chatItem.data.chat_id, }) } this.hovered = false diff --git a/src/components/chat_message/chat_message.vue b/src/components/chat_message/chat_message.vue index 22e2e8eb8..ee3cbdc2c 100644 --- a/src/components/chat_message/chat_message.vue +++ b/src/components/chat_message/chat_message.vue @@ -15,7 +15,7 @@ class="avatar-wrapper" >
- +
diff --git a/src/components/chat_message_list/chat_message_list.js b/src/components/chat_message_list/chat_message_list.js new file mode 100644 index 000000000..ffbedf7c0 --- /dev/null +++ b/src/components/chat_message_list/chat_message_list.js @@ -0,0 +1,76 @@ +import { throttle, orderBy, uniqueId } from 'lodash' +import { mapState as mapPiniaState } from 'pinia' +import { mapGetters, mapState } from 'vuex' + +import ChatMessage from 'src/components/chat_message/chat_message.vue' + +const ChatMessageList = { + components: { + ChatMessage, + }, + props: { + messages: Array, + }, + data() { + return { + hoveredMessageChainId: undefined, + } + }, + computed: { + chatItems() { + const messages = orderBy(this.messages, ['pending', 'id'], ['asc', 'asc']) + return messages.reduceRight((acc, message, index) => { + 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 = message.created_at - (olderMessage?.created_at || 0) + const MAX_DIFF = 1000 * 60 // 5 minutes + + const chatItem = { + type: 'message', + data: message, + date, + id: message.id, + isTail: true, + isHead: true, + } + + if (newerItem == null) { + chatItem.messageChainId = uniqueId() + } else { + if (newerItem.type === 'date') { + chatItem.messageChainId = uniqueId() + } else if (newerItem.type === 'message') { + if (newerItem.data.account_id !== message.account_id) { + chatItem.messageChainId = uniqueId() + } else { + chatItem.messageChainId = newerItem.messageChainId + chatItem.isTail = false + newerItem.isHead = false + } + } + } + + if (diff > MAX_DIFF || !olderMessage) { + return [...acc, chatItem, { + type: 'date', + date, + id: date.getTime().toString(), + }] + } else { + return [...acc, chatItem] + } + }, []).reverse() + } + }, + methods: { + onMessageHover({ isHovered, messageChainId }) { + this.hoveredMessageChainId = isHovered ? messageChainId : undefined + }, + } +} + +export default ChatMessageList diff --git a/src/components/chat_message_list/chat_message_list.scss b/src/components/chat_message_list/chat_message_list.scss new file mode 100644 index 000000000..aa2313f8c --- /dev/null +++ b/src/components/chat_message_list/chat_message_list.scss @@ -0,0 +1,7 @@ +.ChatMessageList { + padding: 0 0.8em; + height: 100%; + display: flex; + flex-direction: column; + justify-content: end; +} diff --git a/src/components/chat_message_list/chat_message_list.vue b/src/components/chat_message_list/chat_message_list.vue new file mode 100644 index 000000000..b1fcd6dd6 --- /dev/null +++ b/src/components/chat_message_list/chat_message_list.vue @@ -0,0 +1,14 @@ + + + +