Skip to content

Commit 8845741

Browse files
Product Selector - Reset filters after completing selection or dismissal (#14764)
2 parents 29d1a49 + 1280bdd commit 8845741

File tree

6 files changed

+152
-1
lines changed

6 files changed

+152
-1
lines changed

Fakes/Fakes/Networking.generated.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,6 +2369,21 @@ extension Networking.StoredProductSettings {
23692369
)
23702370
}
23712371
}
2372+
extension Networking.StoredProductSettings.Setting {
2373+
/// Returns a "ready to use" type filled with fake values.
2374+
///
2375+
public static func fake() -> Networking.StoredProductSettings.Setting {
2376+
.init(
2377+
siteID: .fake(),
2378+
sort: .fake(),
2379+
stockStatusFilter: .fake(),
2380+
productStatusFilter: .fake(),
2381+
productTypeFilter: .fake(),
2382+
productCategoryFilter: .fake(),
2383+
favoriteProduct: .fake()
2384+
)
2385+
}
2386+
}
23722387
extension Networking.Subscription {
23732388
/// Returns a "ready to use" type filled with fake values.
23742389
///

Networking/Networking/Model/Copiable/Models+Copiable.generated.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3502,6 +3502,36 @@ extension Networking.SiteVisitStatsItem {
35023502
}
35033503
}
35043504

3505+
extension Networking.StoredProductSettings.Setting {
3506+
public func copy(
3507+
siteID: CopiableProp<Int64> = .copy,
3508+
sort: NullableCopiableProp<String> = .copy,
3509+
stockStatusFilter: NullableCopiableProp<ProductStockStatus> = .copy,
3510+
productStatusFilter: NullableCopiableProp<ProductStatus> = .copy,
3511+
productTypeFilter: NullableCopiableProp<ProductType> = .copy,
3512+
productCategoryFilter: NullableCopiableProp<ProductCategory> = .copy,
3513+
favoriteProduct: CopiableProp<Bool> = .copy
3514+
) -> Networking.StoredProductSettings.Setting {
3515+
let siteID = siteID ?? self.siteID
3516+
let sort = sort ?? self.sort
3517+
let stockStatusFilter = stockStatusFilter ?? self.stockStatusFilter
3518+
let productStatusFilter = productStatusFilter ?? self.productStatusFilter
3519+
let productTypeFilter = productTypeFilter ?? self.productTypeFilter
3520+
let productCategoryFilter = productCategoryFilter ?? self.productCategoryFilter
3521+
let favoriteProduct = favoriteProduct ?? self.favoriteProduct
3522+
3523+
return Networking.StoredProductSettings.Setting(
3524+
siteID: siteID,
3525+
sort: sort,
3526+
stockStatusFilter: stockStatusFilter,
3527+
productStatusFilter: productStatusFilter,
3528+
productTypeFilter: productTypeFilter,
3529+
productCategoryFilter: productCategoryFilter,
3530+
favoriteProduct: favoriteProduct
3531+
)
3532+
}
3533+
}
3534+
35053535
extension Networking.Subscription {
35063536
public func copy(
35073537
siteID: CopiableProp<Int64> = .copy,

Networking/Networking/Model/Product/StoredProductSettings.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Codegen
66
///
77
public struct StoredProductSettings: Codable, Equatable, GeneratedFakeable {
88

9-
public struct Setting: Codable, Equatable {
9+
public struct Setting: Codable, Equatable, GeneratedFakeable, GeneratedCopiable {
1010
public let siteID: Int64
1111
public let sort: String?
1212
public let stockStatusFilter: ProductStockStatus?

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- [*] Improved image loading in Blaze Campaign Creation: displays a redacted and shimmering effects when loading product image and falls back to a placeholder if no image is available. [https://github.com/woocommerce/woocommerce-ios/pull/15098]
99
- [*] Product List: Display syncing animation on items with image upload in progress [https://github.com/woocommerce/woocommerce-ios/pull/15052]
1010
- [*] Background image upload: Fix missing error notice in iPhones [https://github.com/woocommerce/woocommerce-ios/pull/15117]
11+
- [*] Filters applied in product selector no longer affect the main product list screen. [https://github.com/woocommerce/woocommerce-ios/pull/14764]
1112

1213
21.7
1314
-----

WooCommerce/Classes/ViewRelated/Products/ProductSelector/ProductSelectorViewModel.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,12 +473,14 @@ final class ProductSelectorViewModel: ObservableObject {
473473
func completeMultipleSelection() {
474474
tracker.trackConfirmButtonTapped(with: selectedItemsIDs.count)
475475
onMultipleSelectionCompleted?(selectedItemsIDs)
476+
resetFiltersUsingLocalProductsSettings()
476477
}
477478

478479
/// Triggers completion closure when the close button is tapped
479480
///
480481
func closeButtonTapped() {
481482
onCloseButtonTapped?()
483+
resetFiltersUsingLocalProductsSettings()
482484
}
483485

484486
/// Unselect all items.
@@ -873,6 +875,33 @@ private extension ProductSelectorViewModel {
873875
}
874876
}
875877

878+
// MARK: - Reset filters
879+
private extension ProductSelectorViewModel {
880+
/// The filters applied in product selector will fire the storage closure callback in the main product list screen.
881+
/// Resetting filters from local products settings helps to show the correct products in the main product list screen.
882+
///
883+
func resetFiltersUsingLocalProductsSettings() {
884+
let action = AppSettingsAction.loadProductsSettings(siteID: siteID) { [weak self] (result) in
885+
guard let self else { return }
886+
887+
switch result {
888+
case .success(let settings):
889+
let promotableProductType = settings.productTypeFilter.map { PromotableProductType(productType: $0, isAvailable: true, promoteUrl: nil) }
890+
let filters = FilterProductListViewModel.Filters(stockStatus: settings.stockStatusFilter,
891+
productStatus: settings.productStatusFilter,
892+
promotableProductType: promotableProductType,
893+
productCategory: settings.productCategoryFilter,
894+
favoriteProduct: settings.favoriteProduct ? FavoriteProductsFilter() : nil,
895+
numberOfActiveFilters: settings.numberOfActiveFilters())
896+
self.updateFilters(filters)
897+
case let .failure(error):
898+
DDLogError("⛔️ Error loading product settings: \(error)")
899+
}
900+
}
901+
stores.dispatch(action)
902+
}
903+
}
904+
876905
// MARK: - Utils
877906
extension ProductSelectorViewModel {
878907
/// Represents possible statuses for syncing products

WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Creation/ProductSelectorViewModelTests.swift

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,6 +1634,82 @@ final class ProductSelectorViewModelTests: XCTestCase {
16341634
// Then
16351635
XCTAssertEqual(viewModel.favoriteProductIDs, sampleProductIDs)
16361636
}
1637+
1638+
// MARK: - Resetting filters
1639+
1640+
func test_it_resets_filters_when_tapping_close_button() {
1641+
// Given
1642+
let viewModel = ProductSelectorViewModel(siteID: sampleSiteID,
1643+
source: .orderForm(flow: .creation),
1644+
storageManager: storageManager,
1645+
stores: stores)
1646+
1647+
let filters = FilterProductListViewModel.Filters(
1648+
stockStatus: .outOfStock,
1649+
productStatus: .draft,
1650+
promotableProductType: PromotableProductType(productType: .simple, isAvailable: true, promoteUrl: nil),
1651+
productCategory: nil,
1652+
favoriteProduct: FavoriteProductsFilter(),
1653+
numberOfActiveFilters: 4)
1654+
1655+
viewModel.searchTerm = "shirt"
1656+
viewModel.updateFilters(filters)
1657+
1658+
stores.whenReceivingAction(ofType: AppSettingsAction.self) { action in
1659+
switch action {
1660+
case let .loadProductsSettings(siteID, onCompletion):
1661+
onCompletion(.success(.fake().copy(siteID: siteID, stockStatusFilter: .inStock)))
1662+
default:
1663+
XCTFail("Unsupported Action")
1664+
}
1665+
}
1666+
1667+
// Confidence check
1668+
XCTAssertEqual(viewModel.filterListViewModel.criteria.stockStatus, .outOfStock)
1669+
1670+
// When
1671+
viewModel.closeButtonTapped()
1672+
1673+
// Then
1674+
XCTAssertEqual(viewModel.filterListViewModel.criteria.stockStatus, .inStock)
1675+
}
1676+
1677+
func test_it_resets_filters_when_completing_selection() {
1678+
// Given
1679+
let viewModel = ProductSelectorViewModel(siteID: sampleSiteID,
1680+
source: .orderForm(flow: .creation),
1681+
storageManager: storageManager,
1682+
stores: stores)
1683+
1684+
let filters = FilterProductListViewModel.Filters(
1685+
stockStatus: .outOfStock,
1686+
productStatus: .draft,
1687+
promotableProductType: PromotableProductType(productType: .simple, isAvailable: true, promoteUrl: nil),
1688+
productCategory: nil,
1689+
favoriteProduct: FavoriteProductsFilter(),
1690+
numberOfActiveFilters: 4)
1691+
1692+
viewModel.searchTerm = "shirt"
1693+
viewModel.updateFilters(filters)
1694+
1695+
stores.whenReceivingAction(ofType: AppSettingsAction.self) { action in
1696+
switch action {
1697+
case let .loadProductsSettings(siteID, onCompletion):
1698+
onCompletion(.success(.fake().copy(siteID: siteID, stockStatusFilter: .inStock)))
1699+
default:
1700+
XCTFail("Unsupported Action")
1701+
}
1702+
}
1703+
1704+
// Confidence check
1705+
XCTAssertEqual(viewModel.filterListViewModel.criteria.stockStatus, .outOfStock)
1706+
1707+
// When
1708+
viewModel.completeMultipleSelection()
1709+
1710+
// Then
1711+
XCTAssertEqual(viewModel.filterListViewModel.criteria.stockStatus, .inStock)
1712+
}
16371713
}
16381714

16391715
// MARK: - Utils

0 commit comments

Comments
 (0)