Merge pull request #2054 from BEDOLAGA-DEV/dev5

Dev5
This commit is contained in:
Egor
2025-11-25 04:10:40 +03:00
committed by GitHub

View File

@@ -324,6 +324,45 @@
line-height: 1.4;
}
.maintenance-state {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: var(--radius-lg);
padding: 24px;
box-shadow: var(--shadow-lg);
margin-bottom: 24px;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: 12px;
}
.maintenance-state .maintenance-icon {
width: 54px;
height: 54px;
font-size: 28px;
display: inline-flex;
align-items: center;
justify-content: center;
background: rgba(var(--primary-rgb), 0.1);
border-radius: 50%;
color: var(--primary);
box-shadow: var(--shadow-sm);
}
.maintenance-state .maintenance-title {
font-size: 20px;
font-weight: 800;
color: var(--text-primary);
}
.maintenance-state .maintenance-text {
font-size: 15px;
color: var(--text-secondary);
line-height: 1.7;
}
.spinner {
width: 48px;
height: 48px;
@@ -4812,6 +4851,14 @@
</div>
</div>
<div id="maintenanceState" class="maintenance-state hidden" role="status" aria-live="polite">
<div class="maintenance-icon" aria-hidden="true">🔧</div>
<div class="maintenance-title" data-i18n="maintenance.title">Технические работы</div>
<div id="maintenanceStateMessage" class="maintenance-text" data-i18n="maintenance.message">
Сервис временно недоступен из-за технических работ. Попробуйте позже.
</div>
</div>
<!-- Loading State -->
<div id="loadingState" class="loading">
<div class="spinner"></div>
@@ -7547,6 +7594,21 @@
label.textContent = t(key);
}
function resolveMaintenanceMessage() {
const resolvedMessage = (typeof maintenanceState.message === 'string'
? maintenanceState.message.trim()
: '')
|| t('maintenance.message');
const translatedFallback = t('maintenance.message');
const messageFallback = translatedFallback === 'maintenance.message'
? 'The service is temporarily unavailable due to maintenance. Please try again later.'
: translatedFallback;
return resolvedMessage === 'maintenance.message'
? messageFallback
: resolvedMessage;
}
function renderMaintenanceBanner() {
const banner = document.getElementById('maintenanceBanner');
const messageElement = document.getElementById('maintenanceMessage');
@@ -7560,26 +7622,50 @@
return;
}
const resolvedMessage = (typeof maintenanceState.message === 'string'
? maintenanceState.message.trim()
: '')
|| t('maintenance.message');
const translatedFallback = t('maintenance.message');
const messageFallback = translatedFallback === 'maintenance.message'
? 'The service is temporarily unavailable due to maintenance. Please try again later.'
: translatedFallback;
messageElement.textContent = resolvedMessage === 'maintenance.message'
? messageFallback
: resolvedMessage;
messageElement.textContent = resolveMaintenanceMessage();
banner.classList.remove('hidden');
}
function renderMaintenanceScreen() {
const screen = document.getElementById('maintenanceState');
const messageElement = document.getElementById('maintenanceStateMessage');
const banner = document.getElementById('maintenanceBanner');
const loadingState = document.getElementById('loadingState');
const errorState = document.getElementById('errorState');
const mainContent = document.getElementById('mainContent');
if (!screen || !messageElement) {
return;
}
if (!maintenanceState?.isActive) {
screen.classList.add('hidden');
return;
}
messageElement.textContent = resolveMaintenanceMessage();
screen.classList.remove('hidden');
if (banner) {
banner.classList.add('hidden');
}
if (loadingState) {
loadingState.classList.add('hidden');
}
if (errorState) {
errorState.classList.add('hidden');
}
if (mainContent) {
mainContent.classList.add('hidden');
}
}
function applyMaintenanceStatus(status) {
const isActive = Boolean(status?.isActive ?? status?.is_active);
const message = typeof status?.message === 'string' ? status.message : null;
maintenanceState = { isActive, message };
renderMaintenanceBanner();
renderMaintenanceScreen();
}
function refreshAfterLanguageChange() {
@@ -8050,15 +8136,17 @@
async function checkMaintenance(initData) {
if (!initData) {
applyMaintenanceStatus({ isActive: false, message: null });
return;
return false;
}
try {
const status = await fetchMaintenanceStatus(initData);
applyMaintenanceStatus(status);
return Boolean(status?.isActive ?? status?.is_active);
} catch (error) {
console.warn('Unable to load maintenance status:', error);
applyMaintenanceStatus({ isActive: false, message: null });
return false;
}
}
@@ -8076,7 +8164,10 @@
await loadAppsConfig();
const initData = tg.initData || '';
await checkMaintenance(initData);
const maintenanceActive = await checkMaintenance(initData);
if (maintenanceActive) {
return;
}
await refreshSubscriptionData();
} catch (error) {
console.error('Initialization error:', error);
@@ -8086,12 +8177,13 @@
async function loadAppsConfig() {
try {
const response = await fetch('/app-config.json', { cache: 'no-cache' });
if (!response.ok) {
throw new Error('Failed to load app config');
const fallbackPaths = getAppConfigCandidatePaths();
const data = await fetchFirstAvailableAppConfig(fallbackPaths);
if (!data) {
throw new Error('No available app config sources');
}
const data = await response.json();
appsConfig = sanitizeAppsConfig(data?.platforms || {});
ensurePlatformFilter();
@@ -8155,9 +8247,53 @@
} catch (error) {
console.warn('Unable to load apps configuration:', error);
appsConfig = {};
ensurePlatformFilter();
}
}
function getAppConfigCandidatePaths() {
const paths = [];
const currentPath = window.location?.pathname || '/';
const basePath = currentPath.endsWith('/')
? currentPath
: currentPath.replace(/[^/]*$/, '');
const normalizedBase = basePath || '/';
const relativePath = `${normalizedBase}app-config.json`;
paths.push(relativePath);
['/miniapp/app-config.json', '/app-config.json'].forEach(path => {
if (!paths.includes(path)) {
paths.push(path);
}
});
return paths;
}
async function fetchFirstAvailableAppConfig(paths) {
if (!Array.isArray(paths) || !paths.length) {
return null;
}
for (const path of paths) {
try {
const response = await fetch(path, { cache: 'no-cache' });
if (!response.ok) {
continue;
}
const data = await response.json();
if (data && typeof data === 'object') {
return data;
}
} catch (error) {
console.warn('App config path failed:', path, error);
}
}
return null;
}
function renderUserData() {
if (!userData?.user) {
return;