SHA256
147 lines
5.8 KiB
JavaScript
147 lines
5.8 KiB
JavaScript
import { renderHeader } from '../components/header.js';
|
||
import {
|
||
closeAllSavedProfiles,
|
||
closeSavedProfile,
|
||
getSavedProfiles,
|
||
prepareAddProfileLogin,
|
||
state,
|
||
switchToSavedProfile,
|
||
} from '../state.js';
|
||
|
||
export const pageMeta = { id: 'profiles-view', title: 'Профили' };
|
||
|
||
function reloadTo(path) {
|
||
const clean = String(path || '/profile').trim() || '/profile';
|
||
window.location.assign(clean.startsWith('/') ? clean : `/${clean}`);
|
||
}
|
||
|
||
export function render({ navigate }) {
|
||
const screen = document.createElement('section');
|
||
screen.className = 'stack profiles-screen';
|
||
|
||
screen.append(renderHeader({
|
||
title: 'Профили',
|
||
leftAction: { label: '←', onClick: () => navigate('profile-view') },
|
||
}));
|
||
|
||
const intro = document.createElement('div');
|
||
intro.className = 'meta-muted profiles-summary';
|
||
|
||
const list = document.createElement('div');
|
||
list.className = 'stack profiles-list';
|
||
|
||
const status = document.createElement('div');
|
||
status.className = 'status-line';
|
||
status.hidden = true;
|
||
|
||
const actions = document.createElement('div');
|
||
actions.className = 'stack profiles-actions';
|
||
|
||
const addButton = document.createElement('button');
|
||
addButton.type = 'button';
|
||
addButton.className = 'secondary-btn';
|
||
addButton.textContent = 'Добавить профиль';
|
||
addButton.addEventListener('click', () => {
|
||
prepareAddProfileLogin();
|
||
navigate('login-view');
|
||
});
|
||
|
||
const closeAllButton = document.createElement('button');
|
||
closeAllButton.type = 'button';
|
||
closeAllButton.className = 'secondary-btn profiles-close-all';
|
||
closeAllButton.textContent = 'Закрыть все профили';
|
||
closeAllButton.addEventListener('click', async () => {
|
||
const profiles = getSavedProfiles();
|
||
if (!profiles.length) return;
|
||
const confirmed = window.confirm('Закрыть все профили на этом устройстве? После этого откроется экран входа.');
|
||
if (!confirmed) return;
|
||
closeAllButton.disabled = true;
|
||
status.hidden = false;
|
||
status.textContent = 'Закрываем профили…';
|
||
try {
|
||
await closeAllSavedProfiles();
|
||
reloadTo('/start');
|
||
} catch (error) {
|
||
status.className = 'status-line is-unavailable';
|
||
status.textContent = `Не удалось закрыть профили: ${error?.message || 'unknown'}`;
|
||
closeAllButton.disabled = false;
|
||
}
|
||
});
|
||
|
||
actions.append(addButton, closeAllButton);
|
||
screen.append(intro, list, status, actions);
|
||
|
||
const renderList = () => {
|
||
const profiles = getSavedProfiles();
|
||
const active = profiles.find((item) => item.isActive);
|
||
intro.textContent = profiles.length
|
||
? `Профилей на устройстве: ${profiles.length}. Активен: ${active?.login || state.session.login || '—'}`
|
||
: 'На устройстве нет сохранённых профилей.';
|
||
closeAllButton.disabled = profiles.length === 0;
|
||
list.innerHTML = '';
|
||
|
||
profiles.forEach((profile) => {
|
||
const row = document.createElement('div');
|
||
row.className = `card profiles-row${profile.isActive ? ' is-active' : ''}`;
|
||
|
||
const select = document.createElement('button');
|
||
select.type = 'button';
|
||
select.className = 'profiles-select';
|
||
select.innerHTML = `<span class="profiles-login">${profile.login}</span>${profile.isActive ? '<span class="badge">Активный</span>' : ''}`;
|
||
select.disabled = profile.isActive;
|
||
select.addEventListener('click', async () => {
|
||
if (profile.isActive) return;
|
||
const confirmed = window.confirm(`Переключиться на профиль «${profile.login}»?`);
|
||
if (!confirmed) return;
|
||
status.hidden = false;
|
||
status.className = 'status-line';
|
||
status.textContent = `Подключаем профиль ${profile.login}…`;
|
||
try {
|
||
await switchToSavedProfile(profile.login);
|
||
reloadTo('/profile');
|
||
} catch (error) {
|
||
status.className = 'status-line is-unavailable';
|
||
status.textContent = `Не удалось переключить профиль: ${error?.message || 'unknown'}`;
|
||
}
|
||
});
|
||
|
||
const close = document.createElement('button');
|
||
close.type = 'button';
|
||
close.className = 'profiles-close';
|
||
close.setAttribute('aria-label', `Закрыть профиль ${profile.login}`);
|
||
close.textContent = '×';
|
||
close.addEventListener('click', async () => {
|
||
const others = profiles.filter((item) => item.login.toLowerCase() !== profile.login.toLowerCase());
|
||
const message = profile.isActive
|
||
? (others.length
|
||
? `Закрыть текущий профиль «${profile.login}»? После закрытия приложение переключится на следующий сохранённый профиль.`
|
||
: `Закрыть текущий профиль «${profile.login}»? После закрытия откроется экран входа.`)
|
||
: `Закрыть профиль «${profile.login}» на этом устройстве?`;
|
||
if (!window.confirm(message)) return;
|
||
|
||
status.hidden = false;
|
||
status.className = 'status-line';
|
||
status.textContent = `Закрываем профиль ${profile.login}…`;
|
||
try {
|
||
const result = await closeSavedProfile(profile.login);
|
||
if (profile.isActive) {
|
||
reloadTo(result.nextProfile ? '/profile' : '/start');
|
||
return;
|
||
}
|
||
status.hidden = true;
|
||
renderList();
|
||
} catch (error) {
|
||
status.className = 'status-line is-unavailable';
|
||
status.textContent = `Не удалось закрыть профиль: ${error?.message || 'unknown'}`;
|
||
}
|
||
});
|
||
|
||
row.append(select, close);
|
||
list.append(row);
|
||
});
|
||
};
|
||
|
||
renderList();
|
||
return screen;
|
||
}
|