import { renderHeader } from '../components/header.js?v=20260403081123'; import { profile } from '../mock-data.js?v=20260403081123'; import { state } from '../state.js?v=20260403081123'; import { loadProfileParams, profileFieldDefs, saveProfileParams } from '../services/user-profile-params.js?v=20260403081123'; export const pageMeta = { id: 'profile-view', title: 'Профиль' }; function formatDateTime(timeMs) { if (!timeMs) return 'ещё не заполнено'; return new Date(timeMs).toLocaleString('ru-RU'); } function getDisplayName(fieldMap) { const firstName = fieldMap.get('first_name')?.value?.trim() || ''; const lastName = fieldMap.get('last_name')?.value?.trim() || ''; const fullName = `${firstName} ${lastName}`.trim(); return fullName || profile.name; } export function render({ navigate }) { const login = state.session.login || profile.login; const screen = document.createElement('section'); screen.className = 'stack'; screen.append( renderHeader({ title: 'Профиль', rightActions: [ { label: 'Кошелёк', onClick: () => navigate('wallet-view') }, { label: 'Настройки', onClick: () => navigate('settings-view') }, ], }), ); const card = document.createElement('div'); card.className = 'card stack'; const topRow = document.createElement('div'); topRow.className = 'row'; topRow.innerHTML = `
${profile.avatarInitials}

${profile.name}

${login}

`; const hint = document.createElement('div'); hint.className = 'card profile-data-help'; hint.innerHTML = `
Личные данные пользователя

Поля ниже читаются из реальных пользовательских параметров сервера (ListUserParams). Кнопка «Обновить» отправляет UpsertUserParam, что добавляет новую запись в блокчейн.

`; const status = document.createElement('div'); status.className = 'status-line'; status.textContent = 'Загрузка параметров...'; const listWrap = document.createElement('div'); listWrap.className = 'stack profile-param-list'; const editModal = document.createElement('div'); editModal.className = 'profile-help-modal'; editModal.hidden = true; editModal.innerHTML = `
`; const profileNameEl = topRow.querySelector('[data-profile-name="true"]'); const openEditBtn = topRow.querySelector('[data-open-edit="true"]'); const formEl = editModal.querySelector('[data-profile-form="true"]'); const dialogEl = editModal.querySelector('.profile-help-dialog'); const saveBtn = editModal.querySelector('[data-save-profile="true"]'); let currentFields = profileFieldDefs.map((field) => ({ ...field, value: '', timeMs: 0 })); function renderParams(fields) { const fieldMap = new Map(fields.map((field) => [field.key, field])); profileNameEl.textContent = getDisplayName(fieldMap); listWrap.innerHTML = ''; fields.forEach((field) => { const row = document.createElement('div'); row.className = 'card profile-param-item'; row.innerHTML = `
${field.label} ${field.key}
${field.value || '—'}
Обновлено: ${formatDateTime(field.timeMs)}
`; listWrap.append(row); }); } async function refreshParams() { status.className = 'status-line'; status.textContent = 'Загрузка параметров...'; openEditBtn.disabled = true; try { const fields = await loadProfileParams(login); currentFields = fields; renderParams(fields); status.className = 'status-line is-available'; status.textContent = 'Актуальные параметры загружены с сервера.'; } catch (error) { renderParams(currentFields); status.className = 'status-line is-unavailable'; status.textContent = `Не удалось загрузить параметры: ${error.message || 'ошибка сети'}`; } finally { openEditBtn.disabled = false; } } function closeEditModal() { editModal.hidden = true; } function openEditModal() { formEl.innerHTML = ''; currentFields.forEach((field) => { const fieldWrap = document.createElement('label'); fieldWrap.className = 'stack'; fieldWrap.innerHTML = ` ${field.label} `; formEl.append(fieldWrap); }); editModal.hidden = false; dialogEl.focus(); } async function saveChanges() { const valuesByKey = {}; currentFields.forEach((field) => { const input = formEl.querySelector(`input[name="${field.key}"]`); valuesByKey[field.key] = input instanceof HTMLInputElement ? input.value : ''; }); saveBtn.disabled = true; try { await saveProfileParams(login, valuesByKey); closeEditModal(); await refreshParams(); } catch (error) { status.className = 'status-line is-unavailable'; status.textContent = `Не удалось сохранить: ${error.message || 'ошибка сети'}`; } finally { saveBtn.disabled = false; } } openEditBtn.addEventListener('click', openEditModal); saveBtn.addEventListener('click', saveChanges); editModal.querySelector('[data-cancel-edit="true"]').addEventListener('click', closeEditModal); editModal.addEventListener('click', (event) => { const target = event.target; if (target instanceof HTMLElement && (target.dataset.close === 'true' || target.classList.contains('profile-help-close'))) { closeEditModal(); } }); editModal.addEventListener('keydown', (event) => { if (event.key === 'Escape') closeEditModal(); }); card.append(topRow, hint, status, listWrap); screen.append(card, editModal); refreshParams(); return screen; }