feat(billing): Google Play build shows "not implemented" for coin buys
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:
@@ -6,7 +6,7 @@ import { ScreenHeader, ScreenShell } from "@/components/online/ScreenHeader";
|
|||||||
import { useSessionStore } from "@/lib/session-store";
|
import { useSessionStore } from "@/lib/session-store";
|
||||||
import { useI18n } from "@/lib/i18n";
|
import { useI18n } from "@/lib/i18n";
|
||||||
import { getService } from "@/lib/online/service";
|
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 { sound } from "@/lib/sound";
|
||||||
import { CoinPack } from "@/lib/online/types";
|
import { CoinPack } from "@/lib/online/types";
|
||||||
import { cn } from "@/lib/cn";
|
import { cn } from "@/lib/cn";
|
||||||
@@ -39,6 +39,14 @@ export function BuyCoinsScreen() {
|
|||||||
setBusy(p.id);
|
setBusy(p.id);
|
||||||
setMsg("");
|
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.
|
// Inside a store build (Cafe Bazaar / Myket), route through store billing.
|
||||||
if (isStoreBilling()) {
|
if (isStoreBilling()) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ const fa: Dict = {
|
|||||||
"buy.bonus": "هدیه",
|
"buy.bonus": "هدیه",
|
||||||
"buy.redirecting": "صفحهٔ پرداخت در تب جدید باز شد. پس از پرداخت، سکهها بهصورت خودکار اضافه میشوند.",
|
"buy.redirecting": "صفحهٔ پرداخت در تب جدید باز شد. پس از پرداخت، سکهها بهصورت خودکار اضافه میشوند.",
|
||||||
"buy.failed": "پرداخت در دسترس نیست. بعداً دوباره تلاش کنید.",
|
"buy.failed": "پرداخت در دسترس نیست. بعداً دوباره تلاش کنید.",
|
||||||
|
"buy.notImplemented": "پیادهسازی نشده است.",
|
||||||
"buy.popular": "محبوب",
|
"buy.popular": "محبوب",
|
||||||
"buy.best": "بهترین",
|
"buy.best": "بهترین",
|
||||||
"buy.starter": "شروع",
|
"buy.starter": "شروع",
|
||||||
@@ -528,6 +529,7 @@ const en: Dict = {
|
|||||||
"buy.bonus": "bonus",
|
"buy.bonus": "bonus",
|
||||||
"buy.redirecting": "Payment opened in a new tab. Your coins will be added automatically once you pay.",
|
"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.failed": "Payment unavailable. Please try again later.",
|
||||||
|
"buy.notImplemented": "Not implemented.",
|
||||||
"buy.popular": "Popular",
|
"buy.popular": "Popular",
|
||||||
"buy.best": "Best value",
|
"buy.best": "Best value",
|
||||||
"buy.starter": "Starter",
|
"buy.starter": "Starter",
|
||||||
|
|||||||
+13
-2
@@ -14,7 +14,7 @@
|
|||||||
import { registerPlugin } from "@capacitor/core";
|
import { registerPlugin } from "@capacitor/core";
|
||||||
import { CoinPack } from "./online/types";
|
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 ENV_STORE = ((process.env.NEXT_PUBLIC_STORE as StoreId | undefined) ?? "web");
|
||||||
const PACKAGE = process.env.NEXT_PUBLIC_APP_PACKAGE ?? "com.bargevasat.app";
|
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). */
|
/** True when coin purchases should go through a store (not the web ZarinPal gateway). */
|
||||||
export function isStoreBilling(): boolean {
|
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 {
|
function skuFor(pack: CoinPack): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user