import { renderHeader } from '../components/header.js?v=20260403081123'; import { channelPosts, channels } from '../mock-data.js?v=20260403081123'; import { addLocalChannelPost, authService, getLocalChannelPosts, state } from '../state.js?v=20260403081123'; export const pageMeta = { id: 'channel-view', title: 'Канал' }; function findMockChannel(channelId) { const channel = channels.find((c) => c.id === channelId) || channels[0]; return { channel, posts: [ ...(channelPosts[channel.id] || []).map((post) => ({ title: post.title, body: post.body })), ...getLocalChannelPosts(channelId), ], isOwnChannel: channel.ownerLogin === '@shine.alex', }; } function mapApiMessageToPost(message) { return { title: `${message.authorLogin || 'author'} • #${message.messageRef?.blockNumber ?? '?'}`, body: message.text || '(пусто)', }; } function renderPostCard(post) { const card = document.createElement('article'); card.className = 'card stack'; card.innerHTML = `${post.title}

${post.body}

`; return card; } function openAddMessageModal({ channelId, channelName, onSubmit }) { const root = document.getElementById('modal-root'); root.innerHTML = ` `; const textEl = root.querySelector('#channel-message-text'); const errorEl = root.querySelector('#channel-message-error'); const close = () => { root.innerHTML = ''; }; root.querySelector('#channel-message-cancel').addEventListener('click', close); root.querySelector('#channel-message-submit').addEventListener('click', () => { const body = textEl.value.trim(); if (!body) { errorEl.textContent = 'Введите текст сообщения.'; return; } onSubmit({ title: `${state.session.login || 'Вы'} • сейчас`, body, }); close(); }); if (textEl) textEl.focus(); } function renderBody(screen, navigate, channelId, channelData) { const head = document.createElement('div'); head.className = 'card'; head.innerHTML = ` # ${channelData.channel.name}

${channelData.channel.description}

Владелец: ${channelData.channel.ownerName}

`; const actionButton = document.createElement('button'); actionButton.className = channelData.isOwnChannel ? 'primary-btn' : 'secondary-btn'; actionButton.textContent = channelData.isOwnChannel ? 'Добавить сообщение в канал' : 'Отписаться от канала'; const feed = document.createElement('div'); feed.className = 'stack'; channelData.posts.forEach((post) => { feed.append(renderPostCard(post)); }); if (channelData.isOwnChannel) { actionButton.addEventListener('click', () => { openAddMessageModal({ channelId, channelName: channelData.channel.name, onSubmit: (post) => { addLocalChannelPost(channelId, post); channelData.posts.push(post); feed.append(renderPostCard(post)); }, }); }); } const backButton = document.createElement('button'); backButton.className = 'secondary-btn'; backButton.textContent = 'Назад к списку'; backButton.addEventListener('click', () => navigate('channels-list')); screen.append(head, actionButton, feed, backButton); } async function loadFromApi(channelId) { const summary = state.channelsIndex[channelId]; if (!summary) return null; const selector = { ownerBlockchainName: summary.channel?.ownerBlockchainName, channelRootBlockNumber: summary.channel?.channelRoot?.blockNumber, channelRootBlockHash: summary.channel?.channelRoot?.blockHash, }; if (!selector.ownerBlockchainName || selector.channelRootBlockNumber == null) return null; const payload = await authService.getChannelMessages(selector, 200, 'asc'); const posts = [ ...(payload.messages || []).map(mapApiMessageToPost), ...getLocalChannelPosts(channelId), ]; return { channel: { name: payload.channel?.channelName || summary.channel?.channelName || 'unknown', description: `bch=${payload.channel?.ownerBlockchainName || selector.ownerBlockchainName}`, ownerName: payload.channel?.ownerLogin || summary.channel?.ownerLogin || 'unknown', }, posts, isOwnChannel: (payload.channel?.ownerLogin || '').toLowerCase() === (state.session.login || '').toLowerCase(), }; } export function render({ navigate, route }) { const channelId = route.params.channelId || 'ch1'; const screen = document.createElement('section'); screen.className = 'stack'; const headerTitle = state.channelsIndex[channelId]?.channel?.channelName ? `Канал: ${state.channelsIndex[channelId].channel.channelName}` : `Канал: ${(channels.find((c) => c.id === channelId) || channels[0]).name}`; screen.append( renderHeader({ title: headerTitle, leftAction: { label: '←', onClick: () => navigate('channels-list') }, }) ); const loading = document.createElement('div'); loading.className = 'card meta-muted'; loading.textContent = 'Загрузка канала...'; screen.append(loading); (async () => { try { const apiData = await loadFromApi(channelId); loading.remove(); if (apiData) { renderBody(screen, navigate, channelId, apiData); return; } } catch { // fallback to mock below } loading.remove(); renderBody(screen, navigate, channelId, findMockChannel(channelId)); })(); return screen; }