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