import { createTopBar } from '../components/topbar.js';
import { authService, state } from '../state.js';
export const pageMeta = { id: 'blockchain-archive-view', title: 'Архив блокчейна' };
function text(value) {
return String(value == null ? '' : value).trim();
}
function buildViewerUrl(location, blockchainName, channelName, messageNumber) {
const url = new URL('/Blockchain-Viewer.html', window.location.origin);
url.searchParams.set('tx', text(location.arweaveTxId));
url.searchParams.set('offset', String(location.chunkOffset));
url.searchParams.set('size', String(location.chunkSize));
url.searchParams.set('blockchain', blockchainName);
const channel = text(channelName);
if (channel) url.searchParams.set('channel', channel);
const message = text(messageNumber);
if (message) url.searchParams.set('message', message);
return url.toString();
}
async function copyText(value) {
if (navigator.clipboard?.writeText) {
await navigator.clipboard.writeText(value);
return;
}
const area = document.createElement('textarea');
area.value = value;
document.body.appendChild(area);
area.select();
document.execCommand('copy');
area.remove();
}
export function render({ navigate, chrome }) {
const screen = document.createElement('section');
screen.className = 'stack';
chrome?.setTopbar(createTopBar({
title: 'Архив блокчейна',
back: { label: '←', onClick: () => navigate('settings-view') },
}));
const card = document.createElement('div');
card.className = 'card stack';
card.innerHTML = `
Последний архивный блок
Загружаю...
Технические данные
`;
screen.appendChild(card);
const status = card.querySelector('#archive-status');
const blockchainInput = card.querySelector('#archive-blockchain');
const channelInput = card.querySelector('#archive-channel');
const messageInput = card.querySelector('#archive-message');
const linkInput = card.querySelector('#archive-link');
const copyButton = card.querySelector('#archive-copy');
const openButton = card.querySelector('#archive-open');
const tech = card.querySelector('#archive-tech');
let location = null;
let blockchainName = '';
function refreshLink() {
if (!location || !blockchainName) {
linkInput.value = '';
copyButton.disabled = true;
openButton.disabled = true;
return;
}
linkInput.value = buildViewerUrl(location, blockchainName, channelInput.value, messageInput.value);
copyButton.disabled = false;
openButton.disabled = false;
}
channelInput.addEventListener('input', refreshLink);
messageInput.addEventListener('input', refreshLink);
copyButton.addEventListener('click', async () => {
if (!linkInput.value) return;
await copyText(linkInput.value);
status.textContent = 'Ссылка скопирована.';
});
openButton.addEventListener('click', () => {
if (linkInput.value) window.open(linkInput.value, '_blank', 'noopener,noreferrer');
});
void (async () => {
try {
const login = text(state.session.login);
if (!login) throw new Error('Нет активного пользователя');
const user = await authService.getUser(login);
blockchainName = text(user.blockchainName);
if (!blockchainName) throw new Error('У пользователя не найден blockchainName');
blockchainInput.value = blockchainName;
location = await authService.getArchiveBlockchainLocation(blockchainName);
if (!text(location.arweaveTxId) || !Number.isFinite(Number(location.chunkOffset)) || !Number.isFinite(Number(location.chunkSize))) {
throw new Error('Сервер вернул неполную архивную ссылку');
}
status.textContent = `Известна архивная история до блока ${location.sourceLastBlockNumber ?? '—'}.`;
tech.textContent = [
`publisher: ${text(location.publisherLogin) || '—'}`,
`archive big block: ${location.bigBlockNumber ?? '—'}`,
`Arweave TX: ${text(location.arweaveTxId)}`,
`archive hash: ${text(location.archiveHash) || '—'}`,
`chunk offset: ${location.chunkOffset}`,
`chunk size: ${location.chunkSize}`,
`source last block: ${location.sourceLastBlockNumber ?? '—'}`,
].join('\n');
refreshLink();
} catch (error) {
status.textContent = `Архивная ссылка пока недоступна: ${error?.message || error}`;
tech.textContent = '';
refreshLink();
}
})();
return screen;
}