SHA256
Fix DM name fallbacks and chat header
This commit is contained in:
@@ -128,7 +128,7 @@ function createChatHeaderParts(login, navigate) {
|
||||
loginEl.setAttribute('role', 'heading');
|
||||
loginEl.setAttribute('aria-level', '1');
|
||||
loginEl.setAttribute('aria-label', `Чат с ${cleanLogin}`);
|
||||
loginEl.innerHTML = `<span class="chat-header-display-name">${cleanLogin}</span><span class="chat-header-user-login">${cleanLogin}</span>`;
|
||||
loginEl.innerHTML = `<span class="chat-header-display-name">${cleanLogin}</span><span class="chat-header-user-login" hidden>${cleanLogin}</span>`;
|
||||
|
||||
void loadProfileSnapshot(cleanLogin)
|
||||
.then((snapshot) => {
|
||||
@@ -153,7 +153,10 @@ function createChatHeaderParts(login, navigate) {
|
||||
const nameNode = loginEl.querySelector('.chat-header-display-name');
|
||||
const loginNode = loginEl.querySelector('.chat-header-user-login');
|
||||
if (nameNode) nameNode.textContent = display;
|
||||
if (loginNode) loginNode.textContent = cleanLogin;
|
||||
if (loginNode) {
|
||||
loginNode.textContent = cleanLogin;
|
||||
loginNode.hidden = display === cleanLogin;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
@@ -967,7 +970,6 @@ export function render({ navigate, route, chrome }) {
|
||||
const screen = document.createElement('section');
|
||||
screen.className = 'stack dm-screen dm-chat-screen';
|
||||
const isTextToSpeechReady = isTextToSpeechConfigured(state.entrySettings);
|
||||
const isKnownContact = (state.contacts || []).some((x) => String(x || '').toLowerCase() === String(chatId || '').toLowerCase());
|
||||
const hasUnreadIncoming = getChatMessages(chatId).some((msg) => msg?.from === 'in' && msg?.unread);
|
||||
const UNREAD_SEPARATOR_AUTO_HIDE_MS = 5000;
|
||||
let historyHasMore = true;
|
||||
@@ -1151,44 +1153,59 @@ export function render({ navigate, route, chrome }) {
|
||||
chatHeaderLeft?.append(chatHeaderParts.avatarButton);
|
||||
chrome?.setTopbar(chatHeader);
|
||||
|
||||
if (!isKnownContact) {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card';
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'secondary-btn';
|
||||
btn.type = 'button';
|
||||
btn.textContent = 'Добавить собеседника в контакты';
|
||||
btn.addEventListener('click', async () => {
|
||||
try {
|
||||
const approved = await openConfirmContactModal(chatId);
|
||||
if (!approved) return;
|
||||
await authService.setUserRelation({
|
||||
login: state.session.login,
|
||||
toLogin: chatId,
|
||||
kind: 'contact',
|
||||
enabled: true,
|
||||
storagePwd: state.session.storagePwdInMemory,
|
||||
});
|
||||
const contactsPayload = await authService.listContacts();
|
||||
setContacts(contactsPayload?.contacts || []);
|
||||
addAppLogEntry({
|
||||
level: 'info',
|
||||
source: 'contacts',
|
||||
message: `Пользователь ${chatId} добавлен в контакты`,
|
||||
});
|
||||
card.remove();
|
||||
} catch (e) {
|
||||
addAppLogEntry({
|
||||
level: 'warn',
|
||||
source: 'contacts',
|
||||
message: 'Не удалось добавить пользователя в контакты',
|
||||
details: { login: chatId, error: e?.message || 'unknown' },
|
||||
});
|
||||
}
|
||||
const addContactCard = document.createElement('div');
|
||||
addContactCard.className = 'card dm-add-contact-card';
|
||||
addContactCard.hidden = true;
|
||||
const addContactBtn = document.createElement('button');
|
||||
addContactBtn.className = 'secondary-btn';
|
||||
addContactBtn.type = 'button';
|
||||
addContactBtn.textContent = 'Добавить собеседника в контакты';
|
||||
addContactBtn.addEventListener('click', async () => {
|
||||
try {
|
||||
const approved = await openConfirmContactModal(chatId);
|
||||
if (!approved) return;
|
||||
await authService.setUserRelation({
|
||||
login: state.session.login,
|
||||
toLogin: chatId,
|
||||
kind: 'contact',
|
||||
enabled: true,
|
||||
storagePwd: state.session.storagePwdInMemory,
|
||||
});
|
||||
const contactsPayload = await authService.listContacts();
|
||||
setContacts(contactsPayload?.contacts || []);
|
||||
addAppLogEntry({
|
||||
level: 'info',
|
||||
source: 'contacts',
|
||||
message: `Пользователь ${chatId} добавлен в контакты`,
|
||||
});
|
||||
addContactCard.remove();
|
||||
} catch (e) {
|
||||
addAppLogEntry({
|
||||
level: 'warn',
|
||||
source: 'contacts',
|
||||
message: 'Не удалось добавить пользователя в контакты',
|
||||
details: { login: chatId, error: e?.message || 'unknown' },
|
||||
});
|
||||
}
|
||||
});
|
||||
addContactCard.append(addContactBtn);
|
||||
log.prepend(addContactCard);
|
||||
|
||||
// The button is valid only when there is no social relation at all.
|
||||
// listContacts already returns relationFlag for every dialog/peer, so no extra server API is needed.
|
||||
void authService.listContacts()
|
||||
.then((contactsPayload) => {
|
||||
setContacts(contactsPayload?.contacts || []);
|
||||
const peerKey = String(chatId || '').trim().toLowerCase();
|
||||
const peerDialog = (Array.isArray(contactsPayload?.dialogs) ? contactsPayload.dialogs : [])
|
||||
.find((dialog) => String(dialog?.peerLogin || '').trim().toLowerCase() === peerKey);
|
||||
const relationFlag = String(peerDialog?.relationFlag || 'none').trim().toLowerCase();
|
||||
addContactCard.hidden = relationFlag !== 'none';
|
||||
})
|
||||
.catch(() => {
|
||||
// On an API failure do not offer a potentially invalid relation action.
|
||||
addContactCard.hidden = true;
|
||||
});
|
||||
card.append(btn);
|
||||
screen.append(card);
|
||||
}
|
||||
|
||||
const form = document.createElement('form');
|
||||
form.className = 'chat-input dm-chat-input';
|
||||
|
||||
@@ -319,7 +319,7 @@ function renderRow(item) {
|
||||
const titleEl = row.querySelector('.dm-row-title');
|
||||
const previewEl = row.querySelector('.dm-row-last-message');
|
||||
const timeEl = row.querySelector('.dm-row-time');
|
||||
if (titleEl) titleEl.textContent = userDisplayName(item);
|
||||
if (titleEl) titleEl.textContent = userDisplayName({ login: item.peerLogin, firstName: item.firstName, lastName: item.lastName });
|
||||
if (previewEl) previewEl.textContent = 'Загрузка…';
|
||||
if (timeEl) timeEl.textContent = formatChatRowTime(item.lastMessageTimeMs);
|
||||
row.prepend(avatarWrap);
|
||||
|
||||
@@ -116,6 +116,9 @@ export async function loadProfileSnapshot(login) {
|
||||
});
|
||||
}
|
||||
|
||||
const firstName = String(fields.find((field) => field.key === 'first_name')?.value || '').trim();
|
||||
const lastName = String(fields.find((field) => field.key === 'last_name')?.value || '').trim();
|
||||
|
||||
const latestAccountRole = loadLatestByAliasesFromItems(items, ['account_role']);
|
||||
const rawAccountRole = String(latestAccountRole?.value || '').trim().toLowerCase();
|
||||
const accountRole = rawAccountRole === PROFILE_ACCOUNT_ROLE_PRIMARY || rawAccountRole === PROFILE_ACCOUNT_ROLE_NON_VOTING
|
||||
@@ -157,6 +160,8 @@ export async function loadProfileSnapshot(login) {
|
||||
|
||||
return {
|
||||
fields,
|
||||
firstName,
|
||||
lastName,
|
||||
toggles,
|
||||
accountRole,
|
||||
accountRoleTimeMs: latestAccountRole?.timeMs || 0,
|
||||
|
||||
@@ -6468,6 +6468,14 @@ html, body { overflow-x: hidden; }
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.dm-add-contact-card {
|
||||
margin: 0 14px 2px;
|
||||
}
|
||||
|
||||
.dm-add-contact-card .secondary-btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dm-history-loader {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
@@ -11378,3 +11386,17 @@ body.chat-topbar-overlay .composer-slot {
|
||||
font-size: 9px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Channel list preview/time flex sizing fix (2026-09-02) =====
|
||||
* The global .channel-row-time rule still has width:100%, which makes the
|
||||
* timestamp consume the entire flex row and collapses the message preview.
|
||||
* Keep the timestamp content-sized and reserve a little more room at the
|
||||
* right edge so the final digit is never clipped by the widened list tile. */
|
||||
.channels-screen--list .channel-row {
|
||||
padding-right: 14px !important;
|
||||
}
|
||||
|
||||
.channels-screen--list .channel-row-preview-line .channel-row-time {
|
||||
width: auto !important;
|
||||
max-width: none !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user