feat(ui): hide Telegram/VK link buttons on the native build

The native (Capacitor) sign-in surface is guest + email only: VK ID
web-login is a full-page redirect to id.vk.com that cannot return into the
WebView, and the Telegram Login Widget is unreliable there. Profile now
gates telegramLinkable/vkLinkable on !nativeShell (clientChannel android/
ios), hiding both LINK buttons on native; email and account management —
including an existing link's redirect-free UNLINK — stay. Native tg/vk
login (native SDKs / deep-link OAuth) is a separate later stage.

Covered by e2e/native.spec.ts (the reconcile test opens Profile and asserts
no Link Telegram / Link VK buttons, email present).
This commit is contained in:
Ilia Denisov
2026-07-12 18:09:11 +02:00
parent e077258567
commit 0eb72ba955
3 changed files with 46 additions and 19 deletions
+11
View File
@@ -73,6 +73,17 @@ test.describe('native offline-first', () => {
await expect(page.locator('header.nav.offline')).toHaveCount(0);
await expect(page.getByText('Ann', { exact: false }).first()).toBeVisible({ timeout: 15000 });
await expect(page.locator('button.tab').nth(1)).toBeEnabled();
// The native sign-in surface is guest + email only: on Profile the Telegram + VK LINK buttons are
// hidden (their login widget / full-page redirect cannot return into the WebView), while email account
// management stays. loginWidgetAvailable/vkWebLinkAvailable are true under the mock, so on web these
// buttons DO show (social.spec links Telegram there) — a count of 0 here proves the native gate, not a
// merely-absent button.
await page.getByRole('button', { name: /Settings/ }).click();
await page.getByRole('button', { name: 'Profile', exact: true }).click();
await expect(page.getByRole('button', { name: /Link Telegram/i })).toHaveCount(0);
await expect(page.getByRole('button', { name: /Link VK/i })).toHaveCount(0);
await expect(page.getByText('you@example.com')).toBeVisible();
});
test('starts a 2-player hotseat game as an offline guest', async ({ page }) => {
+8 -2
View File
@@ -16,6 +16,7 @@
import { gateway } from '../lib/gateway';
import { insideTelegram, loginWidgetAvailable, requestTelegramLogin } from '../lib/telegram';
import { insideVK } from '../lib/vk';
import { clientChannel } from '../lib/channel';
import { kickDictPreload } from '../lib/offline.svelte';
import { startVKLink, vkWebLinkAvailable } from '../lib/vkid';
import { t } from '../lib/i18n/index.svelte';
@@ -59,8 +60,13 @@
let deleting = $state<null | { method: 'email' | 'phrase' }>(null);
let deleteCode = $state('');
let deletePhrase = $state('');
const telegramLinkable = loginWidgetAvailable();
const vkLinkable = vkWebLinkAvailable();
// The native build hides the Telegram + VK LINK buttons: VK ID web-login is a full-page redirect to
// id.vk.com that cannot return into the Capacitor WebView, and the Telegram Login Widget is unreliable
// there — so guest + email is the native sign-in surface (native tg/vk login is a later stage). An
// existing link's UNLINK button stays (a pure gateway call, no redirect), as does all account management.
const nativeShell = clientChannel() === 'android' || clientChannel() === 'ios';
const telegramLinkable = loginWidgetAvailable() && !nativeShell;
const vkLinkable = vkWebLinkAvailable() && !nativeShell;
// Inside a host Mini App the current platform's own identity must not be managed from the
// profile — unlinking the very platform you are signed in through is meaningless — so that
// provider's linked-account row is hidden here (the web / native builds still show both).