diff --git a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift index e492e27381d6..1cf2a70fcb87 100644 --- a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift +++ b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift @@ -462,6 +462,10 @@ import Foundation case blazeFlowCanceled case blazeFlowCompleted case blazeFlowError + case blazeCampaignListOpened + case blazeCampaignDetailsOpened + case blazeCampaignDetailsError + case blazeCampaignDetailsDismissed // Moved to Jetpack static screen case removeStaticPosterDisplayed @@ -1292,6 +1296,14 @@ import Foundation return "blaze_flow_completed" case .blazeFlowError: return "blaze_flow_error" + case .blazeCampaignListOpened: + return "blaze_campaign_list_opened" + case .blazeCampaignDetailsOpened: + return "blaze_campaign_details_opened" + case .blazeCampaignDetailsError: + return "blaze_campaign_details_error" + case .blazeCampaignDetailsDismissed: + return "blaze_campaign_details_dismissed" // Moved to Jetpack static screen case .removeStaticPosterDisplayed: diff --git a/WordPress/Classes/ViewRelated/Blaze Campaigns/BlazeCampaignsViewController.swift b/WordPress/Classes/ViewRelated/Blaze Campaigns/BlazeCampaignsViewController.swift index a003f51a6a00..f2c406dc06b1 100644 --- a/WordPress/Classes/ViewRelated/Blaze Campaigns/BlazeCampaignsViewController.swift +++ b/WordPress/Classes/ViewRelated/Blaze Campaigns/BlazeCampaignsViewController.swift @@ -32,18 +32,20 @@ final class BlazeCampaignsViewController: UIViewController, NoResultsViewHost, B private var stream: BlazeCampaignsStream private var pendingStream: AnyObject? + private let source: BlazeSource private let blog: Blog // MARK: - Initializers - init(blog: Blog) { + init(source: BlazeSource, blog: Blog) { + self.source = source self.blog = blog self.stream = BlazeCampaignsStream(blog: blog) super.init(nibName: nil, bundle: nil) } - @objc class func make(blog: Blog) -> BlazeCampaignsViewController { - BlazeCampaignsViewController(blog: blog) + @objc class func makeWithSource(_ source: BlazeSource, blog: Blog) -> BlazeCampaignsViewController { + BlazeCampaignsViewController(source: source, blog: blog) } required init?(coder: NSCoder) { @@ -67,6 +69,11 @@ final class BlazeCampaignsViewController: UIViewController, NoResultsViewHost, B NotificationCenter.default.addObserver(self, selector: #selector(setNeedsToRefreshCampaigns), name: .blazeCampaignCreated, object: nil) } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + BlazeEventsTracker.trackCampaignListOpened(for: source) + } + override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() @@ -155,8 +162,8 @@ final class BlazeCampaignsViewController: UIViewController, NoResultsViewHost, B } @objc private func buttonCreateCampaignTapped() { - BlazeEventsTracker.trackBlazeFlowStarted(for: .campaignsList) - BlazeFlowCoordinator.presentBlaze(in: self, source: .campaignsList, blog: blog) + BlazeEventsTracker.trackBlazeFlowStarted(for: .campaignList) + BlazeFlowCoordinator.presentBlaze(in: self, source: .campaignList, blog: blog) } // MARK: - Private @@ -206,7 +213,7 @@ extension BlazeCampaignsViewController: UITableViewDataSource, UITableViewDelega guard let campaign = stream.campaigns[safe: indexPath.row] else { return } - BlazeFlowCoordinator.presentBlazeCampaignDetails(in: self, source: .campaignsList, blog: blog, campaignID: campaign.campaignID) + BlazeFlowCoordinator.presentBlazeCampaignDetails(in: self, source: .campaignList, blog: blog, campaignID: campaign.campaignID) } } @@ -234,7 +241,7 @@ extension BlazeCampaignsViewController: NoResultsViewControllerDelegate { } func actionButtonPressed() { - BlazeFlowCoordinator.presentBlaze(in: self, source: .campaignsList, blog: blog) + BlazeFlowCoordinator.presentBlaze(in: self, source: .campaignList, blog: blog) } } diff --git a/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeEventsTracker.swift b/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeEventsTracker.swift index 8ee18ef59da2..aa6c0d04bd23 100644 --- a/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeEventsTracker.swift +++ b/WordPress/Classes/ViewRelated/Blaze/Helpers/BlazeEventsTracker.swift @@ -13,6 +13,8 @@ import Foundation WPAnalytics.track(.blazeEntryPointTapped, properties: analyticsProperties(for: source)) } + // MARK: - Dashboard card + static func trackContextualMenuAccessed(for source: BlazeSource) { WPAnalytics.track(.blazeContextualMenuAccessed, properties: analyticsProperties(for: source)) } @@ -21,6 +23,8 @@ import Foundation WPAnalytics.track(.blazeCardHidden, properties: analyticsProperties(for: source)) } + // MARK: - Overlay + static func trackOverlayDisplayed(for source: BlazeSource) { WPAnalytics.track(.blazeOverlayDisplayed, properties: analyticsProperties(for: source)) } @@ -33,6 +37,8 @@ import Foundation WPAnalytics.track(.blazeOverlayDismissed, properties: analyticsProperties(for: source)) } + // MARK: - Blaze webview flow + static func trackBlazeFlowStarted(for source: BlazeSource) { WPAnalytics.track(.blazeFlowStarted, properties: analyticsProperties(for: source)) } @@ -53,6 +59,28 @@ import Foundation WPAnalytics.track(.blazeFlowError, properties: properties) } + // MARK: - Campaign list + + static func trackCampaignListOpened(for source: BlazeSource) { + WPAnalytics.track(.blazeCampaignListOpened, properties: analyticsProperties(for: source)) + } + + // MARK: - Campaign details + + static func trackCampaignDetailsOpened(for source: BlazeSource) { + WPAnalytics.track(.blazeCampaignDetailsOpened, properties: analyticsProperties(for: source)) + } + + static func trackCampaignDetailsError(for source: BlazeSource) { + WPAnalytics.track(.blazeCampaignDetailsError, properties: analyticsProperties(for: source)) + } + + static func trackCampaignDetailsDismissed(for source: BlazeSource) { + WPAnalytics.track(.blazeCampaignDetailsDismissed, properties: analyticsProperties(for: source)) + } + + // MARK: - Helpers + private static func analyticsProperties(for source: BlazeSource) -> [String: String] { return [WPAppAnalyticsKeySource: source.description] } diff --git a/WordPress/Classes/ViewRelated/Blaze/Overlay/BlazeOverlayViewModel.swift b/WordPress/Classes/ViewRelated/Blaze/Overlay/BlazeOverlayViewModel.swift index e6dcf9e150e3..a466d3472464 100644 --- a/WordPress/Classes/ViewRelated/Blaze/Overlay/BlazeOverlayViewModel.swift +++ b/WordPress/Classes/ViewRelated/Blaze/Overlay/BlazeOverlayViewModel.swift @@ -18,7 +18,7 @@ struct BlazeOverlayViewModel { switch source { case .dashboardCard: fallthrough - case .campaignsList: + case .campaignList: fallthrough case .menuItem: return buttonTitleWithIcon(title: Strings.blazeButtonTitle) diff --git a/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeCampaignDetailsWebViewModel.swift b/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeCampaignDetailsWebViewModel.swift index c3cc14a177f6..fd09328913d6 100644 --- a/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeCampaignDetailsWebViewModel.swift +++ b/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeCampaignDetailsWebViewModel.swift @@ -56,22 +56,22 @@ class BlazeCampaignDetailsWebViewModel: BlazeWebViewModel { func startBlazeFlow() { guard let initialURL, let cookieJar = view?.cookieJar else { - // TODO: Track Analytics Error Event + BlazeEventsTracker.trackCampaignDetailsError(for: source) view?.dismissView() return } authenticatedRequest(for: initialURL, with: cookieJar) { [weak self] (request) in - guard let weakSelf = self else { + guard let self else { return } - weakSelf.view?.load(request: request) - // TODO: Track Analytics Event + self.view?.load(request: request) + BlazeEventsTracker.trackCampaignDetailsOpened(for: self.source) } } func dismissTapped() { view?.dismissView() - // TODO: Track Analytics Event + BlazeEventsTracker.trackCampaignDetailsDismissed(for: source) } func shouldNavigate(to request: URLRequest, with type: WKNavigationType) -> WKNavigationActionPolicy { diff --git a/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeFlowCoordinator.swift b/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeFlowCoordinator.swift index 6fdcfa1a71bb..3d1109f17a15 100644 --- a/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeFlowCoordinator.swift +++ b/WordPress/Classes/ViewRelated/Blaze/Webview/BlazeFlowCoordinator.swift @@ -6,7 +6,7 @@ import UIKit case menuItem case postsList case pagesList - case campaignsList + case campaignList var description: String { switch self { @@ -18,8 +18,8 @@ import UIKit return "posts_list" case .pagesList: return "pages_list" - case .campaignsList: - return "campaigns_list" + case .campaignList: + return "campaign_list" } } @@ -107,10 +107,11 @@ import UIKit /// - Parameters: /// - viewController: The view controller where the screen should be presented in. /// - blog: `Blog` object representing the site with Blaze campaigns. - @objc(presentBlazeCampaignsInViewController:blog:) + @objc(presentBlazeCampaignsInViewController:source:blog:) static func presentBlazeCampaigns(in viewController: UIViewController, + source: BlazeSource, blog: Blog) { - let campaignsViewController = BlazeCampaignsViewController(blog: blog) + let campaignsViewController = BlazeCampaignsViewController(source: source, blog: blog) viewController.navigationController?.pushViewController(campaignsViewController, animated: true) } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Blaze/DashboardBlazeCampaignsCardView.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Blaze/DashboardBlazeCampaignsCardView.swift index 78f08de1a331..d4a7bc9598e1 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Blaze/DashboardBlazeCampaignsCardView.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Blaze/DashboardBlazeCampaignsCardView.swift @@ -82,7 +82,7 @@ final class DashboardBlazeCampaignsCardView: UIView { private func showCampaignList() { guard let presentingViewController, let blog else { return } - BlazeFlowCoordinator.presentBlazeCampaigns(in: presentingViewController, blog: blog) + BlazeFlowCoordinator.presentBlazeCampaigns(in: presentingViewController, source: .dashboardCard, blog: blog) } private func makeShowCampaignsMenuAction() -> UIAction { diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m index 1d7e979e9588..5343134c65da 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m @@ -1986,7 +1986,8 @@ - (void)showBlaze [BlazeEventsTracker trackEntryPointTappedFor:BlazeSourceMenuItem]; if ([RemoteFeature enabled:RemoteFeatureFlagBlazeManageCampaigns]) { - BlazeCampaignsViewController *controller = [BlazeCampaignsViewController makeWithBlog:self.blog]; + BlazeCampaignsViewController *controller = [BlazeCampaignsViewController makeWithSource:BlazeSourceMenuItem + blog:self.blog]; [self.presentationDelegate presentBlogDetailsViewController:controller]; } else { [BlazeFlowCoordinator presentBlazeInViewController:self diff --git a/WordPress/WordPressTest/Blaze/BlazeCampaignDetailsWebViewModelTests.swift b/WordPress/WordPressTest/Blaze/BlazeCampaignDetailsWebViewModelTests.swift index 078af985607a..bfac64e6d1a7 100644 --- a/WordPress/WordPressTest/Blaze/BlazeCampaignDetailsWebViewModelTests.swift +++ b/WordPress/WordPressTest/Blaze/BlazeCampaignDetailsWebViewModelTests.swift @@ -24,7 +24,7 @@ final class BlazeCampaignDetailsWebViewModelTests: CoreDataTestCase { func testInternalURLsAllowed() throws { // Given - let viewModel = BlazeCampaignDetailsWebViewModel(source: .campaignsList, blog: blog, campaignID: 0, view: view, externalURLHandler: externalURLHandler) + let viewModel = BlazeCampaignDetailsWebViewModel(source: .campaignList, blog: blog, campaignID: 0, view: view, externalURLHandler: externalURLHandler) let validURL = try XCTUnwrap(URL(string: "https://wordpress.com/advertising/test.blog.com?source=menu_item")) var validRequest = URLRequest(url: validURL) validRequest.mainDocumentURL = validURL @@ -39,7 +39,7 @@ final class BlazeCampaignDetailsWebViewModelTests: CoreDataTestCase { func testExternalURLsBlocked() throws { // Given - let viewModel = BlazeCampaignDetailsWebViewModel(source: .campaignsList, blog: blog, campaignID: 0, view: view, externalURLHandler: externalURLHandler) + let viewModel = BlazeCampaignDetailsWebViewModel(source: .campaignList, blog: blog, campaignID: 0, view: view, externalURLHandler: externalURLHandler) let invalidURL = try XCTUnwrap(URL(string: "https://test.com/test?example=test")) var invalidRequest = URLRequest(url: invalidURL) invalidRequest.mainDocumentURL = invalidURL @@ -55,7 +55,7 @@ final class BlazeCampaignDetailsWebViewModelTests: CoreDataTestCase { func testCallingDismissTappedDismissesTheView() { // Given - let viewModel = BlazeCampaignDetailsWebViewModel(source: .campaignsList, blog: blog, campaignID: 0, view: view, externalURLHandler: externalURLHandler) + let viewModel = BlazeCampaignDetailsWebViewModel(source: .campaignList, blog: blog, campaignID: 0, view: view, externalURLHandler: externalURLHandler) // When viewModel.dismissTapped() @@ -66,14 +66,14 @@ final class BlazeCampaignDetailsWebViewModelTests: CoreDataTestCase { func testCallingStartBlazeSiteFlowLoadsTheView() throws { // Given - let viewModel = BlazeCampaignDetailsWebViewModel(source: .campaignsList, blog: blog, campaignID: 0, view: view, externalURLHandler: externalURLHandler) + let viewModel = BlazeCampaignDetailsWebViewModel(source: .campaignList, blog: blog, campaignID: 0, view: view, externalURLHandler: externalURLHandler) // When viewModel.startBlazeFlow() // Then XCTAssertTrue(view.loadCalled) - XCTAssertEqual(view.requestLoaded?.url?.absoluteString, "https://wordpress.com/advertising/test.blog.com/campaigns/0?source=campaigns_list") + XCTAssertEqual(view.requestLoaded?.url?.absoluteString, "https://wordpress.com/advertising/test.blog.com/campaigns/0?source=campaign_list") } }