feat(ui): refine Telegram invite & close UX
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 13s
CI / ui (pull_request) Successful in 47s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m2s

- Shared invite links open the Mini App fullscreen (mode=fullscreen), so a
  shared link matches the bot's own fullscreen launch.
- A used or expired invite deep-link now lands the visitor in the lobby with a
  gentle notice pointing at the right bot (@<username>, by service language),
  instead of a red "code invalid/expired" error on the Friends screen.
- The in-game close confirmation is armed only on Telegram mobile clients; on
  desktop (tdesktop/macOS/web) it is skipped, where the "changes may not be
  saved" dialog is just noise (drafts auto-save).
This commit is contained in:
Ilia Denisov
2026-06-15 17:22:09 +02:00
parent 01d2d1f368
commit 853730823b
9 changed files with 200 additions and 19 deletions
+20 -1
View File
@@ -52,6 +52,23 @@ function telegramBase(lang: string): string | null {
return byLang || envVar('VITE_TELEGRAM_LINK') || null;
}
/**
* botUsername extracts the bot's @username (without the @) from the configured Mini App
* link for a bot language: the first path segment of https://t.me/<bot>/<app>. Returns
* null when no base is configured or the link carries no path, so callers can fall back
* when they cannot point at a specific bot.
*/
export function botUsername(lang = ''): string | null {
const base = telegramBase(lang);
if (!base) return null;
try {
const seg = new URL(base).pathname.split('/').filter(Boolean)[0];
return seg || null;
} catch {
return null;
}
}
/**
* shareLink wraps a deep-link start parameter in a t.me Mini App link for the given
* bot language (the session's service language). Returns null when no base is
@@ -61,5 +78,7 @@ export function shareLink(param: string, lang = ''): string | null {
const base = telegramBase(lang);
if (!base) return null;
const sep = base.includes('?') ? '&' : '?';
return `${base}${sep}startapp=${encodeURIComponent(param)}`;
// mode=fullscreen opens the Mini App fullscreen, matching how the bot's own entry
// opens it, so a shared link and the bot give the same experience.
return `${base}${sep}startapp=${encodeURIComponent(param)}&mode=fullscreen`;
}