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:
soroush.asadi
2026-06-04 17:59:30 +03:30
parent 4f2e4e14ea
commit cfed2950b2
8 changed files with 171 additions and 5 deletions
@@ -28,6 +28,12 @@ export function BuyCoinsScreen() {
const buy = async (p: CoinPack) => {
setBusy(p.id);
const res = await getService().buyCoins(p.id);
// Live: redirect to the ZarinPal gateway; we credit on return via callback.
if (res.redirectUrl) {
window.location.href = res.redirectUrl;
return;
}
// Mock/offline: instant credit.
if (res.ok && res.profile) {
setProfile(res.profile);
sound.play("purchase");