Skip to content

Commit e84dcb0

Browse files
authored
Merge pull request #8412 from woocommerce/issue/8353-fetch-summary-stats-ui
[Analytics Hub] Fetch site stats for sessions card
2 parents c2bb7fe + b712073 commit e84dcb0

File tree

3 files changed

+83
-5
lines changed

3 files changed

+83
-5
lines changed

WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubViewModel.swift

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ private extension AnalyticsHubViewModel {
126126
try await self.retrieveOrderStats(currentTimeRange: currentTimeRange, previousTimeRange: previousTimeRange)
127127
}
128128
group.addTask {
129-
try await self.retrieveVisitorStats(currentTimeRange: currentTimeRange, previousTimeRange: previousTimeRange)
129+
try await self.retrieveItemsSoldStats(currentTimeRange: currentTimeRange, previousTimeRange: previousTimeRange)
130+
}
131+
group.addTask {
132+
try await self.retrieveSiteStats(currentTimeRange: currentTimeRange)
130133
}
131134
try await group.waitForAll()
132135
}
@@ -147,7 +150,7 @@ private extension AnalyticsHubViewModel {
147150
}
148151

149152
@MainActor
150-
func retrieveVisitorStats(currentTimeRange: AnalyticsHubTimeRange, previousTimeRange: AnalyticsHubTimeRange) async throws {
153+
func retrieveItemsSoldStats(currentTimeRange: AnalyticsHubTimeRange, previousTimeRange: AnalyticsHubTimeRange) async throws {
151154
async let itemsSoldRequest = retrieveTopItemsSoldStats(earliestDateToInclude: currentTimeRange.start,
152155
latestDateToInclude: currentTimeRange.end,
153156
forceRefresh: true)
@@ -156,6 +159,14 @@ private extension AnalyticsHubViewModel {
156159
self.itemsSoldStats = itemsSoldStats
157160
}
158161

162+
@MainActor
163+
func retrieveSiteStats(currentTimeRange: AnalyticsHubTimeRange) async throws {
164+
async let siteStatsRequest = retrieveSiteSummaryStats(latestDateToInclude: currentTimeRange.end)
165+
166+
let summaryStats = try await siteStatsRequest
167+
self.siteStats = summaryStats
168+
}
169+
159170
@MainActor
160171
func retrieveStats(earliestDateToInclude: Date,
161172
latestDateToInclude: Date,
@@ -191,6 +202,25 @@ private extension AnalyticsHubViewModel {
191202
stores.dispatch(action)
192203
}
193204
}
205+
206+
@MainActor
207+
/// Retrieves site summary stats using the `retrieveSiteSummaryStats` action.
208+
///
209+
func retrieveSiteSummaryStats(latestDateToInclude: Date) async throws -> SiteSummaryStats? {
210+
guard let period = timeRangeSelectionType.period else {
211+
return nil
212+
}
213+
214+
return try await withCheckedThrowingContinuation { continuation in
215+
let action = StatsActionV4.retrieveSiteSummaryStats(siteID: siteID,
216+
period: period,
217+
quantity: timeRangeSelectionType.quantity,
218+
latestDateToInclude: latestDateToInclude) { result in
219+
continuation.resume(with: result)
220+
}
221+
stores.dispatch(action)
222+
}
223+
}
194224
}
195225

196226
// MARK: Data - UI mapping
@@ -202,13 +232,15 @@ private extension AnalyticsHubViewModel {
202232
self.ordersCard = ordersCard.redacted
203233
self.productsStatsCard = productsStatsCard.redacted
204234
self.itemsSoldCard = itemsSoldCard.redacted
235+
self.sessionsCard = sessionsCard.redacted
205236
}
206237

207238
@MainActor
208239
func switchToErrorState() {
209240
self.currentOrderStats = nil
210241
self.previousOrderStats = nil
211242
self.itemsSoldStats = nil
243+
self.siteStats = nil
212244
}
213245

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

232-
Publishers.CombineLatest($currentOrderStats, $siteStats)
233-
.sink { [weak self] currentOrderStats, siteStats in
264+
$currentOrderStats.zip($siteStats)
265+
.sink { [weak self] (currentOrderStats, siteStats) in
234266
guard let self else { return }
235267

236268
self.sessionsCard = AnalyticsHubViewModel.sessionsCard(currentPeriodStats: currentOrderStats, siteStats: siteStats)

WooCommerce/Classes/ViewRelated/Dashboard/Analytics Hub/Time Range/AnalyticsHubTimeRangeSelection.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,38 @@ extension AnalyticsHubTimeRangeSelection {
126126
}
127127
}
128128

129+
/// The period used to request site summary stats from the given SelectedType.
130+
///
131+
/// Returns `nil` if there isn't a `StatGranularity` period that can be used to fetch stats for the given SelectedType.
132+
///
133+
var period: StatGranularity? {
134+
switch self {
135+
case .custom:
136+
return nil
137+
case .today, .yesterday:
138+
return .day
139+
case .weekToDate, .lastWeek:
140+
return .week
141+
case .monthToDate, .lastMonth, .quarterToDate, .lastQuarter:
142+
return .month
143+
case .yearToDate, .lastYear:
144+
return .year
145+
}
146+
}
147+
148+
/// The quantity of periods used to request site summary stats from the given SelectedType.
149+
///
150+
/// Defaults to 1 (a single period) except for ranges not matching a `StatGranularity` period.
151+
///
152+
var quantity: Int {
153+
switch self {
154+
case .quarterToDate, .lastQuarter:
155+
return 3 // Stats summary calculated from 3 months of data
156+
default:
157+
return 1
158+
}
159+
}
160+
129161
init(_ statsTimeRange: StatsTimeRangeV4) {
130162
switch statsTimeRange {
131163
case .today:

WooCommerce/WooCommerceTests/ViewRelated/Dashboard/Analytics Hub/AnalyticsHubViewModelTests.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ final class AnalyticsHubViewModelTests: XCTestCase {
2626
case let .retrieveTopEarnerStats(_, _, _, _, _, _, _, completion):
2727
let topEarners = TopEarnerStats.fake().copy(items: [.fake()])
2828
completion(.success(topEarners))
29+
case let .retrieveSiteSummaryStats(_, _, _, _, completion):
30+
let siteStats = SiteSummaryStats.fake().copy(visitors: 30, views: 53)
31+
completion(.success(siteStats))
2932
default:
3033
break
3134
}
@@ -39,12 +42,14 @@ final class AnalyticsHubViewModelTests: XCTestCase {
3942
XCTAssertFalse(vm.ordersCard.isRedacted)
4043
XCTAssertFalse(vm.productsStatsCard.isRedacted)
4144
XCTAssertFalse(vm.itemsSoldCard.isRedacted)
45+
XCTAssertFalse(vm.sessionsCard.isRedacted)
4246

4347
XCTAssertEqual(vm.revenueCard.leadingValue, "$62")
4448
XCTAssertEqual(vm.ordersCard.leadingValue, "15")
4549
XCTAssertEqual(vm.productsStatsCard.itemsSold, "5")
46-
4750
XCTAssertEqual(vm.itemsSoldCard.itemsSoldData.count, 1)
51+
XCTAssertEqual(vm.sessionsCard.leadingValue, "53")
52+
XCTAssertEqual(vm.sessionsCard.trailingValue, "50%")
4853
}
4954

5055
func test_cards_viewmodels_show_sync_error_after_getting_error_from_network() async {
@@ -56,6 +61,8 @@ final class AnalyticsHubViewModelTests: XCTestCase {
5661
completion(.failure(NSError(domain: "Test", code: 1)))
5762
case let .retrieveTopEarnerStats(_, _, _, _, _, _, _, completion):
5863
completion(.failure(NSError(domain: "Test", code: 1)))
64+
case let .retrieveSiteSummaryStats(_, _, _, _, completion):
65+
completion(.failure(NSError(domain: "Test", code: 1)))
5966
default:
6067
break
6168
}
@@ -69,6 +76,7 @@ final class AnalyticsHubViewModelTests: XCTestCase {
6976
XCTAssertTrue(vm.ordersCard.showSyncError)
7077
XCTAssertTrue(vm.productsStatsCard.showStatsError)
7178
XCTAssertTrue(vm.itemsSoldCard.showItemsSoldError)
79+
XCTAssertTrue(vm.sessionsCard.showSyncError)
7280
}
7381

7482
func test_cards_viewmodels_redacted_while_updating_from_network() async {
@@ -78,6 +86,7 @@ final class AnalyticsHubViewModelTests: XCTestCase {
7886
var loadingOrdersCard: AnalyticsReportCardViewModel?
7987
var loadingProductsCard: AnalyticsProductsStatsCardViewModel?
8088
var loadingItemsSoldCard: AnalyticsItemsSoldViewModel?
89+
var loadingSessionsCard: AnalyticsReportCardCurrentPeriodViewModel?
8190
stores.whenReceivingAction(ofType: StatsActionV4.self) { action in
8291
switch action {
8392
case let .retrieveCustomStats(_, _, _, _, _, _, completion):
@@ -90,6 +99,10 @@ final class AnalyticsHubViewModelTests: XCTestCase {
9099
case let .retrieveTopEarnerStats(_, _, _, _, _, _, _, completion):
91100
let topEarners = TopEarnerStats.fake().copy(items: [.fake()])
92101
completion(.success(topEarners))
102+
case let .retrieveSiteSummaryStats(_, _, _, _, completion):
103+
let siteStats = SiteSummaryStats.fake()
104+
loadingSessionsCard = vm.sessionsCard
105+
completion(.success(siteStats))
93106
default:
94107
break
95108
}
@@ -103,5 +116,6 @@ final class AnalyticsHubViewModelTests: XCTestCase {
103116
XCTAssertEqual(loadingOrdersCard?.isRedacted, true)
104117
XCTAssertEqual(loadingProductsCard?.isRedacted, true)
105118
XCTAssertEqual(loadingItemsSoldCard?.isRedacted, true)
119+
XCTAssertEqual(loadingSessionsCard?.isRedacted, true)
106120
}
107121
}

0 commit comments

Comments
 (0)