Сайт: донат-карточку заменил на апселл подписки; убрал внешний QR и ссылку «Поддержать»

Донат на платном сервисе размывал модель. На больших файлах теперь показывается
апселл подписки (не подписчикам), кнопка ведёт в оплату подписки (showPaywall upsell).
QR грузился с api.qrserver.com (недоступен из РФ → пустой) — удалён.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
berkio_admin_gitea
2026-07-17 09:14:02 +00:00
parent 358de0d498
commit ccacbb123c

View File

@@ -1168,36 +1168,16 @@
</div> </div>
</div> </div>
<!-- Donate --> <!-- Апселл подписки (показывается на больших файлах) -->
<div id="donate-card"> <div id="donate-card">
<div class="donate-inner"> <div class="donate-inner">
<div class="donate-text"> <div class="donate-text">
<div class="donate-icon">🍩</div> <div class="donate-icon">💎</div>
<div class="donate-title" data-i18n="donate_title">Поддержите проект</div> <div class="donate-title" data-i18n="upsell_title">Часто обрабатываете большие файлы?</div>
<div class="donate-desc" data-i18n="donate_desc">Если сервис полезен — поддержите его работу донатом. Это помогает оплачивать сервер и развивать проект.</div> <div class="donate-desc" data-i18n="upsell_desc">Подписка снимает лимит 50 МБ и 100 страниц, открывает пакетную обработку нескольких файлов и приоритет в очереди.</div>
<div class="donate-buttons"> <div class="donate-buttons" style="margin-top:12px">
<a class="donate-btn donate-btn-sbp" href="https://finance.ozon.ru/apps/sbp/ozonbankpay/019cbe28-6b54-7eb8-8a52-189633e608ea" target="_blank" rel="noopener" data-i18n="donate_sbp">СБП / Ozon Pay</a> <button type="button" class="donate-btn" onclick="openSubUpsell()" data-i18n="upsell_btn">Оформить подписку</button>
</div> </div>
<!-- Оплата картой через ЮKassa -->
<div class="donate-pay" style="margin-top:14px">
<div style="display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin-bottom:8px">
<button type="button" class="pay-amt" onclick="setPayAmt(100,this)">100 ₽</button>
<button type="button" class="pay-amt active" onclick="setPayAmt(300,this)">300 ₽</button>
<button type="button" class="pay-amt" onclick="setPayAmt(500,this)">500 ₽</button>
<input type="number" id="pay-amt-custom" min="10" max="100000" placeholder="₽" oninput="onCustomAmt()"
style="width:76px;padding:7px 8px;border:1px solid var(--border,#d0d7e2);border-radius:8px;font-family:inherit;font-size:14px">
</div>
<input type="email" id="pay-email" data-i18n-ph="pay_email_ph" placeholder="email для чека"
style="width:100%;max-width:260px;padding:8px 10px;border:1px solid var(--border,#d0d7e2);border-radius:8px;font-family:inherit;font-size:14px;margin-bottom:8px">
<div>
<button type="button" id="pay-card-btn" onclick="payDonate()" class="donate-btn" data-i18n="pay_card_btn">💳 Оплатить картой</button>
</div>
<div id="pay-msg" style="font-size:12px;color:var(--text-secondary);margin-top:6px"></div>
</div>
</div>
<div class="donate-qr">
<img src="https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https%3A%2F%2Ffinance.ozon.ru%2Fapps%2Fsbp%2Fozonbankpay%2F019cbe28-6b54-7eb8-8a52-189633e608ea" alt="QR donate" loading="lazy">
<div class="donate-qr-hint" data-i18n="donate_qr_hint">Сканируйте для оплаты</div>
</div> </div>
</div> </div>
</div> </div>
@@ -1237,7 +1217,7 @@
<!--SEO_FAQ--> <!--SEO_FAQ-->
<footer> <footer>
pdf2scan &mdash; <span data-i18n="footer_text">превращаем PDF в скан</span> &nbsp;|&nbsp; <a href="https://t.me/pdf2scan_pybot" onclick="return openBot(event)" style="color:var(--blue); text-decoration:none;" data-i18n="footer_tg">Telegram-бот</a> &nbsp;|&nbsp; <a href="/developers" style="color:var(--blue); text-decoration:none;" data-i18n="footer_api">API для бизнеса</a> &nbsp;|&nbsp; <a href="#" onclick="showDonateCard(false);document.getElementById('donate-card').scrollIntoView({behavior:'smooth'});return false;" style="color:var(--blue); text-decoration:none;" data-i18n="footer_donate">🍩 Поддержать</a> &nbsp;|&nbsp; <a href="/offer" style="color:var(--blue); text-decoration:none;" data-i18n="footer_offer">Оферта</a> pdf2scan &mdash; <span data-i18n="footer_text">превращаем PDF в скан</span> &nbsp;|&nbsp; <a href="https://t.me/pdf2scan_pybot" onclick="return openBot(event)" style="color:var(--blue); text-decoration:none;" data-i18n="footer_tg">Telegram-бот</a> &nbsp;|&nbsp; <a href="/developers" style="color:var(--blue); text-decoration:none;" data-i18n="footer_api">API для бизнеса</a> &nbsp;|&nbsp; <a href="/offer" style="color:var(--blue); text-decoration:none;" data-i18n="footer_offer">Оферта</a>
</footer> </footer>
<script> <script>
@@ -1358,6 +1338,11 @@
donate_desc_heavy: '⚠️ Большие файлы сильно нагружают сервер. Если сервис полезен — поддержите проект донатом.', donate_desc_heavy: '⚠️ Большие файлы сильно нагружают сервер. Если сервис полезен — поддержите проект донатом.',
donate_sbp: 'СБП / Ozon Pay', donate_sbp: 'СБП / Ozon Pay',
donate_qr_hint: 'Сканируйте для оплаты', donate_qr_hint: 'Сканируйте для оплаты',
upsell_title: 'Часто обрабатываете большие файлы?',
upsell_desc: 'Подписка снимает лимит 50 МБ и 100 страниц, открывает пакетную обработку нескольких файлов и приоритет в очереди.',
upsell_btn: 'Оформить подписку',
paywall_upsell_title: 'Оформить подписку pdf2scan',
paywall_upsell_desc: 'Большие файлы без доплаты, пакетная обработка и приоритет в очереди. Отменить можно в любой момент.',
pay_card_btn: '💳 Оплатить картой', pay_card_btn: '💳 Оплатить картой',
pay_email_ph: 'email для чека', pay_email_ph: 'email для чека',
pay_need_email: 'Укажите корректный email для чека', pay_need_email: 'Укажите корректный email для чека',
@@ -1507,6 +1492,11 @@
donate_sbp: 'SBP / Ozon Pay', donate_sbp: 'SBP / Ozon Pay',
donate_yoo: 'YooMoney', donate_yoo: 'YooMoney',
donate_qr_hint: 'Scan to pay', donate_qr_hint: 'Scan to pay',
upsell_title: 'Processing large files often?',
upsell_desc: 'A subscription removes the 50 MB / 100-page limit, unlocks batch processing and priority in the queue.',
upsell_btn: 'Get a subscription',
paywall_upsell_title: 'Subscribe to pdf2scan',
paywall_upsell_desc: 'Large files with no per-file fee, batch processing and priority queue. Cancel anytime.',
pay_card_btn: '💳 Pay by card', pay_card_btn: '💳 Pay by card',
pay_email_ph: 'email for receipt', pay_email_ph: 'email for receipt',
pay_need_email: 'Enter a valid email for the receipt', pay_need_email: 'Enter a valid email for the receipt',
@@ -2339,12 +2329,6 @@
const flagEl = document.getElementById('lang-flag-img'); const flagEl = document.getElementById('lang-flag-img');
flagEl.src = LANGS[currentLang].img; flagEl.src = LANGS[currentLang].img;
flagEl.alt = LANGS[currentLang].alt; flagEl.alt = LANGS[currentLang].alt;
// Re-render donate desc if visible
const donateCard = document.getElementById('donate-card');
if (donateCard && donateCard.style.display !== 'none') {
const isHeavy = filePages > DONATE_PAGE_THRESHOLD || fileSizeMb > 10;
donateCard.querySelector('.donate-desc').textContent = t(isHeavy ? 'donate_desc_heavy' : 'donate_desc');
}
// Highlight active language in dropdown // Highlight active language in dropdown
document.querySelectorAll('.lang-option').forEach(btn => { document.querySelectorAll('.lang-option').forEach(btn => {
const lang = btn.getAttribute('onclick').match(/setLang\('(\w+)'\)/)[1]; const lang = btn.getAttribute('onclick').match(/setLang\('(\w+)'\)/)[1];
@@ -2378,17 +2362,20 @@
// ── Donate ──────────────────────────────────────────────────────────────── // ── Donate ────────────────────────────────────────────────────────────────
const DONATE_PAGE_THRESHOLD = 20; const DONATE_PAGE_THRESHOLD = 20;
function showDonateCard(heavy) { function showDonateCard() {
const card = document.getElementById('donate-card'); // апселл подписки; действующим подписчикам не показываем
const desc = card.querySelector('.donate-desc'); if (subUntilTs && subUntilTs > (Date.now() / 1000)) return;
desc.textContent = t(heavy ? 'donate_desc_heavy' : 'donate_desc'); document.getElementById('donate-card').style.display = 'block';
card.style.display = 'block';
} }
function hideDonateCard() { function hideDonateCard() {
document.getElementById('donate-card').style.display = 'none'; document.getElementById('donate-card').style.display = 'none';
} }
function openSubUpsell() {
showPaywall(null, paywallFilePrice, paywallSubPrice, 'upsell');
}
// ── Оплата картой (ЮKassa) ──────────────────────────────────────────────── // ── Оплата картой (ЮKassa) ────────────────────────────────────────────────
let payAmount = 300; let payAmount = 300;
function setPayAmt(v, el) { function setPayAmt(v, el) {
@@ -2438,20 +2425,20 @@
} }
function showPaywall(jobId, filePrice, subPrice, mode) { function showPaywall(jobId, filePrice, subPrice, mode) {
// «Продлить» подписку — не пейвол, в воронке не считаем // «Продлить» и апселл подписки — не пейвол, в воронке не считаем
if ((mode || 'file') !== 'renew') track('paywall_shown'); if ((mode || 'file') !== 'renew' && mode !== 'upsell') track('paywall_shown');
paywallMode = mode || 'file'; paywallMode = mode || 'file';
paywallJob = jobId; paywallJob = jobId;
paywallFilePrice = filePrice || 99; paywallFilePrice = filePrice || 99;
paywallSubPrice = subPrice || 299; paywallSubPrice = subPrice || 299;
const subOnly = (paywallMode === 'batch' || paywallMode === 'renew'); const subOnly = (paywallMode === 'batch' || paywallMode === 'renew' || paywallMode === 'upsell');
document.getElementById('paywall-file-price').textContent = paywallFilePrice; document.getElementById('paywall-file-price').textContent = paywallFilePrice;
document.getElementById('paywall-sub-price').textContent = paywallSubPrice; document.getElementById('paywall-sub-price').textContent = paywallSubPrice;
document.getElementById('paywall-file-btn').style.display = subOnly ? 'none' : ''; document.getElementById('paywall-file-btn').style.display = subOnly ? 'none' : '';
const titleEl = document.querySelector('#paywall-card [data-i18n="paywall_title"]'); const titleEl = document.querySelector('#paywall-card [data-i18n="paywall_title"]');
const descEl = document.querySelector('#paywall-card [data-i18n="paywall_desc"]'); const descEl = document.querySelector('#paywall-card [data-i18n="paywall_desc"]');
const tKey = paywallMode === 'renew' ? 'paywall_renew_title' : (paywallMode === 'batch' ? 'paywall_batch_title' : 'paywall_title'); const tKey = paywallMode === 'renew' ? 'paywall_renew_title' : paywallMode === 'upsell' ? 'paywall_upsell_title' : (paywallMode === 'batch' ? 'paywall_batch_title' : 'paywall_title');
const dKey = paywallMode === 'renew' ? 'paywall_renew_desc' : (paywallMode === 'batch' ? 'paywall_batch_desc' : 'paywall_desc'); const dKey = paywallMode === 'renew' ? 'paywall_renew_desc' : paywallMode === 'upsell' ? 'paywall_upsell_desc' : (paywallMode === 'batch' ? 'paywall_batch_desc' : 'paywall_desc');
if (titleEl) titleEl.textContent = t(tKey); if (titleEl) titleEl.textContent = t(tKey);
if (descEl) descEl.textContent = t(dKey); if (descEl) descEl.textContent = t(dKey);
const emailEl = document.getElementById('paywall-email'); const emailEl = document.getElementById('paywall-email');