diff --git a/RevenueCatUI/CustomerCenter/Data/CustomerCenterConfigTestData.swift b/RevenueCatUI/CustomerCenter/Data/CustomerCenterConfigTestData.swift index c41497862f..474a52c430 100644 --- a/RevenueCatUI/CustomerCenter/Data/CustomerCenterConfigTestData.swift +++ b/RevenueCatUI/CustomerCenter/Data/CustomerCenterConfigTestData.swift @@ -20,7 +20,10 @@ enum CustomerCenterConfigTestData { @available(iOS 14.0, *) // swiftlint:disable:next function_body_length - static func customerCenterData(lastPublishedAppVersion: String?) -> CustomerCenterConfigData { + static func customerCenterData( + lastPublishedAppVersion: String?, + shouldWarnCustomerToUpdate: Bool = false + ) -> CustomerCenterConfigData { CustomerCenterConfigData( screens: [.management: .init( @@ -111,7 +114,10 @@ enum CustomerCenterConfigTestData { "back": "Back" ] ), - support: .init(email: "test-support@revenuecat.com"), + support: .init( + email: "test-support@revenuecat.com", + shouldWarnCustomerToUpdate: shouldWarnCustomerToUpdate + ), lastPublishedAppVersion: lastPublishedAppVersion, productId: 1 ) diff --git a/RevenueCatUI/CustomerCenter/ViewModels/CustomerCenterViewModel.swift b/RevenueCatUI/CustomerCenter/ViewModels/CustomerCenterViewModel.swift index 461568874f..391be935ff 100644 --- a/RevenueCatUI/CustomerCenter/ViewModels/CustomerCenterViewModel.swift +++ b/RevenueCatUI/CustomerCenter/ViewModels/CustomerCenterViewModel.swift @@ -38,6 +38,16 @@ import RevenueCat private(set) var appIsLatestVersion: Bool = defaultAppIsLatestVersion private(set) var purchasesProvider: CustomerCenterPurchasesType + var shouldShowAppUpdateWarning: Bool { + return !appIsLatestVersion && (configuration?.support.shouldWarnCustomerToUpdate ?? false) + } + + /// Whether or not the user needs to update their app version to contact support. + var appUpdateRequiredToContactSupport: Bool { + // We're intentionally using the same flag as the app update warning. + return self.shouldShowAppUpdateWarning + } + // @PublicForExternalTesting @Published var state: CustomerCenterViewState { diff --git a/RevenueCatUI/CustomerCenter/Views/CustomerCenterView.swift b/RevenueCatUI/CustomerCenter/Views/CustomerCenterView.swift index f1c6f7c9a2..81d591a874 100644 --- a/RevenueCatUI/CustomerCenter/Views/CustomerCenterView.swift +++ b/RevenueCatUI/CustomerCenter/Views/CustomerCenterView.swift @@ -104,7 +104,8 @@ private extension CustomerCenterView { if viewModel.hasActiveProducts { if viewModel.hasAppleEntitlement, let screen = configuration.screens[.management] { - if let productId = configuration.productId, !ignoreAppUpdateWarning && !viewModel.appIsLatestVersion { + if let productId = configuration.productId, + !ignoreAppUpdateWarning && viewModel.shouldShowAppUpdateWarning { AppUpdateWarningView( productId: productId, onContinueAnywayClick: { diff --git a/RevenueCatUI/CustomerCenter/Views/RestorePurchasesAlert.swift b/RevenueCatUI/CustomerCenter/Views/RestorePurchasesAlert.swift index f88ef75bf0..de53cb9abd 100644 --- a/RevenueCatUI/CustomerCenter/Views/RestorePurchasesAlert.swift +++ b/RevenueCatUI/CustomerCenter/Views/RestorePurchasesAlert.swift @@ -83,7 +83,7 @@ struct RestorePurchasesAlert: ViewModifier { case .purchasesNotFound: let message = Text(localization.commonLocalizedString(for: .purchasesNotRecovered)) - if let url = supportURL { + if let url = supportURL, !customerCenterViewModel.appUpdateRequiredToContactSupport { return Alert(title: Text(""), message: message, primaryButton: .default( diff --git a/RevenueCatUI/CustomerCenter/Views/WrongPlatformView.swift b/RevenueCatUI/CustomerCenter/Views/WrongPlatformView.swift index 72842cd56a..d531871607 100644 --- a/RevenueCatUI/CustomerCenter/Views/WrongPlatformView.swift +++ b/RevenueCatUI/CustomerCenter/Views/WrongPlatformView.swift @@ -32,6 +32,9 @@ struct WrongPlatformView: View { @State private var subscriptionInformation: PurchaseInformation? + @EnvironmentObject + private var customerCenterViewModel: CustomerCenterViewModel + @Environment(\.localization) private var localization: CustomerCenterConfigData.Localization @Environment(\.appearance) @@ -80,7 +83,7 @@ struct WrongPlatformView: View { } } } - if let url = supportURL { + if let url = supportURL, !customerCenterViewModel.appUpdateRequiredToContactSupport { Section { AsyncButton { openURL(url) diff --git a/Sources/CustomerCenter/CustomerCenterConfigData.swift b/Sources/CustomerCenter/CustomerCenterConfigData.swift index 70193af705..34ed10d55e 100644 --- a/Sources/CustomerCenter/CustomerCenterConfigData.swift +++ b/Sources/CustomerCenter/CustomerCenterConfigData.swift @@ -412,9 +412,14 @@ public struct CustomerCenterConfigData { public struct Support { public let email: String + public let shouldWarnCustomerToUpdate: Bool - public init(email: String) { + public init( + email: String, + shouldWarnCustomerToUpdate: Bool + ) { self.email = email + self.shouldWarnCustomerToUpdate = shouldWarnCustomerToUpdate } } @@ -550,6 +555,7 @@ extension CustomerCenterConfigData.Support { init(from response: CustomerCenterConfigResponse.Support) { self.email = response.email + self.shouldWarnCustomerToUpdate = response.shouldWarnCustomerToUpdate ?? false } } diff --git a/Sources/Networking/Responses/CustomerCenterConfigResponse.swift b/Sources/Networking/Responses/CustomerCenterConfigResponse.swift index 2748d169b9..6984bae308 100644 --- a/Sources/Networking/Responses/CustomerCenterConfigResponse.swift +++ b/Sources/Networking/Responses/CustomerCenterConfigResponse.swift @@ -132,6 +132,7 @@ struct CustomerCenterConfigResponse { struct Support { let email: String + let shouldWarnCustomerToUpdate: Bool? } diff --git a/Tests/RevenueCatUITests/CustomerCenter/ContactSupportUtilitiesTests.swift b/Tests/RevenueCatUITests/CustomerCenter/ContactSupportUtilitiesTests.swift index 44f8bff4cd..21e993a56a 100644 --- a/Tests/RevenueCatUITests/CustomerCenter/ContactSupportUtilitiesTests.swift +++ b/Tests/RevenueCatUITests/CustomerCenter/ContactSupportUtilitiesTests.swift @@ -18,7 +18,10 @@ import XCTest class ContactSupportUtilitiesTest: TestCase { - private let support: CustomerCenterConfigData.Support = .init(email: "support@example.com") + private let support: CustomerCenterConfigData.Support = .init( + email: "support@example.com", + shouldWarnCustomerToUpdate: false + ) private let localization: CustomerCenterConfigData.Localization = .init(locale: "en_US", localizedStrings: [:]) func testSupportEmailBodyWithDefaultDataIsCorrect() { diff --git a/Tests/RevenueCatUITests/CustomerCenter/CustomerCenterViewModelTests.swift b/Tests/RevenueCatUITests/CustomerCenter/CustomerCenterViewModelTests.swift index 997740bfa6..2d5b6893e2 100644 --- a/Tests/RevenueCatUITests/CustomerCenter/CustomerCenterViewModelTests.swift +++ b/Tests/RevenueCatUITests/CustomerCenter/CustomerCenterViewModelTests.swift @@ -20,6 +20,7 @@ import XCTest #if os(iOS) +// swiftlint:disable file_length @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) @available(macOS, unavailable) @available(tvOS, unavailable) @@ -218,6 +219,55 @@ class CustomerCenterViewModelTests: TestCase { } } + func testAppUpdateRequiredToContactSupportTrue() { + let mockPurchases = MockCustomerCenterPurchases() + let latestVersion = "3.0.0" + let currentVersion = "2.0.0" + let viewModel = CustomerCenterViewModel( + customerCenterActionHandler: nil, + currentVersionFetcher: { return currentVersion }, + purchasesProvider: mockPurchases + ) + viewModel.configuration = CustomerCenterConfigTestData.customerCenterData( + lastPublishedAppVersion: latestVersion, + shouldWarnCustomerToUpdate: true + ) + + expect(viewModel.appUpdateRequiredToContactSupport).to(beTrue()) + } + + func testAppUpdateRequiredToContactSupportFalse() { + let mockPurchases = MockCustomerCenterPurchases() + let latestVersion = "3.0.0" + let viewModel = CustomerCenterViewModel( + customerCenterActionHandler: nil, + currentVersionFetcher: { return latestVersion }, + purchasesProvider: mockPurchases + ) + viewModel.configuration = CustomerCenterConfigTestData.customerCenterData( + lastPublishedAppVersion: latestVersion, + shouldWarnCustomerToUpdate: true + ) + + expect(viewModel.appUpdateRequiredToContactSupport).to(beFalse()) + } + + func testAppUpdateRequiredToContactSupportReturnsFalseIfBlockedByConfig() { + let mockPurchases = MockCustomerCenterPurchases() + let latestVersion = "3.0.0" + let viewModel = CustomerCenterViewModel( + customerCenterActionHandler: nil, + currentVersionFetcher: { return latestVersion }, + purchasesProvider: mockPurchases + ) + viewModel.configuration = CustomerCenterConfigTestData.customerCenterData( + lastPublishedAppVersion: latestVersion, + shouldWarnCustomerToUpdate: true + ) + + expect(viewModel.appUpdateRequiredToContactSupport).to(beFalse()) + } + } @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) diff --git a/Tests/UnitTests/CustomerCenter/CustomerCenterConfigDataTests.swift b/Tests/UnitTests/CustomerCenter/CustomerCenterConfigDataTests.swift index 869eb5d90b..3e5863d1e1 100644 --- a/Tests/UnitTests/CustomerCenter/CustomerCenterConfigDataTests.swift +++ b/Tests/UnitTests/CustomerCenter/CustomerCenterConfigDataTests.swift @@ -106,7 +106,10 @@ class CustomerCenterConfigDataTests: TestCase { ) ], localization: .init(locale: "en_US", localizedStrings: ["key": "value"]), - support: .init(email: "support@example.com") + support: .init( + email: "support@example.com", + shouldWarnCustomerToUpdate: false + ) ), lastPublishedAppVersion: "1.2.3", itunesTrackId: 123 @@ -178,6 +181,8 @@ class CustomerCenterConfigDataTests: TestCase { expect(configData.lastPublishedAppVersion) == "1.2.3" expect(configData.productId) == 123 + + expect(configData.support.shouldWarnCustomerToUpdate) == false } func testUnknownValuesHandling() throws {