Add ZarinPal sandbox payments for buying coins (config-driven merchant)
- ZarinpalService (request/verify) + /api/coins/pay/request (JWT) and /api/coins/pay/callback (verify → credit via ProfileService.BuyCoins → redirect back with ?pay=success); merchant id from config (sandbox default) - Client buyCoins (live) returns the StartPay redirect URL; BuyCoinsScreen redirects; page.tsx handles the ?pay return (notify + refresh) - Verified: sandbox request returns a real StartPay URL - Documented Cafe Bazaar (Poolakey) / Myket IAB as the required store payment path Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -119,7 +119,8 @@ export interface OnlineService {
|
||||
|
||||
/* ----- coin purchases (real payment gateway: TODO Zarinpal/IDPay) ----- */
|
||||
getCoinPacks(): Promise<CoinPack[]>;
|
||||
buyCoins(packId: string): Promise<{ ok: boolean; profile?: UserProfile; coins: number }>;
|
||||
/** Mock credits instantly; live returns a `redirectUrl` to the ZarinPal gateway. */
|
||||
buyCoins(packId: string): Promise<{ ok: boolean; profile?: UserProfile; coins: number; redirectUrl?: string }>;
|
||||
}
|
||||
|
||||
import { MockOnlineService } from "./mock-service";
|
||||
|
||||
@@ -376,9 +376,9 @@ export class SignalrService implements OnlineService {
|
||||
}
|
||||
getCoinPacks(): Promise<CoinPack[]> { return this.getJson<CoinPack[]>("/api/coins/packs"); }
|
||||
async buyCoins(id: string) {
|
||||
const r = await this.send<{ ok: boolean; profile?: UserProfile; coins: number }>(
|
||||
"POST", "/api/coins/buy", { packId: id });
|
||||
if (r.profile) this.cachedProfile = r.profile;
|
||||
return r;
|
||||
// Real money → start a ZarinPal payment and hand back the redirect URL.
|
||||
const r = await this.send<{ ok: boolean; url?: string }>(
|
||||
"POST", "/api/coins/pay/request", { packId: id });
|
||||
return { ok: r.ok, coins: 0, redirectUrl: r.url };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user