From 5c0f3f43af6aad507167e9375799b8c6ace33dff Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 14 Jun 2024 16:41:55 +0200 Subject: [PATCH] build feedback survey upon JSON --- .../Data/FeedbackSurveyData.swift | 37 ++++++++++ .../ManageSubscriptionsViewModel.swift | 15 +++- .../Views/FeedbackSurveyView.swift | 71 ++++++++++++++++++ .../Views/ManageSubscriptionsView.swift | 74 +++++++++++++------ .../Resources/en.lproj/Localizable.strings | 2 + 5 files changed, 177 insertions(+), 22 deletions(-) create mode 100644 RevenueCatUI/CustomerCenter/Data/FeedbackSurveyData.swift create mode 100644 RevenueCatUI/CustomerCenter/Views/FeedbackSurveyView.swift diff --git a/RevenueCatUI/CustomerCenter/Data/FeedbackSurveyData.swift b/RevenueCatUI/CustomerCenter/Data/FeedbackSurveyData.swift new file mode 100644 index 0000000000..f30deb8235 --- /dev/null +++ b/RevenueCatUI/CustomerCenter/Data/FeedbackSurveyData.swift @@ -0,0 +1,37 @@ +// +// 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 +// +// FeedbackSurveyData.swift +// +// +// Created by Cesar de la Vega on 14/6/24. +// + +import Foundation +import RevenueCat + +#if !os(macOS) && !os(tvOS) && !os(watchOS) && !os(visionOS) + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +@available(macOS, unavailable) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +class FeedbackSurveyData: ObservableObject { + + var configuration: CustomerCenterConfigData.HelpPath.FeedbackSurvey + var action: (() -> Void) + + init(configuration: CustomerCenterConfigData.HelpPath.FeedbackSurvey, action: @escaping (() -> Void)) { + self.configuration = configuration + self.action = action + } + +} + +#endif diff --git a/RevenueCatUI/CustomerCenter/ViewModels/ManageSubscriptionsViewModel.swift b/RevenueCatUI/CustomerCenter/ViewModels/ManageSubscriptionsViewModel.swift index e12be8928f..49da289b9f 100644 --- a/RevenueCatUI/CustomerCenter/ViewModels/ManageSubscriptionsViewModel.swift +++ b/RevenueCatUI/CustomerCenter/ViewModels/ManageSubscriptionsViewModel.swift @@ -33,6 +33,9 @@ class ManageSubscriptionsViewModel: ObservableObject { private(set) var configuration: CustomerCenterConfigData? @Published var showRestoreAlert: Bool = false + @Published + var feedbackSurveyData: FeedbackSurveyData? + @Published var state: CustomerCenterViewState { didSet { @@ -113,7 +116,17 @@ class ManageSubscriptionsViewModel: ObservableObject { } #if os(iOS) || targetEnvironment(macCatalyst) - func handleAction(for path: CustomerCenterConfigData.HelpPath) async { + func determineFlow(for path: CustomerCenterConfigData.HelpPath) { + if case let .feedbackSurvey(feedbackSurvey) = path.detail { + self.feedbackSurveyData = FeedbackSurveyData(configuration: feedbackSurvey) { [weak self] in + self?.performAction(for: path) + } + } else { + performAction(for: path) + } + } + + func performAction(for path: CustomerCenterConfigData.HelpPath) async { switch path.type { case .missingPurchase: self.showRestoreAlert = true diff --git a/RevenueCatUI/CustomerCenter/Views/FeedbackSurveyView.swift b/RevenueCatUI/CustomerCenter/Views/FeedbackSurveyView.swift new file mode 100644 index 0000000000..a5aa9b8fab --- /dev/null +++ b/RevenueCatUI/CustomerCenter/Views/FeedbackSurveyView.swift @@ -0,0 +1,71 @@ +// +// 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 +// +// FeedbackSurveyView.swift +// +// +// Created by Cesar de la Vega on 12/6/24. +// + +import RevenueCat +import SwiftUI + +#if !os(macOS) && !os(tvOS) && !os(watchOS) && !os(visionOS) + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +@available(macOS, unavailable) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +@available(visionOS, unavailable) +struct FeedbackSurveyView: View { + + @ObservedObject + var feedbackSurveyData: FeedbackSurveyData + + var body: some View { + VStack { + Text("Why are you cancelling?") + .font(.title) + .padding() + + Spacer() + + FeedbackSurveyButtonsView(options: feedbackSurveyData.configuration.options, + action: feedbackSurveyData.action) + } + } + +} + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +@available(macOS, unavailable) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +@available(visionOS, unavailable) +struct FeedbackSurveyButtonsView: View { + + let options: [CustomerCenterConfigData.HelpPath.FeedbackSurvey.Option] + let action: (() -> Void) + + var body: some View { + VStack(spacing: 16) { + ForEach(options, id: \.id) { option in + Button(option.title) { + Task { + self.action() + } + } + .buttonStyle(ManageSubscriptionsButtonStyle()) + } + } + } + +} + +#endif diff --git a/RevenueCatUI/CustomerCenter/Views/ManageSubscriptionsView.swift b/RevenueCatUI/CustomerCenter/Views/ManageSubscriptionsView.swift index 08869af465..79ea0a4002 100644 --- a/RevenueCatUI/CustomerCenter/Views/ManageSubscriptionsView.swift +++ b/RevenueCatUI/CustomerCenter/Views/ManageSubscriptionsView.swift @@ -38,28 +38,43 @@ struct ManageSubscriptionsView: View { } var body: some View { - VStack { - if viewModel.isLoaded { - HeaderView(viewModel: viewModel) - - if let subscriptionInformation = self.viewModel.subscriptionInformation { - SubscriptionDetailsView(subscriptionInformation: subscriptionInformation, - refundRequestStatusMessage: viewModel.refundRequestStatusMessage) + NavigationView { + VStack { + if viewModel.isLoaded { + HeaderView(viewModel: viewModel) + + if let subscriptionInformation = self.viewModel.subscriptionInformation { + SubscriptionDetailsView(subscriptionInformation: subscriptionInformation, + refundRequestStatusMessage: viewModel.refundRequestStatusMessage) + } + + Spacer() + + ManageSubscriptionsButtonsView(viewModel: viewModel) + + } else { + ProgressView() + .progressViewStyle(CircularProgressViewStyle()) } - Spacer() - - ManageSubscriptionsButtonsView(viewModel: viewModel) - } else { - ProgressView() - .progressViewStyle(CircularProgressViewStyle()) + if let feedbackSurveyData = viewModel.feedbackSurveyData { + NavigationLink( + destination: FeedbackSurveyView(feedbackSurveyData: feedbackSurveyData) + .onDisappear { + viewModel.feedbackSurveyData = nil + }, + isActive: .constant(true) + ) { + EmptyView() + } + } } - } - .task { - await loadInformationIfNeeded() + .task { + await loadInformationIfNeeded() + } + .navigationBarTitleDisplayMode(.inline) } } - } @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) @@ -88,10 +103,27 @@ struct HeaderView: View { private(set) var viewModel: ManageSubscriptionsViewModel var body: some View { + Text(headerTitle) + .font(.title) + .padding() + } + +} + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +@available(macOS, unavailable) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +@available(visionOS, unavailable) +private extension HeaderView { + + private var headerTitle: String { if let configuration = viewModel.configuration { - Text(configuration.title) - .font(.title) - .padding() + return configuration.title + } else if viewModel.subscriptionInformation != nil { + return "Your subscription details" + } else { + return "Something went wrong" } } @@ -158,7 +190,7 @@ struct ManageSubscriptionsButtonsView: View { } ForEach(filteredPaths, id: \.id) { path in AsyncButton(action: { - await self.viewModel.handleAction(for: path) + self.viewModel.determineFlow(for: path) }, label: { Text(path.title) }) diff --git a/RevenueCatUI/Resources/en.lproj/Localizable.strings b/RevenueCatUI/Resources/en.lproj/Localizable.strings index d22c380a7c..4e8aeec047 100644 --- a/RevenueCatUI/Resources/en.lproj/Localizable.strings +++ b/RevenueCatUI/Resources/en.lproj/Localizable.strings @@ -28,3 +28,5 @@ "We applied the previously purchased items to your account. Sorry for the inconvenience." = "We applied the previously purchased items to your account. Sorry for the inconvenience." "Dismiss" = "Dismiss" "We couldn’t find any additional purchases under this account. \n\nContact support for assistance if you think this is an error." = "We couldn’t find any additional purchases under this account. \n\nContact support for assistance if you think this is an error." +"Your subscription details" = "Your subscription details" +"Something went wrong" = "Something went wrong"