perf: reduce redundant chat rerenders
This commit is contained in:
Vendored
+1
-1
@@ -1 +1 @@
|
||||
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Web IM</title><link rel="icon" href="img/5IuOieu9PF8MJtp43kD2kCkdLVjVwDp7.ico"><script src="config/runtime-config.js"></script><script defer="defer" src="js/chunk-vendors.86756863.js"></script><script defer="defer" src="js/app.5863459a.js"></script><link href="css/app.2c52dabb.css" rel="stylesheet"></head><body><noscript>请启用 JavaScript 后使用 Web IM。</noscript><div id="app"></div></body></html>
|
||||
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Web IM</title><link rel="icon" href="img/5IuOieu9PF8MJtp43kD2kCkdLVjVwDp7.ico"><script src="config/runtime-config.js"></script><script defer="defer" src="js/chunk-vendors.86756863.js"></script><script defer="defer" src="js/app.84630d8b.js"></script><link href="css/app.2c52dabb.css" rel="stylesheet"></head><body><noscript>请启用 JavaScript 后使用 Web IM。</noscript><div id="app"></div></body></html>
|
||||
Vendored
-1
File diff suppressed because one or more lines are too long
+99
-39
@@ -3026,6 +3026,12 @@ const IMAGE_MAX_SCALE = 6;
|
||||
y: 0,
|
||||
message: null
|
||||
});
|
||||
const messageTimeFormatter = new Intl.DateTimeFormat('zh-CN', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false,
|
||||
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
});
|
||||
const imageViewer = (0,vue__WEBPACK_IMPORTED_MODULE_8__/* .reactive */ .Kh)({
|
||||
visible: false,
|
||||
url: '',
|
||||
@@ -3125,20 +3131,20 @@ const IMAGE_MAX_SCALE = 6;
|
||||
});
|
||||
function scrollToBottom() {
|
||||
(0,vue__WEBPACK_IMPORTED_MODULE_6__/* .nextTick */ .dY)(() => {
|
||||
if (listEl.value) {
|
||||
const scroll = () => {
|
||||
if (listEl.value) {
|
||||
listEl.value.scrollTop = listEl.value.scrollHeight;
|
||||
}
|
||||
};
|
||||
scroll();
|
||||
requestAnimationFrame(() => {
|
||||
scroll();
|
||||
requestAnimationFrame(scroll);
|
||||
});
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
if (listEl.value) {
|
||||
listEl.value.scrollTop = listEl.value.scrollHeight;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function isNearBottom() {
|
||||
const element = listEl.value;
|
||||
if (!element) {
|
||||
return true;
|
||||
}
|
||||
return element.scrollHeight - element.scrollTop - element.clientHeight < 120;
|
||||
}
|
||||
function scrollToMessage(messageId) {
|
||||
;(0,vue__WEBPACK_IMPORTED_MODULE_6__/* .nextTick */ .dY)(() => {
|
||||
if (!listEl.value || !messageId) {
|
||||
@@ -3153,7 +3159,11 @@ const IMAGE_MAX_SCALE = 6;
|
||||
}
|
||||
});
|
||||
}
|
||||
;(0,vue__WEBPACK_IMPORTED_MODULE_6__/* .watch */ .wB)(() => props.messages.map(message => `${message.id}:${message.status}:${message.deliveryStatus || ''}:${message.messageUid || ''}:${message.recalled ? '1' : ''}`).join('|'), scrollToBottom, {
|
||||
;(0,vue__WEBPACK_IMPORTED_MODULE_6__/* .watch */ .wB)(() => props.messages.map(messageIdentity).join('|'), (nextKeys, previousKeys) => {
|
||||
if (!previousKeys || nextKeys !== previousKeys && isNearBottom()) {
|
||||
scrollToBottom();
|
||||
}
|
||||
}, {
|
||||
immediate: true
|
||||
});
|
||||
(0,vue__WEBPACK_IMPORTED_MODULE_6__/* .watch */ .wB)(() => props.attentionMessageId, scrollToMessage);
|
||||
@@ -3507,12 +3517,7 @@ const IMAGE_MAX_SCALE = 6;
|
||||
closeMenu();
|
||||
}
|
||||
function formatTime(timestamp) {
|
||||
return new Intl.DateTimeFormat('zh-CN', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false,
|
||||
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
}).format(timestamp);
|
||||
return messageTimeFormatter.format(timestamp);
|
||||
}
|
||||
function deliveryState(message) {
|
||||
if (message.direction !== 'out' || message.status === 'failed' || message.status === 'recalled' || message.recalled) {
|
||||
@@ -7653,6 +7658,25 @@ const useContactStore = (0,pinia__WEBPACK_IMPORTED_MODULE_6__/* .defineStore */
|
||||
|
||||
const LOCAL_CONVERSATION_STORAGE_KEY = 'qmt-web-im-local-conversations-v2';
|
||||
const LOCAL_FAVORITE_MESSAGES_KEY = 'qmt-web-im-favorite-messages-v1';
|
||||
const recentRealtimeNotifications = new Map();
|
||||
function isDuplicateRealtimeNotification(payload) {
|
||||
const messageId = String(payload?.messageId || '');
|
||||
if (!messageId) {
|
||||
return false;
|
||||
}
|
||||
const key = `${payload?.kind || 'message'}:${messageId}`;
|
||||
const now = Date.now();
|
||||
const previousAt = Number(recentRealtimeNotifications.get(key) || 0);
|
||||
recentRealtimeNotifications.set(key, now);
|
||||
if (recentRealtimeNotifications.size > 200) {
|
||||
recentRealtimeNotifications.forEach((seenAt, seenKey) => {
|
||||
if (now - seenAt > 30000) {
|
||||
recentRealtimeNotifications.delete(seenKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
return now - previousAt < 5000;
|
||||
}
|
||||
function scopedStorageKey(baseKey) {
|
||||
const session = (0,_stores_session__WEBPACK_IMPORTED_MODULE_22__/* .useSessionStore */ .B)();
|
||||
const scope = `${_config__WEBPACK_IMPORTED_MODULE_21__/* .appConfig */ .U.appServer || ''}:${session.userId || 'anonymous'}`;
|
||||
@@ -7693,6 +7717,16 @@ function messageStableKey(message) {
|
||||
function messageActivityTimestamp(message) {
|
||||
return Number(message?.activityTimestamp || message?.editedAt || message?.displayTimestamp || message?.timestamp || 0);
|
||||
}
|
||||
function hasSameRenderState(left, right) {
|
||||
if (left === right) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(left) === JSON.stringify(right);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function isRecalledMessage(message) {
|
||||
return Boolean(message?.recalled) || message?.status === 'recalled';
|
||||
}
|
||||
@@ -8229,6 +8263,7 @@ const useConversationStore = (0,pinia__WEBPACK_IMPORTED_MODULE_19__/* .defineSto
|
||||
if (!remote.length && this.conversations.length) {
|
||||
return;
|
||||
}
|
||||
const previousActiveId = this.activeId;
|
||||
const merged = new Map();
|
||||
this.conversations.forEach(conversation => {
|
||||
merged.set(conversation.id, conversation);
|
||||
@@ -8241,7 +8276,11 @@ const useConversationStore = (0,pinia__WEBPACK_IMPORTED_MODULE_19__/* .defineSto
|
||||
unread
|
||||
});
|
||||
});
|
||||
this.conversations = Array.from(merged.values()).map(sanitizeConversation).sort((a, b) => Number(b.updatedAt || 0) - Number(a.updatedAt || 0)).slice(0, 100);
|
||||
const nextConversations = Array.from(merged.values()).map(sanitizeConversation).sort((a, b) => Number(b.updatedAt || 0) - Number(a.updatedAt || 0)).slice(0, 100);
|
||||
const conversationsChanged = !hasSameRenderState(this.conversations, nextConversations);
|
||||
if (conversationsChanged) {
|
||||
this.conversations = nextConversations;
|
||||
}
|
||||
if (!this.conversations.length) {
|
||||
this.activeId = '';
|
||||
this.messagesByConversation = {};
|
||||
@@ -8253,8 +8292,12 @@ const useConversationStore = (0,pinia__WEBPACK_IMPORTED_MODULE_19__/* .defineSto
|
||||
if (!this.conversations.find(item => item.id === this.activeId)) {
|
||||
this.activeId = this.conversations[0].id;
|
||||
}
|
||||
writeLocalConversations(this.conversations);
|
||||
this.loadActiveMessages();
|
||||
if (conversationsChanged) {
|
||||
writeLocalConversations(this.conversations);
|
||||
}
|
||||
if (previousActiveId !== this.activeId || !this.messagesByConversation[this.activeId]) {
|
||||
this.loadActiveMessages();
|
||||
}
|
||||
},
|
||||
appendMessage(conversationId, message) {
|
||||
message = normalizeMessageForDisplay(message);
|
||||
@@ -8362,10 +8405,14 @@ const useConversationStore = (0,pinia__WEBPACK_IMPORTED_MODULE_19__/* .defineSto
|
||||
this.syncVisibleMessages(conversationId);
|
||||
},
|
||||
syncVisibleMessages(conversationId) {
|
||||
this.visibleMessagesByConversation = {
|
||||
...this.visibleMessagesByConversation,
|
||||
[conversationId]: mergeVisibleMessages(this.optimisticMessagesByConversation[conversationId] || [], this.messagesByConversation[conversationId] || [])
|
||||
};
|
||||
const currentMessages = this.visibleMessagesByConversation[conversationId] || [];
|
||||
const nextMessages = mergeVisibleMessages(this.optimisticMessagesByConversation[conversationId] || [], this.messagesByConversation[conversationId] || []);
|
||||
if (!hasSameRenderState(currentMessages, nextMessages)) {
|
||||
this.visibleMessagesByConversation = {
|
||||
...this.visibleMessagesByConversation,
|
||||
[conversationId]: nextMessages
|
||||
};
|
||||
}
|
||||
},
|
||||
keepOptimisticMessage(conversationId, message) {
|
||||
if (!this.optimisticMessagesByConversation[conversationId]) {
|
||||
@@ -8417,10 +8464,13 @@ const useConversationStore = (0,pinia__WEBPACK_IMPORTED_MODULE_19__/* .defineSto
|
||||
this.loading = true;
|
||||
const messages = _services_imClient__WEBPACK_IMPORTED_MODULE_20__/* .imClient */ .wD.getMessages(conversation, 30);
|
||||
this.pruneOptimisticMessages(conversation.id, messages);
|
||||
this.messagesByConversation = {
|
||||
...this.messagesByConversation,
|
||||
[conversation.id]: mergeVisibleMessages(this.messagesByConversation[conversation.id] || [], messages)
|
||||
};
|
||||
const nextMessages = mergeVisibleMessages(this.messagesByConversation[conversation.id] || [], messages);
|
||||
if (!hasSameRenderState(this.messagesByConversation[conversation.id] || [], nextMessages)) {
|
||||
this.messagesByConversation = {
|
||||
...this.messagesByConversation,
|
||||
[conversation.id]: nextMessages
|
||||
};
|
||||
}
|
||||
this.syncVisibleMessages(conversation.id);
|
||||
this.loading = false;
|
||||
this.syncActiveMessages(syncOptions);
|
||||
@@ -8462,10 +8512,13 @@ const useConversationStore = (0,pinia__WEBPACK_IMPORTED_MODULE_19__/* .defineSto
|
||||
}
|
||||
const editedIncomingMessages = incomingEditedMessages(previousMessages, messages);
|
||||
this.pruneOptimisticMessages(syncedConversationId, messages);
|
||||
this.messagesByConversation = {
|
||||
...this.messagesByConversation,
|
||||
[syncedConversationId]: mergeVisibleMessages(this.messagesByConversation[syncedConversationId] || [], messages)
|
||||
};
|
||||
const nextMessages = mergeVisibleMessages(this.messagesByConversation[syncedConversationId] || [], messages);
|
||||
if (!hasSameRenderState(this.messagesByConversation[syncedConversationId] || [], nextMessages)) {
|
||||
this.messagesByConversation = {
|
||||
...this.messagesByConversation,
|
||||
[syncedConversationId]: nextMessages
|
||||
};
|
||||
}
|
||||
this.syncVisibleMessages(syncedConversationId);
|
||||
if (editedIncomingMessages.length && syncedConversationId === this.activeId) {
|
||||
this.focusMessage(editedIncomingMessages.sort((a, b) => messageActivityTimestamp(b) - messageActivityTimestamp(a))[0]);
|
||||
@@ -8478,9 +8531,13 @@ const useConversationStore = (0,pinia__WEBPACK_IMPORTED_MODULE_19__/* .defineSto
|
||||
return latestMessage;
|
||||
}, null);
|
||||
if (latest) {
|
||||
conversation.subtitle = messagePreviewText(latest);
|
||||
conversation.updatedAt = messageActivityTimestamp(latest);
|
||||
writeLocalConversations(this.conversations);
|
||||
const nextSubtitle = messagePreviewText(latest);
|
||||
const nextUpdatedAt = messageActivityTimestamp(latest);
|
||||
if (conversation.subtitle !== nextSubtitle || Number(conversation.updatedAt || 0) !== nextUpdatedAt) {
|
||||
conversation.subtitle = nextSubtitle;
|
||||
conversation.updatedAt = nextUpdatedAt;
|
||||
writeLocalConversations(this.conversations);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Keep the local view usable if a polling request misses.
|
||||
@@ -8536,7 +8593,10 @@ const useConversationStore = (0,pinia__WEBPACK_IMPORTED_MODULE_19__/* .defineSto
|
||||
this.refreshRemoteConversations();
|
||||
}
|
||||
},
|
||||
handleRealtimeNotification() {
|
||||
handleRealtimeNotification(payload) {
|
||||
if (isDuplicateRealtimeNotification(payload)) {
|
||||
return;
|
||||
}
|
||||
window.clearTimeout(this.realtimeSyncTimer);
|
||||
this.realtimeSyncTimer = window.setTimeout(() => {
|
||||
this.refreshRemoteConversations();
|
||||
@@ -9749,4 +9809,4 @@ const __exports__ = _NavigationRail_vue_vue_type_script_setup_true_lang_js__WEBP
|
||||
/******/
|
||||
/******/ })()
|
||||
;
|
||||
//# sourceMappingURL=app.5863459a.js.map
|
||||
//# sourceMappingURL=app.84630d8b.js.map
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
@@ -259,6 +259,12 @@ const contextMenu = reactive({
|
||||
});
|
||||
const IMAGE_MIN_SCALE = 0.5;
|
||||
const IMAGE_MAX_SCALE = 6;
|
||||
const messageTimeFormatter = new Intl.DateTimeFormat('zh-CN', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false,
|
||||
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
});
|
||||
const imageViewer = reactive({
|
||||
visible: false,
|
||||
url: '',
|
||||
@@ -332,21 +338,22 @@ const menuItems = computed(() => {
|
||||
|
||||
function scrollToBottom() {
|
||||
nextTick(() => {
|
||||
if (listEl.value) {
|
||||
const scroll = () => {
|
||||
if (listEl.value) {
|
||||
listEl.value.scrollTop = listEl.value.scrollHeight;
|
||||
}
|
||||
};
|
||||
scroll();
|
||||
requestAnimationFrame(() => {
|
||||
scroll();
|
||||
requestAnimationFrame(scroll);
|
||||
});
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
if (listEl.value) {
|
||||
listEl.value.scrollTop = listEl.value.scrollHeight;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function isNearBottom() {
|
||||
const element = listEl.value;
|
||||
if (!element) {
|
||||
return true;
|
||||
}
|
||||
return element.scrollHeight - element.scrollTop - element.clientHeight < 120;
|
||||
}
|
||||
|
||||
function scrollToMessage(messageId) {
|
||||
nextTick(() => {
|
||||
if (!listEl.value || !messageId) {
|
||||
@@ -361,8 +368,12 @@ function scrollToMessage(messageId) {
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.messages.map(message => `${message.id}:${message.status}:${message.deliveryStatus || ''}:${message.messageUid || ''}:${message.recalled ? '1' : ''}`).join('|'),
|
||||
scrollToBottom,
|
||||
() => props.messages.map(messageIdentity).join('|'),
|
||||
(nextKeys, previousKeys) => {
|
||||
if (!previousKeys || (nextKeys !== previousKeys && isNearBottom())) {
|
||||
scrollToBottom();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
@@ -762,12 +773,7 @@ function chooseMenuAction(action) {
|
||||
}
|
||||
|
||||
function formatTime(timestamp) {
|
||||
return new Intl.DateTimeFormat('zh-CN', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false,
|
||||
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
}).format(timestamp);
|
||||
return messageTimeFormatter.format(timestamp);
|
||||
}
|
||||
|
||||
function deliveryState(message) {
|
||||
|
||||
+82
-22
@@ -6,6 +6,26 @@ import { realtimeNotifications } from '@/services/realtimeNotifications';
|
||||
|
||||
const LOCAL_CONVERSATION_STORAGE_KEY = 'qmt-web-im-local-conversations-v2';
|
||||
const LOCAL_FAVORITE_MESSAGES_KEY = 'qmt-web-im-favorite-messages-v1';
|
||||
const recentRealtimeNotifications = new Map();
|
||||
|
||||
function isDuplicateRealtimeNotification(payload) {
|
||||
const messageId = String(payload?.messageId || '');
|
||||
if (!messageId) {
|
||||
return false;
|
||||
}
|
||||
const key = `${payload?.kind || 'message'}:${messageId}`;
|
||||
const now = Date.now();
|
||||
const previousAt = Number(recentRealtimeNotifications.get(key) || 0);
|
||||
recentRealtimeNotifications.set(key, now);
|
||||
if (recentRealtimeNotifications.size > 200) {
|
||||
recentRealtimeNotifications.forEach((seenAt, seenKey) => {
|
||||
if (now - seenAt > 30000) {
|
||||
recentRealtimeNotifications.delete(seenKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
return now - previousAt < 5000;
|
||||
}
|
||||
|
||||
function scopedStorageKey(baseKey) {
|
||||
const session = useSessionStore();
|
||||
@@ -56,6 +76,17 @@ function messageActivityTimestamp(message) {
|
||||
return Number(message?.activityTimestamp || message?.editedAt || message?.displayTimestamp || message?.timestamp || 0);
|
||||
}
|
||||
|
||||
function hasSameRenderState(left, right) {
|
||||
if (left === right) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(left) === JSON.stringify(right);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isRecalledMessage(message) {
|
||||
return Boolean(message?.recalled) || message?.status === 'recalled';
|
||||
}
|
||||
@@ -616,6 +647,7 @@ export const useConversationStore = defineStore('conversations', {
|
||||
return;
|
||||
}
|
||||
|
||||
const previousActiveId = this.activeId;
|
||||
const merged = new Map();
|
||||
this.conversations.forEach(conversation => {
|
||||
merged.set(conversation.id, conversation);
|
||||
@@ -629,10 +661,14 @@ export const useConversationStore = defineStore('conversations', {
|
||||
});
|
||||
});
|
||||
|
||||
this.conversations = Array.from(merged.values())
|
||||
const nextConversations = Array.from(merged.values())
|
||||
.map(sanitizeConversation)
|
||||
.sort((a, b) => Number(b.updatedAt || 0) - Number(a.updatedAt || 0))
|
||||
.slice(0, 100);
|
||||
const conversationsChanged = !hasSameRenderState(this.conversations, nextConversations);
|
||||
if (conversationsChanged) {
|
||||
this.conversations = nextConversations;
|
||||
}
|
||||
|
||||
if (!this.conversations.length) {
|
||||
this.activeId = '';
|
||||
@@ -646,8 +682,12 @@ export const useConversationStore = defineStore('conversations', {
|
||||
if (!this.conversations.find(item => item.id === this.activeId)) {
|
||||
this.activeId = this.conversations[0].id;
|
||||
}
|
||||
writeLocalConversations(this.conversations);
|
||||
this.loadActiveMessages();
|
||||
if (conversationsChanged) {
|
||||
writeLocalConversations(this.conversations);
|
||||
}
|
||||
if (previousActiveId !== this.activeId || !this.messagesByConversation[this.activeId]) {
|
||||
this.loadActiveMessages();
|
||||
}
|
||||
},
|
||||
appendMessage(conversationId, message) {
|
||||
message = normalizeMessageForDisplay(message);
|
||||
@@ -755,13 +795,17 @@ export const useConversationStore = defineStore('conversations', {
|
||||
this.syncVisibleMessages(conversationId);
|
||||
},
|
||||
syncVisibleMessages(conversationId) {
|
||||
this.visibleMessagesByConversation = {
|
||||
...this.visibleMessagesByConversation,
|
||||
[conversationId]: mergeVisibleMessages(
|
||||
this.optimisticMessagesByConversation[conversationId] || [],
|
||||
this.messagesByConversation[conversationId] || []
|
||||
)
|
||||
};
|
||||
const currentMessages = this.visibleMessagesByConversation[conversationId] || [];
|
||||
const nextMessages = mergeVisibleMessages(
|
||||
this.optimisticMessagesByConversation[conversationId] || [],
|
||||
this.messagesByConversation[conversationId] || []
|
||||
);
|
||||
if (!hasSameRenderState(currentMessages, nextMessages)) {
|
||||
this.visibleMessagesByConversation = {
|
||||
...this.visibleMessagesByConversation,
|
||||
[conversationId]: nextMessages
|
||||
};
|
||||
}
|
||||
},
|
||||
keepOptimisticMessage(conversationId, message) {
|
||||
if (!this.optimisticMessagesByConversation[conversationId]) {
|
||||
@@ -813,10 +857,13 @@ export const useConversationStore = defineStore('conversations', {
|
||||
this.loading = true;
|
||||
const messages = imClient.getMessages(conversation, 30);
|
||||
this.pruneOptimisticMessages(conversation.id, messages);
|
||||
this.messagesByConversation = {
|
||||
...this.messagesByConversation,
|
||||
[conversation.id]: mergeVisibleMessages(this.messagesByConversation[conversation.id] || [], messages)
|
||||
};
|
||||
const nextMessages = mergeVisibleMessages(this.messagesByConversation[conversation.id] || [], messages);
|
||||
if (!hasSameRenderState(this.messagesByConversation[conversation.id] || [], nextMessages)) {
|
||||
this.messagesByConversation = {
|
||||
...this.messagesByConversation,
|
||||
[conversation.id]: nextMessages
|
||||
};
|
||||
}
|
||||
this.syncVisibleMessages(conversation.id);
|
||||
this.loading = false;
|
||||
this.syncActiveMessages(syncOptions);
|
||||
@@ -857,10 +904,16 @@ export const useConversationStore = defineStore('conversations', {
|
||||
}
|
||||
const editedIncomingMessages = incomingEditedMessages(previousMessages, messages);
|
||||
this.pruneOptimisticMessages(syncedConversationId, messages);
|
||||
this.messagesByConversation = {
|
||||
...this.messagesByConversation,
|
||||
[syncedConversationId]: mergeVisibleMessages(this.messagesByConversation[syncedConversationId] || [], messages)
|
||||
};
|
||||
const nextMessages = mergeVisibleMessages(
|
||||
this.messagesByConversation[syncedConversationId] || [],
|
||||
messages
|
||||
);
|
||||
if (!hasSameRenderState(this.messagesByConversation[syncedConversationId] || [], nextMessages)) {
|
||||
this.messagesByConversation = {
|
||||
...this.messagesByConversation,
|
||||
[syncedConversationId]: nextMessages
|
||||
};
|
||||
}
|
||||
this.syncVisibleMessages(syncedConversationId);
|
||||
if (editedIncomingMessages.length && syncedConversationId === this.activeId) {
|
||||
this.focusMessage(editedIncomingMessages.sort((a, b) => messageActivityTimestamp(b) - messageActivityTimestamp(a))[0]);
|
||||
@@ -873,9 +926,13 @@ export const useConversationStore = defineStore('conversations', {
|
||||
return latestMessage;
|
||||
}, null);
|
||||
if (latest) {
|
||||
conversation.subtitle = messagePreviewText(latest);
|
||||
conversation.updatedAt = messageActivityTimestamp(latest);
|
||||
writeLocalConversations(this.conversations);
|
||||
const nextSubtitle = messagePreviewText(latest);
|
||||
const nextUpdatedAt = messageActivityTimestamp(latest);
|
||||
if (conversation.subtitle !== nextSubtitle || Number(conversation.updatedAt || 0) !== nextUpdatedAt) {
|
||||
conversation.subtitle = nextSubtitle;
|
||||
conversation.updatedAt = nextUpdatedAt;
|
||||
writeLocalConversations(this.conversations);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Keep the local view usable if a polling request misses.
|
||||
@@ -931,7 +988,10 @@ export const useConversationStore = defineStore('conversations', {
|
||||
this.refreshRemoteConversations();
|
||||
}
|
||||
},
|
||||
handleRealtimeNotification() {
|
||||
handleRealtimeNotification(payload) {
|
||||
if (isDuplicateRealtimeNotification(payload)) {
|
||||
return;
|
||||
}
|
||||
window.clearTimeout(this.realtimeSyncTimer);
|
||||
this.realtimeSyncTimer = window.setTimeout(() => {
|
||||
this.refreshRemoteConversations();
|
||||
|
||||
Reference in New Issue
Block a user