diff --git a/ios/brave-ios/Sources/AIChat/AIChatStrings.swift b/ios/brave-ios/Sources/AIChat/AIChatStrings.swift index 4b6293c312c2..93ae92a82c84 100644 --- a/ios/brave-ios/Sources/AIChat/AIChatStrings.swift +++ b/ios/brave-ios/Sources/AIChat/AIChatStrings.swift @@ -357,7 +357,7 @@ extension Strings { "aichat.paywallYearlySubscriptionDescription", tableName: "BraveLeo", bundle: .module, - value: "SAVE UP TO 25%", + value: "BEST VALUE", comment: "The description indicating yearly subscription that show how much user is saving percentage" ) @@ -397,6 +397,13 @@ extension Strings { value: "Upgrade Now", comment: "The title of the button for action triggering purchase" ) + public static let paywallPurchaseActionIntroOfferTitle = NSLocalizedString( + "aichat.paywallPurchaseActionIntroOfferTitle", + tableName: "BraveLeo", + bundle: .module, + value: "Try 7 Days Free", + comment: "The title of the button for action triggering purchase" + ) public static let paywallPremiumUpsellTitle = NSLocalizedString( "aichat.paywallPremiumUpsellTitle", tableName: "BraveLeo", diff --git a/ios/brave-ios/Sources/AIChat/Components/Paywall/AIChatPaywallView.swift b/ios/brave-ios/Sources/AIChat/Components/Paywall/AIChatPaywallView.swift index 5c79bc4bb53b..7beee3bdd8e1 100644 --- a/ios/brave-ios/Sources/AIChat/Components/Paywall/AIChatPaywallView.swift +++ b/ios/brave-ios/Sources/AIChat/Components/Paywall/AIChatPaywallView.swift @@ -32,7 +32,7 @@ struct AIChatPaywallView: View { private var selectedTierType: AIChatSubscriptionTier = .monthly @State - private var availableTierTypes: [AIChatSubscriptionTier] = [.monthly] + private var availableTierTypes: [AIChatSubscriptionTier] = [.monthly, .yearly] @ObservedObject private(set) var storeSDK = BraveStoreSDK.shared @@ -40,6 +40,12 @@ struct AIChatPaywallView: View { @State private var paymentStatus: AIChatPaymentStatus = .success + @State + private var isMonthlyIntroOfferAvailable: Bool = false + + @State + private var isYearlyIntroOfferAvailable: Bool = false + @State private var isShowingPurchaseAlert = false @@ -151,6 +157,9 @@ struct AIChatPaywallView: View { .onDisappear { iapRestoreTimer?.cancel() } + .task { + await fetchIntroOfferStatus() + } } private var tierSelection: some View { @@ -203,10 +212,19 @@ struct AIChatPaywallView: View { .tint(Color.white) .padding() } else { - Text(Strings.AIChat.paywallPurchaseActionTitle) - .font(.body.weight(.semibold)) - .foregroundColor(Color(.white)) - .padding() + if (selectedTierType == .monthly && isMonthlyIntroOfferAvailable) + || (selectedTierType == .yearly && isYearlyIntroOfferAvailable) + { + Text(Strings.AIChat.paywallPurchaseActionIntroOfferTitle) + .font(.body.weight(.semibold)) + .foregroundColor(Color(.white)) + .padding() + } else { + Text(Strings.AIChat.paywallPurchaseActionTitle) + .font(.body.weight(.semibold)) + .foregroundColor(Color(.white)) + .padding() + } } } .frame(maxWidth: .infinity) @@ -282,6 +300,20 @@ struct AIChatPaywallView: View { isShowingPurchaseAlert = true } } + + private func fetchIntroOfferStatus() async { + paymentStatus = .ongoing + + isMonthlyIntroOfferAvailable = await storeSDK.isIntroOfferAvailable( + for: BraveStoreProduct.leoMonthly + ) + + isYearlyIntroOfferAvailable = await storeSDK.isIntroOfferAvailable( + for: BraveStoreProduct.leoYearly + ) + + paymentStatus = .success + } } private struct AIChatPremiumTierSelectionView: View { diff --git a/ios/brave-ios/Sources/BraveStore/Subscription/SDK/AppStoreSDK.swift b/ios/brave-ios/Sources/BraveStore/Subscription/SDK/AppStoreSDK.swift index b69f5893225c..7fa54d4f10cf 100644 --- a/ios/brave-ios/Sources/BraveStore/Subscription/SDK/AppStoreSDK.swift +++ b/ios/brave-ios/Sources/BraveStore/Subscription/SDK/AppStoreSDK.swift @@ -339,6 +339,22 @@ public class AppStoreSDK: ObservableObject { (try? await subscription(for: product)?.subscription?.status) ?? [] } + /// Retrieves a product's renewable subscription trial status + /// - Parameter product: The product whose subscription trial status to retrieve + /// - Returns: The renewable subscription's trial status + @MainActor + public func isIntroOfferAvailable(for product: any AppStoreProduct) async -> Bool { + guard let subscription = await subscription(for: product)?.subscription else { + return false + } + + if subscription.introductoryOffer == nil { + return false + } + + return await subscription.isEligibleForIntroOffer == true + } + /// Retrieves a product's renewable subscription renewal information /// - Parameter product: The product whose renewal to retrieve /// - Returns: The renewable subscription's renewal information