Skip to content

Commit 7b9070f

Browse files
authored
Bookings: Update service/event filter to search by name only (#16306)
2 parents df2e5eb + 1414442 commit 7b9070f

File tree

8 files changed

+70
-19
lines changed

8 files changed

+70
-19
lines changed

Modules/Sources/Networking/Remote/ProductsRemote.swift

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public protocol ProductsRemoteProtocol {
2323
excludedProductIDs: [Int64]) async throws -> [Product]
2424
func searchProducts(for siteID: Int64,
2525
keyword: String,
26+
searchFields: [ProductSearchField],
2627
pageNumber: Int,
2728
pageSize: Int,
2829
stockStatus: ProductStockStatus?,
@@ -291,7 +292,7 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
291292
}
292293

293294
/// Remote search of products for the Point of Sale. Simple and variable products are loaded for WC version 9.6+, otherwise only simple products are loaded.
294-
/// `search` is used, which searches in `name`, `description`, `short_description` fields.
295+
/// `search` is used, which searches in `name`, `sku`, `globalUniqueID` fields.
295296
/// We also send `search_name_or_sku`, which will be used in preference to `search` when implemented on a site (in future.)
296297
///
297298
/// - Parameter siteID: Site for which we'll fetch remote products.
@@ -313,7 +314,11 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
313314
parameters.updateValue(query, forKey: ParameterKey.searchNameOrSKU)
314315

315316
// Takes precedence over `search_name_or_sku` from WC 10.1+ and is combined with `search` value
316-
parameters.updateValue([SearchField.name, SearchField.sku, SearchField.globalUniqueID], forKey: ParameterKey.searchFields)
317+
parameters.updateValue([
318+
ProductSearchField.name.rawValue,
319+
ProductSearchField.sku.rawValue,
320+
ProductSearchField.globalUniqueID.rawValue
321+
], forKey: ParameterKey.searchFields)
317322

318323
return try await makePagedPointOfSaleProductsRequest(
319324
for: siteID,
@@ -429,6 +434,7 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
429434
///
430435
public func searchProducts(for siteID: Int64,
431436
keyword: String,
437+
searchFields: [ProductSearchField],
432438
pageNumber: Int,
433439
pageSize: Int,
434440
stockStatus: ProductStockStatus? = nil,
@@ -447,10 +453,11 @@ public final class ProductsRemote: Remote, ProductsRemoteProtocol {
447453
ParameterKey.exclude: stringOfExcludedProductIDs
448454
].filter({ $0.value.isEmpty == false })
449455

450-
let parameters = [
456+
let parameters: [String: Any] = [
451457
ParameterKey.page: String(pageNumber),
452458
ParameterKey.perPage: String(pageSize),
453459
ParameterKey.search: keyword,
460+
ParameterKey.searchFields: searchFields.map { $0.rawValue },
454461
ParameterKey.exclude: stringOfExcludedProductIDs,
455462
ParameterKey.contextKey: Default.context
456463
].merging(filterParameters, uniquingKeysWith: { (first, _) in first })
@@ -774,12 +781,12 @@ public extension ProductsRemote {
774781
static let productSegment = "product"
775782
static let itemsSold = "items_sold"
776783
}
784+
}
777785

778-
private enum SearchField {
779-
static let name = "name"
780-
static let sku = "sku"
781-
static let globalUniqueID = "global_unique_id"
782-
}
786+
public enum ProductSearchField: String {
787+
case name
788+
case sku
789+
case globalUniqueID = "global_unique_id"
783790
}
784791

785792
private extension ProductsRemote {

Modules/Sources/Yosemite/Model/Products/ProductSearchFilter.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
public enum ProductSearchFilter: String, Equatable, CaseIterable {
55
/// Search for all products based on the keyword.
66
case all
7+
/// Search for products that match the name field.
8+
case name
79
/// Search for products that match the SKU field.
810
case sku
11+
12+
/// Options for searching in product selector view.
13+
/// `name` is omitted as it's used for bookable product filters only so far.
14+
public static var productSelectorOptions: [ProductSearchFilter] {
15+
[.all, .sku]
16+
}
917
}

Modules/Sources/Yosemite/Stores/ProductStore.swift

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -231,20 +231,27 @@ private extension ProductStore {
231231
productCategory: ProductCategory?,
232232
excludedProductIDs: [Int64],
233233
onCompletion: @escaping (Result<Bool, Error>) -> Void) {
234+
/// internal helper search method
235+
func searchProductsByKeyword(searchFields: [ProductSearchField]) async throws -> [Product] {
236+
try await remote.searchProducts(for: siteID,
237+
keyword: keyword,
238+
searchFields: searchFields,
239+
pageNumber: pageNumber,
240+
pageSize: pageSize,
241+
stockStatus: stockStatus,
242+
productStatus: productStatus,
243+
productType: productType,
244+
productCategory: productCategory,
245+
excludedProductIDs: excludedProductIDs)
246+
}
234247
Task { @MainActor in
235248
do {
236249
let products: [Product]
237250
switch filter {
238251
case .all:
239-
products = try await remote.searchProducts(for: siteID,
240-
keyword: keyword,
241-
pageNumber: pageNumber,
242-
pageSize: pageSize,
243-
stockStatus: stockStatus,
244-
productStatus: productStatus,
245-
productType: productType,
246-
productCategory: productCategory,
247-
excludedProductIDs: excludedProductIDs)
252+
products = try await searchProductsByKeyword(searchFields: [])
253+
case .name:
254+
products = try await searchProductsByKeyword(searchFields: [.name])
248255
case .sku:
249256
products = try await remote.searchProductsBySKU(for: siteID,
250257
keyword: keyword,

Modules/Tests/NetworkingTests/Remote/ProductsRemoteTests.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ final class ProductsRemoteTests: XCTestCase {
458458
// When
459459
let products = try await remote.searchProducts(for: sampleSiteID,
460460
keyword: "photo",
461+
searchFields: [],
461462
pageNumber: 0,
462463
pageSize: 100)
463464

@@ -475,6 +476,7 @@ final class ProductsRemoteTests: XCTestCase {
475476
do {
476477
_ = try await remote.searchProducts(for: sampleSiteID,
477478
keyword: String(),
479+
searchFields: [],
478480
pageNumber: 0,
479481
pageSize: 100)
480482
XCTFail("Expected error to be thrown")
@@ -483,6 +485,26 @@ final class ProductsRemoteTests: XCTestCase {
483485
}
484486
}
485487

488+
/// Verifies that searchProducts with name search field includes the search_fields param in network request.
489+
///
490+
func test_searchProducts_with_name_search_field_includes_search_fields_param_in_network_request() async throws {
491+
// Given
492+
let remote = ProductsRemote(network: network)
493+
network.simulateResponse(requestUrlSuffix: "products", filename: "products-search-photo")
494+
495+
// When
496+
_ = try await remote.searchProducts(for: sampleSiteID,
497+
keyword: "test",
498+
searchFields: [.name],
499+
pageNumber: 0,
500+
pageSize: 100)
501+
502+
// Then
503+
let queryParameters = try XCTUnwrap(network.queryParameters)
504+
let expectedParam = "search_fields=[\"name\"]"
505+
XCTAssertTrue(queryParameters.contains(expectedParam), "Expected to have param: \(expectedParam)")
506+
}
507+
486508
// MARK: - Search Products by SKU
487509

488510
func test_searchProductsBySKU_properly_returns_parsed_products() async throws {

Modules/Tests/YosemiteTests/Mocks/Networking/Remote/MockProductsRemote.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ extension MockProductsRemote: ProductsRemoteProtocol {
286286

287287
func searchProducts(for siteID: Int64,
288288
keyword: String,
289+
searchFields: [ProductSearchField],
289290
pageNumber: Int,
290291
pageSize: Int,
291292
stockStatus: ProductStockStatus?,

WooCommerce/Classes/Bookings/BookingFilters/BookableProductListSyncable.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ struct BookableProductListSyncable: ListSyncable {
6060
ProductAction.searchProducts(
6161
siteID: siteID,
6262
keyword: keyword,
63+
filter: .name,
6364
pageNumber: pageNumber,
6465
pageSize: pageSize,
6566
productType: .booking,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ private extension ProductSelectorView {
336336
.submitLabel(.done)
337337
.accessibilityIdentifier("product-selector-search-bar")
338338
Picker(selection: $viewModel.productSearchFilter, label: EmptyView()) {
339-
ForEach(ProductSearchFilter.allCases, id: \.self) { option in Text(option.title) }
339+
ForEach(ProductSearchFilter.productSelectorOptions, id: \.self) { option in Text(option.title) }
340340
}
341341
.if(geometry.size.width <= Constants.headerSearchRowWidth) { $0.pickerStyle(.menu) }
342342
.if(geometry.size.width > Constants.headerSearchRowWidth) { $0.pickerStyle(.segmented) }

WooCommerce/Classes/ViewRelated/Search/Product/ProductSearchUICommand.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,22 +200,27 @@ private extension ProductSearchUICommand {
200200
}
201201

202202
extension ProductSearchFilter {
203+
/// The title of the option on the picker of product selector view.
203204
var title: String {
204205
switch self {
205206
case .all:
206207
return NSLocalizedString("All Products", comment: "Title of the product search filter to search for all products.")
207208
case .sku:
208209
return NSLocalizedString("SKU", comment: "Title of the product search filter to search for products that match the SKU.")
210+
case .name:
211+
fatalError("This option is not supported on the product selector UI")
209212
}
210213
}
211214

212-
/// The value that is set in the analytics event property.
215+
/// The value that is set in the analytics event property when selecting the option on the product selector view.
213216
var analyticsValue: String {
214217
switch self {
215218
case .all:
216219
return "all"
217220
case .sku:
218221
return "sku"
222+
case .name:
223+
fatalError("This option is not supported on the product selector UI")
219224
}
220225
}
221226
}

0 commit comments

Comments
 (0)