diff --git a/Source/CourseDashboardAccessErrorView.swift b/Source/CourseDashboardAccessErrorView.swift index aacded5b5..6e9a6ec79 100644 --- a/Source/CourseDashboardAccessErrorView.swift +++ b/Source/CourseDashboardAccessErrorView.swift @@ -11,7 +11,7 @@ import Foundation protocol CourseDashboardAccessErrorViewDelegate: AnyObject { func findCourseAction() func upgradeCourseAction(course: OEXCourse, coursePrice: String, price: NSDecimalNumber?, currencyCode: String?, completion: @escaping ((Bool)->())) - func coursePrice(cell: CourseDashboardAccessErrorView, price: String?, elapsedTime: Int) + func coursePrice(cell: CourseDashboardAccessErrorView, price: String?, error: PurchaseError?, elapsedTime: Int) } class CourseDashboardAccessErrorView: UIView { @@ -224,7 +224,7 @@ class CourseDashboardAccessErrorView: UIView { let startTime = CFAbsoluteTimeGetCurrent() DispatchQueue.main.async { [weak self] in self?.upgradeButton.startShimeringEffect() - PaymentManager.shared.fetchPrroduct(courseSku) { [weak self] product in + PaymentManager.shared.fetchPrroduct(courseSku) { [weak self] product, error in guard let weakSelf = self else { return } if let product = product, let coursePrice = product.localizedPrice { @@ -232,12 +232,12 @@ class CourseDashboardAccessErrorView: UIView { weakSelf.localizedCoursePrice = coursePrice weakSelf.price = product.price weakSelf.currencyCode = product.priceLocale.currencyCode - weakSelf.delegate?.coursePrice(cell: weakSelf, price: coursePrice, elapsedTime: elapsedTime.millisecond) + weakSelf.delegate?.coursePrice(cell: weakSelf, price: coursePrice, error: nil, elapsedTime: elapsedTime.millisecond) weakSelf.upgradeButton.setPrice(coursePrice) weakSelf.upgradeButton.stopShimmerEffect() } else { - weakSelf.delegate?.coursePrice(cell: weakSelf, price: nil, elapsedTime: 0) + weakSelf.delegate?.coursePrice(cell: weakSelf, price: nil, error: error, elapsedTime: 0) } } } diff --git a/Source/EnrolledCoursesViewController+CourseUpgrade.swift b/Source/EnrolledCoursesViewController+CourseUpgrade.swift index 0729c374a..691cb970f 100644 --- a/Source/EnrolledCoursesViewController+CourseUpgrade.swift +++ b/Source/EnrolledCoursesViewController+CourseUpgrade.swift @@ -100,7 +100,7 @@ extension EnrolledCoursesViewController { guard let courseSku = course.sku, environment.serverConfig.iapConfig?.enabledforUser == true else { return } - PaymentManager.shared.fetchPrroduct(courseSku) { [weak self] product in + PaymentManager.shared.fetchPrroduct(courseSku) { [weak self] product, _ in if let product = product { self?.upgradeCourse(course: course, localizedCoursePrice: product.localizedPrice, price: product.price, currencyCode: product.priceLocale.currencyCode) } diff --git a/Source/NewCourseDashboardViewController.swift b/Source/NewCourseDashboardViewController.swift index 7ba0f6a1b..b94a7aefa 100644 --- a/Source/NewCourseDashboardViewController.swift +++ b/Source/NewCourseDashboardViewController.swift @@ -428,12 +428,12 @@ extension NewCourseDashboardViewController: CourseDashboardAccessErrorViewDelega redirectToDiscovery() } - func coursePrice(cell: CourseDashboardAccessErrorView, price: String?, elapsedTime: Int) { + func coursePrice(cell: CourseDashboardAccessErrorView, price: String?, error: PurchaseError?, elapsedTime: Int) { if let price = price { trackPriceLoadDuration(price: price, elapsedTime: elapsedTime) } else { - trackPriceLoadError(cell: cell) + trackPriceLoadError(cell: cell, error: error) } } @@ -500,24 +500,26 @@ extension NewCourseDashboardViewController { environment.analytics.trackCourseUpgradeTimeToLoadPrice(courseID: courseID, pacing: pacing, coursePrice: price, screen: screen, elapsedTime: elapsedTime) } - private func trackPriceLoadError(cell: CourseDashboardAccessErrorView) { + private func trackPriceLoadError(cell: CourseDashboardAccessErrorView, error: PurchaseError?) { guard let course = course, let courseID = course.course_id else { return } environment.analytics.trackCourseUpgradeLoadError(courseID: courseID, pacing: pacing, screen: screen) - showCoursePriceErrorAlert(cell: cell) + showCoursePriceErrorAlert(cell: cell, error: error) } - private func showCoursePriceErrorAlert(cell: CourseDashboardAccessErrorView) { + private func showCoursePriceErrorAlert(cell: CourseDashboardAccessErrorView, error: PurchaseError?) { guard let topController = UIApplication.shared.topMostController() else { return } let alertController = UIAlertController().showAlert(withTitle: Strings.CourseUpgrade.FailureAlert.alertTitle, message: Strings.CourseUpgrade.FailureAlert.priceFetchErrorMessage, cancelButtonTitle: nil, onViewController: topController) { _, _, _ in } - - alertController.addButton(withTitle: Strings.CourseUpgrade.FailureAlert.priceFetchError) { [weak self] _ in - cell.fetchCoursePrice() - self?.environment.analytics.trackCourseUpgradeErrorAction(courseID: self?.course?.course_id ?? "" , blockID: "", pacing: self?.pacing ?? "", coursePrice: "", screen: self?.screen ?? .none, errorAction: CourseUpgradeHelper.ErrorAction.reloadPrice.rawValue, upgradeError: "price", flowType: CourseUpgradeHandler.CourseUpgradeMode.userInitiated.rawValue) + if error != .productNotExist { + alertController.addButton(withTitle: Strings.CourseUpgrade.FailureAlert.priceFetchError) { [weak self] _ in + cell.fetchCoursePrice() + self?.environment.analytics.trackCourseUpgradeErrorAction(courseID: self?.course?.course_id ?? "" , blockID: "", pacing: self?.pacing ?? "", coursePrice: "", screen: self?.screen ?? .none, errorAction: CourseUpgradeHelper.ErrorAction.reloadPrice.rawValue, upgradeError: "price", flowType: CourseUpgradeHandler.CourseUpgradeMode.userInitiated.rawValue) + } } - alertController.addButton(withTitle: Strings.cancel, style: .default) { [weak self] _ in + let cancelButtonTitle = error == .productNotExist ? Strings.ok : Strings.cancel + alertController.addButton(withTitle: cancelButtonTitle, style: .default) { [weak self] _ in cell.hideUpgradeButton() self?.environment.analytics.trackCourseUpgradeErrorAction(courseID: self?.course?.course_id ?? "" , blockID: "", pacing: self?.pacing ?? "", coursePrice: "", screen: self?.screen ?? .none, errorAction: CourseUpgradeHelper.ErrorAction.close.rawValue, upgradeError: "price", flowType: CourseUpgradeHandler.CourseUpgradeMode.userInitiated.rawValue) } diff --git a/Source/PaymentManager.swift b/Source/PaymentManager.swift index 34c36c5ce..0acf26979 100644 --- a/Source/PaymentManager.swift +++ b/Source/PaymentManager.swift @@ -27,6 +27,7 @@ enum PurchaseError: String { case basketError // basket API returns error case checkoutError // checkout API returns error case verifyReceiptError // verify receipt API returns error + case productNotExist // product not existed on app appstore case generalError // general error var errorString: String { @@ -153,16 +154,16 @@ enum PurchaseError: String { } } - func fetchPrroduct(_ identifier: String, completion: ((SKProduct?) -> Void)? = nil) { - SwiftyStoreKit.retrieveProductsInfo([identifier]) { result in + func fetchPrroduct(_ identifier: String, completion: ((SKProduct?, PurchaseError?) -> Void)? = nil) { + SwiftyStoreKit.retrieveProductsInfo(["identifier"]) { result in if let product = result.retrievedProducts.first { - completion?(product) + completion?(product, nil) } else if let _ = result.invalidProductIDs.first { - completion?(nil) + completion?(nil, .productNotExist) } else { - completion?(nil) + completion?(nil, .generalError) } } } diff --git a/Source/ProfileOptionsViewController.swift b/Source/ProfileOptionsViewController.swift index 6e5cbcf61..9e6adba63 100644 --- a/Source/ProfileOptionsViewController.swift +++ b/Source/ProfileOptionsViewController.swift @@ -424,7 +424,7 @@ extension ProfileOptionsViewController: RestorePurchasesCellDelegate { guard let courseSku = course.sku, environment.serverConfig.iapConfig?.enabledforUser == true else { return } - PaymentManager.shared.fetchPrroduct(courseSku) { [weak self] product in + PaymentManager.shared.fetchPrroduct(courseSku) { [weak self] product, _ in if let product = product { self?.upgradeCourse(course: course, localizedCoursePrice: product.localizedPrice, price: product.price, currencyCode: product.priceLocale.currencyCode, indicator: indicator) } diff --git a/Source/ValuePropComponentView.swift b/Source/ValuePropComponentView.swift index da2debfcd..909930637 100644 --- a/Source/ValuePropComponentView.swift +++ b/Source/ValuePropComponentView.swift @@ -186,7 +186,7 @@ class ValuePropComponentView: UIView { DispatchQueue.main.async { [weak self] in self?.upgradeButton.startShimeringEffect() - PaymentManager.shared.fetchPrroduct(courseSku) { [weak self] product in + PaymentManager.shared.fetchPrroduct(courseSku) { [weak self] product, error in if let product = product, let localizedPrice = product.localizedPrice { let endTime = CFAbsoluteTimeGetCurrent() - startTime self?.localizedCoursePrice = localizedPrice @@ -197,7 +197,7 @@ class ValuePropComponentView: UIView { self?.upgradeButton.setPrice(localizedPrice) } else { self?.trackLoadError() - self?.showCoursePriceErrorAlert() + self?.showCoursePriceErrorAlert(error: error) } } } @@ -225,17 +225,19 @@ class ValuePropComponentView: UIView { environment.analytics.trackCourseUpgradeLoadError(courseID: courseID, blockID: blockID, pacing: pacing, screen: .courseComponent) } - private func showCoursePriceErrorAlert() { + private func showCoursePriceErrorAlert(error: PurchaseError?) { guard let topController = UIApplication.shared.topMostController() else { return } let alertController = UIAlertController().showAlert(withTitle: Strings.CourseUpgrade.FailureAlert.alertTitle, message: Strings.CourseUpgrade.FailureAlert.priceFetchErrorMessage, cancelButtonTitle: nil, onViewController: topController) { _, _, _ in } - alertController.addButton(withTitle: Strings.CourseUpgrade.FailureAlert.priceFetchError) { [weak self] _ in - self?.fetchCoursePrice() - self?.environment.analytics.trackCourseUpgradeErrorAction(courseID: self?.courseID ?? "" , blockID: self?.blockID ?? "", pacing: self?.pacing ?? "", coursePrice: "", screen: .courseComponent, errorAction: CourseUpgradeHelper.ErrorAction.reloadPrice.rawValue, upgradeError: "price", flowType: CourseUpgradeHandler.CourseUpgradeMode.userInitiated.rawValue) + if error != .productNotExist { + alertController.addButton(withTitle: Strings.CourseUpgrade.FailureAlert.priceFetchError) { [weak self] _ in + self?.fetchCoursePrice() + self?.environment.analytics.trackCourseUpgradeErrorAction(courseID: self?.courseID ?? "" , blockID: self?.blockID ?? "", pacing: self?.pacing ?? "", coursePrice: "", screen: .courseComponent, errorAction: CourseUpgradeHelper.ErrorAction.reloadPrice.rawValue, upgradeError: "price", flowType: CourseUpgradeHandler.CourseUpgradeMode.userInitiated.rawValue) + } } - - alertController.addButton(withTitle: Strings.cancel, style: .default) { [weak self] _ in + let cancelButtonTitle = error == .productNotExist ? Strings.ok : Strings.cancel + alertController.addButton(withTitle: cancelButtonTitle, style: .default) { [weak self] _ in self?.upgradeButton.stopShimmerEffect() self?.upgradeButton.updateVisibility(visible: false) self?.environment.analytics.trackCourseUpgradeErrorAction(courseID: self?.courseID ?? "" , blockID: self?.blockID ?? "", pacing: self?.pacing ?? "", coursePrice: "", screen: .courseComponent, errorAction: CourseUpgradeHelper.ErrorAction.close.rawValue, upgradeError: "price", flowType: CourseUpgradeHandler.CourseUpgradeMode.userInitiated.rawValue) diff --git a/Source/ValuePropDetailViewController.swift b/Source/ValuePropDetailViewController.swift index 32501f4f0..606a96fe5 100644 --- a/Source/ValuePropDetailViewController.swift +++ b/Source/ValuePropDetailViewController.swift @@ -98,7 +98,7 @@ class ValuePropDetailViewController: UIViewController, InterfaceOrientationOverr DispatchQueue.main.async { [weak self] in self?.upgradeButton.startShimeringEffect() - PaymentManager.shared.fetchPrroduct(courseSku) { [weak self] product in + PaymentManager.shared.fetchPrroduct(courseSku) { [weak self] product, error in if let product = product { let endTime = CFAbsoluteTimeGetCurrent() - startTime self?.localizedCoursePrice = product.localizedPrice @@ -109,7 +109,7 @@ class ValuePropDetailViewController: UIViewController, InterfaceOrientationOverr self?.upgradeButton.setPrice(product.localizedPrice ?? "") } else { self?.trackLoadError() - self?.showCoursePriceErrorAlert() + self?.showCoursePriceErrorAlert(error: error) } } } @@ -135,18 +135,20 @@ class ValuePropDetailViewController: UIViewController, InterfaceOrientationOverr environment.analytics.trackCourseUpgradeLoadError(courseID: courseID, blockID: blockID, pacing: pacing, screen: screen) } - private func showCoursePriceErrorAlert() { + private func showCoursePriceErrorAlert(error: PurchaseError?) { guard let topController = UIApplication.shared.topMostController() else { return } let alertController = UIAlertController().showAlert(withTitle: Strings.CourseUpgrade.FailureAlert.alertTitle, message: Strings.CourseUpgrade.FailureAlert.priceFetchErrorMessage, cancelButtonTitle: nil, onViewController: topController) { _, _, _ in } - - alertController.addButton(withTitle: Strings.CourseUpgrade.FailureAlert.priceFetchError) { [weak self] _ in - self?.fetchCoursePrice() - self?.environment.analytics.trackCourseUpgradeErrorAction(courseID: self?.course.course_id ?? "" , blockID: self?.blockID ?? "", pacing: self?.pacing ?? "", coursePrice: "", screen: self?.screen ?? .none, errorAction: CourseUpgradeHelper.ErrorAction.reloadPrice.rawValue, upgradeError: "price", flowType: CourseUpgradeHandler.CourseUpgradeMode.userInitiated.rawValue) + if error != .productNotExist { + alertController.addButton(withTitle: Strings.CourseUpgrade.FailureAlert.priceFetchError) { [weak self] _ in + self?.fetchCoursePrice() + self?.environment.analytics.trackCourseUpgradeErrorAction(courseID: self?.course.course_id ?? "" , blockID: self?.blockID ?? "", pacing: self?.pacing ?? "", coursePrice: "", screen: self?.screen ?? .none, errorAction: CourseUpgradeHelper.ErrorAction.reloadPrice.rawValue, upgradeError: "price", flowType: CourseUpgradeHandler.CourseUpgradeMode.userInitiated.rawValue) + } } - alertController.addButton(withTitle: Strings.cancel, style: .default) { [weak self] _ in + let cancelButtonTitle = error == .productNotExist ? Strings.ok : Strings.cancel + alertController.addButton(withTitle: cancelButtonTitle, style: .default) { [weak self] _ in self?.upgradeButton.stopShimmerEffect() self?.upgradeButton.isHidden = true self?.environment.analytics.trackCourseUpgradeErrorAction(courseID: self?.course.course_id ?? "" , blockID: self?.blockID ?? "", pacing: self?.pacing ?? "", coursePrice: "", screen: self?.screen ?? .none, errorAction: CourseUpgradeHelper.ErrorAction.close.rawValue, upgradeError: "price", flowType: CourseUpgradeHandler.CourseUpgradeMode.userInitiated.rawValue)