feat(ui): старт с личных сообщений и бейдж непрочитанных
This commit is contained in:
parent
58bbf063ca
commit
97a2bee81a
@ -448,7 +448,7 @@ function renderPageFailureFallback(pageId, error) {
|
|||||||
|
|
||||||
function renderApp() {
|
function renderApp() {
|
||||||
const route = getRoute();
|
const route = getRoute();
|
||||||
const pageId = route.pageId || (state.session.isAuthorized ? 'profile-view' : 'start-view');
|
const pageId = route.pageId || (state.session.isAuthorized ? 'messages-list' : 'start-view');
|
||||||
|
|
||||||
if (!state.session.isAuthorized && !PRE_AUTH_PAGES.includes(pageId)) {
|
if (!state.session.isAuthorized && !PRE_AUTH_PAGES.includes(pageId)) {
|
||||||
navigate('start-view');
|
navigate('start-view');
|
||||||
@ -456,7 +456,7 @@ function renderApp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.session.isAuthorized && PRE_AUTH_PAGES.includes(pageId)) {
|
if (state.session.isAuthorized && PRE_AUTH_PAGES.includes(pageId)) {
|
||||||
navigate('profile-view');
|
navigate('messages-list');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,6 +629,8 @@ async function init() {
|
|||||||
? new TextDecoder().decode(parsed.payloadBytes || new Uint8Array(0))
|
? new TextDecoder().decode(parsed.payloadBytes || new Uint8Array(0))
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
|
let shouldRefreshToolbarUnread = false;
|
||||||
|
|
||||||
if (messageType === 1 || messageType === 2) {
|
if (messageType === 1 || messageType === 2) {
|
||||||
const isIncomingForCurrent = messageType === 1;
|
const isIncomingForCurrent = messageType === 1;
|
||||||
const added = addSignedMessageToChat({
|
const added = addSignedMessageToChat({
|
||||||
@ -651,6 +653,9 @@ async function init() {
|
|||||||
details: { messageKey, baseKey: parsed.baseKey, messageType },
|
details: { messageKey, baseKey: parsed.baseKey, messageType },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (added && isIncomingForCurrent) {
|
||||||
|
shouldRefreshToolbarUnread = true;
|
||||||
|
}
|
||||||
if (added && isIncomingForCurrent && Notification.permission === 'granted' && !payload.backlog) {
|
if (added && isIncomingForCurrent && Notification.permission === 'granted' && !payload.backlog) {
|
||||||
try {
|
try {
|
||||||
new Notification(`Сообщение от ${fromLogin}`, { body: text || '' });
|
new Notification(`Сообщение от ${fromLogin}`, { body: text || '' });
|
||||||
@ -691,7 +696,7 @@ async function init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pageId = getRoute().pageId || '';
|
const pageId = getRoute().pageId || '';
|
||||||
if (pageId === 'chat-view' || pageId === 'messages-list') {
|
if (pageId === 'chat-view' || pageId === 'messages-list' || shouldRefreshToolbarUnread) {
|
||||||
renderApp();
|
renderApp();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -773,7 +778,7 @@ async function init() {
|
|||||||
await ensureSessionRuntimeStarted();
|
await ensureSessionRuntimeStarted();
|
||||||
|
|
||||||
if (!window.location.hash) {
|
if (!window.location.hash) {
|
||||||
navigate(state.session.isAuthorized ? 'profile-view' : 'start-view');
|
navigate(state.session.isAuthorized ? 'messages-list' : 'start-view');
|
||||||
} else {
|
} else {
|
||||||
renderApp();
|
renderApp();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { resolveToolbarActive } from '../router.js';
|
import { resolveToolbarActive } from '../router.js';
|
||||||
|
import { state } from '../state.js';
|
||||||
|
|
||||||
const ITEMS = [
|
const ITEMS = [
|
||||||
{ pageId: 'messages-list', label: 'Личные сообщения', icon: '💬' },
|
{ pageId: 'messages-list', label: 'Личные сообщения', icon: '💬' },
|
||||||
@ -8,15 +9,29 @@ const ITEMS = [
|
|||||||
{ pageId: 'profile-view', label: 'Профиль', icon: '👤' },
|
{ pageId: 'profile-view', label: 'Профиль', icon: '👤' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function getTotalUnreadMessages() {
|
||||||
|
const chats = Object.values(state.chats || {});
|
||||||
|
let total = 0;
|
||||||
|
chats.forEach((messages) => {
|
||||||
|
if (!Array.isArray(messages)) return;
|
||||||
|
messages.forEach((msg) => {
|
||||||
|
if (msg?.from === 'in' && msg?.unread) total += 1;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
export function renderToolbar(currentPageId, navigate) {
|
export function renderToolbar(currentPageId, navigate) {
|
||||||
const root = document.createElement('nav');
|
const root = document.createElement('nav');
|
||||||
root.className = 'toolbar';
|
root.className = 'toolbar';
|
||||||
const active = resolveToolbarActive(currentPageId);
|
const active = resolveToolbarActive(currentPageId);
|
||||||
|
const unreadTotal = getTotalUnreadMessages();
|
||||||
|
|
||||||
ITEMS.forEach((item) => {
|
ITEMS.forEach((item) => {
|
||||||
const btn = document.createElement('button');
|
const btn = document.createElement('button');
|
||||||
const isProfile = item.pageId === 'profile-view';
|
const isProfile = item.pageId === 'profile-view';
|
||||||
btn.className = `toolbar-btn${item.pageId === active ? ' active' : ''}${isProfile ? ' toolbar-btn-profile' : ''}`;
|
const isMessages = item.pageId === 'messages-list';
|
||||||
|
btn.className = `toolbar-btn${item.pageId === active ? ' active' : ''}${isProfile ? ' toolbar-btn-profile' : ''}${isMessages ? ' toolbar-btn-messages' : ''}`;
|
||||||
if (isProfile) {
|
if (isProfile) {
|
||||||
btn.innerHTML = `
|
btn.innerHTML = `
|
||||||
<span>${item.icon}</span>
|
<span>${item.icon}</span>
|
||||||
@ -31,6 +46,13 @@ export function renderToolbar(currentPageId, navigate) {
|
|||||||
} else {
|
} else {
|
||||||
btn.innerHTML = `<span>${item.icon}</span><span>${item.label}</span>`;
|
btn.innerHTML = `<span>${item.icon}</span><span>${item.label}</span>`;
|
||||||
}
|
}
|
||||||
|
if (isMessages && unreadTotal > 0) {
|
||||||
|
const badge = document.createElement('span');
|
||||||
|
badge.className = 'toolbar-unread-badge';
|
||||||
|
badge.textContent = unreadTotal > 99 ? '99+' : String(unreadTotal);
|
||||||
|
badge.setAttribute('aria-label', `Непрочитанных сообщений: ${badge.textContent}`);
|
||||||
|
btn.append(badge);
|
||||||
|
}
|
||||||
btn.addEventListener('click', () => navigate(item.pageId));
|
btn.addEventListener('click', () => navigate(item.pageId));
|
||||||
root.append(btn);
|
root.append(btn);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -621,6 +621,31 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbar-btn-messages {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-unread-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
right: 6px;
|
||||||
|
min-width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 0 5px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #f07f8a;
|
||||||
|
color: #fff2f4;
|
||||||
|
border: 1px solid rgba(255, 222, 227, 0.55);
|
||||||
|
box-shadow: 0 4px 10px rgba(152, 36, 52, 0.35);
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.toolbar-btn-profile .toolbar-label-wrap {
|
.toolbar-btn-profile .toolbar-label-wrap {
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user