Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ErrorView to CustomerCenter #4574

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions RevenueCat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@
351B51C226D450E800BD2BD7 /* ProductRequestDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E350E57B0A393455A72B40 /* ProductRequestDataTests.swift */; };
351B51C326D450F200BD2BD7 /* InMemoryCachedObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35E3250FBBB03D92E06EC /* InMemoryCachedObjectTests.swift */; };
352137322CDBA2AA00FE961B /* FeatureEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 352137312CDBA2A700FE961B /* FeatureEvent.swift */; };
3523048A2D0A0F30003971A4 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 352304892D0A0F2B003971A4 /* ErrorView.swift */; };
3525D8A42C4AB3D600C21D99 /* CustomerCenterEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3525D8A32C4AB3D500C21D99 /* CustomerCenterEnvironment.swift */; };
35272E1B26D0029300F22C3B /* DeviceCacheSubscriberAttributesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35C4A795A0F056381A1B3 /* DeviceCacheSubscriberAttributesTests.swift */; };
35272E2226D0048D00F22C3B /* HTTPClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E353CBE9CF2572A72A347F /* HTTPClientTests.swift */; };
Expand Down Expand Up @@ -1517,6 +1518,7 @@
351B517326D44F4B00BD2BD7 /* MockPaymentDiscount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPaymentDiscount.swift; sourceTree = "<group>"; };
351B517926D44FF000BD2BD7 /* MockRequestFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRequestFetcher.swift; sourceTree = "<group>"; };
352137312CDBA2A700FE961B /* FeatureEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureEvent.swift; sourceTree = "<group>"; };
352304892D0A0F2B003971A4 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; };
3525D8A32C4AB3D500C21D99 /* CustomerCenterEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomerCenterEnvironment.swift; sourceTree = "<group>"; };
352B7D7827BD919B002A47DD /* DangerousSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DangerousSettings.swift; sourceTree = "<group>"; };
3530C18822653E8F00D6DF52 /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; };
Expand Down Expand Up @@ -3563,6 +3565,7 @@
C3AD12B92C6EA61F00A4F86F /* CompatibilityNavigationStack.swift */,
C3AD12BB2C6EA69D00A4F86F /* SubscriptionDetailsView.swift */,
77372D982C6F8C7B008E59D3 /* AppUpdateWarningView.swift */,
352304892D0A0F2B003971A4 /* ErrorView.swift */,
);
path = Views;
sourceTree = "<group>";
Expand Down Expand Up @@ -6490,6 +6493,7 @@
88A543E72C37A4C40039C6A5 /* TierSelectorView.swift in Sources */,
2C74571F2CE7028E004ACE52 /* ScreenCondition.swift in Sources */,
88A543E12C37A4820039C6A5 /* TemplateView+MultiTier.swift in Sources */,
3523048A2D0A0F30003971A4 /* ErrorView.swift in Sources */,
887A60B72C1D037000E1A461 /* WatchTemplateView.swift in Sources */,
887A60722C1D037000E1A461 /* PaywallViewMode+Extensions.swift in Sources */,
887A60C32C1D037000E1A461 /* FooterView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ protocol CustomerCenterPurchasesType: Sendable {

func track(customerCenterEvent: any CustomerCenterEventType)

func loadCustomerCenter() async throws -> CustomerCenterConfigData

func restorePurchases() async throws -> CustomerInfo

}
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,12 @@ final class CustomerCenterPurchases: CustomerCenterPurchasesType {
Purchases.shared.track(customerCenterEvent: customerCenterEvent)
}

func loadCustomerCenter() async throws -> CustomerCenterConfigData {
try await Purchases.shared.loadCustomerCenter()
}

func restorePurchases() async throws -> CustomerInfo {
try await Purchases.shared.restorePurchases()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,6 @@ import RevenueCat
}
}

var isLoaded: Bool {
return state != .notLoaded && configuration != nil
}

private let currentVersionFetcher: CurrentVersionFetcher
internal let customerCenterActionHandler: CustomerCenterActionHandler?

Expand Down Expand Up @@ -105,55 +101,20 @@ import RevenueCat

#endif

func loadPurchaseInformation() async {
func loadScreen() async {
do {
let customerInfo = try await purchasesProvider.customerInfo(fetchPolicy: .fetchCurrent)
let hasActiveProducts =
!customerInfo.activeSubscriptions.isEmpty || !customerInfo.nonSubscriptions.isEmpty

if !hasActiveProducts {
self.purchaseInformation = nil
self.state = .success
return
}

guard let activeTransaction = findActiveTransaction(customerInfo: customerInfo) else {
Logger.warning(Strings.could_not_find_subscription_information)
self.purchaseInformation = nil
throw CustomerCenterError.couldNotFindSubscriptionInformation
}

let entitlement = customerInfo.entitlements.all.values
.first(where: { $0.productIdentifier == activeTransaction.productIdentifier })

self.purchaseInformation = try await createPurchaseInformation(for: activeTransaction,
entitlement: entitlement)

try await self.loadPurchaseInformation()
try await self.loadCustomerCenterConfig()
self.state = .success
} catch {
self.state = .error(error)
}
}

func loadCustomerCenterConfig() async {
do {
self.configuration = try await Purchases.shared.loadCustomerCenter()
if let productId = configuration?.productId {
self.onUpdateAppClick = {
// productId is a positive integer, so it should be safe to construct a URL from it.
let url = URL(string: "https://itunes.apple.com/app/id\(productId)")!
URLUtilities.openURLIfNotAppExtension(url)
}
}
} catch {
self.state = .error(error)
}
}

func performRestore() async -> RestorePurchasesAlert.AlertType {
self.customerCenterActionHandler?(.restoreStarted)
do {
let customerInfo = try await Purchases.shared.restorePurchases()
let customerInfo = try await purchasesProvider.restorePurchases()
self.customerCenterActionHandler?(.restoreCompleted(customerInfo))
let hasEntitlements = customerInfo.entitlements.active.count > 0
return hasEntitlements ? .purchasesRecovered : .purchasesNotFound
Expand Down Expand Up @@ -182,6 +143,42 @@ import RevenueCat
@available(watchOS, unavailable)
private extension CustomerCenterViewModel {

func loadPurchaseInformation() async throws {
let customerInfo = try await purchasesProvider.customerInfo(fetchPolicy: .fetchCurrent)

let hasActiveProducts =
!customerInfo.activeSubscriptions.isEmpty || !customerInfo.nonSubscriptions.isEmpty

if !hasActiveProducts {
self.purchaseInformation = nil
self.state = .success
return
}

guard let activeTransaction = findActiveTransaction(customerInfo: customerInfo) else {
Logger.warning(Strings.could_not_find_subscription_information)
self.purchaseInformation = nil
throw CustomerCenterError.couldNotFindSubscriptionInformation
}

let entitlement = customerInfo.entitlements.all.values
.first(where: { $0.productIdentifier == activeTransaction.productIdentifier })

self.purchaseInformation = try await createPurchaseInformation(for: activeTransaction,
entitlement: entitlement)
}

func loadCustomerCenterConfig() async throws {
self.configuration = try await purchasesProvider.loadCustomerCenter()
if let productId = configuration?.productId {
self.onUpdateAppClick = {
// productId is a positive integer, so it should be safe to construct a URL from it.
let url = URL(string: "https://itunes.apple.com/app/id\(productId)")!
URLUtilities.openURLIfNotAppExtension(url)
}
}
}

func findActiveTransaction(customerInfo: CustomerInfo) -> Transaction? {
let activeSubscriptions = customerInfo.subscriptionsByProductIdentifier.values
.filter(\.isActive)
Expand Down
14 changes: 9 additions & 5 deletions RevenueCatUI/CustomerCenter/Views/CustomerCenterView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,20 @@ public struct CustomerCenterView: View {
// swiftlint:disable:next missing_docs
public var body: some View {
Group {
if !self.viewModel.isLoaded {
switch self.viewModel.state {
case .error:
ErrorView()
case .notLoaded:
TintedProgressView()
} else {
case .success:
if let configuration = self.viewModel.configuration {
destinationView(configuration: configuration)
.environment(\.localization, configuration.localization)
.environment(\.appearance, configuration.appearance)
.environment(\.supportInformation, configuration.support)
.environment(\.customerCenterPresentationMode, self.mode)
} else {
TintedProgressView()
}
}
}
Expand All @@ -104,9 +109,8 @@ public struct CustomerCenterView: View {
private extension CustomerCenterView {

func loadInformationIfNeeded() async {
if !viewModel.isLoaded {
await viewModel.loadPurchaseInformation()
await viewModel.loadCustomerCenterConfig()
if viewModel.state == .notLoaded {
await viewModel.loadScreen()
}
}

Expand Down
60 changes: 60 additions & 0 deletions RevenueCatUI/CustomerCenter/Views/ErrorView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// Copyright RevenueCat Inc. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// ErrorView.swift
//
// Created by Cesar de la Vega on 11/12/24.

import SwiftUI

#if os(iOS)

@available(iOS 15.0, *)
@available(macOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
struct ErrorView: View {

@Environment(\.locale)
private var locale

var body: some View {
VStack(spacing: 20) {
let errorMessage: String = Localization.localizedBundle(self.locale)
.localizedString(forKey: "Something went wrong",
value: "Something went wrong",
table: nil)
CompatibilityContentUnavailableView(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm wondering if it would make sense to have a "retry" button... It might also be worth at least displaying network errors with a different message... But we can improve that in future PRs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to do that, but it involves checking the type of network error, and thought it would complicate things a bit. Let's leave it for a future PR. I will add it to the list of things to do

String(errorMessage),
systemImage: "exclamationmark.triangle.fill",
description: nil
)
}
.padding(.vertical, 24)
.padding(.horizontal, 16)
.background(Color(uiColor: .secondarySystemGroupedBackground))
.cornerRadius(16)
}

}

#if DEBUG
@available(iOS 15.0, *)
@available(macOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
struct ErrorView_Previews: PreviewProvider {

static var previews: some View {
ErrorView()
}
}
#endif

#endif
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/ar.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ خلال %@";
"pay_up_front_period" = "%@ مقابل %@";
"then_price_per_period" = "ثم %@";
"Something went wrong" = "هناك خطأ ما";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/bg.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ през %@";
"pay_up_front_period" = "%@ за %@";
"then_price_per_period" = "след това %@";
"Something went wrong" = "Нещо се обърка";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/ca.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ durant %@";
"pay_up_front_period" = "%@ per %@";
"then_price_per_period" = "després %@";
"Something went wrong" = "Alguna cosa ha anat malament";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/cs.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ během %@";
"pay_up_front_period" = "%@ za %@";
"then_price_per_period" = "poté %@";
"Something went wrong" = "Něco se pokazilo";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/da.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ i løbet af %@";
"pay_up_front_period" = "%@ for %@";
"then_price_per_period" = "derefter %@";
"Something went wrong" = "Noget gik galt";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ während %@";
"pay_up_front_period" = "%@ für %@";
"then_price_per_period" = "dann %@";
"Something went wrong" = "Etwas ist schief gelaufen";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/el.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ κατά τη διάρκεια %@";
"pay_up_front_period" = "%@ για %@";
"then_price_per_period" = "μετά %@";
"Something went wrong" = "Κάτι πήγε στραβά";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
"pay_as_you_go_period" = "%@ during %@";
"pay_up_front_period" = "%@ for %@";
"then_price_per_period" = "then %@";
"Something went wrong" = "Something went wrong";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/en_AU.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
"pay_as_you_go_period" = "%@ during %@";
"pay_up_front_period" = "%@ for %@";
"then_price_per_period" = "then %@";
"Something went wrong" = "Something went wrong";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/en_CA.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
"pay_as_you_go_period" = "%@ during %@";
"pay_up_front_period" = "%@ for %@";
"then_price_per_period" = "then %@";
"Something went wrong" = "Something went wrong";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/en_GB.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
"pay_as_you_go_period" = "%@ during %@";
"pay_up_front_period" = "%@ for %@";
"then_price_per_period" = "then %@";
"Something went wrong" = "Something went wrong";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/en_US.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
"pay_as_you_go_period" = "%@ during %@";
"pay_up_front_period" = "%@ for %@";
"then_price_per_period" = "then %@";
"Something went wrong" = "Something went wrong";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/es_419.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
"pay_as_you_go_period" = "%@ durante %@";
"pay_up_front_period" = "%@ por %@";
"then_price_per_period" = "luego %@";
"Something went wrong" = "Algo salió mal";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/es_ES.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
"pay_as_you_go_period" = "%@ durante %@";
"pay_up_front_period" = "%@ por %@";
"then_price_per_period" = "luego %@";
"Something went wrong" = "Algo salió mal";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/fi.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ aikana %@";
"pay_up_front_period" = "%@ hinnalla %@";
"then_price_per_period" = "sitten %@";
"Something went wrong" = "Jotain meni pieleen";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/fr_CA.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ pendant %@";
"pay_up_front_period" = "%@ pour %@";
"then_price_per_period" = "puis %@";
"Something went wrong" = "Quelque chose s'est mal passé";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/he.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ במהלך %@";
"pay_up_front_period" = "%@ עבור %@";
"then_price_per_period" = "לאחר מכן %@";
"Something went wrong" = "משהו השתבש";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/hi.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ के दौरान %@";
"pay_up_front_period" = "%@ के लिए %@";
"then_price_per_period" = "फिर %@";
"Something went wrong" = "कुछ गलत हो गया";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/hr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ tijekom %@";
"pay_up_front_period" = "%@ za %@";
"then_price_per_period" = "zatim %@";
"Something went wrong" = "Nešto je pošlo po zlu";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/hu.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ során %@";
"pay_up_front_period" = "%@ ért %@";
"then_price_per_period" = "majd %@";
"Something went wrong" = "Valami elromlott";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/id.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ selama %@";
"pay_up_front_period" = "%@ untuk %@";
"then_price_per_period" = "kemudian %@";
"Something went wrong" = "Ada yang salah";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/it.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ durante %@";
"pay_up_front_period" = "%@ per %@";
"then_price_per_period" = "poi %@";
"Something went wrong" = "Qualcosa è andato storto";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/ja.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ の期間 %@";
"pay_up_front_period" = "%@ で %@";
"then_price_per_period" = "次に %@";
"Something went wrong" = "問題が発生しました";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/kk.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ ішінде %@";
"pay_up_front_period" = "%@ үшін %@";
"then_price_per_period" = "содан кейін %@";
"Something went wrong" = "Бірдеңе дұрыс болмады";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/ko.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ 동안 %@";
"pay_up_front_period" = "%@ 에 %@";
"then_price_per_period" = "그런 다음 %@";
"Something went wrong" = "문제가 발생했습니다";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/ms.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ semasa %@";
"pay_up_front_period" = "%@ untuk %@";
"then_price_per_period" = "kemudian %@";
"Something went wrong" = "Ada sesuatu yang tidak kena";
1 change: 1 addition & 0 deletions RevenueCatUI/Resources/nl.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
"pay_as_you_go_period" = "%@ tijdens %@";
"pay_up_front_period" = "%@ voor %@";
"then_price_per_period" = "dan %@";
"Something went wrong" = "Er is iets misgegaan";
Loading