Files
purchases-ios/RevenueCatUI/CustomerCenter/Views/ManageSubscriptionsView.swift
T

221 lines
9.0 KiB
Swift

//
// 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
//
// ManageSubscriptionsView.swift
//
//
// Created by Andrés Boedo on 5/3/24.
//
import RevenueCat
import SwiftUI
#if os(iOS)
@available(iOS 15.0, *)
@available(macOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
struct ManageSubscriptionsView: View {
@Environment(\.appearance)
private var appearance: CustomerCenterConfigData.Appearance
@Environment(\.colorScheme)
private var colorScheme
@Environment(\.supportInformation)
private var support
@Environment(\.localization)
private var localization: CustomerCenterConfigData.Localization
@Environment(\.navigationOptions)
var navigationOptions
@StateObject
private var viewModel: ManageSubscriptionsViewModel
private let customerCenterActionHandler: CustomerCenterActionHandler?
init(screen: CustomerCenterConfigData.Screen,
purchaseInformation: PurchaseInformation?,
customerCenterActionHandler: CustomerCenterActionHandler?) {
let viewModel = ManageSubscriptionsViewModel(
screen: screen,
customerCenterActionHandler: customerCenterActionHandler,
purchaseInformation: purchaseInformation)
self.init(viewModel: viewModel, customerCenterActionHandler: customerCenterActionHandler)
}
fileprivate init(viewModel: ManageSubscriptionsViewModel,
customerCenterActionHandler: CustomerCenterActionHandler?) {
self._viewModel = .init(wrappedValue: viewModel)
self.customerCenterActionHandler = customerCenterActionHandler
}
var body: some View {
content
.compatibleNavigation(
item: $viewModel.feedbackSurveyData,
usesNavigationStack: navigationOptions.usesNavigationStack
) { feedbackSurveyData in
FeedbackSurveyView(
feedbackSurveyData: feedbackSurveyData,
customerCenterActionHandler: self.customerCenterActionHandler,
isPresented: .isNotNil(self.$viewModel.feedbackSurveyData))
.environment(\.appearance, appearance)
.environment(\.localization, localization)
.environment(\.navigationOptions, navigationOptions)
}
.compatibleNavigation(
isPresented: $viewModel.showPurchases,
usesNavigationStack: navigationOptions.usesNavigationStack
) {
PurchaseHistoryView(viewModel: PurchaseHistoryViewModel())
.environment(\.appearance, appearance)
.environment(\.localization, localization)
.environment(\.navigationOptions, navigationOptions)
}
.sheet(item: self.$viewModel.promotionalOfferData) { promotionalOfferData in
PromotionalOfferView(
promotionalOffer: promotionalOfferData.promotionalOffer,
product: promotionalOfferData.product,
promoOfferDetails: promotionalOfferData.promoOfferDetails,
onDismissPromotionalOfferView: { userAction in
Task(priority: .userInitiated) {
await self.viewModel.handleDismissPromotionalOfferView(userAction)
}
}
)
.environment(\.appearance, appearance)
.environment(\.localization, localization)
.interactiveDismissDisabled()
}
.sheet(item: self.$viewModel.inAppBrowserURL,
onDismiss: {
self.viewModel.onDismissInAppBrowser()
}, content: { inAppBrowserURL in
SafariView(url: inAppBrowserURL.url)
})
}
@ViewBuilder
var content: some View {
List {
if let purchaseInformation = self.viewModel.purchaseInformation {
SubscriptionDetailsView(
purchaseInformation: purchaseInformation,
refundRequestStatus: self.viewModel.refundRequestStatus
)
if support?.displayPurchaseHistoryLink == true {
Button {
viewModel.showPurchases = true
} label: {
Text(localization[.seeAllPurchases])
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.contentShape(Rectangle())
}
}
Section {
ManageSubscriptionsButtonsView(
viewModel: self.viewModel
)
} header: {
if let subtitle = self.viewModel.screen.subtitle {
Text(subtitle)
.textCase(nil)
}
}
} else {
let fallbackDescription = localization[.tryCheckRestore]
Section {
CompatibilityContentUnavailableView(
self.viewModel.screen.title,
systemImage: "exclamationmark.triangle.fill",
description: Text(self.viewModel.screen.subtitle ?? fallbackDescription)
)
}
Section {
ManageSubscriptionsButtonsView(viewModel: self.viewModel)
}
}
}
.dismissCircleButtonToolbarIfNeeded()
.restorePurchasesAlert(isPresented: self.$viewModel.showRestoreAlert)
.applyIf(self.viewModel.screen.type == .management, apply: {
$0.navigationTitle(self.viewModel.screen.title)
.navigationBarTitleDisplayMode(.inline)
})
}
}
#if DEBUG
@available(iOS 15.0, *)
@available(macOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
struct ManageSubscriptionsView_Previews: PreviewProvider {
// swiftlint:disable force_unwrapping
static var previews: some View {
ForEach(ColorScheme.allCases, id: \.self) { colorScheme in
CompatibilityNavigationStack {
let viewModelMonthlyRenewing = ManageSubscriptionsViewModel(
screen: CustomerCenterConfigTestData.customerCenterData.screens[.management]!,
customerCenterActionHandler: nil,
purchaseInformation: CustomerCenterConfigTestData.subscriptionInformationMonthlyRenewing,
refundRequestStatus: .success)
ManageSubscriptionsView(viewModel: viewModelMonthlyRenewing,
customerCenterActionHandler: nil)
.environment(\.localization, CustomerCenterConfigTestData.customerCenterData.localization)
.environment(\.appearance, CustomerCenterConfigTestData.customerCenterData.appearance)
}
.preferredColorScheme(colorScheme)
.previewDisplayName("Monthly renewing - \(colorScheme)")
CompatibilityNavigationStack {
let viewModelYearlyExpiring = ManageSubscriptionsViewModel(
screen: CustomerCenterConfigTestData.customerCenterData.screens[.management]!,
customerCenterActionHandler: nil,
purchaseInformation: CustomerCenterConfigTestData.subscriptionInformationYearlyExpiring)
ManageSubscriptionsView(viewModel: viewModelYearlyExpiring,
customerCenterActionHandler: nil)
.environment(\.localization, CustomerCenterConfigTestData.customerCenterData.localization)
.environment(\.appearance, CustomerCenterConfigTestData.customerCenterData.appearance)
}
.preferredColorScheme(colorScheme)
.previewDisplayName("Yearly expiring - \(colorScheme)")
CompatibilityNavigationStack {
let viewModelYearlyExpiring = ManageSubscriptionsViewModel(
screen: CustomerCenterConfigTestData.customerCenterData.screens[.management]!,
customerCenterActionHandler: nil,
purchaseInformation: CustomerCenterConfigTestData.subscriptionInformationFree)
ManageSubscriptionsView(viewModel: viewModelYearlyExpiring,
customerCenterActionHandler: nil)
.environment(\.localization, CustomerCenterConfigTestData.customerCenterData.localization)
.environment(\.appearance, CustomerCenterConfigTestData.customerCenterData.appearance)
}
.preferredColorScheme(colorScheme)
.previewDisplayName("Free subscription - \(colorScheme)")
}
}
}
#endif
#endif