UI: мультиаккаунты профиля и улучшенный поиск каналов

This commit is contained in:
AidarKC
2026-05-14 16:28:17 +03:00
parent 56a69ab683
commit 94263a46bd
9 changed files with 329 additions and 30 deletions
+76 -11
View File
@@ -1,9 +1,9 @@
import { AuthService } from './services/auth-service.js';
import { clearClientAuthData } from './services/key-vault.js';
import { clearStoredMessages, listStoredMessages, putStoredMessage } from './services/message-store.js';
import { listStoredMessages, putStoredMessage } from './services/message-store.js';
const clone = (value) => JSON.parse(JSON.stringify(value));
const SESSION_STORAGE_KEY = 'shine-ui-current-session-v1';
const ACCOUNTS_STORAGE_KEY = 'shine-ui-accounts-v1';
const REACTIONS_STORAGE_KEY = 'shine-ui-message-reactions-v2';
const WEB_PUSH_SUBSCRIPTION_KEY = 'shine-ui-webpush-subscription-v1';
const ENTRY_SETTINGS_STORAGE_KEY = 'shine-ui-entry-settings-v1';
@@ -117,6 +117,33 @@ function loadStoredSession() {
}
}
function loadStoredAccounts() {
try {
const raw = localStorage.getItem(ACCOUNTS_STORAGE_KEY);
if (!raw) return [];
const parsed = JSON.parse(raw);
if (!Array.isArray(parsed)) return [];
return parsed
.map((item) => ({
login: String(item?.login || '').trim(),
sessionId: String(item?.sessionId || '').trim(),
updatedAtMs: Number(item?.updatedAtMs || Date.now()),
}))
.filter((item) => item.login && item.sessionId);
} catch {
return [];
}
}
function persistStoredAccounts(accounts) {
try {
const payload = Array.isArray(accounts) ? accounts : [];
localStorage.setItem(ACCOUNTS_STORAGE_KEY, JSON.stringify(payload));
} catch {
// ignore storage errors
}
}
function loadStoredReactions() {
try {
const raw = localStorage.getItem(REACTIONS_STORAGE_KEY);
@@ -189,6 +216,7 @@ function persistEntrySettings(settings) {
function clearBrowserClientData() {
const localKeys = [
SESSION_STORAGE_KEY,
ACCOUNTS_STORAGE_KEY,
REACTIONS_STORAGE_KEY,
WEB_PUSH_SUBSCRIPTION_KEY,
CHANNEL_NOTIFY_KEY,
@@ -211,6 +239,7 @@ function clearBrowserClientData() {
function createInitialState({ withStoredSession = true } = {}) {
const storedSession = withStoredSession ? loadStoredSession() : null;
const storedAccounts = loadStoredAccounts();
const storedReactions = loadStoredReactions();
const storedEntrySettings = loadStoredEntrySettings();
const initialShineServer = LOCAL_WS_OVERRIDE_URL || DEFAULT_SHINE_SERVER;
@@ -230,6 +259,9 @@ function createInitialState({ withStoredSession = true } = {}) {
sessionId: storedSession?.sessionId || '',
storagePwdInMemory: '',
},
accounts: storedAccounts,
activeAccountLogin: String(storedSession?.login || ''),
accountAddingMode: false,
startHint: '',
entrySettings: {
language: String(storedEntrySettings?.language || 'ru'),
@@ -699,6 +731,19 @@ export function authorizeSession({
login,
sessionId,
});
const loginKey = String(login || '').trim().toLowerCase();
const nextAccounts = [
{
login: String(login || '').trim(),
sessionId: String(sessionId || '').trim(),
updatedAtMs: Date.now(),
},
...state.accounts.filter((item) => String(item?.login || '').trim().toLowerCase() !== loginKey),
];
state.accounts = nextAccounts;
state.activeAccountLogin = String(login || '').trim();
state.accountAddingMode = false;
persistStoredAccounts(nextAccounts);
state.startHint = '';
if (onSessionAuthorized) {
onSessionAuthorized();
@@ -722,6 +767,20 @@ export async function refreshSessions() {
return state.sessions;
}
export async function switchToAccount(login) {
const targetLogin = String(login || '').trim();
if (!targetLogin) throw new Error('Не передан логин аккаунта.');
const account = (state.accounts || []).find((item) => String(item?.login || '').trim().toLowerCase() === targetLogin.toLowerCase());
if (!account?.sessionId) throw new Error('Сессия аккаунта не найдена.');
const resumed = await authService.resumeSession(account.login, account.sessionId);
authorizeSession({
login: resumed.login || account.login,
sessionId: resumed.sessionId || account.sessionId,
storagePwd: resumed.storagePwd || state.session.storagePwdInMemory,
});
return resumed;
}
function resetStateForSignedOut() {
const next = createInitialState({ withStoredSession: false });
state.chats = next.chats;
@@ -733,6 +792,9 @@ function resetStateForSignedOut() {
state.notificationsTab = next.notificationsTab;
state.pageLabelCollapsed = next.pageLabelCollapsed;
state.session = next.session;
state.accounts = next.accounts;
state.activeAccountLogin = next.activeAccountLogin;
state.accountAddingMode = next.accountAddingMode;
state.startHint = next.startHint;
state.entrySettings = next.entrySettings;
state.registrationDraft = next.registrationDraft;
@@ -749,18 +811,13 @@ function resetStateForSignedOut() {
}
export async function terminateCurrentSession({ infoMessage = '' } = {}) {
const currentLogin = String(state.session.login || '').trim().toLowerCase();
const nextAccounts = (state.accounts || []).filter((item) => String(item?.login || '').trim().toLowerCase() !== currentLogin);
state.accounts = nextAccounts;
persistStoredAccounts(nextAccounts);
clearStoredSession();
clearBrowserClientData();
resetStateForSignedOut();
authService.close();
try {
await Promise.all([
clearClientAuthData(),
clearStoredMessages(),
]);
} catch {
// ignore cleanup errors in prototype mode
}
if (infoMessage) {
state.startHint = infoMessage;
}
@@ -792,6 +849,14 @@ export async function closeCurrentSessionAndSignOut({ infoMessage = '' } = {}) {
await terminateCurrentSession({ infoMessage });
}
export function beginAddAccountFlow() {
state.accountAddingMode = true;
}
export function cancelAddAccountFlow() {
state.accountAddingMode = false;
}
export function refreshRegistrationBalance() {
const next = (0.005 + Math.random() * 0.03).toFixed(4);
state.registrationPayment.balanceSOL = next;