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

@@ -235,13 +235,13 @@
"connectDevice": "Connect Device",
"devicesConnected": "{{count}} connected",
"devicesOfMax": "{{used}} of {{max}} connected",
"devicesConnectedUnlimited": "{{used}} connected · unlimited",
"devicesShort": "dev.",
"trafficUsage": "{{used}} / {{limit}} GB",
"trafficUsageTitle": "Traffic Usage",
"usedTraffic": "used {{amount}}",
"usedSuffix": "used",
"unlimited": "Unlimited",
"unlimitedTraffic": "Unlimited traffic",
"tariff": "Tariff",
"validUntil": "until {{date}}",
"remaining": "Remaining",
@@ -1043,7 +1043,8 @@
"roleAssign": "Role Assignment",
"policies": "Access Policies",
"auditLog": "Audit Log",
"salesStats": "Sales Statistics"
"salesStats": "Sales Statistics",
"landings": "Landings"
},
"panel": {
"title": "Admin Panel",
@@ -1076,7 +1077,8 @@
"roleAssignDesc": "Assign and revoke user roles",
"policiesDesc": "Configure ABAC access policies",
"auditLogDesc": "Review system activity and access history",
"salesStatsDesc": "Sales analytics and trends"
"salesStatsDesc": "Sales analytics and trends",
"landingsDesc": "Quick purchase landing pages"
},
"salesStats": {
"title": "Sales Statistics",
@@ -3138,6 +3140,51 @@
"loadFailed": "Failed to load audit log",
"retry": "Try again"
}
},
"landings": {
"title": "Landing Pages",
"create": "Create Landing",
"edit": "Edit",
"slug": "URL Identifier",
"slugHint": "Lowercase, numbers and hyphens",
"pageTitle": "Title",
"subtitle": "Subtitle",
"footerText": "Footer (HTML)",
"features": "Features",
"addFeature": "Add",
"featureIcon": "Icon",
"featureTitle": "Title",
"featureDesc": "Description",
"tariffs": "Plans",
"selectTariffs": "Select plans",
"periods": "Periods",
"paymentMethods": "Payment Methods",
"addMethod": "Add method",
"methodId": "Method ID",
"methodName": "Name",
"methodDesc": "Description",
"methodIcon": "Icon URL",
"gifts": "Gifts",
"giftEnabled": "Gift purchases",
"customCss": "CSS",
"seo": "SEO",
"metaTitle": "Meta Title",
"metaDesc": "Meta Description",
"active": "Active",
"inactive": "Inactive",
"purchases": "purchases",
"copyUrl": "Copy URL",
"urlCopied": "URL copied",
"deleteConfirm": "Delete landing \"{{title}}\"?",
"created": "Landing created",
"updated": "Landing updated",
"deleted": "Landing deleted",
"saveOrder": "Save order",
"orderSaved": "Order saved",
"general": "General",
"content": "Content",
"save": "Save",
"back": "Back"
}
},
"adminUpdates": {
@@ -3865,5 +3912,44 @@
"error": "Failed to merge accounts. Please try again later.",
"expiresIn": "Expires in {{minutes}}",
"merging": "Merging..."
},
"landing": {
"notFound": "Page not found",
"forMe": "For me",
"asGift": "As a gift",
"contactLabel": "Your email or @username",
"yourContact": "Your email or @username",
"contactPlaceholder": "email@example.com or @username",
"contactHint": "Enter email or Telegram @username",
"recipientLabel": "Gift recipient",
"recipientPlaceholder": "Recipient email or @username",
"giftMessageLabel": "Greeting (optional)",
"giftMessagePlaceholder": "Write a greeting...",
"chooseTariff": "Choose a plan",
"devices": "devices",
"paymentMethod": "Payment method",
"processing": "Processing...",
"payButton": "Pay {{price}}",
"accessFor": "Access for {{period}}",
"purchaseError": "Failed to create payment",
"purchaseNotFound": "Purchase not found",
"awaitingPayment": "Awaiting payment",
"awaitingPaymentDesc": "Complete the payment in the opened window",
"purchaseSuccess": "Payment successful!",
"keySentTo": "Subscription key sent to {{contact}}",
"giftSentTo": "Gift sent to {{contact}}",
"purchaseFailed": "Payment failed",
"purchaseFailedDesc": "Payment was unsuccessful. Try again.",
"subscriptionLink": "Subscription link",
"daysAccess": "days of access",
"error": "Error",
"gb": "GB",
"selectedTariff": "Tariff",
"period": "Period",
"total": "Total",
"pay": "Pay",
"choosePeriod": "Choose period",
"copied": "Copied!",
"copyLink": "Copy link"
}
}