fix(chat): catch-up сообщений при возврате на вкладку; fix(sw): фокус на открытой вкладке вместо навигации всех; fix(history): числа не резолвятся в имена пользователей

This commit is contained in:
2026-09-21 17:03:01 +03:00
parent 1f878b61a1
commit 2f9d049718
3 changed files with 82 additions and 57 deletions

View File

@@ -1,4 +1,4 @@
const CACHE_NAME = 'iistwin-pwa-v13';
const CACHE_NAME = 'iistwin-pwa-v14';
const STATIC_ASSETS = [
'/',
'/index.html',
@@ -577,47 +577,55 @@ self.addEventListener('push', (event) => {
);
});
// Нормализация URL для сравнения «та же ли страница открыта»:
// сравниваем только pathname (суффикс), игнорируем query (?tab=chat) и origin.
// Матчим по суффиксу, чтобы ловить и org-префиксные роуты (/:org/tasks/<id>).
function samePage(clientUrl, targetUrl) {
try {
const targetPath = new URL(targetUrl, self.location.origin).pathname;
const clientPath = new URL(clientUrl, self.location.origin).pathname;
if (clientPath === targetPath) return true;
// суффикс: /tasks/123 или /chat/123 в конце пути
const suffixMatch = targetPath.match(/\/(tasks|chat)\/(\d+)$/);
if (suffixMatch && clientPath.endsWith(suffixMatch[0])) return true;
return false;
} catch {
return false;
}
}
// focus() штатно отклоняется по спецификации (нет transient activation, окно
// не получило фокус и т.п.) — он ВСЕГДА в отдельном try/catch, иначе его отказ
// роняет общий catch и цикл идёт навигировать следующую вкладку.
async function focusClient(client) {
try {
if ('focus' in client) await client.focus();
} catch (err) {
console.log('[SW] focus() rejected (best effort):', err?.message || err);
}
}
async function openOrFocusChat(url) {
const absoluteUrl = new URL(url, self.location.origin).href;
console.log('[SW] openOrFocusChat:', absoluteUrl);
try {
// Ищем любые окна (включая неподконтрольные) — focus работает и на них,
// а navigate может не сработать на uncontrolled, поэтому оборачиваем в try/catch.
const clientList = await clients.matchAll({ type: 'window', includeUncontrolled: true });
console.log('[SW] clients found:', clientList.length);
// Сначала ищем клиент с уже открытым этим URL — просто фокусируем.
// 1. Задача/чат уже открыт в какой-то вкладке — просто фокусируем её.
for (const client of clientList) {
try {
if (client.url === absoluteUrl && 'focus' in client) {
console.log('[SW] focusing existing client with same URL');
return await client.focus();
}
} catch (err) {
console.error('[SW] focus same-url client error:', err);
if (samePage(client.url, absoluteUrl)) {
console.log('[SW] page already open, focusing client:', client.url);
await focusClient(client);
return client;
}
}
// Затем пытаемся навигировать любой доступный клиент.
for (const client of clientList) {
try {
if ('focus' in client) {
console.log('[SW] navigating client to', absoluteUrl);
await client.navigate(absoluteUrl);
return await client.focus();
}
} catch (err) {
console.error('[SW] navigate client error:', err);
}
}
// Нет подходящих клиентов — открываем новое окно/вкладку.
// 2. Не открыта — открываем НОВУЮ вкладку, чужие не перехватываем.
console.log('[SW] opening new window');
const newClient = await clients.openWindow(absoluteUrl);
if (newClient && 'focus' in newClient) {
return await newClient.focus();
}
if (newClient) await focusClient(newClient);
return newClient;
} catch (err) {
console.error('[SW] openOrFocusChat fatal error:', err);