From f6aa0ba4b0a6abafd733ab2723c696bd83546e21 Mon Sep 17 00:00:00 2001 From: Ilia Denisov Date: Thu, 9 Jul 2026 20:11:35 +0200 Subject: [PATCH] fix(ui): correct the VK-iOS purchase block + add an iOS store note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VK-iOS detection used platformSubtype(), which is server-derived for VK and so never reported iOS on the client — the pack CTA stayed active and a tap hit a 403 with a generic error. Read the device family from the signed vk_platform launch param (normalizeSubtype(vkPlatform())) instead. Under the store header on VK-iOS, add a note that purchases are prohibited by Apple policy, linking to the web version (opened through VK's external-link route). --- ui/src/lib/i18n/en.ts | 3 +++ ui/src/lib/i18n/ru.ts | 3 +++ ui/src/screens/Wallet.svelte | 26 +++++++++++++++++++++----- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/ui/src/lib/i18n/en.ts b/ui/src/lib/i18n/en.ts index 59888f6..bde3ce2 100644 --- a/ui/src/lib/i18n/en.ts +++ b/ui/src/lib/i18n/en.ts @@ -244,6 +244,9 @@ export const en = { 'wallet.buy': 'Buy', 'wallet.offer': 'Public offer', 'wallet.platformNoBuy': 'Purchases are not available on this platform', + 'wallet.iosBlockedPre': 'Purchases on iOS are prohibited by Apple policy. Try the ', + 'wallet.iosBlockedLink': 'other version', + 'wallet.iosBlockedPost': ' of the game.', 'wallet.gpStub': 'To buy chips, install the RuStore build.', 'wallet.cur.RUB': '₽', 'wallet.cur.VOTE': 'votes', diff --git a/ui/src/lib/i18n/ru.ts b/ui/src/lib/i18n/ru.ts index 17f8e68..89ed89c 100644 --- a/ui/src/lib/i18n/ru.ts +++ b/ui/src/lib/i18n/ru.ts @@ -244,6 +244,9 @@ export const ru: Record = { 'wallet.buy': 'Купить', 'wallet.offer': 'Публичная оферта', 'wallet.platformNoBuy': 'На данной платформе покупки невозможны', + 'wallet.iosBlockedPre': 'Покупки на iOS запрещены политикой Apple. Попробуйте воспользоваться ', + 'wallet.iosBlockedLink': 'другой версией', + 'wallet.iosBlockedPost': ' игры.', 'wallet.gpStub': 'Чтобы покупать фишки, установите версию из RuStore.', 'wallet.cur.RUB': '₽', 'wallet.cur.VOTE': 'голосов', diff --git a/ui/src/screens/Wallet.svelte b/ui/src/screens/Wallet.svelte index 6e26b7e..936eb91 100644 --- a/ui/src/screens/Wallet.svelte +++ b/ui/src/screens/Wallet.svelte @@ -3,12 +3,12 @@ import Modal from '../components/Modal.svelte'; import { app, handleError, showToast } from '../lib/app.svelte'; import { gateway } from '../lib/gateway'; - import { platformSubtype } from '../lib/platform'; + import { normalizeSubtype } from '../lib/platform'; import { t, i18n, type MessageKey } from '../lib/i18n/index.svelte'; import { executionContext, formatAmount, needsWebSpendWarning, type SpendContext } from '../lib/wallet'; import { isGooglePlayBuild } from '../lib/distribution'; - import { openExternalUrl } from '../lib/links'; - import { vkShowOrderBox } from '../lib/vk'; + import { onExternalLinkClick, openExternalUrl } from '../lib/links'; + import { vkPlatform, vkShowOrderBox } from '../lib/vk'; import type { Wallet, Catalog, CatalogProduct } from '../lib/model'; // The Wallet section: the context-visible chip balances, the active benefits, and the storefront. @@ -27,8 +27,9 @@ const context: SpendContext = executionContext(); const gpBuild = isGooglePlayBuild(); // Money purchases are not permitted inside the VK iOS app (Apple ToS); the pack CTA is shown - // muted and taps explain why, rather than hiding the storefront. - const purchaseBlocked = context === 'vk' && platformSubtype() === 'ios'; + // muted and taps explain why, rather than hiding the storefront. VK's device family is not on the + // client platformSubtype (server-derived) — read it from the signed vk_platform launch param. + const purchaseBlocked = context === 'vk' && normalizeSubtype(vkPlatform()) === 'ios'; const values = $derived(catalog?.products.filter((p) => p.kind === 'value') ?? []); const packs = $derived(catalog?.products.filter((p) => p.kind === 'pack') ?? []); @@ -151,6 +152,10 @@

{t('wallet.store')}

+ {#if purchaseBlocked} + +

{t('wallet.iosBlockedPre')}{t('wallet.iosBlockedLink')}{t('wallet.iosBlockedPost')}

+ {/if} {#each values as p (p.productId)}
{p.title} @@ -260,6 +265,17 @@ .buy.blocked { opacity: 0.5; } + .ios-note { + margin: 0 0 4px; + padding: 8px 12px; + color: var(--text-muted); + font-size: 0.85rem; + border: 1px dashed var(--border); + border-radius: var(--radius-sm); + } + .ios-note a { + color: var(--accent); + } .empty, .stub { margin: 0;