Skip to content

Commit 627565c

Browse files
release: promote development → main (supported-providers catalog) (#147)
* fix(dashboard): surface Google Play + App Store on the Providers list (#123) The store-sync credential pages (/providers/google-play, /providers/app-store) shipped in 2.2.0 but were never linked from the Providers index (only web PSPs render there), so they were unreachable. Adds an 'In-app billing (native app stores)' section with Connect/Manage cards + live connection status. * fix(dashboard): surface store sync in products UI (bulk + badges + Re-sync feedback) (#124) * fix(dashboard): surface Google Play + App Store on the Providers list (#123) The store-sync credential pages (/providers/google-play, /providers/app-store) shipped in 2.2.0 but were never linked from the Providers index (only web PSPs render there), so they were unreachable. Adds an 'In-app billing (native app stores)' section with Connect/Manage cards + live connection status. * fix(dashboard): surface store sync in products UI (bulk + badges + Re-sync) Closes the two store-sync UI gaps from 2.2.0: - Bulk 'sync-to-providers' now includes Google Play + App Store. - Products table shows Play / App Store badges; per-product Re-sync panel + unsynced banner + sync panel surface store connection/results. Matches the /sync route snake_case keys (google_play/app_store). tsc clean. * chore(source): update .github/workflows/deploy-cloud.yml dashboard/app/api/products/[id]/sync/route.ts dashboard/app/api/products/sync-to-providers/route.ts * chore(source): update dashboard/__tests__/lib/googleplay-product-sync.test.ts dashboard/app/api/products/[id]/sync/route.ts dashboard/app/api/products/sync-to-providers/route.ts * chore(source): update cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftInitializer.kt cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftPlatform.android.kt cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/di/PayCraftModule.kt (#126) * chore(release): bump paycraft 2.2.0 → 2.3.0 (commonMain-only native billing) (#127) * chore(source): update cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftInitializer.kt cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftPlatform.android.kt cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/di/PayCraftModule.kt * chore(source): update gradle.properties * feat paywall currency fix native store price and usd fallback (#128) * chore: initialize session branch — feat paywall currency fix native store price and usd fallback * chore(source): update cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/billing/PlayBillingNativeClient.android.kt cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/CurrencyResolver.kt cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/PayCraft.kt * fix(billing): resolve CI blockers on native-billing PR — Android getBillingConfig + ktlint - PlayBillingNativeClient.android: billing-ktx v8 has no suspend getBillingConfig extension; rewrite storefrontCountry() with the callback getBillingConfigAsync wrapped in suspendCancellableCoroutine (fixes 'unresolved reference getBillingConfig' + type inference) - PayCraft.kt: drop leading underscore on two purely-private vars (nativePricesBySku, currentSuite) that have no matching public member — ktlint standard:backing-property-naming was aborting spotless with an AssertionError - spotless reformat of touched files Verified green locally: spotlessCheck, :cmp-paycraft:compileAndroidMain, :cmp-paycraft:compileKotlinIosSimulatorArm64 (native StoreKit2), :cmp-paycraft:jvmTest. * chore: initialize session branch — chore(paycraft): reconcile + close v2 production-readiness epic (OBE by 2.3.x) * chore(source): update .gitignore CHANGELOG.md cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/CurrencyResolver.kt * chore(source): update cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/CountryDetector.kt * chore: initialize session branch — fix(auth): multi-tenant login callback redirect + ship platform-provider epic dashboard * chore(source): update dashboard/app/auth/callback/route.ts supabase/.temp/cli-latest * feat(dashboard): platform→provider selector panel on providers page (#132) * chore: initialize session branch — feat(dashboard): platform→provider selector panel on providers page * chore(source): update dashboard/app/(dashboard)/providers/page.tsx dashboard/components/providers/platform-providers-panel.tsx * feat(dashboard): platform panel to top + fees + default provider (#134) * chore: initialize session branch — feat(dashboard): platform panel to top + fees + default provider * chore(source): update dashboard/app/(dashboard)/providers/page.tsx dashboard/components/providers/platform-providers-panel.tsx * fix(dashboard): remove duplicate platform providers panel (#136) * chore: initialize session branch — fix(dashboard): remove duplicate platform providers panel * chore(source): update dashboard/app/(dashboard)/providers/page.tsx * feat(dashboard): platform providers as separate sidebar page (#138) * chore(source): update dashboard/app/(dashboard)/providers/page.tsx dashboard/components/sidebar.tsx dashboard/app/(dashboard)/providers/platform/ * chore: initialize session branch — feat(dashboard): platform providers as separate sidebar page * feat(dashboard): platform panel — explicit primary provider + save confirmation (#140) * chore: initialize session branch — feat(dashboard): platform panel — explicit primary provider + save confirmation * chore(source): update dashboard/components/providers/platform-providers-panel.tsx * refactor(dashboard): simplify platform providers to primary + fallback list (#142) * chore: initialize session branch — refactor(dashboard): simplify platform providers to primary + fallback list * chore(source): update dashboard/app/(dashboard)/providers/platform/page.tsx dashboard/components/providers/platform-providers-panel.tsx * feat(dashboard): per-platform primary + fallback provider selectors (#144) * chore: initialize session branch — feat(dashboard): per-platform primary + fallback provider selectors * chore(source): update dashboard/app/(dashboard)/providers/platform/page.tsx dashboard/components/providers/platform-providers-panel.tsx * feat(dashboard): supported-providers catalog with connection status (#146) * chore: initialize session branch — feat(dashboard): supported-providers catalog with connection status * chore(source): update dashboard/components/providers/platform-providers-panel.tsx --------- Co-authored-by: MobileByteSensei Community <mobilebytesensei@gmail.com>
1 parent 18d9987 commit 627565c

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

dashboard/components/providers/platform-providers-panel.tsx

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,26 @@ const DISPLAY: Record<string, string> = {
3636
razorpay: "Razorpay",
3737
cashfree: "Cashfree",
3838
direct_upi: "UPI Direct",
39+
google_play: "Google Play Billing",
40+
app_store: "App Store (StoreKit 2)",
3941
}
42+
43+
/** Every provider PayCraft supports — native store lanes + routable web providers. */
44+
const CATALOG: {
45+
key: string
46+
lane: "native" | "web"
47+
on?: string
48+
href: string
49+
nativeFee?: string
50+
}[] = [
51+
{ key: "app_store", lane: "native", on: "iOS", href: "/providers/app-store", nativeFee: "15–30% store cut" },
52+
{ key: "google_play", lane: "native", on: "Android", href: "/providers/google-play", nativeFee: "15–30% store cut" },
53+
{ key: "stripe", lane: "web", href: "/providers/stripe" },
54+
{ key: "razorpay", lane: "web", href: "/providers/razorpay" },
55+
{ key: "cashfree", lane: "web", href: "/providers/cashfree" },
56+
{ key: "direct_upi", lane: "web", href: "/providers/upi" },
57+
]
58+
4059
const PLATFORMS: { key: string; label: string; native?: string; nativeHref?: string }[] = [
4160
{ key: "ios", label: "iOS", native: "App Store (StoreKit 2)", nativeHref: "/providers/app-store" },
4261
{ key: "android", label: "Android", native: "Google Play Billing", nativeHref: "/providers/google-play" },
@@ -136,7 +155,72 @@ export function PlatformProvidersPanel({
136155

137156
const noProviders = options.length === 0
138157

158+
// fee label for the catalog: web → registry %, native → store-cut range
159+
const catalogFee = (c: (typeof CATALOG)[number]) => {
160+
if (c.lane === "native") return c.nativeFee ?? ""
161+
const f = providerInfo.get(c.key)?.fee
162+
return f != null && f < 99 ? `${f}%` : "—"
163+
}
164+
139165
return (
166+
<div className="space-y-4">
167+
{/* ── Supported providers catalog (all providers + connection status) ── */}
168+
<Card>
169+
<CardBody>
170+
<div className="flex items-center justify-between mb-1">
171+
<h2 className="text-sm font-bold text-ink-900">Supported providers</h2>
172+
<Badge>{options.length + CATALOG.filter((c) => c.lane === "native" && connected.has(c.key)).length} connected</Badge>
173+
</div>
174+
<p className="text-xs text-ink-500 mb-4 max-w-2xl">
175+
Every provider PayCraft supports. Connect the ones you want, then choose a primary +
176+
fallback per platform below. Fees are the provider's domestic rate — lower routes cheaper.
177+
</p>
178+
<div className="rounded-xl border border-ink-200 divide-y divide-ink-100">
179+
<div className="hidden sm:grid grid-cols-[1fr_120px_140px_130px] gap-3 px-4 py-2 text-[10px] font-bold uppercase tracking-wider text-ink-400">
180+
<span>Provider</span>
181+
<span>Lane</span>
182+
<span>Fee</span>
183+
<span>Status</span>
184+
</div>
185+
{CATALOG.map((c) => {
186+
const isConnected = connected.has(c.key)
187+
return (
188+
<div key={c.key} className="grid grid-cols-1 sm:grid-cols-[1fr_120px_140px_130px] gap-1 sm:gap-3 px-4 py-3 sm:items-center">
189+
<div className="flex items-center gap-2">
190+
<span className="text-sm font-semibold text-ink-900">{DISPLAY[c.key] ?? c.key}</span>
191+
</div>
192+
<div>
193+
{c.lane === "native" ? (
194+
<span className="text-[11px] font-medium text-ink-600">Native · {c.on}</span>
195+
) : (
196+
<span className="text-[11px] font-medium text-ink-600">Web</span>
197+
)}
198+
</div>
199+
<div className="text-[13px] tabular-nums text-ink-700">{catalogFee(c)}</div>
200+
<div>
201+
{isConnected ? (
202+
<span className="inline-flex items-center gap-1 text-[11px] font-semibold text-emerald-600">
203+
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500" /> Connected
204+
</span>
205+
) : (
206+
<Link href={c.href} className="inline-flex items-center gap-1 text-[11px] font-semibold text-brand-600 hover:text-brand-700">
207+
<span className="w-1.5 h-1.5 rounded-full bg-ink-300" /> Connect →
208+
</Link>
209+
)}
210+
</div>
211+
</div>
212+
)
213+
})}
214+
</div>
215+
<p className="text-[11px] text-ink-400 mt-3">
216+
Native stores (App Store / Google Play) are mandatory for iOS &amp; Android digital
217+
subscriptions per store policy. Web providers route Desktop, Web, and the physical-goods
218+
lane.
219+
</p>
220+
</CardBody>
221+
</Card>
222+
223+
{/* ── Per-platform primary + fallback routing ── */}
140224
<Card>
141225
<CardBody>
142226
<div className="flex items-center justify-between mb-1">
@@ -218,6 +302,7 @@ export function PlatformProvidersPanel({
218302
</p>
219303
</CardBody>
220304
</Card>
305+
</div>
221306
)
222307
}
223308

0 commit comments

Comments
 (0)