import Foundation import StoreKit /// Shared purchase/restore logic used by FeatureComparisonView, UpgradeFeatureView, and UpgradePromptView. /// Each view owns an instance via @StateObject and binds its published properties to the UI. @MainActor final class SubscriptionPurchaseHelper: ObservableObject { @Published var isProcessing = false @Published var errorMessage: String? @Published var showSuccessAlert = false @Published var selectedProduct: Product? private var storeKit: StoreKitManager { StoreKitManager.shared } func handlePurchase(_ product: Product) { selectedProduct = product isProcessing = true errorMessage = nil Task { do { let transaction = try await storeKit.purchase(product) await MainActor.run { isProcessing = false if transaction != nil { // Check if backend verification failed (purchase is valid but pending server confirmation) if let backendError = storeKit.purchaseError { errorMessage = backendError } else { showSuccessAlert = true } } } } catch { await MainActor.run { isProcessing = false errorMessage = String(format: String(localized: "Purchase failed: %@"), error.localizedDescription) } } } } func handleRestore() { isProcessing = true errorMessage = nil Task { await storeKit.restorePurchases() await MainActor.run { isProcessing = false if !storeKit.purchasedProductIDs.isEmpty { showSuccessAlert = true } else { errorMessage = String(localized: "No purchases found to restore") } } } } }