import { createTopBar } from '../components/topbar.js'; import { authService, cancelAddProfileLogin, consumeAuthReturnPage, authorizeSession, refreshSessions, resetRegistrationFlow, setAuthError, setAuthInfo, state, } from '../state.js'; import { clearStoredMessages } from '../services/message-store.js'; import { toUserMessage } from '../services/ui-error-texts.js'; export const pageMeta = { id: 'registration-keys-view', title: 'Сохранение ключей', showAppChrome: false }; const EMPTY_PASSWORD_WORDS = Array.from({ length: 12 }, () => ''); export function render({ navigate }) { const screen = document.createElement('section'); screen.className = 'stack keys-screen'; const isLoginFlow = state.registrationDraft.flowType === 'login'; const normalizedLogin = (state.registrationDraft.login || '').trim(); const displayLogin = normalizedLogin ? `@${normalizedLogin.replace(/^@/, '')}` : '@new.user'; const lead = document.createElement('div'); lead.className = 'keys-lead'; const title = document.createElement('h1'); title.className = 'keys-lead__title'; title.textContent = isLoginFlow ? `Вы вошли как ${displayLogin}` : `${displayLogin} зарегистрирован`; const question = document.createElement('p'); question.className = 'keys-lead__text'; question.textContent = 'Какие ключи хранить на этом устройстве?'; const questionHint = document.createElement('p'); questionHint.className = 'keys-lead__text'; questionHint.textContent = 'Они хранятся в зашифрованном виде.'; lead.append(title, question, questionHint); const status = document.createElement('p'); status.className = 'status-line is-unavailable'; status.style.display = 'none'; const createKeyRow = (toggle, titleText, descriptionText) => { const row = document.createElement('label'); row.className = 'keys-row'; const text = document.createElement('span'); text.className = 'keys-row__text'; const name = document.createElement('span'); name.className = 'keys-row__title'; name.textContent = titleText; const description = document.createElement('span'); description.className = 'keys-row__hint'; description.textContent = descriptionText; text.append(name, description); toggle.className = 'switch'; row.append(text, toggle); return row; }; const rootToggle = document.createElement('input'); rootToggle.type = 'checkbox'; rootToggle.checked = state.keyStorage.saveRoot; const blockchainToggle = document.createElement('input'); blockchainToggle.type = 'checkbox'; blockchainToggle.checked = state.keyStorage.saveBlockchain; const deviceToggle = document.createElement('input'); deviceToggle.type = 'checkbox'; deviceToggle.checked = true; deviceToggle.disabled = true; const list = document.createElement('div'); list.className = 'keys-list'; list.append( createKeyRow(rootToggle, 'Главный ключ', 'Смена пароля, восстановление доступа, важные настройки'), createKeyRow(blockchainToggle, 'Ключ публикаций', 'Подписывает ваши записи и действия'), createKeyRow(deviceToggle, 'Ключ устройства', 'Вход с этого устройства – нужен всегда'), ); const simpleNote = document.createElement('p'); simpleNote.className = 'keys-note'; simpleNote.textContent = 'Не уверены – оставьте все включёнными.'; const actions = document.createElement('div'); actions.className = 'keys-actions'; const cancelButton = document.createElement('button'); cancelButton.className = 'secondary-btn'; cancelButton.type = 'button'; cancelButton.textContent = 'Отмена'; cancelButton.addEventListener('click', async () => { if (state.authReturnHash === '/profiles') { await cancelAddProfileLogin(); navigate('profiles-view'); return; } resetRegistrationFlow(); navigate('start-view'); }); const okButton = document.createElement('button'); okButton.className = 'primary-btn'; okButton.type = 'button'; okButton.textContent = 'Готово'; okButton.addEventListener('click', async () => { status.style.display = 'none'; try { if (!state.registrationDraft.pendingKeyBundle || !state.registrationDraft.pendingSessionMaterial) { throw new Error('Сначала завершите шаг регистрации на предыдущем экране'); } state.keyStorage.saveRoot = rootToggle.checked; state.keyStorage.saveBlockchain = blockchainToggle.checked; await authService.persistSelectedKeys( state.registrationDraft.login, state.registrationDraft.storagePwd, state.registrationDraft.pendingKeyBundle, { saveRoot: state.keyStorage.saveRoot, saveBlockchain: state.keyStorage.saveBlockchain, }, ); await authService.persistSessionMaterial( state.registrationDraft.login, state.registrationDraft.pendingSessionMaterial, ); if (!state.keyStorage.saveRoot && state.registrationDraft.pendingKeyBundle) { state.registrationDraft.pendingKeyBundle.rootPair = null; } if (!state.keyStorage.saveBlockchain && state.registrationDraft.pendingKeyBundle) { state.registrationDraft.pendingKeyBundle.blockchainPair = null; } await clearStoredMessages(state.registrationDraft.login).catch(() => {}); authorizeSession({ login: state.registrationDraft.login, sessionId: state.registrationDraft.sessionId, storagePwd: state.registrationDraft.storagePwd, }); state.loginDraft.login = state.registrationDraft.login; state.loginDraft.password = ''; state.loginDraft.passwordMode = 'single'; state.loginDraft.passwordWords = EMPTY_PASSWORD_WORDS.slice(); state.registrationDraft.flowType = ''; state.registrationDraft.password = ''; state.registrationDraft.passwordMode = 'single'; state.registrationDraft.passwordWords = EMPTY_PASSWORD_WORDS.slice(); state.registrationDraft.passwordWordsLinked = false; state.registrationDraft.usePromoCode = false; state.registrationDraft.promoCode = ''; state.registrationDraft.storagePwd = ''; state.registrationDraft.sessionId = ''; state.registrationDraft.pendingKeyBundle = null; state.registrationDraft.pendingSessionMaterial = null; state.registrationDraft.preGeneratedKeyBundle = null; state.registrationPayment.walletAddress = ''; state.registrationPayment.balanceSOL = '0.0000'; await refreshSessions(); setAuthInfo(isLoginFlow ? `Ключи сохранены. Вы вошли как @${state.registrationDraft.login}. Далее откройте вкладку «Каналы».` : `Ключи сохранены. Регистрация завершена для @${state.registrationDraft.login}. Далее откройте вкладку «Каналы».`); navigate(consumeAuthReturnPage('profile-view')); } catch (error) { const message = toUserMessage(error, 'Не удалось сохранить ключи на устройстве.'); setAuthError(message); status.textContent = message; status.style.display = ''; } }); actions.append(okButton, cancelButton); screen.append( createTopBar({ title: 'Сохранение ключей', back: { label: '←', onClick: async () => { if (state.authReturnHash === '/profiles') { await cancelAddProfileLogin(); navigate('profiles-view'); return; } resetRegistrationFlow(); navigate('start-view'); }, }, }), lead, list, simpleNote, status, actions, ); return screen; }