feat(telegram): native dialogs for confirms and deep-link notices
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 15s
CI / ui (pull_request) Successful in 56s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m19s

Inside the Mini App, route the destructive confirmations (resign, block, unfriend)
through Telegram's native showConfirm, and present the deep-link info modals (stale
invite, welcome-on-redeem) as a native showPopup whose button opens the bot chat.
Outside Telegram, or on a client predating the dialogs, the existing in-app Modal is
used unchanged; offline also keeps the modal so the action retains its disabled state.

Adds showConfirm/showPopup wrappers to telegram.ts and a pure popup-params builder
(nativedialogs.ts) with unit tests; the deep-link modal components choose native vs
in-app via an effect gated on insideTelegram + dialog availability.
This commit is contained in:
Ilia Denisov
2026-06-24 12:36:52 +02:00
parent 29b6c7e4d8
commit 2ba7cc3086
8 changed files with 209 additions and 15 deletions
+22 -2
View File
@@ -2,7 +2,8 @@
import { app, dismissStaleInvite } from '../lib/app.svelte';
import { t } from '../lib/i18n/index.svelte';
import { botUsername } from '../lib/deeplink';
import { telegramOpenLink } from '../lib/telegram';
import { insideTelegram, telegramDialogsAvailable, telegramOpenLink, telegramShowPopup } from '../lib/telegram';
import { BOT_BUTTON_ID, botInfoPopup } from '../lib/nativedialogs';
import Modal from './Modal.svelte';
// The single bot's @username, for the deep link.
@@ -10,6 +11,10 @@
// Split the message around the {bot} token so the bot handle renders as an inline link.
const parts = $derived(t('friends.staleInvite').split('{bot}'));
// Inside the Mini App with native popups, present the notice as Telegram's own popup instead of
// the in-app modal.
const useNative = insideTelegram() && telegramDialogsAvailable();
function openBot() {
if (username) {
const url = `https://t.me/${username}`;
@@ -19,9 +24,24 @@
}
dismissStaleInvite();
}
// Native path: raise Telegram's popup when the notice appears; its "open bot" button opens the
// bot chat, any other dismissal just clears the notice. The `shown` guard fires it once per notice.
let shown = false;
$effect(() => {
if (!useNative) return;
if (app.staleInvite && !shown) {
shown = true;
void telegramShowPopup(
botInfoPopup(t('friends.staleInviteTitle'), t('friends.staleInvite'), username ?? '', t('common.ok')),
).then((id) => (id === BOT_BUTTON_ID ? openBot() : dismissStaleInvite()));
} else if (!app.staleInvite) {
shown = false;
}
});
</script>
{#if app.staleInvite}
{#if app.staleInvite && !useNative}
<Modal title={t('friends.staleInviteTitle')} onclose={dismissStaleInvite}>
<p class="msg">{parts[0]}{#if username}<button type="button" class="bot" onclick={openBot}>@{username}</button>{/if}{parts[1] ?? ''}</p>
<button class="ok" onclick={dismissStaleInvite}>{t('common.ok')}</button>