fix(ui): correct the VK-iOS purchase block + add an iOS store note
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 21s
CI / ui (pull_request) Successful in 1m9s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m59s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 21s
CI / ui (pull_request) Successful in 1m9s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m59s
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).
This commit is contained in:
@@ -244,6 +244,9 @@ export const en = {
|
|||||||
'wallet.buy': 'Buy',
|
'wallet.buy': 'Buy',
|
||||||
'wallet.offer': 'Public offer',
|
'wallet.offer': 'Public offer',
|
||||||
'wallet.platformNoBuy': 'Purchases are not available on this platform',
|
'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.gpStub': 'To buy chips, install the RuStore build.',
|
||||||
'wallet.cur.RUB': '₽',
|
'wallet.cur.RUB': '₽',
|
||||||
'wallet.cur.VOTE': 'votes',
|
'wallet.cur.VOTE': 'votes',
|
||||||
|
|||||||
@@ -244,6 +244,9 @@ export const ru: Record<MessageKey, string> = {
|
|||||||
'wallet.buy': 'Купить',
|
'wallet.buy': 'Купить',
|
||||||
'wallet.offer': 'Публичная оферта',
|
'wallet.offer': 'Публичная оферта',
|
||||||
'wallet.platformNoBuy': 'На данной платформе покупки невозможны',
|
'wallet.platformNoBuy': 'На данной платформе покупки невозможны',
|
||||||
|
'wallet.iosBlockedPre': 'Покупки на iOS запрещены политикой Apple. Попробуйте воспользоваться ',
|
||||||
|
'wallet.iosBlockedLink': 'другой версией',
|
||||||
|
'wallet.iosBlockedPost': ' игры.',
|
||||||
'wallet.gpStub': 'Чтобы покупать фишки, установите версию из RuStore.',
|
'wallet.gpStub': 'Чтобы покупать фишки, установите версию из RuStore.',
|
||||||
'wallet.cur.RUB': '₽',
|
'wallet.cur.RUB': '₽',
|
||||||
'wallet.cur.VOTE': 'голосов',
|
'wallet.cur.VOTE': 'голосов',
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
import Modal from '../components/Modal.svelte';
|
import Modal from '../components/Modal.svelte';
|
||||||
import { app, handleError, showToast } from '../lib/app.svelte';
|
import { app, handleError, showToast } from '../lib/app.svelte';
|
||||||
import { gateway } from '../lib/gateway';
|
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 { t, i18n, type MessageKey } from '../lib/i18n/index.svelte';
|
||||||
import { executionContext, formatAmount, needsWebSpendWarning, type SpendContext } from '../lib/wallet';
|
import { executionContext, formatAmount, needsWebSpendWarning, type SpendContext } from '../lib/wallet';
|
||||||
import { isGooglePlayBuild } from '../lib/distribution';
|
import { isGooglePlayBuild } from '../lib/distribution';
|
||||||
import { openExternalUrl } from '../lib/links';
|
import { onExternalLinkClick, openExternalUrl } from '../lib/links';
|
||||||
import { vkShowOrderBox } from '../lib/vk';
|
import { vkPlatform, vkShowOrderBox } from '../lib/vk';
|
||||||
import type { Wallet, Catalog, CatalogProduct } from '../lib/model';
|
import type { Wallet, Catalog, CatalogProduct } from '../lib/model';
|
||||||
|
|
||||||
// The Wallet section: the context-visible chip balances, the active benefits, and the storefront.
|
// The Wallet section: the context-visible chip balances, the active benefits, and the storefront.
|
||||||
@@ -27,8 +27,9 @@
|
|||||||
const context: SpendContext = executionContext();
|
const context: SpendContext = executionContext();
|
||||||
const gpBuild = isGooglePlayBuild();
|
const gpBuild = isGooglePlayBuild();
|
||||||
// Money purchases are not permitted inside the VK iOS app (Apple ToS); the pack CTA is shown
|
// 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.
|
// muted and taps explain why, rather than hiding the storefront. VK's device family is not on the
|
||||||
const purchaseBlocked = context === 'vk' && platformSubtype() === 'ios';
|
// 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 values = $derived(catalog?.products.filter((p) => p.kind === 'value') ?? []);
|
||||||
const packs = $derived(catalog?.products.filter((p) => p.kind === 'pack') ?? []);
|
const packs = $derived(catalog?.products.filter((p) => p.kind === 'pack') ?? []);
|
||||||
@@ -151,6 +152,10 @@
|
|||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h3>{t('wallet.store')}</h3>
|
<h3>{t('wallet.store')}</h3>
|
||||||
|
{#if purchaseBlocked}
|
||||||
|
<!-- prettier-ignore -->
|
||||||
|
<p class="ios-note" data-testid="ios-note">{t('wallet.iosBlockedPre')}<a href="https://erudit-game.ru/app/" target="_blank" rel="noopener noreferrer" onclick={onExternalLinkClick}>{t('wallet.iosBlockedLink')}</a>{t('wallet.iosBlockedPost')}</p>
|
||||||
|
{/if}
|
||||||
{#each values as p (p.productId)}
|
{#each values as p (p.productId)}
|
||||||
<div class="row product" data-testid="product" data-kind="value" data-pid={p.productId}>
|
<div class="row product" data-testid="product" data-kind="value" data-pid={p.productId}>
|
||||||
<span class="name">{p.title}</span>
|
<span class="name">{p.title}</span>
|
||||||
@@ -260,6 +265,17 @@
|
|||||||
.buy.blocked {
|
.buy.blocked {
|
||||||
opacity: 0.5;
|
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,
|
.empty,
|
||||||
.stub {
|
.stub {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user