fix ui dm chatid lowercase normalization
This commit is contained in:
parent
c8ffb6cf29
commit
2a834f1b14
@ -0,0 +1,19 @@
|
||||
# Исправление chatId личных сообщений через lowercase
|
||||
|
||||
- краткое описание фичи:
|
||||
- В клиентском UI SHiNE для личных сообщений технический `chatId` теперь канонизируется через `trim().toLowerCase()` при приёме DM, открытии чата и восстановлении сообщений из IndexedDB.
|
||||
- Цель: исключить рассинхрон, когда unread-индикатор есть, а входящие сообщения конкретного собеседника не видны из-за разного регистра логина.
|
||||
|
||||
- что именно проверять:
|
||||
- Отправить личные сообщения между двумя пользователями, у одного из которых логин отображается с заглавными буквами.
|
||||
- Убедиться, что входящие сообщения показываются внутри открытого чата, а не только в общем unread-индикаторе.
|
||||
- Перезагрузить страницу и проверить, что история чата после гидрации из IndexedDB остаётся в одном диалоге.
|
||||
- Проверить, что переход в чат из списка диалогов и из графа связей открывает тот же диалог без дублирования.
|
||||
|
||||
- ожидаемый результат:
|
||||
- Все сообщения одного собеседника попадают в один и тот же DM-чат независимо от регистра логина.
|
||||
- Общий unread, список диалогов и содержимое открытого чата совпадают между собой.
|
||||
- После перезагрузки UI не появляется отдельный дубль диалога с тем же логином в другом регистре.
|
||||
|
||||
- статус:
|
||||
- pending
|
||||
@ -1,2 +1,2 @@
|
||||
client.version=1.2.228
|
||||
server.version=1.2.214
|
||||
client.version=1.2.230
|
||||
server.version=1.2.216
|
||||
|
||||
@ -29,6 +29,7 @@ import {
|
||||
addSignedMessageToChat,
|
||||
markIncomingReadByBaseKey,
|
||||
markOutgoingReadByBaseKey,
|
||||
normalizeDmChatId,
|
||||
setContacts,
|
||||
} from './state.js';
|
||||
|
||||
@ -912,7 +913,7 @@ async function init() {
|
||||
const fromLogin = parsed.fromLogin || '';
|
||||
const toLogin = parsed.toLogin || '';
|
||||
const messageType = Number(parsed.messageType || 0);
|
||||
const chatId = messageType === 2 ? toLogin : fromLogin;
|
||||
const chatId = normalizeDmChatId(messageType === 2 ? toLogin : fromLogin);
|
||||
const text = (messageType === 1 || messageType === 2)
|
||||
? String(parsed.text || '')
|
||||
: '';
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
markChatRead,
|
||||
markOutgoingSent,
|
||||
markReadReceiptSentByBaseKey,
|
||||
normalizeDmChatId,
|
||||
authService,
|
||||
setContacts,
|
||||
state,
|
||||
@ -334,11 +335,12 @@ function renderLog(list, chatId, { onOpenActions } = {}) {
|
||||
}
|
||||
|
||||
export function render({ navigate, route }) {
|
||||
const chatId = route.params.chatId || 'u1';
|
||||
const contact = directMessages.find((d) => d.id === chatId) || {
|
||||
const routeChatId = route.params.chatId || 'u1';
|
||||
const chatId = normalizeDmChatId(routeChatId) || 'u1';
|
||||
const contact = directMessages.find((d) => normalizeDmChatId(d.id) === chatId) || {
|
||||
id: chatId,
|
||||
name: chatId,
|
||||
initials: (chatId[0] || '?').toUpperCase(),
|
||||
name: String(routeChatId || chatId),
|
||||
initials: (String(routeChatId || chatId)[0] || '?').toUpperCase(),
|
||||
};
|
||||
|
||||
const screen = document.createElement('section');
|
||||
|
||||
@ -2,6 +2,7 @@ import { directMessages } from '../mock-data.js';
|
||||
import {
|
||||
getChatMessages,
|
||||
isSessionInvalidError,
|
||||
normalizeDmChatId,
|
||||
setContacts,
|
||||
state,
|
||||
terminateCurrentSession,
|
||||
@ -126,7 +127,7 @@ export function render({ navigate }) {
|
||||
</div>
|
||||
`;
|
||||
row.prepend(avatarWrap);
|
||||
row.addEventListener('click', () => navigate(`chat-view/${encodeURIComponent(item.id)}`));
|
||||
row.addEventListener('click', () => navigate(`chat-view/${encodeURIComponent(normalizeDmChatId(item.id))}`));
|
||||
return row;
|
||||
}
|
||||
|
||||
@ -139,12 +140,13 @@ export function render({ navigate }) {
|
||||
|
||||
const contactRows = contacts.map((login) => {
|
||||
const preview = directMessages.find((item) => item.id.toLowerCase() === login.toLowerCase());
|
||||
const chat = getChatMessages(login);
|
||||
const canonicalLogin = normalizeDmChatId(login);
|
||||
const chat = getChatMessages(canonicalLogin);
|
||||
const lastChat = chat[chat.length - 1];
|
||||
const unread = chat.filter((m) => m?.from === 'in' && m?.unread).length;
|
||||
const lastTimeMs = Number(lastChat?.createdAtMs || 0);
|
||||
return {
|
||||
id: login,
|
||||
id: canonicalLogin,
|
||||
name: preview?.name || login,
|
||||
lastMessage: lastChat?.text || preview?.lastMessage || 'Диалог пока пуст.',
|
||||
time: formatChatRowTime(lastTimeMs),
|
||||
|
||||
@ -92,6 +92,10 @@ const DEFAULT_ARWEAVE_SERVER = 'https://arweave.net';
|
||||
const DEFAULT_CALL_PREFLIGHT_TIMEOUT_MS = 6000;
|
||||
const DEFAULT_OPENAI_BASE_URL = 'https://api.openai.com/v1';
|
||||
|
||||
export function normalizeDmChatId(value) {
|
||||
return String(value || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
function normalizeToolsSettings(rawTools) {
|
||||
const source = rawTools && typeof rawTools === 'object' ? rawTools : {};
|
||||
const stt = source.speechToText && typeof source.speechToText === 'object' ? source.speechToText : {};
|
||||
@ -376,11 +380,12 @@ function sortChatMessagesInPlace(chatId) {
|
||||
}
|
||||
|
||||
function persistMessageRecord(chatId, row) {
|
||||
if (!chatId || !row?.messageKey) return;
|
||||
const normalizedChatId = normalizeDmChatId(chatId);
|
||||
if (!normalizedChatId || !row?.messageKey) return;
|
||||
const resolvedTs = resolveChatMessageTimeMs(row);
|
||||
void putStoredMessage({
|
||||
messageKey: row.messageKey,
|
||||
chatId,
|
||||
chatId: normalizedChatId,
|
||||
from: row.from || 'in',
|
||||
text: String(row.text || ''),
|
||||
baseKey: String(row.baseKey || ''),
|
||||
@ -408,7 +413,7 @@ export async function hydrateMessagesFromStore() {
|
||||
rows
|
||||
.sort((a, b) => Number(a?.ts || 0) - Number(b?.ts || 0))
|
||||
.forEach((row) => {
|
||||
const chatId = String(row?.chatId || '').trim();
|
||||
const chatId = normalizeDmChatId(row?.chatId);
|
||||
const messageKey = String(row?.messageKey || '').trim();
|
||||
if (!chatId || !messageKey) return;
|
||||
if (state.knownMessageKeys[messageKey]) return;
|
||||
@ -437,10 +442,12 @@ export async function hydrateMessagesFromStore() {
|
||||
}
|
||||
|
||||
export function getChatMessages(chatId) {
|
||||
if (!state.chats[chatId]) {
|
||||
state.chats[chatId] = [];
|
||||
const normalizedChatId = normalizeDmChatId(chatId);
|
||||
if (!normalizedChatId) return [];
|
||||
if (!state.chats[normalizedChatId]) {
|
||||
state.chats[normalizedChatId] = [];
|
||||
}
|
||||
return state.chats[chatId];
|
||||
return state.chats[normalizedChatId];
|
||||
}
|
||||
|
||||
export function addChatMessage(chatId, text) {
|
||||
@ -583,9 +590,10 @@ export function addSignedMessageToChat({
|
||||
revisionTimeMs = 0,
|
||||
deleted = false,
|
||||
} = {}) {
|
||||
const normalizedChatId = normalizeDmChatId(chatId);
|
||||
const id = String(messageKey || '').trim();
|
||||
if (!chatId || !id) return false;
|
||||
const list = getChatMessages(chatId);
|
||||
if (!normalizedChatId || !id) return false;
|
||||
const list = getChatMessages(normalizedChatId);
|
||||
const existingIndex = list.findIndex((row) => String(row?.messageKey || '').trim() === id);
|
||||
const existing = existingIndex >= 0 ? list[existingIndex] : null;
|
||||
const nextRevision = Number(revisionTimeMs || 0);
|
||||
@ -599,7 +607,7 @@ export function addSignedMessageToChat({
|
||||
if (existingIndex >= 0) {
|
||||
list.splice(existingIndex, 1);
|
||||
removeStoredMessageRecord(id);
|
||||
sortChatMessagesInPlace(chatId);
|
||||
sortChatMessagesInPlace(normalizedChatId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -623,17 +631,18 @@ export function addSignedMessageToChat({
|
||||
if (existingIndex < 0) {
|
||||
list.push(row);
|
||||
}
|
||||
sortChatMessagesInPlace(chatId);
|
||||
persistMessageRecord(chatId, row);
|
||||
sortChatMessagesInPlace(normalizedChatId);
|
||||
persistMessageRecord(normalizedChatId, row);
|
||||
return true;
|
||||
}
|
||||
|
||||
export function markChatRead(chatId) {
|
||||
const list = getChatMessages(chatId);
|
||||
const normalizedChatId = normalizeDmChatId(chatId);
|
||||
const list = getChatMessages(normalizedChatId);
|
||||
list.forEach((row) => {
|
||||
if (row?.from === 'in') {
|
||||
row.unread = false;
|
||||
persistMessageRecord(chatId, row);
|
||||
persistMessageRecord(normalizedChatId, row);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user