SHA256
50 lines
4.0 KiB
JavaScript
50 lines
4.0 KiB
JavaScript
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=`<strong>История ваших действий</strong><span class="meta-muted">Это текущая активная версия вашего блокчейна. Хэши записей сохраняют логическую идентичность при fork.</span>`;
|
|
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=`<strong>${data.blockchainName||'—'}</strong><span class="meta-muted">Последний блок: #${Number(data.tipBlockNumber??-1)} · ${shortHash(data.tipBlockHash)}</span>`;list.append(head);}
|
|
for(const item of data.blocks||[]){
|
|
const card=document.createElement('div');card.className='card stack';
|
|
const target=item.toLogin?`<span class="meta-muted">Цель: ${escapeHtml(item.toLogin)} #${item.toBlockNumber??'—'} · ${shortHash(item.toBlockHash)}</span>`:'';
|
|
card.innerHTML=`<div><strong>#${item.blockNumber} · ${escapeHtml(eventLabel(item))}</strong></div><span class="meta-muted">${formatDate(item.timestampMs)} · hash ${shortHash(item.blockHash)}</span>${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]));}
|