mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-02-22 12:21:26 +00:00
Merge pull request #1163 from Fr1ngg/revert-1162-revert-1155-revert-1154-c3rvdj-bedolaga/update-miniapp/index.html-logic
Revert "Revert "Revert "Handle registration and empty subscription states in mini app"""
This commit is contained in:
@@ -301,47 +301,6 @@
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.state-block {
|
||||
text-align: center;
|
||||
padding: 48px 24px;
|
||||
background: var(--bg-secondary);
|
||||
border-radius: var(--radius-xl);
|
||||
margin: 20px 0;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.state-block.compact {
|
||||
padding: 32px 20px;
|
||||
margin: 16px 0 24px;
|
||||
}
|
||||
|
||||
.state-icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.state-title {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 12px;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.state-text {
|
||||
font-size: 15px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.6;
|
||||
margin: 0 auto 20px;
|
||||
max-width: 360px;
|
||||
}
|
||||
|
||||
.state-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.error-icon {
|
||||
font-size: 64px;
|
||||
margin-bottom: 16px;
|
||||
@@ -1923,11 +1882,6 @@
|
||||
color: #41464b;
|
||||
}
|
||||
|
||||
.status-inactive {
|
||||
background: linear-gradient(135deg, #dbeafe, #eff6ff);
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
/* Stats Grid */
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
@@ -4254,23 +4208,6 @@
|
||||
<div class="loading-text" id="loadingText" data-i18n="app.loading">Loading your subscription...</div>
|
||||
</div>
|
||||
|
||||
<!-- Registration Required State -->
|
||||
<div id="registrationState" class="state-block hidden">
|
||||
<div class="state-icon">🤖</div>
|
||||
<div class="state-title" id="registrationTitle" data-i18n="registration.title">Register in the bot</div>
|
||||
<div class="state-text" id="registrationText" data-i18n="registration.description">
|
||||
Open the Telegram bot to create an account and get access to subscription options.
|
||||
</div>
|
||||
<div class="state-actions">
|
||||
<button
|
||||
id="openBotBtn"
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
data-i18n="registration.button"
|
||||
>Open bot</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Error State -->
|
||||
<div id="errorState" class="error hidden">
|
||||
<div class="error-icon">⚠️</div>
|
||||
@@ -4288,22 +4225,6 @@
|
||||
|
||||
<!-- Main Content -->
|
||||
<div id="mainContent" class="hidden">
|
||||
<div id="noSubscriptionNotice" class="state-block compact hidden">
|
||||
<div class="state-icon">🛡️</div>
|
||||
<div class="state-title" data-i18n="subscription_missing.title">No active subscription yet</div>
|
||||
<div class="state-text" data-i18n="subscription_missing.description">
|
||||
Choose a plan to activate VPN access. You can top up your balance and pay right inside the mini app.
|
||||
</div>
|
||||
<div class="state-actions">
|
||||
<button
|
||||
id="noSubscriptionAction"
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
data-i18n="subscription_missing.button"
|
||||
>Choose a subscription</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Promo Offers -->
|
||||
<div id="promoOffersContainer" class="promo-offers hidden"></div>
|
||||
|
||||
@@ -4905,17 +4826,11 @@
|
||||
showPopup: null,
|
||||
};
|
||||
|
||||
const pageParams = new URLSearchParams(window.location.search || '');
|
||||
const botUsername = detectBotUsername();
|
||||
const botStartParam = resolveBotStartParam();
|
||||
|
||||
let hasAnimatedCards = false;
|
||||
let promoOfferTimers = [];
|
||||
let promoOfferTimerHandle = null;
|
||||
let referralListExpanded = false;
|
||||
let referralCopyResetHandle = null;
|
||||
let subscriptionMissingMode = false;
|
||||
let registrationRequired = false;
|
||||
|
||||
if (typeof tg.expand === 'function') {
|
||||
tg.expand();
|
||||
@@ -5057,13 +4972,6 @@
|
||||
'app.loading': 'Loading your subscription...',
|
||||
'error.default.title': 'Subscription Not Found',
|
||||
'error.default.message': 'Please contact support to activate your subscription.',
|
||||
'registration.title': 'Register in the bot',
|
||||
'registration.description': 'Open the Telegram bot to create an account and unlock subscription options.',
|
||||
'registration.button': 'Open bot',
|
||||
'registration.error': 'Unable to open the bot automatically. Please open it from Telegram.',
|
||||
'subscription_missing.title': 'No active subscription yet',
|
||||
'subscription_missing.description': 'Choose a plan to activate VPN access. You can top up your balance and pay right inside the mini app.',
|
||||
'subscription_missing.button': 'Choose a subscription',
|
||||
'stats.days_left': 'Days left',
|
||||
'stats.servers': 'Servers',
|
||||
'stats.devices': 'Devices',
|
||||
@@ -5372,11 +5280,9 @@
|
||||
'status.trial': 'Trial',
|
||||
'status.expired': 'Expired',
|
||||
'status.disabled': 'Disabled',
|
||||
'status.inactive': 'Inactive',
|
||||
'status.unknown': 'Unknown',
|
||||
'subscription.type.trial': 'Trial',
|
||||
'subscription.type.paid': 'Paid',
|
||||
'subscription.type.none': 'Not available',
|
||||
'autopay.enabled': 'Enabled',
|
||||
'autopay.disabled': 'Disabled',
|
||||
'platform.ios': 'iOS',
|
||||
@@ -5421,13 +5327,6 @@
|
||||
'app.loading': 'Загружаем вашу подписку...',
|
||||
'error.default.title': 'Подписка не найдена',
|
||||
'error.default.message': 'Свяжитесь с поддержкой, чтобы активировать подписку.',
|
||||
'registration.title': 'Зарегистрируйтесь в боте',
|
||||
'registration.description': 'Откройте Telegram-бота, чтобы создать аккаунт и получить доступ к оформлению подписки.',
|
||||
'registration.button': 'Открыть бота',
|
||||
'registration.error': 'Не удалось открыть бота автоматически. Откройте его вручную в Telegram.',
|
||||
'subscription_missing.title': 'Подписка ещё не оформлена',
|
||||
'subscription_missing.description': 'Выберите подходящий тариф, пополните баланс и оплатите подписку прямо в мини-приложении.',
|
||||
'subscription_missing.button': 'Выбрать подписку',
|
||||
'stats.days_left': 'Осталось дней',
|
||||
'stats.servers': 'Серверы',
|
||||
'stats.devices': 'Устройства',
|
||||
@@ -5736,11 +5635,9 @@
|
||||
'status.trial': 'Пробная',
|
||||
'status.expired': 'Истекла',
|
||||
'status.disabled': 'Отключена',
|
||||
'status.inactive': 'Не активна',
|
||||
'status.unknown': 'Неизвестно',
|
||||
'subscription.type.trial': 'Триал',
|
||||
'subscription.type.paid': 'Платная',
|
||||
'subscription.type.none': 'Нет подписки',
|
||||
'autopay.enabled': 'Включен',
|
||||
'autopay.disabled': 'Выключен',
|
||||
'platform.ios': 'iOS',
|
||||
@@ -6560,98 +6457,6 @@
|
||||
return trimmed.length ? trimmed : null;
|
||||
}
|
||||
|
||||
function normalizeBotUsername(value) {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
const normalized = String(value).trim().replace(/^@/, '');
|
||||
return normalized ? normalized : null;
|
||||
}
|
||||
|
||||
function detectBotUsername() {
|
||||
const overrides = [
|
||||
typeof window.MINIAPP_BOT_USERNAME === 'string' ? window.MINIAPP_BOT_USERNAME : null,
|
||||
document.body?.dataset?.botUsername ?? null,
|
||||
document.querySelector('meta[name="telegram-bot-username"]')?.getAttribute('content') ?? null,
|
||||
document.querySelector('meta[name="bot-username"]')?.getAttribute('content') ?? null,
|
||||
];
|
||||
for (const override of overrides) {
|
||||
const normalized = normalizeBotUsername(override);
|
||||
if (normalized) {
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
|
||||
const queryKeys = ['bot', 'bot_username', 'botUsername'];
|
||||
for (const key of queryKeys) {
|
||||
const candidate = pageParams.get(key);
|
||||
const normalized = normalizeBotUsername(candidate);
|
||||
if (normalized) {
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
|
||||
const referrer = document.referrer;
|
||||
if (referrer) {
|
||||
try {
|
||||
const url = new URL(referrer);
|
||||
const host = url.hostname.replace(/^www\./, '').toLowerCase();
|
||||
if (['t.me', 'telegram.me', 'telegram.dog'].includes(host)) {
|
||||
const path = url.pathname.replace(/^\//, '').split('/')[0];
|
||||
const normalized = normalizeBotUsername(path);
|
||||
if (normalized) {
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Unable to parse referrer for bot username:', error);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolveBotStartParam() {
|
||||
const queryKeys = ['start', 'startapp', 'bot_start'];
|
||||
for (const key of queryKeys) {
|
||||
const candidate = pageParams.get(key);
|
||||
if (candidate) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
const initParam = tg.initDataUnsafe?.start_param;
|
||||
return typeof initParam === 'string' && initParam ? initParam : null;
|
||||
}
|
||||
|
||||
function getBotLink() {
|
||||
const username = normalizeBotUsername(botUsername);
|
||||
if (!username) {
|
||||
return null;
|
||||
}
|
||||
const base = `https://t.me/${username}`;
|
||||
if (botStartParam) {
|
||||
return `${base}?start=${encodeURIComponent(botStartParam)}`;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
function openBot() {
|
||||
const link = getBotLink();
|
||||
if (!link) {
|
||||
showPopup(t('registration.error'), t('registration.title'));
|
||||
return;
|
||||
}
|
||||
if (typeof tg.openTelegramLink === 'function') {
|
||||
try {
|
||||
tg.openTelegramLink(link);
|
||||
return;
|
||||
} catch (error) {
|
||||
console.warn('Unable to open Telegram link directly:', error);
|
||||
}
|
||||
}
|
||||
openExternalLink(link, { openInMiniApp: true });
|
||||
}
|
||||
|
||||
function getEffectivePurchaseUrl() {
|
||||
const candidates = [
|
||||
currentErrorState?.purchaseUrl,
|
||||
@@ -6817,7 +6622,6 @@
|
||||
: 'Subscription not found';
|
||||
let title = response.status === 401 ? 'Authorization Error' : 'Subscription Not Found';
|
||||
let purchaseUrl = null;
|
||||
let errorCode = null;
|
||||
|
||||
try {
|
||||
const errorPayload = await response.json();
|
||||
@@ -6828,9 +6632,6 @@
|
||||
if (typeof errorPayload.detail.message === 'string') {
|
||||
detail = errorPayload.detail.message;
|
||||
}
|
||||
if (typeof errorPayload.detail.code === 'string') {
|
||||
errorCode = errorPayload.detail.code;
|
||||
}
|
||||
purchaseUrl = errorPayload.detail.purchase_url
|
||||
|| errorPayload.detail.purchaseUrl
|
||||
|| purchaseUrl;
|
||||
@@ -6843,10 +6644,6 @@
|
||||
title = errorPayload.title;
|
||||
}
|
||||
|
||||
if (!errorCode && typeof errorPayload?.code === 'string') {
|
||||
errorCode = errorPayload.code;
|
||||
}
|
||||
|
||||
purchaseUrl = purchaseUrl
|
||||
|| errorPayload?.purchase_url
|
||||
|| errorPayload?.purchaseUrl
|
||||
@@ -6860,9 +6657,6 @@
|
||||
if (normalizedPurchaseUrl) {
|
||||
errorObject.purchaseUrl = normalizedPurchaseUrl;
|
||||
}
|
||||
if (errorCode) {
|
||||
errorObject.code = errorCode;
|
||||
}
|
||||
throw errorObject;
|
||||
}
|
||||
|
||||
@@ -6871,8 +6665,6 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
subscriptionMissingMode = false;
|
||||
registrationRequired = false;
|
||||
userData = payload;
|
||||
userData.subscriptionUrl = userData.subscription_url || null;
|
||||
userData.subscriptionCryptoLink = userData.subscription_crypto_link || null;
|
||||
@@ -6905,9 +6697,6 @@
|
||||
errorState.classList.add('hidden');
|
||||
}
|
||||
|
||||
const registrationStateElement = document.getElementById('registrationState');
|
||||
registrationStateElement?.classList.add('hidden');
|
||||
|
||||
const loadingState = document.getElementById('loadingState');
|
||||
if (loadingState) {
|
||||
loadingState.classList.add('hidden');
|
||||
@@ -6961,10 +6750,7 @@
|
||||
await refreshSubscriptionData();
|
||||
} catch (error) {
|
||||
console.error('Initialization error:', error);
|
||||
const handled = await handleInitialSubscriptionError(error);
|
||||
if (!handled) {
|
||||
showError(error);
|
||||
}
|
||||
showError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6998,187 +6784,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
function buildPlaceholderUserData(purchaseData) {
|
||||
const telegramUser = tg.initDataUnsafe?.user || {};
|
||||
const username = typeof telegramUser.username === 'string' && telegramUser.username
|
||||
? `@${telegramUser.username}`
|
||||
: '';
|
||||
const nameFromParts = [telegramUser.first_name, telegramUser.last_name]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
.trim();
|
||||
const displayName = telegramUser.display_name
|
||||
|| nameFromParts
|
||||
|| username
|
||||
|| (telegramUser.first_name || telegramUser.last_name || '')
|
||||
|| (telegramUser.id ? `User ${telegramUser.id}` : 'User');
|
||||
|
||||
const balanceKopeksRaw = coercePositiveInt(
|
||||
purchaseData?.balanceKopeks ?? purchaseData?.balance_kopeks,
|
||||
null
|
||||
);
|
||||
const balanceKopeks = Number.isFinite(balanceKopeksRaw) ? balanceKopeksRaw : 0;
|
||||
const currency = (purchaseData?.currency || 'RUB').toString().toUpperCase();
|
||||
|
||||
return {
|
||||
user: {
|
||||
telegram_id: telegramUser.id ?? null,
|
||||
username: telegramUser.username || '',
|
||||
first_name: telegramUser.first_name || '',
|
||||
last_name: telegramUser.last_name || '',
|
||||
display_name: displayName,
|
||||
language: telegramUser.language_code || '',
|
||||
status: 'inactive',
|
||||
subscription_status: 'inactive',
|
||||
subscription_actual_status: 'inactive',
|
||||
status_label: 'Inactive',
|
||||
expires_at: null,
|
||||
device_limit: null,
|
||||
traffic_used_gb: 0,
|
||||
traffic_used_label: '0 GB',
|
||||
traffic_limit_gb: 0,
|
||||
traffic_limit_label: '—',
|
||||
lifetime_used_traffic_gb: 0,
|
||||
has_active_subscription: false,
|
||||
},
|
||||
subscription_type: 'none',
|
||||
subscription_url: null,
|
||||
subscriptionUrl: null,
|
||||
subscriptionCryptoLink: null,
|
||||
subscription_crypto_link: null,
|
||||
subscriptionPurchaseUrl: null,
|
||||
subscription_purchase_url: null,
|
||||
remnawave_short_uuid: null,
|
||||
balance_kopeks: balanceKopeks,
|
||||
balance_rubles: balanceKopeks / 100,
|
||||
balance_currency: currency,
|
||||
transactions: [],
|
||||
promo_offers: [],
|
||||
promo_group: null,
|
||||
auto_assign_promo_groups: [],
|
||||
referral: null,
|
||||
total_spent_kopeks: 0,
|
||||
total_spent_rubles: 0,
|
||||
total_spent_label: null,
|
||||
connected_devices: [],
|
||||
connected_devices_count: 0,
|
||||
connected_servers: [],
|
||||
connected_squads: [],
|
||||
links: [],
|
||||
ss_conf_links: {},
|
||||
happ: null,
|
||||
happ_link: null,
|
||||
happ_crypto_link: null,
|
||||
happ_cryptolink_redirect_link: null,
|
||||
autopay_enabled: false,
|
||||
faq: null,
|
||||
legal_documents: null,
|
||||
branding: userData?.branding || null,
|
||||
};
|
||||
}
|
||||
|
||||
function enterSubscriptionMissingMode(purchasePayload) {
|
||||
subscriptionMissingMode = true;
|
||||
registrationRequired = false;
|
||||
|
||||
const normalized = normalizeSubscriptionPurchasePayload(purchasePayload);
|
||||
subscriptionPurchaseData = normalized;
|
||||
subscriptionPurchaseError = null;
|
||||
subscriptionPurchaseLoading = false;
|
||||
subscriptionPurchasePromise = null;
|
||||
subscriptionPurchaseFeatureEnabled = true;
|
||||
subscriptionPurchaseUrl = null;
|
||||
resetSubscriptionPurchaseSelections(normalized);
|
||||
|
||||
subscriptionPurchasePreview = null;
|
||||
subscriptionPurchasePreviewPromise = null;
|
||||
subscriptionPurchasePreviewError = null;
|
||||
subscriptionPurchasePreviewLoading = false;
|
||||
|
||||
userData = buildPlaceholderUserData(normalized);
|
||||
|
||||
currentErrorState = null;
|
||||
updateErrorTexts();
|
||||
|
||||
document.getElementById('errorState')?.classList.add('hidden');
|
||||
document.getElementById('loadingState')?.classList.add('hidden');
|
||||
document.getElementById('registrationState')?.classList.add('hidden');
|
||||
document.getElementById('mainContent')?.classList.remove('hidden');
|
||||
|
||||
refreshAfterLanguageChange();
|
||||
animateCardsOnce();
|
||||
}
|
||||
|
||||
function showRegistrationPrompt() {
|
||||
registrationRequired = true;
|
||||
subscriptionMissingMode = false;
|
||||
userData = null;
|
||||
subscriptionPurchaseData = null;
|
||||
subscriptionPurchaseError = null;
|
||||
subscriptionPurchaseLoading = false;
|
||||
subscriptionPurchasePromise = null;
|
||||
subscriptionPurchasePreview = null;
|
||||
subscriptionPurchasePreviewPromise = null;
|
||||
subscriptionPurchasePreviewError = null;
|
||||
subscriptionPurchasePreviewLoading = false;
|
||||
subscriptionPurchaseUrl = null;
|
||||
|
||||
currentErrorState = null;
|
||||
updateErrorTexts();
|
||||
|
||||
document.getElementById('loadingState')?.classList.add('hidden');
|
||||
document.getElementById('errorState')?.classList.add('hidden');
|
||||
document.getElementById('mainContent')?.classList.add('hidden');
|
||||
document.getElementById('registrationState')?.classList.remove('hidden');
|
||||
updateConnectButtonLabel();
|
||||
updateActionButtons();
|
||||
}
|
||||
|
||||
async function handleInitialSubscriptionError(error) {
|
||||
if (!error || error.status !== 404) {
|
||||
return false;
|
||||
}
|
||||
if (error.code === 'user_not_found') {
|
||||
showRegistrationPrompt();
|
||||
return true;
|
||||
}
|
||||
const initData = tg.initData || '';
|
||||
if (!initData) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
const purchasePayload = await fetchSubscriptionPurchaseOptions(initData);
|
||||
enterSubscriptionMissingMode(purchasePayload);
|
||||
return true;
|
||||
} catch (purchaseError) {
|
||||
if (purchaseError?.code === 'user_not_found') {
|
||||
showRegistrationPrompt();
|
||||
return true;
|
||||
}
|
||||
console.warn('Unable to handle subscription absence via purchase options:', purchaseError);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function renderUserData() {
|
||||
if (!userData?.user) {
|
||||
const notice = document.getElementById('noSubscriptionNotice');
|
||||
if (notice) {
|
||||
notice.classList.toggle('hidden', true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const userCard = document.querySelector('.card.user-card');
|
||||
const notice = document.getElementById('noSubscriptionNotice');
|
||||
if (subscriptionMissingMode) {
|
||||
userCard?.classList.add('hidden');
|
||||
notice?.classList.remove('hidden');
|
||||
} else {
|
||||
userCard?.classList.remove('hidden');
|
||||
notice?.classList.add('hidden');
|
||||
}
|
||||
|
||||
const user = userData.user;
|
||||
const rawName = user.display_name || user.username || '';
|
||||
const fallbackName = rawName
|
||||
@@ -7189,7 +6799,7 @@
|
||||
document.getElementById('userAvatar').textContent = avatarChar;
|
||||
document.getElementById('userName').textContent = fallbackName;
|
||||
|
||||
const knownStatuses = ['active', 'trial', 'expired', 'disabled', 'inactive'];
|
||||
const knownStatuses = ['active', 'trial', 'expired', 'disabled'];
|
||||
const statusValueRaw = (user.subscription_actual_status || user.subscription_status || 'active').toLowerCase();
|
||||
const statusClass = knownStatuses.includes(statusValueRaw) ? statusValueRaw : 'unknown';
|
||||
const statusBadge = document.getElementById('statusBadge');
|
||||
@@ -11056,9 +10666,6 @@
|
||||
}
|
||||
|
||||
const typeRaw = String(userData.subscription_type || '').toLowerCase();
|
||||
if (!typeRaw || typeRaw === 'none') {
|
||||
return false;
|
||||
}
|
||||
if (typeRaw === 'trial') {
|
||||
return false;
|
||||
}
|
||||
@@ -11075,7 +10682,7 @@
|
||||
|| userData.user.subscription_status
|
||||
|| ''
|
||||
).toLowerCase();
|
||||
if (['trial', 'expired', 'disabled', 'inactive'].includes(statusRaw)) {
|
||||
if (['trial', 'expired', 'disabled'].includes(statusRaw)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -13812,26 +13419,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function extractErrorCode(payload) {
|
||||
if (!payload || typeof payload !== 'object') {
|
||||
return null;
|
||||
}
|
||||
if (typeof payload.code === 'string' && payload.code) {
|
||||
return payload.code;
|
||||
}
|
||||
const detail = payload.detail;
|
||||
if (!detail) {
|
||||
return null;
|
||||
}
|
||||
if (typeof detail === 'string') {
|
||||
return null;
|
||||
}
|
||||
if (typeof detail.code === 'string' && detail.code) {
|
||||
return detail.code;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractPurchaseErrorMessage(payload, status) {
|
||||
if (!payload || typeof payload !== 'object') {
|
||||
return status === 401
|
||||
@@ -13850,25 +13437,6 @@
|
||||
return t('subscription_purchase.error.default');
|
||||
}
|
||||
|
||||
async function fetchSubscriptionPurchaseOptions(initData) {
|
||||
const response = await fetch('/miniapp/subscription/purchase/options', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ initData }),
|
||||
});
|
||||
const body = await parseJsonSafe(response);
|
||||
if (!response.ok || (body && body.success === false)) {
|
||||
const message = extractPurchaseErrorMessage(body, response.status);
|
||||
const error = createError('Subscription purchase error', message, response.status);
|
||||
const code = extractErrorCode(body);
|
||||
if (code) {
|
||||
error.code = code;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
function ensureSubscriptionPurchaseData(options = {}) {
|
||||
const { force = false } = options;
|
||||
|
||||
@@ -13894,7 +13462,18 @@
|
||||
subscriptionPurchaseError = null;
|
||||
renderSubscriptionPurchaseCard();
|
||||
|
||||
const request = fetchSubscriptionPurchaseOptions(initData).then(body => {
|
||||
const payload = { initData };
|
||||
const request = fetch('/miniapp/subscription/purchase/options', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
}).then(async response => {
|
||||
const body = await parseJsonSafe(response);
|
||||
if (!response.ok || (body && body.success === false)) {
|
||||
const message = extractPurchaseErrorMessage(body, response.status);
|
||||
throw createError('Subscription purchase error', message, response.status);
|
||||
}
|
||||
|
||||
const normalized = normalizeSubscriptionPurchasePayload(body);
|
||||
subscriptionPurchaseData = normalized;
|
||||
subscriptionPurchaseError = null;
|
||||
@@ -15697,7 +15276,6 @@
|
||||
function showError(error) {
|
||||
document.getElementById('loadingState').classList.add('hidden');
|
||||
document.getElementById('mainContent').classList.add('hidden');
|
||||
document.getElementById('registrationState')?.classList.add('hidden');
|
||||
currentErrorState = {
|
||||
title: error?.title,
|
||||
message: error?.message,
|
||||
@@ -15722,23 +15300,6 @@
|
||||
openExternalLink(link);
|
||||
});
|
||||
|
||||
document.getElementById('openBotBtn')?.addEventListener('click', () => {
|
||||
openBot();
|
||||
});
|
||||
|
||||
document.getElementById('noSubscriptionAction')?.addEventListener('click', () => {
|
||||
if (shouldShowPurchaseConfigurator()) {
|
||||
openSubscriptionPurchaseModal();
|
||||
return;
|
||||
}
|
||||
const link = getEffectivePurchaseUrl();
|
||||
if (link) {
|
||||
openExternalLink(link, { openInMiniApp: true });
|
||||
} else {
|
||||
openSubscriptionPurchaseModal();
|
||||
}
|
||||
});
|
||||
|
||||
const topupButton = document.getElementById('topupBalanceBtn');
|
||||
if (topupButton) {
|
||||
topupButton.addEventListener('click', () => {
|
||||
|
||||
Reference in New Issue
Block a user