Skip to content

Commit 2e1bc10

Browse files
authored
Merge pull request #3851 from woocommerce/issue/add-variations-banner
Add variations announcement banner
2 parents c3665ef + 358d045 commit 2e1bc10

File tree

12 files changed

+82
-82
lines changed

12 files changed

+82
-82
lines changed

Storage/Storage/Model/FeedbackType.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ public enum FeedbackType: String, Codable {
55
///
66
case general
77

8-
/// Identifier for the Products M5: Linked Products, Downloadable Files, Trashing.
8+
/// Identifier for the Products Variations.
99
///
10-
case productsM5
10+
case productsVariations
1111

1212
/// identifier for the shipping labels m1 feedback survey
1313
///

WooCommerce/Classes/Analytics/WooAnalyticsEvent.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,8 @@ extension WooAnalyticsEvent {
5858
public enum FeedbackContext: String {
5959
/// Shown in Stats but is for asking general feedback.
6060
case general
61-
/// Shown in products banner for Milestone 4 features. New product banners should have
62-
/// their own `FeedbackContext` option.
63-
case productsM4 = "products_m4"
61+
/// Shown in products banner for Variations release.
62+
case productsVariations = "products_variations"
6463
/// Shown in shipping labels banner for Milestone 1 features.
6564
case shippingLabelsRelease1 = "shipping_labels_m1"
6665
}

WooCommerce/Classes/System/WooConstants.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ extension WooConstants {
7979
case inAppFeedback = "https://automattic.survey.fm/woo-app-general-feedback-user-survey"
8080
#endif
8181

82-
/// URL for the products M4 feedback survey
82+
/// URL for the products feedback survey
8383
///
84-
case productsM4Feedback = "https://automattic.survey.fm/woo-app-feature-feedback-products"
84+
case productsFeedback = "https://automattic.survey.fm/woo-app-feature-feedback-products"
8585

8686
/// URL for the shipping labels M1 feedback survey
8787
///

WooCommerce/Classes/ViewRelated/Products/ProductsTopBannerFactory.swift

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,54 @@ import UIKit
22
import Yosemite
33

44
struct ProductsTopBannerFactory {
5+
6+
enum BannerType {
7+
case variations
8+
9+
var title: String {
10+
Localization.title
11+
}
12+
13+
var info: String {
14+
switch self {
15+
case .variations:
16+
return Localization.infoVariations
17+
}
18+
}
19+
20+
var feedbackContext: WooAnalyticsEvent.FeedbackContext {
21+
switch self {
22+
case .variations:
23+
return .productsVariations
24+
}
25+
}
26+
}
27+
528
/// Creates a products tab top banner asynchronously based on the app settings.
629
/// - Parameters:
730
/// - isExpanded: whether the top banner is expanded by default.
31+
/// - type: sets banner content and related analytics events.
832
/// - expandedStateChangeHandler: called when the top banner expanded state changes.
933
/// - onGiveFeedbackButtonPressed: called the give feedback button is pressed.
1034
/// - onDismissButtonPressed: called the dismiss button is pressed
1135
/// - onCompletion: called when the view controller is created and ready for display.
1236
static func topBanner(isExpanded: Bool,
1337
stores: StoresManager = ServiceLocator.stores,
1438
analytics: Analytics = ServiceLocator.analytics,
39+
type: BannerType,
1540
expandedStateChangeHandler: @escaping () -> Void,
1641
onGiveFeedbackButtonPressed: @escaping () -> Void,
1742
onDismissButtonPressed: @escaping () -> Void,
1843
onCompletion: @escaping (TopBannerView) -> Void) {
19-
let title = Localization.title
44+
let title = type.title
45+
let infoText = type.info
2046
let icon: UIImage = .megaphoneIcon
21-
let infoText = Localization.info
2247
let giveFeedbackAction = TopBannerViewModel.ActionButton(title: Localization.giveFeedback) {
23-
analytics.track(event: .featureFeedbackBanner(context: .productsM4, action: .gaveFeedback))
48+
analytics.track(event: .featureFeedbackBanner(context: type.feedbackContext, action: .gaveFeedback))
2449
onGiveFeedbackButtonPressed()
2550
}
2651
let dismissAction = TopBannerViewModel.ActionButton(title: Localization.dismiss) {
27-
analytics.track(event: .featureFeedbackBanner(context: .productsM4, action: .dismissed))
52+
analytics.track(event: .featureFeedbackBanner(context: type.feedbackContext, action: .dismissed))
2853
onDismissButtonPressed()
2954
}
3055
let actions = [giveFeedbackAction, dismissAction]
@@ -42,13 +67,12 @@ struct ProductsTopBannerFactory {
4267

4368
private extension ProductsTopBannerFactory {
4469
enum Localization {
45-
static let title =
46-
NSLocalizedString("New features available!",
47-
comment: "The title of the top banner on the Products tab.")
48-
static let info =
49-
NSLocalizedString(
50-
"You can now add downloadable files to a product and link upsell & cross-sell products. No longer want a product? Trash it!",
51-
comment: "The info of the top banner on the Products tab.")
70+
static let title = NSLocalizedString("New features available!",
71+
comment: "The title of the top banner on the Products tab.")
72+
73+
static let infoVariations = NSLocalizedString("You can now create and manage product variations!",
74+
comment: "The info of the top banner on the Products tab.")
75+
5276
static let giveFeedback =
5377
NSLocalizedString("Give feedback",
5478
comment: "The title of the button to give feedback about products beta features on the banner on the products tab")

WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ final class ProductsViewController: UIViewController {
162162
configureSyncingCoordinator()
163163
registerTableViewCells()
164164

165-
updateTopBannerView()
165+
showTopBannerViewIfNeeded()
166166

167167
/// We sync the local product settings for configuring local sorting and filtering.
168168
/// If there are some info stored when this screen is loaded, the data will be updated using the stored sort/filters.
@@ -397,12 +397,12 @@ private extension ProductsViewController {
397397
private extension ProductsViewController {
398398
/// Fetches products feedback visibility from AppSettingsStore and update products top banner accordingly
399399
///
400-
func updateTopBannerView() {
401-
let action = AppSettingsAction.loadFeedbackVisibility(type: .productsM5) { [weak self] result in
400+
func showTopBannerViewIfNeeded() {
401+
let action = AppSettingsAction.loadFeedbackVisibility(type: .productsVariations) { [weak self] result in
402402
switch result {
403403
case .success(let visible):
404404
if visible {
405-
self?.requestAndShowNewTopBannerView()
405+
self?.requestAndShowNewTopBannerView(for: .variations)
406406
} else {
407407
self?.hideTopBannerView()
408408
}
@@ -416,9 +416,10 @@ private extension ProductsViewController {
416416

417417
/// Request a new product banner from `ProductsTopBannerFactory` and wire actionButtons actions
418418
///
419-
func requestAndShowNewTopBannerView() {
419+
func requestAndShowNewTopBannerView(for bannerType: ProductsTopBannerFactory.BannerType) {
420420
let isExpanded = topBannerView?.isExpanded ?? false
421421
ProductsTopBannerFactory.topBanner(isExpanded: isExpanded,
422+
type: bannerType,
422423
expandedStateChangeHandler: { [weak self] in
423424
self?.updateTableHeaderViewHeight()
424425
}, onGiveFeedbackButtonPressed: { [weak self] in
@@ -593,14 +594,15 @@ private extension ProductsViewController {
593594
///
594595
func presentProductsFeedback() {
595596
// Present survey
596-
let navigationController = SurveyCoordinatingController(survey: .productsM5Feedback)
597+
let navigationController = SurveyCoordinatingController(survey: .productsVariationsFeedback)
597598
present(navigationController, animated: true, completion: nil)
598599
}
599600

600601
/// Mark feedback request as dismissed and update banner visibility
601602
///
602603
func dismissProductsBanner() {
603-
let action = AppSettingsAction.updateFeedbackStatus(type: .productsM5, status: .dismissed) { [weak self] result in
604+
let action = AppSettingsAction.updateFeedbackStatus(type: .productsVariations,
605+
status: .dismissed) { [weak self] result in
604606
if let error = result.failure {
605607
CrashLogging.logError(error)
606608
}

WooCommerce/Classes/ViewRelated/Survey/SurveyViewController.swift

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ final class SurveyViewController: UIViewController, SurveyViewControllerOutputs
6363
extension SurveyViewController {
6464
enum Source {
6565
case inAppFeedback
66-
case productsM5Feedback
66+
case productsVariationsFeedback
6767
case shippingLabelsRelease1Feedback
6868

6969
fileprivate var url: URL {
@@ -74,11 +74,10 @@ extension SurveyViewController {
7474
.tagPlatform("ios")
7575
.tagAppVersion(Bundle.main.bundleVersion())
7676

77-
case .productsM5Feedback:
78-
return WooConstants.URLs.productsM4Feedback
77+
case .productsVariationsFeedback:
78+
return WooConstants.URLs.productsFeedback
7979
.asURL()
8080
.tagPlatform("ios")
81-
.tagProductMilestone("5")
8281
.tagAppVersion(Bundle.main.bundleVersion())
8382
case .shippingLabelsRelease1Feedback:
8483
return WooConstants.URLs.shippingLabelsRelease1Feedback
@@ -93,7 +92,7 @@ extension SurveyViewController {
9392
switch self {
9493
case .inAppFeedback:
9594
return Localization.title
96-
case .productsM5Feedback, .shippingLabelsRelease1Feedback:
95+
case .productsVariationsFeedback, .shippingLabelsRelease1Feedback:
9796
return Localization.giveFeedback
9897
}
9998
}
@@ -103,8 +102,8 @@ extension SurveyViewController {
103102
switch self {
104103
case .inAppFeedback:
105104
return .general
106-
case .productsM5Feedback:
107-
return .productsM4
105+
case .productsVariationsFeedback:
106+
return .productsVariations
108107
case .shippingLabelsRelease1Feedback:
109108
return .shippingLabelsRelease1
110109
}
@@ -152,10 +151,6 @@ extension URL {
152151
appendingQueryItem(URLQueryItem(name: Tags.surveyRequestAppVersionTag, value: version))
153152
}
154153

155-
func tagProductMilestone(_ milestone: String) -> URL {
156-
appendingQueryItem(URLQueryItem(name: Tags.surveyRequestProductMilestoneTag, value: milestone))
157-
}
158-
159154
func tagShippingLabelsMilestone(_ milestone: String) -> URL {
160155
appendingQueryItem(URLQueryItem(name: Tags.surveyRequestShippingLabelsMilestoneTag, value: milestone))
161156
}

WooCommerce/WooCommerceTests/ViewRelated/Products/ProductsTopBannerFactoryTests.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ final class ProductsTopBannerFactoryTests: XCTestCase {
2828

2929
func test_it_tracks_featureFeedbackBanner_gaveFeedback_event_when_giveFeedback_button_is_pressed() throws {
3030
// Given
31-
let bannerMirror = try makeBannerViewMirror()
31+
let bannerMirror = try makeBannerViewMirror(for: .variations)
3232
let giveFeedbackButton = try XCTUnwrap(bannerMirror.actionButtons.first)
3333

3434
assertEmpty(analyticsProvider.receivedEvents)
@@ -41,13 +41,13 @@ final class ProductsTopBannerFactoryTests: XCTestCase {
4141
XCTAssertEqual(analyticsProvider.receivedEvents.first, "feature_feedback_banner")
4242

4343
let properties = try XCTUnwrap(analyticsProvider.receivedProperties.first)
44-
XCTAssertEqual(properties["context"] as? String, "products_m4")
44+
XCTAssertEqual(properties["context"] as? String, "products_variations")
4545
XCTAssertEqual(properties["action"] as? String, "gave_feedback")
4646
}
4747

4848
func test_it_tracks_featureFeedbackBanner_dismissed_event_when_dismiss_button_is_pressed() throws {
4949
// Given
50-
let bannerMirror = try makeBannerViewMirror()
50+
let bannerMirror = try makeBannerViewMirror(for: .variations)
5151
let dismissButton = try XCTUnwrap(bannerMirror.actionButtons.last)
5252

5353
assertEmpty(analyticsProvider.receivedEvents)
@@ -60,13 +60,13 @@ final class ProductsTopBannerFactoryTests: XCTestCase {
6060
XCTAssertEqual(analyticsProvider.receivedEvents.first, "feature_feedback_banner")
6161

6262
let properties = try XCTUnwrap(analyticsProvider.receivedProperties.first)
63-
XCTAssertEqual(properties["context"] as? String, "products_m4")
63+
XCTAssertEqual(properties["context"] as? String, "products_variations")
6464
XCTAssertEqual(properties["action"] as? String, "dismissed")
6565
}
6666
}
6767

6868
private extension ProductsTopBannerFactoryTests {
69-
func makeBannerViewMirror() throws -> TopBannerViewMirror {
69+
func makeBannerViewMirror(for bannerType: ProductsTopBannerFactory.BannerType) throws -> TopBannerViewMirror {
7070
storesManager.whenReceivingAction(ofType: AppSettingsAction.self) { action in
7171
if case let .loadProductsFeatureSwitch(onCompletion) = action {
7272
onCompletion(true)
@@ -78,6 +78,7 @@ private extension ProductsTopBannerFactoryTests {
7878
ProductsTopBannerFactory.topBanner(isExpanded: false,
7979
stores: storesManager,
8080
analytics: analytics,
81+
type: bannerType,
8182
expandedStateChangeHandler: {
8283

8384
}, onGiveFeedbackButtonPressed: {

WooCommerce/WooCommerceTests/ViewRelated/Survey/SurveyViewControllerTests.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,16 @@ final class SurveyViewControllerTests: XCTestCase {
2424

2525
func test_it_loads_the_correct_product_feedback_survey() throws {
2626
// Given
27-
let viewController = SurveyViewController(survey: .productsM5Feedback, onCompletion: {})
27+
let viewController = SurveyViewController(survey: .productsVariationsFeedback, onCompletion: {})
2828

2929
// When
3030
_ = try XCTUnwrap(viewController.view)
3131
let mirror = try self.mirror(of: viewController)
3232

3333
// Then
3434
XCTAssertTrue(mirror.webView.isLoading)
35-
XCTAssertEqual(mirror.webView.url, WooConstants.URLs.productsM4Feedback
35+
XCTAssertEqual(mirror.webView.url, WooConstants.URLs.productsFeedback
3636
.asURL().tagPlatform("ios")
37-
.tagProductMilestone("5")
3837
.tagAppVersion(Bundle.main.bundleVersion()))
3938
}
4039

WooCommerce/WooCommerceTests/ViewRelated/Survey/URL+SurveyViewControllerTests.swift

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,6 @@ final class URL_SurveyViewControllerTests: XCTestCase {
2323
XCTAssertEqual(expectedURL, actualURL)
2424
}
2525

26-
func test_tagging_product_milestone_appends_the_correct_tag_data() throws {
27-
let expectedURL = "https://testurl.com?product-milestone=test"
28-
29-
let actualURL = URL(string: "https://testurl.com")?.tagProductMilestone("test").absoluteString
30-
31-
XCTAssertEqual(expectedURL, actualURL)
32-
}
33-
3426
func test_tagging_shipping_labels_milestone_appends_the_correct_tag_data() throws {
3527
let expectedURL = "https://testurl.com?shipping_label_milestone=test"
3628

@@ -39,26 +31,14 @@ final class URL_SurveyViewControllerTests: XCTestCase {
3931
XCTAssertEqual(expectedURL, actualURL)
4032
}
4133

42-
func test_tagging_platform_and_tagging_product_milestone_does_stack() throws {
43-
let actualURL =
44-
URL(string: "https://testurl.com")?
45-
.tagPlatform("ios")
46-
.tagProductMilestone("123")
47-
.absoluteString
48-
49-
let expectedURL = "https://testurl.com?woo-mobile-platform=ios&product-milestone=123"
50-
51-
XCTAssertEqual(expectedURL, actualURL)
52-
}
53-
54-
func test_tagging_platform_and_tagging_product_milestone_does_stack_in_order() throws {
34+
func test_tagging_platform_and_tagging_shipping_labels_milestone_does_stack_in_order() throws {
5535
let actualURL =
5636
URL(string: "https://testurl.com")?
57-
.tagProductMilestone("123")
37+
.tagShippingLabelsMilestone("123")
5838
.tagPlatform("ios")
5939
.absoluteString
6040

61-
let expectedURL = "https://testurl.com?product-milestone=123&woo-mobile-platform=ios"
41+
let expectedURL = "https://testurl.com?shipping_label_milestone=123&woo-mobile-platform=ios"
6242

6343
XCTAssertEqual(expectedURL, actualURL)
6444
}

Yosemite/Yosemite/Stores/AppSettings/InAppFeedbackCardVisibilityUseCase.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct InAppFeedbackCardVisibilityUseCase {
3737
switch feedbackType {
3838
case .general:
3939
return try shouldGeneralFeedbackBeVisible(currentDate: currentDate)
40-
case .productsM5:
40+
case .productsVariations:
4141
return shouldProductsFeedbackBeVisible()
4242
case .shippingLabelsRelease1:
4343
return shouldShippingLabelsRelease1FeedbackBeVisible()
@@ -66,7 +66,7 @@ struct InAppFeedbackCardVisibilityUseCase {
6666
return true
6767
}
6868

69-
/// Returns whether the productsM4 feedback request should be displayed
69+
/// Returns whether the products feedback request should be displayed
7070
///
7171
private func shouldProductsFeedbackBeVisible() -> Bool {
7272
return settings.feedbackStatus(of: feedbackType) == .pending

0 commit comments

Comments
 (0)