From c6a9a70a8494efcaee1ef78681f34f0ca117091d Mon Sep 17 00:00:00 2001 From: Huong Do Date: Fri, 10 Jan 2025 09:48:42 +0700 Subject: [PATCH 1/6] Add new event names for filter history --- WooCommerce/Classes/Analytics/WooAnalyticsStat.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift b/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift index 5a211ef86e0..5158a7a66e2 100644 --- a/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift +++ b/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift @@ -552,6 +552,13 @@ enum WooAnalyticsStat: String { // case orderListViewFilterOptionsTapped = "order_list_view_filter_options_tapped" + // MARK: Filter History + // + case filterHistoryButtonTapped = "filter_history_button_tapped" + case filterHistoryPastFilterApplied = "filter_history_past_filter_applied" + case filterHistoryPastFilterRemoved = "filter_history_past_filter_removed" + case filterHistoryCleared = "filter_history_cleared" + // MARK: Barcode Scanning events // case orderCreationProductBarcodeScanningTapped = "order_creation_product_barcode_scanning_tapped" From fdc618da9ee4d410d6d7e411642fb27e1f5fdfc3 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Fri, 10 Jan 2025 10:26:19 +0700 Subject: [PATCH 2/6] Add extensions to track events for filter history --- .../WooAnalyticsEvent+FilterHistory.swift | 30 +++++++++++++++++++ .../WooCommerce.xcodeproj/project.pbxproj | 4 +++ 2 files changed, 34 insertions(+) create mode 100644 WooCommerce/Classes/Analytics/WooAnalyticsEvent+FilterHistory.swift diff --git a/WooCommerce/Classes/Analytics/WooAnalyticsEvent+FilterHistory.swift b/WooCommerce/Classes/Analytics/WooAnalyticsEvent+FilterHistory.swift new file mode 100644 index 00000000000..6390e7ced2f --- /dev/null +++ b/WooCommerce/Classes/Analytics/WooAnalyticsEvent+FilterHistory.swift @@ -0,0 +1,30 @@ +import Foundation + +extension WooAnalyticsEvent { + enum FilterHistory { + private enum Keys { + static let source = "source" + } + + enum Source: String { + case orders + case products + } + + static func trackEntryPointTapped(from source: Source) -> WooAnalyticsEvent { + WooAnalyticsEvent(statName: .filterHistoryButtonTapped, properties: [Keys.source: source.rawValue]) + } + + static func trackPastFilterApplied(source: Source) -> WooAnalyticsEvent { + WooAnalyticsEvent(statName: .filterHistoryPastFilterApplied, properties: [Keys.source: source.rawValue]) + } + + static func trackPastFilterRemoved(source: Source) -> WooAnalyticsEvent { + WooAnalyticsEvent(statName: .filterHistoryPastFilterRemoved, properties: [Keys.source: source.rawValue]) + } + + static func trackFilterHistoryCleared(source: Source) -> WooAnalyticsEvent { + WooAnalyticsEvent(statName: .filterHistoryCleared, properties: [Keys.source: source.rawValue]) + } + } +} diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index ed8a09ebd30..9fc0b000414 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -2707,6 +2707,7 @@ DE86E9272A4BEA2500A89A5B /* FeedbackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE86E9262A4BEA2500A89A5B /* FeedbackView.swift */; }; DE86E9292A4C213A00A89A5B /* WooAnalyticsEvent+AIFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE86E9282A4C213A00A89A5B /* WooAnalyticsEvent+AIFeedback.swift */; }; DE87F4082D2D375E00869522 /* FilterHistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE87F4072D2D375E00869522 /* FilterHistoryView.swift */; }; + DE87F40E2D30C90B00869522 /* WooAnalyticsEvent+FilterHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE87F40D2D30C90300869522 /* WooAnalyticsEvent+FilterHistory.swift */; }; DE8AA0B12BBE50CF0084D2CC /* DashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8AA0B02BBE50CF0084D2CC /* DashboardView.swift */; }; DE8AA0B32BBE55E40084D2CC /* DashboardViewHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8AA0B22BBE55E40084D2CC /* DashboardViewHostingController.swift */; }; DE8AA0B52BBEBE590084D2CC /* ViewControllerContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE8AA0B42BBEBE590084D2CC /* ViewControllerContainer.swift */; }; @@ -5843,6 +5844,7 @@ DE86E9262A4BEA2500A89A5B /* FeedbackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackView.swift; sourceTree = ""; }; DE86E9282A4C213A00A89A5B /* WooAnalyticsEvent+AIFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WooAnalyticsEvent+AIFeedback.swift"; sourceTree = ""; }; DE87F4072D2D375E00869522 /* FilterHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterHistoryView.swift; sourceTree = ""; }; + DE87F40D2D30C90300869522 /* WooAnalyticsEvent+FilterHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WooAnalyticsEvent+FilterHistory.swift"; sourceTree = ""; }; DE8AA0B02BBE50CF0084D2CC /* DashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardView.swift; sourceTree = ""; }; DE8AA0B22BBE55E40084D2CC /* DashboardViewHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardViewHostingController.swift; sourceTree = ""; }; DE8AA0B42BBEBE590084D2CC /* ViewControllerContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerContainer.swift; sourceTree = ""; }; @@ -9792,6 +9794,7 @@ DE6D84A82C3D07850014FBFF /* WooAnalyticsEvent+GoogleAds.swift */, 262562342C52A6410075A8CC /* WooAnalyticsEvent+BackgroudUpdates.swift */, 86EC6EBC2CD3882900D7D2FE /* WooAnalyticsEvent+CustomFields.swift */, + DE87F40D2D30C90300869522 /* WooAnalyticsEvent+FilterHistory.swift */, ); path = Analytics; sourceTree = ""; @@ -16436,6 +16439,7 @@ DE74F2A327E41D650002FE59 /* EnableAnalyticsViewModel.swift in Sources */, AE77EA5027A47C99006A21BD /* View+AddingDividers.swift in Sources */, EE5B5BB32AB30C0A009BCBD6 /* ProductCreationAIEligibilityChecker.swift in Sources */, + DE87F40E2D30C90B00869522 /* WooAnalyticsEvent+FilterHistory.swift in Sources */, B98C6D502B149C3900A243E1 /* UINavigationItem+Configuration.swift in Sources */, 0298430C259351F100979CAE /* ShippingLabelsTopBannerFactory.swift in Sources */, 262EB5AE298C70EF009DCC36 /* SupportFormViewModel.swift in Sources */, From 1bb9673551464533203cf5d3d752f6030a31656b Mon Sep 17 00:00:00 2001 From: Huong Do Date: Fri, 10 Jan 2025 11:00:05 +0700 Subject: [PATCH 3/6] Add filter source for tracking --- .../Analytics/WooAnalyticsEvent+FilterHistory.swift | 13 ++++--------- .../Filters/FilterListViewController.swift | 8 ++++++++ .../Order Filters/FilterOrderListViewModel.swift | 2 ++ .../Filters/FilterProductListViewModel.swift | 2 ++ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/WooCommerce/Classes/Analytics/WooAnalyticsEvent+FilterHistory.swift b/WooCommerce/Classes/Analytics/WooAnalyticsEvent+FilterHistory.swift index 6390e7ced2f..f29070f1eb2 100644 --- a/WooCommerce/Classes/Analytics/WooAnalyticsEvent+FilterHistory.swift +++ b/WooCommerce/Classes/Analytics/WooAnalyticsEvent+FilterHistory.swift @@ -6,24 +6,19 @@ extension WooAnalyticsEvent { static let source = "source" } - enum Source: String { - case orders - case products - } - - static func trackEntryPointTapped(from source: Source) -> WooAnalyticsEvent { + static func trackEntryPointTapped(from source: FilterSource) -> WooAnalyticsEvent { WooAnalyticsEvent(statName: .filterHistoryButtonTapped, properties: [Keys.source: source.rawValue]) } - static func trackPastFilterApplied(source: Source) -> WooAnalyticsEvent { + static func trackPastFilterApplied(source: FilterSource) -> WooAnalyticsEvent { WooAnalyticsEvent(statName: .filterHistoryPastFilterApplied, properties: [Keys.source: source.rawValue]) } - static func trackPastFilterRemoved(source: Source) -> WooAnalyticsEvent { + static func trackPastFilterRemoved(source: FilterSource) -> WooAnalyticsEvent { WooAnalyticsEvent(statName: .filterHistoryPastFilterRemoved, properties: [Keys.source: source.rawValue]) } - static func trackFilterHistoryCleared(source: Source) -> WooAnalyticsEvent { + static func trackFilterHistoryCleared(source: FilterSource) -> WooAnalyticsEvent { WooAnalyticsEvent(statName: .filterHistoryCleared, properties: [Keys.source: source.rawValue]) } } diff --git a/WooCommerce/Classes/ViewRelated/Filters/FilterListViewController.swift b/WooCommerce/Classes/ViewRelated/Filters/FilterListViewController.swift index 0b53abeadff..68c30754e50 100644 --- a/WooCommerce/Classes/ViewRelated/Filters/FilterListViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Filters/FilterListViewController.swift @@ -2,6 +2,11 @@ import Combine import UIKit import Yosemite +enum FilterSource: String { + case orders + case products +} + protocol HumanReadable { var readableString: String { get } } @@ -29,6 +34,9 @@ protocol FilterListViewModel { /// Whether to display the entry point to the filter history var shouldShowHistory: Bool { get } + /// The entry point where the filter was opened + var source: FilterSource { get } + // Navigation & Actions /// Retrieves past filters diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Filters/FilterOrderListViewModel.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Filters/FilterOrderListViewModel.swift index 8fc42bb8f8b..d74e62a672f 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Filters/FilterOrderListViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Filters/FilterOrderListViewModel.swift @@ -59,6 +59,8 @@ final class FilterOrderListViewModel: FilterListViewModel { let shouldShowHistory: Bool + let source = FilterSource.orders + private let orderStatusFilterViewModel: FilterTypeViewModel private let dateRangeFilterViewModel: FilterTypeViewModel private let productFilterViewModel: FilterTypeViewModel diff --git a/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift b/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift index 44a0e54e4d9..54e8e952e5a 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift @@ -64,6 +64,8 @@ final class FilterProductListViewModel: FilterListViewModel { let shouldShowHistory: Bool + let source = FilterSource.products + private let stockStatusFilterViewModel: FilterTypeViewModel private let productStatusFilterViewModel: FilterTypeViewModel private let productTypeFilterViewModel: FilterTypeViewModel From 60a9e639ebacb1a056c28a2d9980d88bd8ff2d5a Mon Sep 17 00:00:00 2001 From: Huong Do Date: Fri, 10 Jan 2025 11:03:14 +0700 Subject: [PATCH 4/6] Track entry point tapped --- .../Classes/ViewRelated/Filters/FilterListViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/Classes/ViewRelated/Filters/FilterListViewController.swift b/WooCommerce/Classes/ViewRelated/Filters/FilterListViewController.swift index 68c30754e50..dfa06b14a9d 100644 --- a/WooCommerce/Classes/ViewRelated/Filters/FilterListViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Filters/FilterListViewController.swift @@ -218,6 +218,7 @@ final class FilterListViewController: UIViewCont } @objc private func showFilterHistory() { + ServiceLocator.analytics.track(event: .FilterHistory.trackEntryPointTapped(from: viewModel.source)) let controller = FilterHistoryViewHostingController(viewModel: viewModel, onSelection: { [weak self] selectedCriteria in guard let self else { return } viewModel.applyPastFilter(selectedCriteria) From dfaad9c94abeaa542fe06b0bc56dedb789a132b5 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Fri, 10 Jan 2025 11:06:09 +0700 Subject: [PATCH 5/6] Track events for product filter history --- .../Products/Filters/FilterProductListViewModel.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift b/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift index 54e8e952e5a..53257ad6d78 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Filters/FilterProductListViewModel.swift @@ -75,6 +75,7 @@ final class FilterProductListViewModel: FilterListViewModel { private let siteID: Int64 private let stores: StoresManager private let featureFlagService: FeatureFlagService + private let analytics: Analytics /// - Parameters: /// - filters: the filters to be applied initially. @@ -83,7 +84,8 @@ final class FilterProductListViewModel: FilterListViewModel { init(filters: Filters, siteID: Int64, stores: StoresManager = ServiceLocator.stores, - featureFlagService: FeatureFlagService = ServiceLocator.featureFlagService) { + featureFlagService: FeatureFlagService = ServiceLocator.featureFlagService, + analytics: Analytics = ServiceLocator.analytics) { self.featureFlagService = featureFlagService self.stockStatusFilterViewModel = ProductListFilter.stockStatus.createViewModel(filters: filters) self.productStatusFilterViewModel = ProductListFilter.productStatus.createViewModel(filters: filters) @@ -93,6 +95,7 @@ final class FilterProductListViewModel: FilterListViewModel { self.shouldShowHistory = featureFlagService.isFeatureFlagEnabled(.filterHistoryOnOrderAndProductLists) self.stores = stores self.siteID = siteID + self.analytics = analytics if featureFlagService.isFeatureFlagEnabled(.favoriteProducts) { self.filterTypeViewModels = [ @@ -135,6 +138,7 @@ final class FilterProductListViewModel: FilterListViewModel { productTypeFilterViewModel.selectedValue = filter.promotableProductType productCategoryFilterViewModel.selectedValue = filter.productCategory productFavoriteFilterViewModel.selectedValue = filter.favoriteProduct + analytics.track(event: .FilterHistory.trackPastFilterApplied(source: source)) } @MainActor @@ -176,6 +180,7 @@ final class FilterProductListViewModel: FilterListViewModel { } func removeFilterFromHistory(_ filter: Filters) { + analytics.track(event: .FilterHistory.trackPastFilterRemoved(source: source)) let productSettings = StoredProductSettings.Setting(siteID: siteID, sort: nil, // This will be ignored in product filter anyway stockStatusFilter: filter.stockStatus, @@ -191,6 +196,7 @@ final class FilterProductListViewModel: FilterListViewModel { } func clearAllFilterHistory() { + analytics.track(event: .FilterHistory.trackFilterHistoryCleared(source: source)) stores.dispatch(AppSettingsAction.resetProductFilterHistory(siteID: siteID, onCompletion: { error in if let error { DDLogError("⛔️ Error resetting product filter history: \(error)") From af9726d4e571c6223e58e4d14eeace31cbde41de Mon Sep 17 00:00:00 2001 From: Huong Do Date: Fri, 10 Jan 2025 11:10:51 +0700 Subject: [PATCH 6/6] Add events for order filter history --- .../Orders/Order Filters/FilterOrderListViewModel.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Filters/FilterOrderListViewModel.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Filters/FilterOrderListViewModel.swift index d74e62a672f..dbe57c2fe36 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Filters/FilterOrderListViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Filters/FilterOrderListViewModel.swift @@ -1,6 +1,7 @@ import UIKit import Yosemite import Experiments +import WooFoundation /// `FilterListViewModel` for filtering a list of orders. final class FilterOrderListViewModel: FilterListViewModel { @@ -68,6 +69,7 @@ final class FilterOrderListViewModel: FilterListViewModel { private let siteID: Int64 private let stores: StoresManager + private let analytics: Analytics /// - Parameters: /// - filters: the filters to be applied initially. @@ -79,7 +81,8 @@ final class FilterOrderListViewModel: FilterListViewModel { allowedStatuses: [OrderStatus], siteID: Int64, featureFlagService: FeatureFlagService = ServiceLocator.featureFlagService, - stores: StoresManager = ServiceLocator.stores) { + stores: StoresManager = ServiceLocator.stores, + analytics: Analytics = ServiceLocator.analytics) { orderStatusFilterViewModel = OrderListFilter.orderStatus.createViewModel(filters: filters, allowedStatuses: allowedStatuses) dateRangeFilterViewModel = OrderListFilter.dateRange.createViewModel(filters: filters, allowedStatuses: allowedStatuses) productFilterViewModel = OrderListFilter.product(siteID: siteID).createViewModel(filters: filters, allowedStatuses: allowedStatuses) @@ -87,6 +90,7 @@ final class FilterOrderListViewModel: FilterListViewModel { self.siteID = siteID self.stores = stores + self.analytics = analytics shouldShowHistory = featureFlagService.isFeatureFlagEnabled(.filterHistoryOnOrderAndProductLists) filterTypeViewModels = [orderStatusFilterViewModel, dateRangeFilterViewModel, customerFilterViewModel, productFilterViewModel] @@ -132,6 +136,7 @@ final class FilterOrderListViewModel: FilterListViewModel { dateRangeFilterViewModel.selectedValue = filter.dateRange productFilterViewModel.selectedValue = filter.product customerFilterViewModel.selectedValue = filter.customer + analytics.track(event: .FilterHistory.trackPastFilterApplied(source: source)) } func saveSelectedFilterToHistory(_ filter: Criteria) { @@ -148,6 +153,7 @@ final class FilterOrderListViewModel: FilterListViewModel { } func removeFilterFromHistory(_ filter: Criteria) { + analytics.track(event: .FilterHistory.trackPastFilterRemoved(source: source)) let settings = StoredOrderSettings.Setting(siteID: siteID, orderStatusesFilter: filter.orderStatus, dateRangeFilter: filter.dateRange, @@ -161,6 +167,7 @@ final class FilterOrderListViewModel: FilterListViewModel { } func clearAllFilterHistory() { + analytics.track(event: .FilterHistory.trackFilterHistoryCleared(source: source)) stores.dispatch(AppSettingsAction.resetOrderFilterHistory(siteID: siteID, onCompletion: { error in if let error { DDLogError("⛔️ Error clearing all filter history: \(error)")