SHA256
166 lines
6.0 KiB
JavaScript
166 lines
6.0 KiB
JavaScript
import { renderHeader } from '../components/header.js';
|
|
import {
|
|
authService,
|
|
clearAuthMessages,
|
|
setAuthBusy,
|
|
setAuthError,
|
|
state,
|
|
} from '../state.js';
|
|
import { buildShineHttpUrlFromAddress } from '../services/shine-server-resolver.js';
|
|
import { toUserMessage } from '../services/ui-error-texts.js';
|
|
|
|
export const pageMeta = { id: 'login-view', title: 'Войти', showAppChrome: false };
|
|
|
|
function setStatus(statusEl, message, kind = 'error') {
|
|
statusEl.classList.toggle('is-unavailable', kind === 'error');
|
|
statusEl.classList.toggle('is-available', kind !== 'error');
|
|
statusEl.textContent = message;
|
|
statusEl.style.display = message ? '' : 'none';
|
|
}
|
|
|
|
function setRemoteServer(remoteWrap, serverLoginEl, serverLinkEl, payload) {
|
|
const serverLogin = String(payload?.accessServerLogin || '').trim();
|
|
const serverUrl = String(payload?.accessServerUrl || '').trim();
|
|
serverLoginEl.textContent = serverLogin ? `@${serverLogin}` : 'другой сервер доступа';
|
|
serverLinkEl.textContent = serverUrl || 'Открыть сервер';
|
|
serverLinkEl.href = buildShineHttpUrlFromAddress(serverUrl);
|
|
remoteWrap.style.display = '';
|
|
}
|
|
|
|
export function render({ navigate }) {
|
|
const screen = document.createElement('section');
|
|
screen.className = 'stack auth-screen auth-screen--lower login-choice-screen';
|
|
|
|
clearAuthMessages();
|
|
|
|
const panel = document.createElement('section');
|
|
panel.className = 'login-panel stack';
|
|
|
|
const title = document.createElement('h1');
|
|
title.className = 'login-panel-title';
|
|
title.textContent = 'Введите логин';
|
|
|
|
const loginField = document.createElement('label');
|
|
loginField.className = 'stack';
|
|
|
|
const loginInput = document.createElement('input');
|
|
loginInput.className = 'input';
|
|
loginInput.type = 'text';
|
|
loginInput.autocomplete = 'username';
|
|
loginInput.autocapitalize = 'off';
|
|
loginInput.spellcheck = false;
|
|
loginInput.placeholder = 'Логин';
|
|
loginInput.value = String(state.loginDraft.login || '');
|
|
|
|
loginField.append(loginInput);
|
|
|
|
const status = document.createElement('p');
|
|
status.className = 'status-line is-unavailable';
|
|
status.style.display = 'none';
|
|
|
|
const remoteWrap = document.createElement('div');
|
|
remoteWrap.className = 'login-remote-server stack';
|
|
remoteWrap.style.display = 'none';
|
|
|
|
const remoteText = document.createElement('p');
|
|
remoteText.className = 'auth-copy';
|
|
const serverLoginEl = document.createElement('strong');
|
|
const textBefore = document.createTextNode('Этот пользователь SHiNE зарегистрирован на другом сервере доступа: ');
|
|
remoteText.append(textBefore, serverLoginEl, document.createTextNode('. Для входа перейдите на его сервер.'));
|
|
|
|
const serverLinkEl = document.createElement('a');
|
|
serverLinkEl.className = 'primary-btn login-server-link';
|
|
serverLinkEl.target = '_self';
|
|
serverLinkEl.rel = 'noopener';
|
|
|
|
remoteWrap.append(remoteText, serverLinkEl);
|
|
|
|
const passwordButton = document.createElement('button');
|
|
passwordButton.className = 'primary-btn';
|
|
passwordButton.type = 'button';
|
|
passwordButton.textContent = 'Войти по паролю';
|
|
|
|
const deviceButton = document.createElement('button');
|
|
deviceButton.className = 'ghost-btn';
|
|
deviceButton.type = 'button';
|
|
deviceButton.textContent = 'Войти через другое устройство';
|
|
|
|
const actions = document.createElement('div');
|
|
actions.className = 'auth-actions login-actions-wide';
|
|
actions.append(passwordButton, deviceButton);
|
|
|
|
const resolveAndContinue = async (targetPage) => {
|
|
const login = String(loginInput.value || '').trim();
|
|
setStatus(status, '');
|
|
remoteWrap.style.display = 'none';
|
|
if (!login) {
|
|
setStatus(status, 'Введите логин.');
|
|
loginInput.focus();
|
|
return;
|
|
}
|
|
|
|
passwordButton.disabled = true;
|
|
deviceButton.disabled = true;
|
|
setAuthBusy(true);
|
|
setAuthError('');
|
|
|
|
try {
|
|
await authService.reconnect(state.entrySettings.shineServer);
|
|
const resolved = await authService.resolveLoginForAuth(login);
|
|
const resolution = String(resolved?.resolution || '').trim().toUpperCase();
|
|
|
|
if (resolution === 'NOT_FOUND') {
|
|
setStatus(status, 'Пользователь с таким логином не зарегистрирован в SHiNE.');
|
|
return;
|
|
}
|
|
if (resolution === 'NO_ACCESS_SERVER') {
|
|
setStatus(status, 'Пользователь зарегистрирован в SHiNE, но для него не найден действующий сервер доступа.');
|
|
return;
|
|
}
|
|
if (resolution === 'REMOTE') {
|
|
state.loginDraft.login = String(resolved?.login || login).trim();
|
|
setRemoteServer(remoteWrap, serverLoginEl, serverLinkEl, resolved);
|
|
return;
|
|
}
|
|
if (resolution !== 'LOCAL') {
|
|
setStatus(status, 'Сервер вернул неизвестный статус проверки логина.');
|
|
return;
|
|
}
|
|
|
|
state.loginDraft.login = String(resolved?.login || login).trim();
|
|
state.loginDraft.password = '';
|
|
navigate(targetPage);
|
|
} catch (error) {
|
|
const message = toUserMessage(error, 'Не удалось проверить логин.');
|
|
setAuthError(message);
|
|
setStatus(status, message);
|
|
} finally {
|
|
setAuthBusy(false);
|
|
passwordButton.disabled = false;
|
|
deviceButton.disabled = false;
|
|
}
|
|
};
|
|
|
|
passwordButton.addEventListener('click', () => resolveAndContinue('login-password-view'));
|
|
deviceButton.addEventListener('click', () => resolveAndContinue('login-other-device-view'));
|
|
loginInput.addEventListener('keydown', (event) => {
|
|
if (event.key === 'Enter') {
|
|
event.preventDefault();
|
|
void resolveAndContinue('login-password-view');
|
|
}
|
|
});
|
|
|
|
panel.append(title, loginField, status, remoteWrap, actions);
|
|
|
|
screen.append(
|
|
renderHeader({
|
|
title: '',
|
|
leftAction: { label: '←', onClick: () => navigate('start-view') },
|
|
}),
|
|
panel,
|
|
);
|
|
|
|
window.setTimeout(() => loginInput.focus(), 0);
|
|
return screen;
|
|
}
|