feat(billing): Google Play build shows "not implemented" for coin buys
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 6m7s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m12s
CI/CD / Deploy - local stack (db + server + web) (push) Successful in 1m4s

Add a gated `googleplay` store flavor (NEXT_PUBLIC_STORE=googleplay) so the
appeal/Play build ships a payment-free coin shop. isPurchaseDisabled() makes
BuyCoinsScreen short-circuit to a "not implemented" notice instead of starting
ZarinPal or Iranian IAB (both rejected on Play). Default web/Bazaar/Myket
builds are unaffected. New i18n key buy.notImplemented (fa+en).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-21 05:00:15 +03:30
parent b12a7c7813
commit 5f43392de2
3 changed files with 24 additions and 3 deletions
+9 -1
View File
@@ -6,7 +6,7 @@ import { ScreenHeader, ScreenShell } from "@/components/online/ScreenHeader";
import { useSessionStore } from "@/lib/session-store";
import { useI18n } from "@/lib/i18n";
import { getService } from "@/lib/online/service";
import { consumeStorePurchase, isStoreBilling, purchaseViaStore } from "@/lib/storeBilling";
import { consumeStorePurchase, isPurchaseDisabled, isStoreBilling, purchaseViaStore } from "@/lib/storeBilling";
import { sound } from "@/lib/sound";
import { CoinPack } from "@/lib/online/types";
import { cn } from "@/lib/cn";
@@ -39,6 +39,14 @@ export function BuyCoinsScreen() {
setBusy(p.id);
setMsg("");
// Google Play build: coin purchases are intentionally not wired (no Iranian
// IAB on Play). Show a notice instead of starting any payment flow.
if (isPurchaseDisabled()) {
setMsg(t("buy.notImplemented"));
setBusy(null);
return;
}
// Inside a store build (Cafe Bazaar / Myket), route through store billing.
if (isStoreBilling()) {
try {
+2
View File
@@ -139,6 +139,7 @@ const fa: Dict = {
"buy.bonus": "هدیه",
"buy.redirecting": "صفحهٔ پرداخت در تب جدید باز شد. پس از پرداخت، سکه‌ها به‌صورت خودکار اضافه می‌شوند.",
"buy.failed": "پرداخت در دسترس نیست. بعداً دوباره تلاش کنید.",
"buy.notImplemented": "پیاده‌سازی نشده است.",
"buy.popular": "محبوب",
"buy.best": "بهترین",
"buy.starter": "شروع",
@@ -528,6 +529,7 @@ const en: Dict = {
"buy.bonus": "bonus",
"buy.redirecting": "Payment opened in a new tab. Your coins will be added automatically once you pay.",
"buy.failed": "Payment unavailable. Please try again later.",
"buy.notImplemented": "Not implemented.",
"buy.popular": "Popular",
"buy.best": "Best value",
"buy.starter": "Starter",
+13 -2
View File
@@ -14,7 +14,7 @@
import { registerPlugin } from "@capacitor/core";
import { CoinPack } from "./online/types";
export type StoreId = "bazaar" | "myket" | "web";
export type StoreId = "bazaar" | "myket" | "web" | "googleplay";
const ENV_STORE = ((process.env.NEXT_PUBLIC_STORE as StoreId | undefined) ?? "web");
const PACKAGE = process.env.NEXT_PUBLIC_APP_PACKAGE ?? "com.bargevasat.app";
@@ -54,7 +54,18 @@ export function getStore(): StoreId {
/** True when coin purchases should go through a store (not the web ZarinPal gateway). */
export function isStoreBilling(): boolean {
return getStore() !== "web";
const s = getStore();
return s !== "web" && s !== "googleplay";
}
/**
* True for the Google Play build, where real-money coin purchases are NOT wired
* (no Iranian IAB on Play, and we don't ship a Play billing path). The Buy-Coins
* screen shows a "not implemented" notice instead of starting a purchase. Set via
* the build flavor `NEXT_PUBLIC_STORE=googleplay`.
*/
export function isPurchaseDisabled(): boolean {
return getStore() === "googleplay";
}
function skuFor(pack: CoinPack): string {