feat: add multi-channel subscription blocking UI and admin management

- Channel subscription blocking screen with per-channel status display
- Safe URL handling with protocol validation (no open redirect)
- Race-condition-safe subscription check with useRef guard
- Admin channel management page with create, toggle, delete
- Error handlers on all admin mutations with haptic feedback
- Proper type guard for channel subscription error detection
- Accessibility: aria-labels on icon-only buttons
- Localization: en, ru, zh, fa translations
This commit is contained in:
Fringg
2026-02-24 02:50:52 +03:00
parent 8ea9a1d6a0
commit a767fe96d3
12 changed files with 758 additions and 113 deletions

View File

@@ -861,7 +861,8 @@
"updates": "Updates",
"pinnedMessages": "Pinned Messages",
"partners": "Partners",
"withdrawals": "Withdrawals"
"withdrawals": "Withdrawals",
"channelSubscriptions": "Required Channels"
},
"panel": {
"title": "Admin Panel",
@@ -888,7 +889,8 @@
"updatesDesc": "Bot & cabinet versions",
"pinnedMessagesDesc": "Manage pinned messages for users",
"partnersDesc": "Manage partner applications and commissions",
"withdrawalsDesc": "Review and process withdrawal requests"
"withdrawalsDesc": "Review and process withdrawal requests",
"channelSubscriptionsDesc": "Manage required channel subscriptions"
},
"trafficUsage": {
"title": "Traffic Usage",
@@ -1297,6 +1299,28 @@
"editMessage": "Edit",
"cantDeleteActive": "Cannot delete active message"
},
"channelSubscriptions": {
"title": "Required Channels",
"subtitle": "Users must subscribe to these channels",
"addChannel": "Add Channel",
"empty": "No channels configured",
"enabled": "Enabled",
"disabled": "Disabled",
"enable": "Enable",
"disable": "Disable",
"delete": "Delete",
"deleteConfirm": "Delete this channel?",
"sortOrder": "Order",
"form": {
"title": "Display Name",
"channelId": "Channel ID",
"channelIdHint": "@username or -100XXXXXXXXXX",
"channelLink": "Channel Link",
"channelLinkHint": "https://t.me/channel",
"submit": "Add",
"cancel": "Cancel"
}
},
"settings": {
"title": "System Settings",
"allCategories": "All categories",
@@ -3144,7 +3168,9 @@
"waitSeconds": "Wait {{seconds}} sec.",
"hint": "Click check button after subscribing",
"notSubscribed": "You haven't subscribed to the channel yet",
"checkError": "Check failed. Please try again later."
"checkError": "Check failed. Please try again later.",
"subscribed": "Subscribed",
"channelsRequired": "Subscribe to all channels below to continue"
},
"blacklisted": {
"title": "Access Denied",

View File

@@ -741,7 +741,8 @@
"updates": "به‌روزرسانی‌ها",
"pinnedMessages": "پیام‌های سنجاق‌شده",
"partners": "شرکا",
"withdrawals": "برداشت‌ها"
"withdrawals": "برداشت‌ها",
"channelSubscriptions": "کانال‌های اجباری"
},
"panel": {
"title": "پنل مدیریت",
@@ -768,7 +769,8 @@
"updatesDesc": "نسخه‌های ربات و کابینت",
"pinnedMessagesDesc": "مدیریت پیام‌های سنجاق‌شده",
"partnersDesc": "مدیریت درخواست‌های شراکت و کمیسیون‌ها",
"withdrawalsDesc": "بررسی و پردازش درخواست‌های برداشت"
"withdrawalsDesc": "بررسی و پردازش درخواست‌های برداشت",
"channelSubscriptionsDesc": "مدیریت اشتراک‌های اجباری کانال"
},
"trafficUsage": {
"title": "مصرف ترافیک",
@@ -1000,6 +1002,28 @@
"editMessage": "Edit",
"cantDeleteActive": "Cannot delete active message"
},
"channelSubscriptions": {
"title": "کانال‌های اجباری",
"subtitle": "کاربران باید در این کانال‌ها عضو شوند",
"addChannel": "افزودن کانال",
"empty": "کانالی تنظیم نشده",
"enabled": "فعال",
"disabled": "غیرفعال",
"enable": "فعال‌سازی",
"disable": "غیرفعال‌سازی",
"delete": "حذف",
"deleteConfirm": "این کانال حذف شود؟",
"sortOrder": "ترتیب",
"form": {
"title": "نام نمایشی",
"channelId": "شناسه کانال",
"channelIdHint": "@username یا -100XXXXXXXXXX",
"channelLink": "لینک کانال",
"channelLinkHint": "https://t.me/channel",
"submit": "افزودن",
"cancel": "لغو"
}
},
"payments": {
"title": "تأیید پرداخت",
"description": "پرداخت‌های معلق در ۲۴ ساعت گذشته",
@@ -2759,7 +2783,9 @@
"waitSeconds": "{{seconds}} ثانیه صبر کنید",
"hint": "پس از عضویت دکمه بررسی را بزنید",
"notSubscribed": "شما هنوز در کانال عضو نشده‌اید",
"checkError": "بررسی ناموفق بود. لطفاً بعداً دوباره امتحان کنید."
"checkError": "بررسی ناموفق بود. لطفاً بعداً دوباره امتحان کنید.",
"subscribed": "عضو شده",
"channelsRequired": "برای ادامه در همه کانال‌های زیر عضو شوید"
},
"blacklisted": {
"title": "دسترسی ممنوع",

View File

@@ -883,7 +883,8 @@
"updates": "Обновления",
"pinnedMessages": "Закреплённые",
"partners": "Партнёры",
"withdrawals": "Выводы"
"withdrawals": "Выводы",
"channelSubscriptions": "Обязательные каналы"
},
"panel": {
"title": "Панель администратора",
@@ -910,7 +911,8 @@
"updatesDesc": "Версии бота и кабинета",
"pinnedMessagesDesc": "Управление закреплёнными сообщениями",
"partnersDesc": "Управление заявками партнёров и комиссиями",
"withdrawalsDesc": "Проверка и обработка заявок на вывод"
"withdrawalsDesc": "Проверка и обработка заявок на вывод",
"channelSubscriptionsDesc": "Управление обязательными подписками на каналы"
},
"trafficUsage": {
"title": "Расход трафика",
@@ -1323,6 +1325,28 @@
"editMessage": "Редактировать",
"cantDeleteActive": "Нельзя удалить активное сообщение"
},
"channelSubscriptions": {
"title": "Обязательные каналы",
"subtitle": "Пользователи должны подписаться на эти каналы",
"addChannel": "Добавить канал",
"empty": "Каналы не настроены",
"enabled": "Активен",
"disabled": "Отключён",
"enable": "Включить",
"disable": "Отключить",
"delete": "Удалить",
"deleteConfirm": "Удалить этот канал?",
"sortOrder": "Порядок",
"form": {
"title": "Название",
"channelId": "ID канала",
"channelIdHint": "@username или -100XXXXXXXXXX",
"channelLink": "Ссылка на канал",
"channelLinkHint": "https://t.me/channel",
"submit": "Добавить",
"cancel": "Отмена"
}
},
"settings": {
"title": "Настройки системы",
"allCategories": "Все категории",
@@ -3699,7 +3723,9 @@
"waitSeconds": "Подождите {{seconds}} сек.",
"hint": "После подписки нажмите кнопку проверки",
"notSubscribed": "Вы ещё не подписались на канал",
"checkError": "Ошибка проверки. Попробуйте позже."
"checkError": "Ошибка проверки. Попробуйте позже.",
"subscribed": "Подписан",
"channelsRequired": "Подпишитесь на все каналы ниже для продолжения"
},
"blacklisted": {
"title": "Доступ запрещён",

View File

@@ -741,7 +741,8 @@
"updates": "更新",
"pinnedMessages": "置顶消息",
"partners": "合作伙伴",
"withdrawals": "提现"
"withdrawals": "提现",
"channelSubscriptions": "必订频道"
},
"panel": {
"title": "管理面板",
@@ -768,7 +769,8 @@
"updatesDesc": "机器人和面板版本",
"pinnedMessagesDesc": "管理用户置顶消息",
"partnersDesc": "管理合作伙伴申请和佣金",
"withdrawalsDesc": "审核和处理提现请求"
"withdrawalsDesc": "审核和处理提现请求",
"channelSubscriptionsDesc": "管理必订频道订阅"
},
"trafficUsage": {
"title": "流量使用",
@@ -1052,6 +1054,28 @@
"editMessage": "编辑",
"cantDeleteActive": "无法删除活跃消息"
},
"channelSubscriptions": {
"title": "必订频道",
"subtitle": "用户必须订阅这些频道",
"addChannel": "添加频道",
"empty": "未配置频道",
"enabled": "已启用",
"disabled": "已禁用",
"enable": "启用",
"disable": "禁用",
"delete": "删除",
"deleteConfirm": "删除此频道?",
"sortOrder": "排序",
"form": {
"title": "显示名称",
"channelId": "频道ID",
"channelIdHint": "@username 或 -100XXXXXXXXXX",
"channelLink": "频道链接",
"channelLinkHint": "https://t.me/channel",
"submit": "添加",
"cancel": "取消"
}
},
"settings": {
"title": "系统设置",
"allCategories": "所有分类",
@@ -2640,7 +2664,9 @@
"waitSeconds": "请等待 {{seconds}} 秒",
"hint": "订阅后点击检查按钮",
"notSubscribed": "您还没有订阅该频道",
"checkError": "检查失败。请稍后重试。"
"checkError": "检查失败。请稍后重试。",
"subscribed": "已订阅",
"channelsRequired": "请订阅以下所有频道以继续"
},
"blacklisted": {
"title": "访问被拒绝",