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