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:
+27
-17
@@ -91,7 +91,10 @@ Kept current as parts land so a fresh session resumes without re-deriving. Verif
|
||||
`clientver`/config/`connectsrv` tests green, `svelte-check` 0, `vitest` 591, e2e 232 (incl.
|
||||
`update.spec.ts`), client build clean. Silent reconciliation seam deferred to D (owner); in-app
|
||||
store-update SDK noted Out of scope.
|
||||
- **D. Offline-first — 🚧 IN PROGRESS (D.1–D.4 done; D.6 + the D-close verification remain).**
|
||||
- **D. Offline-first — ✅ CODE-COMPLETE & e2e-verified (D.1–D.6 done, 2026-07-12).** Remaining: the on-device
|
||||
emulator **airplane-mode smoke** (owner / stage G) and the **deferred local-game-visibility decision** (below).
|
||||
D.5 (both offline modes render + play for the local guest) is verified by `e2e/native.spec.ts` (vs_ai move +
|
||||
hotseat start).
|
||||
- **D.1 + D.2 (foundations) — ✅ DONE & committed `bcd5a1d` (2026-07-12).** `ui/scripts/bundle-dicts.mjs`
|
||||
(release DAWGs → `dist/dict/<variant>@<version>.dawg`, keyed on `VITE_DICT_VERSION`, `OUT_DIR` override
|
||||
for the e2e); the `dict/loader.ts` **bundled tier** (between IndexedDB and network, **native-gated** —
|
||||
@@ -110,7 +113,11 @@ Kept current as parts land so a fresh session resumes without re-deriving. Verif
|
||||
the dawgs into `dist-e2e/dict/`. `svelte-check` 0, `vitest` 591, web + native builds clean; e2e runs in CI.
|
||||
See §D.3/§D.4 for the as-built corrections (shouldBootOffline **not** changed; `allowOffline` +
|
||||
checkReachable-token findings; the `__native.reconcile` e2e hook).
|
||||
- **D.6 (Profile tg/vk hide on native) — ▢ TODO** (owner deferred to a follow-up this session).
|
||||
- **D.6 (Profile tg/vk hide on native) — ✅ DONE & verified (2026-07-12).** `Profile.svelte` gates
|
||||
`telegramLinkable`/`vkLinkable` on `!nativeShell` (`clientChannel()` android/ios), so the Telegram + VK
|
||||
LINK buttons are hidden on the native build; email + account management (incl. any existing link's UNLINK,
|
||||
a redirect-free gateway call) stay. Covered by the `e2e/native.spec.ts` reconcile test (Profile → no Link
|
||||
Telegram / Link VK buttons, email present).
|
||||
- **DEFERRED DECISION (owner-agreed 2026-07-12) — native local-game visibility.** The online lobby lists
|
||||
only server games (`Lobby.svelte:42/54`), so a native guest's **device-local vs_ai/hotseat games hide from
|
||||
the lobby once reconciled online** (the pre-existing offline↔online split). For native this IS the primary
|
||||
@@ -420,16 +427,18 @@ purchase actions are absent; `pnpm check` + `pnpm test:unit` pass.
|
||||
**Done when:** Go `clientver` + gate tests pass; `pnpm check`/`test:unit`/`test:e2e` pass; a local
|
||||
gateway with `GATEWAY_MIN_CLIENT_VERSION=v99.0.0` shows the overlay, unset ⇒ unchanged.
|
||||
|
||||
### D. Offline-first (bundled dicts + local guest + cold boot + reconciliation) — 🚧 IN PROGRESS
|
||||
### D. Offline-first (bundled dicts + local guest + cold boot + reconciliation) — ✅ CODE-COMPLETE
|
||||
|
||||
Both offline modes already exist and are gated on `offlineMode.active`: local vs_ai and 2-4-player
|
||||
hotseat (pass-and-play with a host PIN referee) — see `ui/src/lib/localgame/source.hotseat.test.ts`
|
||||
and `ui/src/screens/NewGame.svelte:177-431`. This phase makes them reachable on a **cold first launch
|
||||
with no network**.
|
||||
|
||||
**Status:** the additive foundations (D.1, D.2) are **done & committed (`bcd5a1d`)** and inert on the
|
||||
web; the boot rewrite (D.3), reconciliation + the silent seam (D.4), the Profile soft-sign-in (D.6) and
|
||||
the tests remain. **Verify every line ref below against current code** (they are as of 2026-07-12).
|
||||
**Status:** D.1–D.6 are **done & verified** (foundations committed `bcd5a1d`; boot + reconciliation +
|
||||
Profile committed on `feature/android-native`, 2026-07-12), with `e2e/native.spec.ts` green locally
|
||||
(chromium + webkit) and in CI. Remaining for D: the on-device emulator airplane-mode smoke (owner /
|
||||
stage G) and the deferred local-game-visibility decision (Progress §D / §G). **Verify every line ref
|
||||
below against current code.**
|
||||
|
||||
**Decisions locked this session (owner-approved) — bake these before implementing:**
|
||||
- **The blocking Login is bypassed on native only.** Web / PWA / Telegram / VK keep the current
|
||||
@@ -514,17 +523,18 @@ the tests remain. **Verify every line ref below against current code** (they are
|
||||
offline flows on `guest || offlineMode.active`; the local guest makes `offlineMode.active` true, so both
|
||||
"quick" (vs_ai) and "with friends" (hotseat) show. The vs_ai human seat already uses the local-guest id
|
||||
(D.2).
|
||||
6. **Soft registration = reuse the `Profile` screen — ▢ TODO.**
|
||||
- Profile is already reachable for an **online** guest (guests keep the Profile tab —
|
||||
`SettingsHub.svelte:27` only hides friends/wallet for guests; `:33` hides profile/friends/wallet in
|
||||
**offline** mode). So once the native guest is online and reconciled (D.4 clears the auto-offline),
|
||||
Profile shows and email sign-in works. Offline you cannot register anyway (every method needs the
|
||||
server), so the offline-hidden behaviour is correct — **no change is needed to reach Profile**, provided
|
||||
D.4 clears the auto-offline when online.
|
||||
- **Hide tg/vk on native:** `Profile.svelte` — the Telegram link button (`~line 485`, gated on
|
||||
`telegramLinkable = loginWidgetAvailable()`, `:62`) and the VK link button (`~line 499`). Add a
|
||||
`clientChannel()` android/ios check to hide both on the native build; keep email + account management.
|
||||
(See the decision block above for why.)
|
||||
6. **Soft registration = reuse the `Profile` screen — ✅ DONE & verified (2026-07-12).** As built:
|
||||
- **Reaching Profile needed no change:** guests keep the Profile tab (`SettingsHub.svelte:27` only hides
|
||||
friends/wallet for guests; `:33` hides profile/friends/wallet in **offline** mode), so once the native
|
||||
guest is online and reconciled (D.4 clears the auto-offline) Profile shows and email sign-in works.
|
||||
Offline you cannot register anyway (every method needs the server), so the offline-hidden behaviour is
|
||||
correct.
|
||||
- **Hid tg/vk on native:** `Profile.svelte` gates `telegramLinkable = loginWidgetAvailable() && !nativeShell`
|
||||
and `vkLinkable = vkWebLinkAvailable() && !nativeShell` (`nativeShell = clientChannel()` android/ios), so
|
||||
both LINK buttons are hidden on native while email + account management (and an existing link's UNLINK — a
|
||||
redirect-free `link.unlink` call) stay. Verified in `e2e/native.spec.ts` (the reconcile test opens Profile
|
||||
and asserts no Link Telegram / Link VK, email present; `loginWidgetAvailable`/`vkWebLinkAvailable` are true
|
||||
under the mock, so the buttons show on web — the native count-0 proves the gate).
|
||||
|
||||
**Tests — ✅ DONE for D.3/D.4 (2026-07-12):**
|
||||
- **Unit (vitest, node):** no NEW unit test was added for D.3/D.4 — the boot decision, reconciliation and
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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).
|
||||
|
||||
Reference in New Issue
Block a user