SHiNE-server/shine-UI/js/pages/messages-list.js

157 lines
5.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { renderHeader } from '../components/header.js';
import { directMessages } from '../mock-data.js';
import {
getChatMessages,
isSessionInvalidError,
setContacts,
state,
terminateCurrentSession,
} from '../state.js';
import { loadCurrentRelations } from '../services/user-connections.js';
export const pageMeta = { id: 'messages-list', title: 'Личные сообщения' };
export function render({ navigate }) {
const screen = document.createElement('section');
screen.className = 'stack';
screen.append(
renderHeader({
title: 'Личные сообщения',
leftLabel: String(state.session.login || '').trim(),
rightActions: [{ label: '+', onClick: () => navigate('contact-search-view') }],
}),
);
const list = document.createElement('div');
list.className = 'stack';
const status = document.createElement('div');
status.className = 'status-line';
status.textContent = 'Загрузка списка сообщений...';
function renderRow(item) {
const row = document.createElement('article');
row.className = 'list-item';
row.innerHTML = `
<div class="avatar">${item.initials}</div>
<div>
<div class="row" style="justify-content:flex-start; gap:8px;">
<strong>${item.name}</strong>
${item.notInContacts ? '<span class="meta-muted">не в контактах</span>' : ''}
</div>
<p class="meta-muted" style="margin-top:4px;">${item.lastMessage}</p>
</div>
<div style="display:grid; justify-items:end; gap:6px;">
<span class="meta-muted">${item.time}</span>
${item.unread ? `<span class="unread">${item.unread}</span>` : '<span></span>'}
</div>
`;
row.addEventListener('click', () => navigate(`chat-view/${encodeURIComponent(item.id)}`));
return row;
}
async function loadList() {
try {
const relations = await loadCurrentRelations();
const contacts = relations.outContacts || [];
setContacts(contacts);
list.innerHTML = '';
const contactRows = contacts.map((login) => {
const preview = directMessages.find((item) => item.id.toLowerCase() === login.toLowerCase());
const chat = getChatMessages(login);
const lastChat = chat[chat.length - 1];
const unread = chat.filter((m) => m?.from === 'in' && m?.unread).length;
return {
id: login,
initials: (login[0] || '?').toUpperCase(),
name: preview?.name || login,
lastMessage: lastChat?.text || preview?.lastMessage || 'Диалог пока пуст.',
time: preview?.time || '—',
unread,
notInContacts: false,
};
});
const allChatIds = Object.keys(state.chats || {})
.filter((id) => id && id.toLowerCase() !== String(state.session.login || '').toLowerCase())
.filter((id) => (getChatMessages(id) || []).length > 0);
const contactKeys = new Set(contacts.map((x) => String(x || '').toLowerCase()));
const extraRows = allChatIds
.filter((login) => !contactKeys.has(String(login || '').toLowerCase()))
.map((login) => {
const chat = getChatMessages(login);
const lastChat = chat[chat.length - 1];
const unread = chat.filter((m) => m?.from === 'in' && m?.unread).length;
return {
id: login,
initials: (login[0] || '?').toUpperCase(),
name: login,
lastMessage: lastChat?.text || 'Диалог пока пуст.',
time: 'сейчас',
unread,
notInContacts: true,
};
});
const rows = [...contactRows, ...extraRows];
if (!rows.length) {
const empty = document.createElement('div');
empty.className = 'card meta-muted';
empty.textContent = 'Пока нет ни контактов, ни сообщений';
list.append(empty);
status.className = 'status-line is-available';
status.textContent = 'Нет диалогов.';
return;
}
rows.forEach((item) => list.append(renderRow(item)));
status.className = 'status-line is-available';
status.textContent = `Загружено диалогов: ${rows.length}`;
} catch (error) {
if (isSessionInvalidError(error)) {
list.innerHTML = '';
status.className = 'status-line is-unavailable';
status.textContent = 'Сессия устарела.';
const card = document.createElement('div');
card.className = 'card stack';
const title = document.createElement('strong');
title.textContent = 'Сессия устарела';
const details = document.createElement('p');
details.className = 'meta-muted';
details.textContent = 'Ваша сессия больше не действует. Авторизуйтесь заново.';
const okBtn = document.createElement('button');
okBtn.type = 'button';
okBtn.className = 'primary-btn';
okBtn.textContent = 'ОК';
okBtn.addEventListener('click', async () => {
await terminateCurrentSession({
infoMessage: 'Ваша сессия устарела. Выполните вход заново.',
});
navigate('start-view');
});
card.append(title, details, okBtn);
list.append(card);
return;
}
list.innerHTML = '';
const fail = document.createElement('div');
fail.className = 'card meta-muted';
fail.textContent = `Не удалось загрузить сообщения: ${error.message || 'unknown'}`;
list.append(fail);
status.className = 'status-line is-unavailable';
status.textContent = 'Список недоступен.';
}
}
screen.append(status, list);
loadList();
return screen;
}