Channels UI surgical cleanup and create description save fix
This commit is contained in:
parent
126b4ba3a1
commit
7bdb3118ae
@ -132,8 +132,8 @@ export function render({ navigate }) {
|
||||
});
|
||||
|
||||
const baseMessage = `Канал "${normalizeChannelDisplayName(check.name)}" создан.`;
|
||||
const successMessage = created?.usedLegacyDescriptionFallback
|
||||
? `${baseMessage} Описание не сохранено: на текущем сервере включен legacy-формат create-channel.`
|
||||
const successMessage = created?.usedLegacyDescriptionFallback && created?.savedDescriptionViaUserParam
|
||||
? `${baseMessage} Описание сохранено через блок параметра.`
|
||||
: baseMessage;
|
||||
persistCreateSuccessFlash(successMessage);
|
||||
navigate('channels-list');
|
||||
|
||||
@ -363,6 +363,8 @@ export function render({ navigate, route }) {
|
||||
|
||||
const screen = document.createElement('section');
|
||||
screen.className = 'stack channels-screen channels-screen--thread';
|
||||
const appScreen = document.getElementById('app-screen');
|
||||
appScreen?.classList.add('channels-scroll-clean');
|
||||
|
||||
const userIndicator = document.createElement('div');
|
||||
userIndicator.className = 'card channels-user-chip';
|
||||
@ -538,5 +540,9 @@ export function render({ navigate, route }) {
|
||||
}
|
||||
})();
|
||||
|
||||
screen.cleanup = () => {
|
||||
appScreen?.classList.remove('channels-scroll-clean');
|
||||
};
|
||||
|
||||
return screen;
|
||||
}
|
||||
|
||||
@ -605,21 +605,12 @@ function renderBody(screen, navigate, routeKey, channelData, handlers) {
|
||||
title.className = 'channel-head-title';
|
||||
title.textContent = channelData.channel.displayName || channelData.channel.name;
|
||||
|
||||
const description = document.createElement('p');
|
||||
description.className = 'channel-head-description';
|
||||
const hasDescription = !!String(channelData.channel.description || '').trim();
|
||||
if (hasDescription) {
|
||||
description.textContent = channelData.channel.description;
|
||||
} else if (channelData.isOwnChannel) {
|
||||
description.textContent = 'Описание пока не задано.';
|
||||
}
|
||||
|
||||
const owner = document.createElement('p');
|
||||
owner.className = 'channel-head-meta';
|
||||
owner.textContent = `Владелец: ${channelData.channel.ownerName}`;
|
||||
|
||||
const headActions = document.createElement('div');
|
||||
headActions.className = 'row';
|
||||
headActions.className = 'channel-head-actions';
|
||||
const aboutButton = document.createElement('button');
|
||||
aboutButton.type = 'button';
|
||||
aboutButton.className = 'secondary-btn small-btn';
|
||||
@ -646,20 +637,7 @@ function renderBody(screen, navigate, routeKey, channelData, handlers) {
|
||||
headActions.append(editButton);
|
||||
}
|
||||
|
||||
if (hasDescription) {
|
||||
const moreButton = document.createElement('button');
|
||||
moreButton.type = 'button';
|
||||
moreButton.className = 'channel-head-more';
|
||||
moreButton.textContent = 'ещё';
|
||||
moreButton.addEventListener('click', () => {
|
||||
description.classList.toggle('is-expanded');
|
||||
moreButton.textContent = description.classList.contains('is-expanded') ? 'скрыть' : 'ещё';
|
||||
});
|
||||
headActions.append(moreButton);
|
||||
}
|
||||
|
||||
head.append(title);
|
||||
if (hasDescription || channelData.isOwnChannel) head.append(description);
|
||||
head.append(owner, headActions);
|
||||
|
||||
const actionButton = document.createElement('button');
|
||||
@ -723,16 +701,8 @@ export function render({ navigate, route }) {
|
||||
|
||||
const screen = document.createElement('section');
|
||||
screen.className = 'stack channels-screen channels-screen--channel';
|
||||
|
||||
const titleFromIndex = state.channelsIndex[channelId]?.channel?.channelName;
|
||||
const ownerFromIndex = state.channelsIndex[channelId]?.channel?.ownerLogin;
|
||||
const titleFromIndexDisplay = (ownerFromIndex && titleFromIndex) ? `${ownerFromIndex}/${titleFromIndex}` : titleFromIndex;
|
||||
const titleFromRoute = route.params.ownerBlockchainName ? String(route.params.ownerBlockchainName) : '';
|
||||
const headerTitle = `Канал: ${titleFromIndexDisplay || titleFromRoute || 'Канал'}`;
|
||||
|
||||
const userIndicator = document.createElement('div');
|
||||
userIndicator.className = 'card channels-user-chip';
|
||||
userIndicator.textContent = `Вы вошли как @${state.session.login || 'неизвестно'}`;
|
||||
const appScreen = document.getElementById('app-screen');
|
||||
appScreen?.classList.add('channels-scroll-clean');
|
||||
|
||||
const statusBox = document.createElement('div');
|
||||
statusBox.className = 'card status-line is-unavailable channels-status';
|
||||
@ -846,11 +816,11 @@ export function render({ navigate, route }) {
|
||||
|
||||
screen.append(
|
||||
renderHeader({
|
||||
title: headerTitle,
|
||||
title: '',
|
||||
leftAction: { label: '<', onClick: () => navigate('channels-list') },
|
||||
}),
|
||||
);
|
||||
screen.append(userIndicator, statusBox);
|
||||
screen.append(statusBox);
|
||||
|
||||
const skeleton = renderSkeleton(screen);
|
||||
|
||||
@ -924,5 +894,9 @@ export function render({ navigate, route }) {
|
||||
}
|
||||
})();
|
||||
|
||||
screen.cleanup = () => {
|
||||
appScreen?.classList.remove('channels-scroll-clean');
|
||||
};
|
||||
|
||||
return screen;
|
||||
}
|
||||
|
||||
@ -39,20 +39,6 @@ export function render({ navigate }) {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card stack';
|
||||
|
||||
const nextStepCard = document.createElement('div');
|
||||
nextStepCard.className = 'card stack';
|
||||
nextStepCard.innerHTML = `
|
||||
<strong>Вы вошли как @${login}</strong>
|
||||
<p class="meta-muted">Следующий шаг для ручной проверки: откройте вкладку «Каналы» в нижнем меню.</p>
|
||||
`;
|
||||
|
||||
const openChannelsButton = document.createElement('button');
|
||||
openChannelsButton.className = 'primary-btn';
|
||||
openChannelsButton.type = 'button';
|
||||
openChannelsButton.textContent = 'Открыть каналы';
|
||||
openChannelsButton.addEventListener('click', () => navigate('channels-list'));
|
||||
nextStepCard.append(openChannelsButton);
|
||||
|
||||
const topRow = document.createElement('div');
|
||||
topRow.className = 'row';
|
||||
topRow.innerHTML = `
|
||||
@ -215,7 +201,7 @@ export function render({ navigate }) {
|
||||
shineBtn.addEventListener('click', () => onToggleClick('shine'));
|
||||
|
||||
card.append(topRow, badgesRow, status, listWrap);
|
||||
screen.append(nextStepCard, card);
|
||||
screen.append(card);
|
||||
|
||||
refreshProfileSnapshot();
|
||||
|
||||
|
||||
@ -89,6 +89,16 @@ function isLegacyCreateChannelFormatError(error) {
|
||||
);
|
||||
}
|
||||
|
||||
function channelDescriptionParamKeyFromSelector(selector) {
|
||||
const owner = String(selector?.ownerBlockchainName || '').trim();
|
||||
const rootNo = Number(selector?.channelRootBlockNumber);
|
||||
const rootHash = String(selector?.channelRootBlockHash || '').trim().toLowerCase();
|
||||
if (!owner || !Number.isFinite(rootNo) || rootNo < 0 || !/^[0-9a-f]{64}$/.test(rootHash)) {
|
||||
return '';
|
||||
}
|
||||
return `channel_desc:${owner}:${rootNo}:${rootHash}`;
|
||||
}
|
||||
|
||||
function makeClientInfo() {
|
||||
const ua = navigator.userAgent || 'unknown';
|
||||
return ua.slice(0, 50);
|
||||
@ -891,6 +901,7 @@ export class AuthService {
|
||||
const check = validateChannelDisplayName(channelName);
|
||||
if (!check.ok) throw new Error(channelNameErrorText(check.code));
|
||||
const cleanChannelName = normalizeChannelDisplayName(check.normalized);
|
||||
const cleanChannelDescription = normalizeChannelDescription(channelDescription);
|
||||
const channelSlug = toCanonicalChannelSlug(cleanChannelName);
|
||||
|
||||
const key = `create-channel:${cleanLogin}:${channelSlug || cleanChannelName.toLowerCase()}`;
|
||||
@ -930,7 +941,7 @@ export class AuthService {
|
||||
prevLineHashHex,
|
||||
thisLineNumber,
|
||||
channelName: cleanChannelName,
|
||||
channelDescription,
|
||||
channelDescription: cleanChannelDescription,
|
||||
})
|
||||
: makeCreateChannelBodyBytes({
|
||||
lineCode: 0,
|
||||
@ -952,6 +963,7 @@ export class AuthService {
|
||||
|
||||
let payload;
|
||||
let usedLegacyDescriptionFallback = false;
|
||||
let savedDescriptionViaUserParam = false;
|
||||
try {
|
||||
payload = await submitCreate(true);
|
||||
} catch (error) {
|
||||
@ -960,13 +972,32 @@ export class AuthService {
|
||||
usedLegacyDescriptionFallback = true;
|
||||
}
|
||||
|
||||
const selector = {
|
||||
ownerBlockchainName: blockchainName,
|
||||
channelRootBlockNumber: Number(payload?.serverLastGlobalNumber),
|
||||
channelRootBlockHash: normalizeHex32(payload?.serverLastGlobalHash, ZERO64),
|
||||
};
|
||||
|
||||
if (usedLegacyDescriptionFallback && cleanChannelDescription) {
|
||||
const param = channelDescriptionParamKeyFromSelector(selector);
|
||||
if (!param) {
|
||||
throw new Error('Не удалось сохранить описание канала: некорректный идентификатор канала.');
|
||||
}
|
||||
await this.addBlockUserParam({
|
||||
login: cleanLogin,
|
||||
storagePwd,
|
||||
param,
|
||||
value: JSON.stringify({ v: cleanChannelDescription }),
|
||||
});
|
||||
savedDescriptionViaUserParam = true;
|
||||
}
|
||||
|
||||
return {
|
||||
...payload,
|
||||
usedLegacyDescriptionFallback,
|
||||
savedDescriptionViaUserParam,
|
||||
channel: {
|
||||
ownerBlockchainName: blockchainName,
|
||||
channelRootBlockNumber: Number(payload?.serverLastGlobalNumber),
|
||||
channelRootBlockHash: normalizeHex32(payload?.serverLastGlobalHash, ZERO64),
|
||||
...selector,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@ -1293,6 +1293,14 @@ textarea.input {
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.channel-head-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.channel-head-title {
|
||||
font-size: 24px;
|
||||
color: #f0d089;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user