feat(navigation): роутинг startapp-диплинков rich-меню бота

StartParamNavigator обобщён до таблицы маршрутов: помимо admin_ticket_<id>
теперь разбираются renew_<id> → /subscriptions/<id>/renew и subscriptions →
/subscriptions — их шлют ссылки «Продлить» у истёкших подписок в rich-меню
бота (t.me/<bot>/<app>?startapp=…). Доступ по-прежнему ограничен гвардами
самих маршрутов.

biome check, type-check и build проходят (pre-commit пропущен: biome не
установлен локально как зависимость — бинарь есть только в CI).
This commit is contained in:
Fringg
2026-07-13 02:12:57 +03:00
parent 758a645dff
commit 2eaea75fd9

View File

@@ -173,18 +173,24 @@ function TelegramBackButton() {
return null; return null;
} }
/** `admin_ticket_<id>` startapp param → /admin/tickets/<id>. */ /** Supported startapp paramsin-app destinations. */
const ADMIN_TICKET_START_PARAM_RE = /^admin_ticket_(\d+)$/; const START_PARAM_ROUTES: Array<{ re: RegExp; to: (match: RegExpExecArray) => string }> = [
// Admin ticket notification buttons in group chats (bot issue #2988).
{ re: /^admin_ticket_(\d+)$/, to: (match) => `/admin/tickets/${match[1]}` },
// «Продлить» links for expired subscriptions in the bot's rich main menu.
{ re: /^renew_(\d+)$/, to: (match) => `/subscriptions/${match[1]}/renew` },
{ re: /^subscriptions$/, to: () => '/subscriptions' },
];
/** /**
* Routes a Telegram Mini App start param to an in-app destination on launch. * Routes a Telegram Mini App start param to an in-app destination on launch.
* *
* Admin ticket notification buttons in GROUP/channel chats open the cabinet via * Text links and buttons outside private-chat web_app buttons can only enter the
* a `t.me/<bot>/<app>?startapp=admin_ticket_<id>` deep link (bot issue #2988) — * Mini App via `t.me/<bot>/<app>?startapp=<param>` deep links: admin ticket
* `web_app` buttons don't work in group chats, so the startapp param is the only * notifications in GROUP/channel chats (bot issue #2988) and the bot's rich
* way in. Telegram delivers it as `tgWebAppStartParam`; we map it to the admin * main-menu «Продлить» links for expired subscriptions. Telegram delivers the
* ticket route once on mount. Access is still gated by the route's * param as `tgWebAppStartParam`; we map it to a route once on mount. Access is
* `PermissionRoute permission="tickets:read"`. * still gated by each route's own guards (e.g. `PermissionRoute`).
*/ */
function StartParamNavigator() { function StartParamNavigator() {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -202,9 +208,12 @@ function StartParamNavigator() {
} }
if (!startParam) return; if (!startParam) return;
const match = ADMIN_TICKET_START_PARAM_RE.exec(startParam); for (const { re, to } of START_PARAM_ROUTES) {
if (match) { const match = re.exec(startParam);
navigate(`/admin/tickets/${match[1]}`, { replace: true }); if (match) {
navigate(to(match), { replace: true });
return;
}
} }
}, [navigate]); }, [navigate]);