fix: retry StoreKit tip product lookup

This commit is contained in:
FuelBoard Contributor
2026-09-20 14:33:28 +01:00
parent 7dbd48786f
commit 7cb23e09c2
+26 -13
View File
@@ -721,7 +721,7 @@ final class TipStore: ObservableObject {
// (or restored transactions) are picked up.
do {
let fetched = try await Product.products(for: Self.tiers.map(\.id))
products = Dictionary(uniqueKeysWithValues: fetched.map { ($0.id, $0) })
merge(fetched)
} catch {
// No products yet (sideloaded build) the buttons still show the
// intended prices and report purchase attempts gracefully.
@@ -729,24 +729,37 @@ final class TipStore: ObservableObject {
}
}
private func merge(_ fetched: [Product]) {
products.merge(Dictionary(uniqueKeysWithValues: fetched.map { ($0.id, $0) })) { _, new in new }
}
private func product(for tier: TipTier) async throws -> Product? {
if let product = products[tier.id] { return product }
// TestFlight/App Store Connect product availability can lag the Settings
// onAppear load. Re-query the tapped tier before falling back so a newly
// approved IAP opens the system purchase sheet instead of showing stale
// "not available" copy.
let fetched = try await Product.products(for: [tier.id])
merge(fetched)
return fetched.first { $0.id == tier.id }
}
func purchase(_ tier: TipTier) async {
guard !purchaseInProgress else { return }
purchaseInProgress = true
defer { purchaseInProgress = false }
// If the product hasn't loaded (e.g. not configured in App Store
// Connect yet), still allow the attempt so the user sees a clear
// outcome rather than a dead button.
guard let product = products[tier.id] else {
showOutcome(
NSLocalizedString("The tip isn't available in this build yet — check back after an App Store release.", comment: ""),
icon: "info.circle.fill",
tint: Color(.secondaryLabel)
)
return
}
do {
guard let product = try await product(for: tier) else {
showOutcome(
NSLocalizedString("This tip isn't available from the App Store yet. Please try again shortly.", comment: ""),
icon: "info.circle.fill",
tint: Color(.secondaryLabel)
)
return
}
let result = try await product.purchase()
switch result {
case .success(let verification):