Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,39 @@ import SwiftUI
/// Hosting Controller for the `AnalyticsHubView` view.
///
final class AnalyticsHubHostingViewController: UIHostingController<AnalyticsHubView> {
init(siteID: Int64, timeRange: StatsTimeRangeV4) {

/// Presents an error notice in the tab bar context after this `self` is dismissed.
///
private let systemNoticePresenter: NoticePresenter

/// Defines a notice that should be presented after `self` is dismissed.
/// Defaults to `nil`.
///
var notice: Notice?

init(siteID: Int64, timeRange: StatsTimeRangeV4, systemNoticePresenter: NoticePresenter = ServiceLocator.noticePresenter) {
let viewModel = AnalyticsHubViewModel(siteID: siteID, statsTimeRange: timeRange)
self.systemNoticePresenter = systemNoticePresenter
super.init(rootView: AnalyticsHubView(viewModel: viewModel))

// Needed to pop the hosting controller from within the SwiftUI view
rootView.dismissWithNotice = { [weak self] notice in
self?.notice = notice
self?.navigationController?.popViewController(animated: true)
}
}

@available(*, unavailable)
required dynamic init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

// Show any notice that should be presented after the underlying disappears.
enqueuePendingNotice(notice, using: systemNoticePresenter)
}
}

/// Main Analytics Hub View
Expand All @@ -23,6 +47,11 @@ struct AnalyticsHubView: View {
/// Environment safe areas
@Environment(\.safeAreaInsets) var safeAreaInsets: EdgeInsets

/// Set this closure with UIKit code to pop the view controller and display the provided notice.
/// Needed because we need access to the UIHostingController `popViewController` method.
///
var dismissWithNotice: ((Notice) -> Void) = { _ in }

@StateObject var viewModel: AnalyticsHubViewModel

var body: some View {
Expand Down Expand Up @@ -81,6 +110,10 @@ struct AnalyticsHubView: View {
.task {
await viewModel.updateData()
}
.onReceive(viewModel.$dismissNotice) { notice in
guard let notice else { return }
dismissWithNotice(notice)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ final class AnalyticsHubViewModel: ObservableObject {
///
@Published var timeRangeCard: AnalyticsTimeRangeCardViewModel

/// Defines a notice that, when set, dismisses the view and is then displayed.
/// Defaults to `nil`.
///
@Published var dismissNotice: Notice?

// MARK: Private data

/// Order stats for the current selected time period
Expand All @@ -67,9 +72,13 @@ final class AnalyticsHubViewModel: ObservableObject {

/// Request stats data from network
///
@MainActor
func updateData() async {
do {
try await retrieveOrderStats()
} catch is AnalyticsHubTimeRangeSelection.TimeRangeGeneratorError {
dismissNotice = Notice(title: Localization.timeRangeGeneratorError, feedbackType: .error)
DDLogWarn("⚠️ Error selecting analytics time range: \(timeRangeSelectionType.description)")
} catch {
switchToErrorState()
DDLogWarn("⚠️ Error fetching analytics data: \(error)")
Expand Down Expand Up @@ -308,5 +317,8 @@ private extension AnalyticsHubViewModel {
value)
}
}

static let timeRangeGeneratorError = NSLocalizedString("Sorry, something went wrong. We can't load analytics for the selected date range.",
comment: "Error shown when there is a problem retrieving the dates for the selected date range.")
}
}