feat: публичные лендинг-страницы для быстрой покупки VPN-подписок

- QuickPurchase: публичная страница покупки с выбором тарифа/периода/оплаты
- PurchaseSuccess: статус покупки с поллингом и копированием ссылки
- AdminLandings: управление лендингами (создание, сортировка, удаление)
- AdminLandingEditor: полнофункциональный редактор лендинга
- API-клиент landings.ts для всех эндпоинтов
- Роутинг /buy/:slug и /buy/success/:token
- Локализация ru/en/zh/fa для всех текстов лендинга
- Санитизация HTML/CSS, rate limit защита, DOMPurify
This commit is contained in:
Fringg
2026-03-06 07:02:21 +03:00
parent e278fec506
commit 8b5d777f0a
16 changed files with 3813 additions and 766 deletions

View File

@@ -772,7 +772,9 @@ export default function SubscriptionPurchase() {
/>
</svg>
<span className="text-dark-300">
{t('subscription.devices', { count: tariff.device_limit })}
{tariff.device_limit === 0
? '∞'
: t('subscription.devices', { count: tariff.device_limit })}
</span>
</div>
{tariff.traffic_reset_mode &&
@@ -959,7 +961,7 @@ export default function SubscriptionPurchase() {
<div>
<span className="text-dark-500">{t('subscription.devices')}:</span>
<span className="ml-2 text-dark-200">
{selectedTariff.device_limit}
{selectedTariff.device_limit === 0 ? '∞' : selectedTariff.device_limit}
{selectedTariff.extra_devices_count > 0 && (
<span className="ml-1 text-xs text-accent-400">
(+{selectedTariff.extra_devices_count})