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 @@ -126,7 +126,10 @@ private extension AnalyticsHubViewModel {
try await self.retrieveOrderStats(currentTimeRange: currentTimeRange, previousTimeRange: previousTimeRange)
}
group.addTask {
try await self.retrieveVisitorStats(currentTimeRange: currentTimeRange, previousTimeRange: previousTimeRange)
try await self.retrieveItemsSoldStats(currentTimeRange: currentTimeRange, previousTimeRange: previousTimeRange)
}
group.addTask {
try await self.retrieveSiteStats(currentTimeRange: currentTimeRange)
}
try await group.waitForAll()
}
Expand All @@ -147,7 +150,7 @@ private extension AnalyticsHubViewModel {
}

@MainActor
func retrieveVisitorStats(currentTimeRange: AnalyticsHubTimeRange, previousTimeRange: AnalyticsHubTimeRange) async throws {
func retrieveItemsSoldStats(currentTimeRange: AnalyticsHubTimeRange, previousTimeRange: AnalyticsHubTimeRange) async throws {
async let itemsSoldRequest = retrieveTopItemsSoldStats(earliestDateToInclude: currentTimeRange.start,
latestDateToInclude: currentTimeRange.end,
forceRefresh: true)
Expand All @@ -156,6 +159,14 @@ private extension AnalyticsHubViewModel {
self.itemsSoldStats = itemsSoldStats
}

@MainActor
func retrieveSiteStats(currentTimeRange: AnalyticsHubTimeRange) async throws {
async let siteStatsRequest = retrieveSiteSummaryStats(latestDateToInclude: currentTimeRange.end)

let summaryStats = try await siteStatsRequest
self.siteStats = summaryStats
}

@MainActor
func retrieveStats(earliestDateToInclude: Date,
latestDateToInclude: Date,
Expand Down Expand Up @@ -191,6 +202,25 @@ private extension AnalyticsHubViewModel {
stores.dispatch(action)
}
}

@MainActor
/// Retrieves site summary stats using the `retrieveSiteSummaryStats` action.
///
func retrieveSiteSummaryStats(latestDateToInclude: Date) async throws -> SiteSummaryStats? {
guard let period = timeRangeSelectionType.period else {
return nil
}

return try await withCheckedThrowingContinuation { continuation in
let action = StatsActionV4.retrieveSiteSummaryStats(siteID: siteID,
period: period,
quantity: timeRangeSelectionType.quantity,
latestDateToInclude: latestDateToInclude) { result in
continuation.resume(with: result)
}
stores.dispatch(action)
}
}
}

// MARK: Data - UI mapping
Expand All @@ -202,13 +232,15 @@ private extension AnalyticsHubViewModel {
self.ordersCard = ordersCard.redacted
self.productsStatsCard = productsStatsCard.redacted
self.itemsSoldCard = itemsSoldCard.redacted
self.sessionsCard = sessionsCard.redacted
}

@MainActor
func switchToErrorState() {
self.currentOrderStats = nil
self.previousOrderStats = nil
self.itemsSoldStats = nil
self.siteStats = nil
}

func bindViewModelsWithData() {
Expand All @@ -229,8 +261,8 @@ private extension AnalyticsHubViewModel {
self.itemsSoldCard = AnalyticsHubViewModel.productsItemsSoldCard(itemsSoldStats: itemsSoldStats)
}.store(in: &subscriptions)

Publishers.CombineLatest($currentOrderStats, $siteStats)
.sink { [weak self] currentOrderStats, siteStats in
$currentOrderStats.zip($siteStats)
.sink { [weak self] (currentOrderStats, siteStats) in
guard let self else { return }

self.sessionsCard = AnalyticsHubViewModel.sessionsCard(currentPeriodStats: currentOrderStats, siteStats: siteStats)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,38 @@ extension AnalyticsHubTimeRangeSelection {
}
}

/// The period used to request site summary stats from the given SelectedType.
///
/// Returns `nil` if there isn't a `StatGranularity` period that can be used to fetch stats for the given SelectedType.
///
var period: StatGranularity? {
switch self {
case .custom:
return nil
case .today, .yesterday:
return .day
case .weekToDate, .lastWeek:
return .week
case .monthToDate, .lastMonth, .quarterToDate, .lastQuarter:
return .month
case .yearToDate, .lastYear:
return .year
}
}

/// The quantity of periods used to request site summary stats from the given SelectedType.
///
/// Defaults to 1 (a single period) except for ranges not matching a `StatGranularity` period.
///
var quantity: Int {
switch self {
case .quarterToDate, .lastQuarter:
return 3 // Stats summary calculated from 3 months of data
default:
return 1
}
}

init(_ statsTimeRange: StatsTimeRangeV4) {
switch statsTimeRange {
case .today:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ final class AnalyticsHubViewModelTests: XCTestCase {
case let .retrieveTopEarnerStats(_, _, _, _, _, _, _, completion):
let topEarners = TopEarnerStats.fake().copy(items: [.fake()])
completion(.success(topEarners))
case let .retrieveSiteSummaryStats(_, _, _, _, completion):
let siteStats = SiteSummaryStats.fake().copy(visitors: 30, views: 53)
completion(.success(siteStats))
default:
break
}
Expand All @@ -39,12 +42,14 @@ final class AnalyticsHubViewModelTests: XCTestCase {
XCTAssertFalse(vm.ordersCard.isRedacted)
XCTAssertFalse(vm.productsStatsCard.isRedacted)
XCTAssertFalse(vm.itemsSoldCard.isRedacted)
XCTAssertFalse(vm.sessionsCard.isRedacted)

XCTAssertEqual(vm.revenueCard.leadingValue, "$62")
XCTAssertEqual(vm.ordersCard.leadingValue, "15")
XCTAssertEqual(vm.productsStatsCard.itemsSold, "5")

XCTAssertEqual(vm.itemsSoldCard.itemsSoldData.count, 1)
XCTAssertEqual(vm.sessionsCard.leadingValue, "53")
XCTAssertEqual(vm.sessionsCard.trailingValue, "50%")
}

func test_cards_viewmodels_show_sync_error_after_getting_error_from_network() async {
Expand All @@ -56,6 +61,8 @@ final class AnalyticsHubViewModelTests: XCTestCase {
completion(.failure(NSError(domain: "Test", code: 1)))
case let .retrieveTopEarnerStats(_, _, _, _, _, _, _, completion):
completion(.failure(NSError(domain: "Test", code: 1)))
case let .retrieveSiteSummaryStats(_, _, _, _, completion):
completion(.failure(NSError(domain: "Test", code: 1)))
default:
break
}
Expand All @@ -69,6 +76,7 @@ final class AnalyticsHubViewModelTests: XCTestCase {
XCTAssertTrue(vm.ordersCard.showSyncError)
XCTAssertTrue(vm.productsStatsCard.showStatsError)
XCTAssertTrue(vm.itemsSoldCard.showItemsSoldError)
XCTAssertTrue(vm.sessionsCard.showSyncError)
}

func test_cards_viewmodels_redacted_while_updating_from_network() async {
Expand All @@ -78,6 +86,7 @@ final class AnalyticsHubViewModelTests: XCTestCase {
var loadingOrdersCard: AnalyticsReportCardViewModel?
var loadingProductsCard: AnalyticsProductsStatsCardViewModel?
var loadingItemsSoldCard: AnalyticsItemsSoldViewModel?
var loadingSessionsCard: AnalyticsReportCardCurrentPeriodViewModel?
stores.whenReceivingAction(ofType: StatsActionV4.self) { action in
switch action {
case let .retrieveCustomStats(_, _, _, _, _, _, completion):
Expand All @@ -90,6 +99,10 @@ final class AnalyticsHubViewModelTests: XCTestCase {
case let .retrieveTopEarnerStats(_, _, _, _, _, _, _, completion):
let topEarners = TopEarnerStats.fake().copy(items: [.fake()])
completion(.success(topEarners))
case let .retrieveSiteSummaryStats(_, _, _, _, completion):
let siteStats = SiteSummaryStats.fake()
loadingSessionsCard = vm.sessionsCard
completion(.success(siteStats))
default:
break
}
Expand All @@ -103,5 +116,6 @@ final class AnalyticsHubViewModelTests: XCTestCase {
XCTAssertEqual(loadingOrdersCard?.isRedacted, true)
XCTAssertEqual(loadingProductsCard?.isRedacted, true)
XCTAssertEqual(loadingItemsSoldCard?.isRedacted, true)
XCTAssertEqual(loadingSessionsCard?.isRedacted, true)
}
}