diff --git a/Sources/BraveVPN/BuyVPNViewController.swift b/Sources/BraveVPN/BuyVPNViewController.swift index 17b1f2c51beb..2f056b81909b 100644 --- a/Sources/BraveVPN/BuyVPNViewController.swift +++ b/Sources/BraveVPN/BuyVPNViewController.swift @@ -13,7 +13,8 @@ import DesignSystem class BuyVPNViewController: VPNSetupLoadingController { let iapObserver: IAPObserver - + private var iapRestoreTimer: Timer? + var activeSubcriptionChoice: SubscriptionType = .yearly { didSet { buyVPNView.activeSubcriptionChoice = activeSubcriptionChoice @@ -134,6 +135,19 @@ class BuyVPNViewController: VPNSetupLoadingController { @objc func restorePurchasesAction() { isLoading = true SKPaymentQueue.default().restoreCompletedTransactions() + + if iapRestoreTimer != nil { + iapRestoreTimer?.invalidate() + iapRestoreTimer = nil + } + + // Adding 1 minute timer for restore + iapRestoreTimer = Timer.scheduledTimer( + timeInterval: 1.minutes, + target: self, + selector: #selector(handleRestoreTimeoutFailure), + userInfo: nil, + repeats: false) } @objc func startSubscriptionAction() { @@ -182,6 +196,25 @@ extension BuyVPNViewController: IAPObserverDelegate { } func purchaseFailed(error: IAPObserver.PurchaseError) { + // Handle Transaction or Restore error + guard isLoading else { + return + } + + handleTransactionError(error: error) + } + + @objc func handleRestoreTimeoutFailure() { + // Handle Restore error from timeout + guard isLoading else { + return + } + + let errorRestore = SKError(SKError.unknown, userInfo: ["detail": "time-out"]) + handleTransactionError(error: .transactionError(error: errorRestore)) + } + + private func handleTransactionError(error: IAPObserver.PurchaseError) { DispatchQueue.main.async { self.isLoading = false diff --git a/Sources/BraveVPN/IAPObserver.swift b/Sources/BraveVPN/IAPObserver.swift index 213c6f811a27..d5956ec99f5f 100644 --- a/Sources/BraveVPN/IAPObserver.swift +++ b/Sources/BraveVPN/IAPObserver.swift @@ -85,4 +85,14 @@ public class IAPObserver: NSObject, SKPaymentTransactionObserver { Logger.module.debug("Restoring transaction failed") self.delegate?.purchaseFailed(error: .transactionError(error: error as? SKError)) } + + // Used to handle restoring transaction error for users never purchased but trying to restore + public func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { + if queue.transactions.isEmpty { + Logger.module.debug("Restoring transaction failed - Nothing to restore - Account never bought this product") + + let errorRestore = SKError(SKError.unknown, userInfo: ["detail": "not-purchased"]) + delegate?.purchaseFailed(error: .transactionError(error: errorRestore)) + } + } }