import { createTopBar } from '../components/topbar.js'; import { authService } from '../state.js'; import { KeyRotationClient } from '../services/key-rotation-service.js'; export const pageMeta = { id: 'my-blockchain-view', title: 'Мой блокчейн' }; const TYPE_LABELS = new Map([ ['0:0','Начало блокчейна'], ['0:2','Смена ключей / fork'], ['1:1','Публикация'], ['1:2','Ответ'], ['1:3','Редактирование'], ['2:1','Реакция'], ['3:1','Связь'], ['4:1','Статус'], ]); function shortHash(v){const s=String(v||'');return s.length>18?`${s.slice(0,9)}…${s.slice(-7)}`:s;} function eventLabel(item){return TYPE_LABELS.get(`${item.msgType}:${item.msgSubType}`)||`Событие ${item.msgType}/${item.msgSubType}`;} function formatDate(ms){try{return new Date(Number(ms)||0).toLocaleString('ru-RU');}catch{return '';}} export function render({ navigate, chrome }) { const screen=document.createElement('section'); screen.className='stack'; chrome?.setTopbar(createTopBar({ title:'Мой блокчейн', back:{label:'←',onClick:()=>navigate('settings-view')} })); const intro=document.createElement('div'); intro.className='card stack'; intro.innerHTML=`История ваших действийЭто текущая активная версия вашего блокчейна. Хэши записей сохраняют логическую идентичность при fork.`; const rotate=document.createElement('button'); rotate.type='button'; rotate.className='primary-btn'; rotate.textContent='Сменить пароль / ключи'; rotate.addEventListener('click',()=>navigate('key-rotation-view')); intro.append(rotate); screen.append(intro); const list=document.createElement('div'); list.className='stack'; screen.append(list); const more=document.createElement('button'); more.type='button'; more.className='secondary-btn'; more.textContent='Показать более ранние записи'; more.hidden=true; screen.append(more); const client=new KeyRotationClient(authService); let before=null; let loading=false; let disposed=false; async function load(reset=false){ if(loading||disposed)return; loading=true; more.disabled=true; if(reset){list.innerHTML='';before=null;} try{ const data=await client.getMyBlockchain({beforeBlock:before,limit:50,includeBlockBytes:false}); if(reset){const head=document.createElement('div');head.className='card stack';head.innerHTML=`${data.blockchainName||'—'}Последний блок: #${Number(data.tipBlockNumber??-1)} · ${shortHash(data.tipBlockHash)}`;list.append(head);} for(const item of data.blocks||[]){ const card=document.createElement('div');card.className='card stack'; const target=item.toLogin?`Цель: ${escapeHtml(item.toLogin)} #${item.toBlockNumber??'—'} · ${shortHash(item.toBlockHash)}`:''; card.innerHTML=`
#${item.blockNumber} · ${escapeHtml(eventLabel(item))}
${formatDate(item.timestampMs)} · hash ${shortHash(item.blockHash)}${target}`; list.append(card); } before=data.nextBeforeBlock; more.hidden=before==null; if(!(data.blocks||[]).length && reset){const empty=document.createElement('div');empty.className='card';empty.textContent='Записей пока нет.';list.append(empty);} }catch(e){const err=document.createElement('div');err.className='card';err.textContent=`Не удалось загрузить блокчейн: ${e?.message||e}`;list.append(err);} finally{loading=false;more.disabled=false;} } more.addEventListener('click',()=>void load(false)); void load(true); screen.cleanup=()=>{disposed=true;}; return screen; } function escapeHtml(value){return String(value??'').replace(/[&<>"]/g,c=>({'&':'&','<':'<','>':'>','"':'"'}[c]));}