Skip to content

Commit 3cd945e

Browse files
committed
Return delta value and formatted string from stats formatter
1 parent 09bf974 commit 3cd945e

File tree

2 files changed

+71
-50
lines changed

2 files changed

+71
-50
lines changed

WooCommerce/Classes/ViewRelated/Dashboard/Factories/StatsDataTextFormatter.swift

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,10 @@ struct StatsDataTextFormatter {
2626

2727
/// Creates the text to display for the total revenue delta.
2828
///
29-
static func createTotalRevenueDelta(from previousPeriod: OrderStatsV4?, to currentPeriod: OrderStatsV4?) -> String {
30-
if let previousRevenue = totalRevenue(at: nil, orderStats: previousPeriod), let currentRevenue = totalRevenue(at: nil, orderStats: currentPeriod) {
31-
return createDeltaText(from: previousRevenue, to: currentRevenue)
32-
} else {
33-
return Constants.placeholderText
34-
}
29+
static func createTotalRevenueDelta(from previousPeriod: OrderStatsV4?, to currentPeriod: OrderStatsV4?) -> DeltaPercentage {
30+
let previousRevenue = totalRevenue(at: nil, orderStats: previousPeriod)
31+
let currentRevenue = totalRevenue(at: nil, orderStats: currentPeriod)
32+
return createDeltaPercentage(from: previousRevenue, to: currentRevenue)
3533
}
3634

3735
// MARK: Orders Stats
@@ -48,12 +46,10 @@ struct StatsDataTextFormatter {
4846

4947
/// Creates the text to display for the order count delta.
5048
///
51-
static func createOrderCountDelta(from previousPeriod: OrderStatsV4?, to currentPeriod: OrderStatsV4?) -> String {
52-
if let previousCount = orderCount(at: nil, orderStats: previousPeriod), let currentCount = orderCount(at: nil, orderStats: currentPeriod) {
53-
return createDeltaText(from: previousCount, to: currentCount)
54-
} else {
55-
return Constants.placeholderText
56-
}
49+
static func createOrderCountDelta(from previousPeriod: OrderStatsV4?, to currentPeriod: OrderStatsV4?) -> DeltaPercentage {
50+
let previousCount = orderCount(at: nil, orderStats: previousPeriod)
51+
let currentCount = orderCount(at: nil, orderStats: currentPeriod)
52+
return createDeltaPercentage(from: previousCount, to: currentCount)
5753
}
5854

5955
/// Creates the text to display for the average order value.
@@ -70,12 +66,10 @@ struct StatsDataTextFormatter {
7066

7167
/// Creates the text to display for the average order value delta.
7268
///
73-
static func createAverageOrderValueDelta(from previousPeriod: OrderStatsV4?, to currentPeriod: OrderStatsV4?) -> String {
74-
if let previousAverage = averageOrderValue(orderStats: previousPeriod), let currentAverage = averageOrderValue(orderStats: currentPeriod) {
75-
return createDeltaText(from: previousAverage, to: currentAverage)
76-
} else {
77-
return Constants.placeholderText
78-
}
69+
static func createAverageOrderValueDelta(from previousPeriod: OrderStatsV4?, to currentPeriod: OrderStatsV4?) -> DeltaPercentage {
70+
let previousAverage = averageOrderValue(orderStats: previousPeriod)
71+
let currentAverage = averageOrderValue(orderStats: currentPeriod)
72+
return createDeltaPercentage(from: previousAverage, to: currentAverage)
7973
}
8074

8175
// MARK: Views and Visitors Stats
@@ -92,12 +86,10 @@ struct StatsDataTextFormatter {
9286

9387
/// Creates the text to display for the visitor count delta.
9488
///
95-
static func createVisitorCountDelta(from previousPeriod: SiteVisitStats?, to currentPeriod: SiteVisitStats?) -> String {
96-
if let previousCount = visitorCount(at: nil, siteStats: previousPeriod), let currentCount = visitorCount(at: nil, siteStats: currentPeriod) {
97-
return createDeltaText(from: previousCount, to: currentCount)
98-
} else {
99-
return Constants.placeholderText
100-
}
89+
static func createVisitorCountDelta(from previousPeriod: SiteVisitStats?, to currentPeriod: SiteVisitStats?) -> DeltaPercentage {
90+
let previousCount = visitorCount(at: nil, siteStats: previousPeriod)
91+
let currentCount = visitorCount(at: nil, siteStats: currentPeriod)
92+
return createDeltaPercentage(from: previousCount, to: currentCount)
10193
}
10294

10395
// MARK: Conversion Stats
@@ -128,21 +120,42 @@ extension StatsDataTextFormatter {
128120

129121
// MARK: Delta Calculations
130122

131-
/// Creates the text showing the percent change from the previous `Decimal` value to the current `Decimal` value
123+
/// Creates the `DeltaPercentage` for the percent change from the previous `Decimal` value to the current `Decimal` value
132124
///
133-
static func createDeltaText(from previousValue: Decimal, to currentValue: Decimal) -> String {
125+
static func createDeltaPercentage(from previousValue: Decimal?, to currentValue: Decimal?) -> DeltaPercentage {
126+
guard let previousValue, let currentValue else {
127+
return DeltaPercentage(value: 0) // Placeholder for missing data: `+0%`
128+
}
129+
134130
guard previousValue > 0 else {
135-
return deltaNumberFormatter.string(from: 1) ?? "+100%"
131+
return DeltaPercentage(value: 1) // When previous value was 0: `+100%`
136132
}
137133

138-
let deltaValue = ((currentValue - previousValue) / previousValue)
139-
return deltaNumberFormatter.string(from: deltaValue as NSNumber) ?? Constants.placeholderText
134+
return DeltaPercentage(value: (currentValue - previousValue) / previousValue)
140135
}
141136

142-
/// Creates the text showing the percent change from the previous `Double` value to the current `Double` value
137+
/// Creates the `DeltaPercentage` for the percent change from the previous `Double` value to the current `Double` value
143138
///
144-
static func createDeltaText(from previousValue: Double, to currentValue: Double) -> String {
145-
createDeltaText(from: Decimal(previousValue), to: Decimal(currentValue))
139+
static func createDeltaPercentage(from previousValue: Double?, to currentValue: Double?) -> DeltaPercentage {
140+
guard let previousValue, let currentValue else {
141+
return DeltaPercentage(value: 0) // Placeholder for missing data: `+0%`
142+
}
143+
144+
return createDeltaPercentage(from: Decimal(previousValue), to: Decimal(currentValue))
145+
}
146+
147+
/// Represents a delta percentage value and its formatted string
148+
struct DeltaPercentage {
149+
/// The delta percentage value
150+
let value: Decimal
151+
152+
/// The delta percentage formatted as a localized string (e.g. `+100%`)
153+
let string: String
154+
155+
init(value: Decimal) {
156+
self.value = value
157+
self.string = deltaNumberFormatter.string(from: value as NSNumber) ?? Constants.placeholderText
158+
}
146159
}
147160

148161
// MARK: Stats Intervals

WooCommerce/WooCommerceTests/ViewRelated/Dashboard/StatsDataTextFormatterTests.swift

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ final class StatsDataTextFormatterTests: XCTestCase {
6262
XCTAssertEqual(totalRevenue, "$25")
6363
}
6464

65-
func test_createTotalRevenueDelta_returns_expected_delta_text() {
65+
func test_createTotalRevenueDelta_returns_expected_delta() {
6666
// Given
6767
let previousOrderStats = OrderStatsV4.fake().copy(totals: .fake().copy(grossRevenue: 10))
6868
let currentOrderStats = OrderStatsV4.fake().copy(totals: .fake().copy(grossRevenue: 15))
@@ -71,7 +71,8 @@ final class StatsDataTextFormatterTests: XCTestCase {
7171
let totalRevenueDelta = StatsDataTextFormatter.createTotalRevenueDelta(from: previousOrderStats, to: currentOrderStats)
7272

7373
// Then
74-
XCTAssertEqual(totalRevenueDelta, "+50%")
74+
XCTAssertEqual(totalRevenueDelta.value, 0.5)
75+
XCTAssertEqual(totalRevenueDelta.string, "+50%")
7576
}
7677

7778
// MARK: Orders Stats
@@ -106,7 +107,7 @@ final class StatsDataTextFormatterTests: XCTestCase {
106107
XCTAssertEqual(orderCount, "1")
107108
}
108109

109-
func test_createOrderCountDelta_returns_expected_delta_text() {
110+
func test_createOrderCountDelta_returns_expected_delta() {
110111
// Given
111112
let previousOrderStats = OrderStatsV4.fake().copy(totals: .fake().copy(totalOrders: 10))
112113
let currentOrderStats = OrderStatsV4.fake().copy(totals: .fake().copy(totalOrders: 15))
@@ -115,7 +116,8 @@ final class StatsDataTextFormatterTests: XCTestCase {
115116
let orderCountDelta = StatsDataTextFormatter.createOrderCountDelta(from: previousOrderStats, to: currentOrderStats)
116117

117118
// Then
118-
XCTAssertEqual(orderCountDelta, "+50%")
119+
XCTAssertEqual(orderCountDelta.value, 0.5)
120+
XCTAssertEqual(orderCountDelta.string, "+50%")
119121
}
120122

121123
func test_createAverageOrderValueText_does_not_return_decimal_points_for_integer_value() {
@@ -144,7 +146,7 @@ final class StatsDataTextFormatterTests: XCTestCase {
144146
XCTAssertEqual(averageOrderValue, "$62.86")
145147
}
146148

147-
func test_createAverageOrderValueDelta_returns_expected_delta_text() {
149+
func test_createAverageOrderValueDelta_returns_expected_delta() {
148150
// Given
149151
let previousOrderStats = OrderStatsV4.fake().copy(totals: .fake().copy(averageOrderValue: 10.00))
150152
let currentOrderStats = OrderStatsV4.fake().copy(totals: .fake().copy(averageOrderValue: 15.00))
@@ -153,7 +155,8 @@ final class StatsDataTextFormatterTests: XCTestCase {
153155
let averageOrderValueDelta = StatsDataTextFormatter.createAverageOrderValueDelta(from: previousOrderStats, to: currentOrderStats)
154156

155157
// Then
156-
XCTAssertEqual(averageOrderValueDelta, "+50%")
158+
XCTAssertEqual(averageOrderValueDelta.value, 0.5)
159+
XCTAssertEqual(averageOrderValueDelta.string, "+50%")
157160
}
158161

159162
// MARK: Views and Visitors Stats
@@ -186,7 +189,7 @@ final class StatsDataTextFormatterTests: XCTestCase {
186189
XCTAssertEqual(visitorCount, "17")
187190
}
188191

189-
func test_createVisitorCountDelta_returns_expected_delta_text() {
192+
func test_createVisitorCountDelta_returns_expected_delta() {
190193
// Given
191194
let previousSiteStats = SiteVisitStats.fake().copy(items: [.fake().copy(period: "0", visitors: 10)])
192195
let currentSiteStats = SiteVisitStats.fake().copy(items: [.fake().copy(period: "0", visitors: 15)])
@@ -195,7 +198,8 @@ final class StatsDataTextFormatterTests: XCTestCase {
195198
let visitorCountDelta = StatsDataTextFormatter.createVisitorCountDelta(from: previousSiteStats, to: currentSiteStats)
196199

197200
// Then
198-
XCTAssertEqual(visitorCountDelta, "+50%")
201+
XCTAssertEqual(visitorCountDelta.value, 0.5)
202+
XCTAssertEqual(visitorCountDelta.string, "+50%")
199203
}
200204

201205
// MARK: Conversion Stats
@@ -257,22 +261,24 @@ final class StatsDataTextFormatterTests: XCTestCase {
257261
let currentValue: Double = 150
258262

259263
// When
260-
let deltaText = StatsDataTextFormatter.createDeltaText(from: previousValue, to: currentValue)
264+
let delta = StatsDataTextFormatter.createDeltaPercentage(from: previousValue, to: currentValue)
261265

262266
// Then
263-
XCTAssertEqual(deltaText, "+50%")
267+
XCTAssertEqual(delta.value, 0.5)
268+
XCTAssertEqual(delta.string, "+50%")
264269
}
265270

266271
func test_createDeltaText_returns_expected_negative_text() {
267272
// Given
268-
let previousValue: Double = 150
269-
let currentValue: Double = 100
273+
let previousValue: Double = 100
274+
let currentValue: Double = 50
270275

271276
// When
272-
let deltaText = StatsDataTextFormatter.createDeltaText(from: previousValue, to: currentValue)
277+
let delta = StatsDataTextFormatter.createDeltaPercentage(from: previousValue, to: currentValue)
273278

274279
// Then
275-
XCTAssertEqual(deltaText, "-33%")
280+
XCTAssertEqual(delta.value, -0.5)
281+
XCTAssertEqual(delta.string, "-50%")
276282
}
277283

278284
func test_createDeltaText_returns_100_percent_change_when_previous_value_is_zero() {
@@ -281,10 +287,11 @@ final class StatsDataTextFormatterTests: XCTestCase {
281287
let currentValue: Double = 10
282288

283289
// When
284-
let deltaText = StatsDataTextFormatter.createDeltaText(from: previousValue, to: currentValue)
290+
let delta = StatsDataTextFormatter.createDeltaPercentage(from: previousValue, to: currentValue)
285291

286292
// Then
287-
XCTAssertEqual(deltaText, "+100%")
293+
XCTAssertEqual(delta.value, 1)
294+
XCTAssertEqual(delta.string, "+100%")
288295
}
289296

290297
func test_createDeltaText_returns_negative_100_percent_change_when_current_value_is_zero() {
@@ -293,9 +300,10 @@ final class StatsDataTextFormatterTests: XCTestCase {
293300
let currentValue: Double = 0
294301

295302
// When
296-
let deltaText = StatsDataTextFormatter.createDeltaText(from: previousValue, to: currentValue)
303+
let delta = StatsDataTextFormatter.createDeltaPercentage(from: previousValue, to: currentValue)
297304

298305
// Then
299-
XCTAssertEqual(deltaText, "-100%")
306+
XCTAssertEqual(delta.value, -1)
307+
XCTAssertEqual(delta.string, "-100%")
300308
}
301309
}

0 commit comments

Comments
 (0)