import { renderHeader } from '../components/header.js'; import { authService } from '../state.js'; import { renderUserAvatar } from '../components/avatar-image.js'; import { loadProfileSnapshot } from '../services/user-profile-params.js'; import { makeProfileRoute } from '../services/shine-routes.js'; export const pageMeta = { id: 'contact-search-view', title: 'Поиск контактов' }; const searchAvatarSnapshotCache = new Map(); const searchAvatarPendingByLogin = new Map(); async function loadSearchAvatarSnapshot(login) { const cleanLogin = String(login || '').trim(); if (!cleanLogin) return null; const key = cleanLogin.toLowerCase(); if (searchAvatarSnapshotCache.has(key)) return searchAvatarSnapshotCache.get(key); if (searchAvatarPendingByLogin.has(key)) return searchAvatarPendingByLogin.get(key); const pending = loadProfileSnapshot(cleanLogin) .then((snapshot) => { searchAvatarSnapshotCache.set(key, snapshot || null); searchAvatarPendingByLogin.delete(key); return snapshot || null; }) .catch(() => { searchAvatarSnapshotCache.set(key, null); searchAvatarPendingByLogin.delete(key); return null; }); searchAvatarPendingByLogin.set(key, pending); return pending; } function createSearchAvatar(login) { const cleanLogin = String(login || '').trim(); const title = cleanLogin ? `Профиль ${cleanLogin}` : ''; const avatarEl = renderUserAvatar({ login: cleanLogin || 'unknown', size: 'small', className: 'avatar', title, }); if (!cleanLogin) return avatarEl; void loadSearchAvatarSnapshot(cleanLogin).then((snapshot) => { if (!avatarEl.isConnected) return; const upgraded = renderUserAvatar({ login: cleanLogin, avatar: snapshot?.avatar?.txId ? { ar: String(snapshot.avatar.txId || '').trim(), sha256Hex: String(snapshot?.avatar?.sha256Hex || '').trim().toLowerCase(), } : null, size: 'small', className: 'avatar', title, }); avatarEl.replaceWith(upgraded); }); return avatarEl; } export function render({ navigate }) { const screen = document.createElement('section'); screen.className = 'stack dm-screen dm-search-screen'; const input = document.createElement('input'); input.className = 'input dm-input'; input.type = 'text'; input.name = 'contact'; input.placeholder = 'Введите начало логина'; input.autocomplete = 'off'; input.maxLength = 80; const resultsCard = document.createElement('section'); resultsCard.className = 'card stack dm-dialog-card'; resultsCard.hidden = true; const status = document.createElement('p'); status.className = 'meta-muted'; const resultsList = document.createElement('div'); resultsList.className = 'stack dm-list'; const renderResults = (matches, query) => { resultsList.innerHTML = ''; resultsCard.hidden = false; if (!query.trim()) { status.textContent = 'Введите начало логина пользователя.'; return; } if (!matches.length) { status.textContent = 'Совпадений не найдено.'; return; } status.textContent = `Найдено пользователей: ${matches.length}`; matches.forEach((login) => { const row = document.createElement('article'); row.className = 'list-item dm-dialog-card'; const avatarEl = createSearchAvatar(login); row.innerHTML = `