Skip to content

Commit c95a36e

Browse files
authored
Merge pull request #7764 from woocommerce/issue/7741-implement-loadCustomer-action
Add CustomerStore and support for loadCustomer action
2 parents 7b8a062 + e7cbe30 commit c95a36e

File tree

12 files changed

+204
-3
lines changed

12 files changed

+204
-3
lines changed

Networking/Networking/Remote/CustomerRemote.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ public class CustomerRemote: Remote {
88
/// - siteID: Site for which we'll fetch the customer.
99
/// - completion: Closure to be executed upon completion.
1010
///
11-
func retrieveCustomer(for siteID: Int64, with customerID: Int64, completion: @escaping (Result<Customer, Error>) -> Void) {
12-
let path = "/customers/\(customerID)"
11+
public func retrieveCustomer(for siteID: Int64, with customerID: Int64, completion: @escaping (Result<Customer, Error>) -> Void) {
12+
let path = "customers/\(customerID)"
1313
let request = JetpackRequest(wooApiVersion: .mark3,
1414
method: .get,
1515
siteID: siteID,

WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CreateOrderAddressFormViewModel.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ final class CreateOrderAddressFormViewModel: AddressFormViewModel, AddressFormVi
7474
Localization.differentAddressToggleTitle
7575
}
7676

77+
var siteID: Int64 {
78+
stores.sessionManager.defaultStoreID ?? Int64.min
79+
}
80+
7781
func saveAddress(onFinish: @escaping (Bool) -> Void) {
7882
guard validateEmail() else {
7983
notice = AddressFormViewModel.NoticeFactory.createInvalidEmailNotice()
@@ -93,6 +97,24 @@ final class CreateOrderAddressFormViewModel: AddressFormViewModel, AddressFormVi
9397
override func trackOnLoad() { }
9498

9599
func userDidCancelFlow() { }
100+
101+
/// Dispatches the retrieveCustomer action when the Search button is tapped
102+
/// customerID is temporary until we implement that part of the feature:
103+
/// https://github.com/woocommerce/woocommerce-ios/issues/7741
104+
///
105+
func customerSearchTapped() {
106+
let action = CustomerAction.retrieveCustomer(
107+
siteID: siteID,
108+
customerID: 1) { result in
109+
switch result {
110+
case .success(let data):
111+
print(data)
112+
case .failure(let error):
113+
print(error)
114+
}
115+
}
116+
stores.dispatch(action)
117+
}
96118
}
97119

98120
private extension CreateOrderAddressFormViewModel {

WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressFormViewModelProtocol.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ protocol AddressFormViewModelProtocol: ObservableObject {
9999
/// Creates a view model to be used when selecting a state for secondary fields
100100
///
101101
func createSecondaryStateViewModel() -> StateSelectorViewModel
102+
103+
/// Callback method when the Customer Search button is tapped
104+
///
105+
func customerSearchTapped()
102106
}
103107

104108
/// Type to hold values from all the form fields

WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/EditOrderAddressForm.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Combine
22
import SwiftUI
33
import UIKit
44
import Yosemite
5+
import Experiments
56

67
/// Hosting controller that wraps an `EditOrderAddressForm`.
78
///
@@ -89,6 +90,8 @@ struct EditOrderAddressForm<ViewModel: AddressFormViewModelProtocol>: View {
8990

9091
@Environment(\.safeAreaInsets) var safeAreaInsets: EdgeInsets
9192

93+
let isSearchCustomersEnabled = DefaultFeatureFlagService().isFeatureFlagEnabled(.orderCreationSearchCustomers)
94+
9295
var body: some View {
9396
Group {
9497
ScrollView {
@@ -146,6 +149,15 @@ struct EditOrderAddressForm<ViewModel: AddressFormViewModelProtocol>: View {
146149
viewModel.userDidCancelFlow()
147150
})
148151
}
152+
ToolbarItem(placement: .automatic) {
153+
if isSearchCustomersEnabled {
154+
Button(action: {
155+
viewModel.customerSearchTapped()
156+
}, label: {
157+
Image(systemName: "magnifyingglass")
158+
})
159+
}
160+
}
149161
ToolbarItem(placement: .confirmationAction) {
150162
navigationBarTrailingItem()
151163
}

WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/EditOrderAddressFormViewModel.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ final class EditOrderAddressFormViewModel: AddressFormViewModel, AddressFormView
161161
func userDidCancelFlow() {
162162
analytics.track(event: WooAnalyticsEvent.OrderDetailsEdit.orderDetailEditFlowCanceled(subject: self.analyticsFlowType()))
163163
}
164+
165+
func customerSearchTapped() {}
164166
}
165167

166168
extension EditOrderAddressFormViewModel {

WooCommerce/Classes/Yosemite/AuthenticatedState.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class AuthenticatedState: StoresManagerState {
3535
AddOnGroupStore(dispatcher: dispatcher, storageManager: storageManager, network: network),
3636
CommentStore(dispatcher: dispatcher, storageManager: storageManager, network: network),
3737
CouponStore(dispatcher: dispatcher, storageManager: storageManager, network: network),
38+
CustomerStore(dispatcher: dispatcher, storageManager: storageManager, network: network),
3839
DataStore(dispatcher: dispatcher, storageManager: storageManager, network: network),
3940
InboxNotesStore(dispatcher: dispatcher, storageManager: storageManager, network: network),
4041
MediaStore(dispatcher: dispatcher, storageManager: storageManager, network: network),

Yosemite/Yosemite.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,10 @@
212212
578CE7942475F52F00492EBF /* MockNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 578CE7932475F52F00492EBF /* MockNote.swift */; };
213213
578CE7972475FD8200492EBF /* MockProductReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 578CE7962475FD8200492EBF /* MockProductReview.swift */; };
214214
57DFCC7925003C4000251E0C /* FetchResultSnapshotsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57DFCC7825003C4000251E0C /* FetchResultSnapshotsProvider.swift */; };
215+
681D952B28E0F62B00C4039E /* CustomerAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 681D952A28E0F62B00C4039E /* CustomerAction.swift */; };
215216
689D11D52891B9A400F6A83F /* WooFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 689D11D42891B9A400F6A83F /* WooFoundation.framework */; };
217+
68BD37B528DB2E9800C2A517 /* CustomerStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68BD37B428DB2E9800C2A517 /* CustomerStore.swift */; };
218+
68BD37B928DB323D00C2A517 /* CustomerStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68BD37B828DB323D00C2A517 /* CustomerStoreTests.swift */; };
216219
741F34802195EA62005F5BD9 /* CommentAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 741F347F2195EA62005F5BD9 /* CommentAction.swift */; };
217220
741F34822195EA71005F5BD9 /* CommentStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 741F34812195EA71005F5BD9 /* CommentStore.swift */; };
218221
741F34842195F752005F5BD9 /* CommentStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 741F34832195F752005F5BD9 /* CommentStoreTests.swift */; };
@@ -609,7 +612,10 @@
609612
578CE7962475FD8200492EBF /* MockProductReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProductReview.swift; sourceTree = "<group>"; };
610613
57DFCC7825003C4000251E0C /* FetchResultSnapshotsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchResultSnapshotsProvider.swift; sourceTree = "<group>"; };
611614
585B973F61632665297738A3 /* Pods-Yosemite.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Yosemite.release-alpha.xcconfig"; path = "../Pods/Target Support Files/Pods-Yosemite/Pods-Yosemite.release-alpha.xcconfig"; sourceTree = "<group>"; };
615+
681D952A28E0F62B00C4039E /* CustomerAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerAction.swift; sourceTree = "<group>"; };
612616
689D11D42891B9A400F6A83F /* WooFoundation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = WooFoundation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
617+
68BD37B428DB2E9800C2A517 /* CustomerStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerStore.swift; sourceTree = "<group>"; };
618+
68BD37B828DB323D00C2A517 /* CustomerStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerStoreTests.swift; sourceTree = "<group>"; };
613619
741F347F2195EA62005F5BD9 /* CommentAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentAction.swift; sourceTree = "<group>"; };
614620
741F34812195EA71005F5BD9 /* CommentStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentStore.swift; sourceTree = "<group>"; };
615621
741F34832195F752005F5BD9 /* CommentStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentStoreTests.swift; sourceTree = "<group>"; };
@@ -1360,6 +1366,7 @@
13601366
FE28F6EF26844231004465C7 /* UserStore.swift */,
13611367
B9AECD3B2850F3C600E78584 /* OrderCardPresentPaymentEligibilityStore.swift */,
13621368
DE3404FD28BC5F4200CF0D97 /* JetpackConnectionStore.swift */,
1369+
68BD37B428DB2E9800C2A517 /* CustomerStore.swift */,
13631370
);
13641371
path = Stores;
13651372
sourceTree = "<group>";
@@ -1416,6 +1423,7 @@
14161423
FE28F6F1268462A6004465C7 /* UserStoreTests.swift */,
14171424
D4CBAE5B26D401BC00BBE6D1 /* AnnouncementsStoreTests.swift */,
14181425
DE50296628C7114800551736 /* JetpackConnectionStoreTests.swift */,
1426+
68BD37B828DB323D00C2A517 /* CustomerStoreTests.swift */,
14191427
);
14201428
path = Stores;
14211429
sourceTree = "<group>";
@@ -1566,6 +1574,7 @@
15661574
D83B093425DECFCC00B21F45 /* CardPresentPaymentAction.swift */,
15671575
741F347F2195EA62005F5BD9 /* CommentAction.swift */,
15681576
03FBDA212631521100ACE257 /* CouponAction.swift */,
1577+
681D952A28E0F62B00C4039E /* CustomerAction.swift */,
15691578
45E462112684C7A400011BF2 /* DataAction.swift */,
15701579
45151A8E27B156E40080845F /* InboxNotesAction.swift */,
15711580
02FF056223DE9C490058E6E7 /* MediaAction.swift */,
@@ -1866,6 +1875,7 @@
18661875
74685D4E20F7EFA7008958C1 /* OrderItem+ReadOnlyConvertible.swift in Sources */,
18671876
7471401121877668009A11CC /* NotificationAction.swift in Sources */,
18681877
266503512620E2EB0079A159 /* ProductAddOn+ReadOnlyConvertible.swift in Sources */,
1878+
681D952B28E0F62B00C4039E /* CustomerAction.swift in Sources */,
18691879
45182D2127B5533400B4C05C /* InboxAction+ReadOnlyConvertible.swift in Sources */,
18701880
453305F9245AE6B200264E50 /* SitePostAction.swift in Sources */,
18711881
CE4FD4522350FB5400A16B31 /* OrderItemTaxRefund+ReadOnlyConvertible.swift in Sources */,
@@ -2065,6 +2075,7 @@
20652075
7499936420EFBC1B00CF01CD /* OrderNoteAction.swift in Sources */,
20662076
7455D4692141B59E00FA8C1F /* TopEarnerStatsItem+ReadOnlyConvertible.swift in Sources */,
20672077
D8C11A5222DF2DA200D4A88D /* StatsActionV4.swift in Sources */,
2078+
68BD37B528DB2E9800C2A517 /* CustomerStore.swift in Sources */,
20682079
CE179D55235F4E1700C24EB3 /* RefundAction.swift in Sources */,
20692080
CE5F9A7A22B2D455001755E8 /* Array+Helpers.swift in Sources */,
20702081
031C1EB027B1879C00298699 /* WCPayCardPaymentDetails+ReadOnlyConvertible.swift in Sources */,
@@ -2175,6 +2186,7 @@
21752186
B5C9DE282087FF20006B910A /* MockSiteStore.swift in Sources */,
21762187
FEEB2F5F268A1C5E0075A6E0 /* User+RolesTests.swift in Sources */,
21772188
B5BC736820D1AA8F00B5B6FA /* AccountStoreTests.swift in Sources */,
2189+
68BD37B928DB323D00C2A517 /* CustomerStoreTests.swift in Sources */,
21782190
DE50296728C7114800551736 /* JetpackConnectionStoreTests.swift in Sources */,
21792191
0212AC67242C799B00C51F6C /* ResultsController+StorageProductTests.swift in Sources */,
21802192
D4CBAE6026D440FA00BBE6D1 /* MockAnnouncementsRemote.swift in Sources */,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Foundation
2+
3+
/// Defines the `actions` supported by the `CustomerStore`.
4+
///
5+
public enum CustomerAction: Action {
6+
7+
/// Retrieves a single Customer from a site
8+
///
9+
///- `siteID`: The site for which customers should be fetched.
10+
///- `customerID`: ID of the Customer to be fetched.
11+
///- `onCompletion`: Invoked when the operation finishes.
12+
/// - `result.success(Customer)`: The Customer object
13+
/// - `result.failure(Error)`: Error fetching Customer
14+
case retrieveCustomer(
15+
siteID: Int64,
16+
customerID: Int64,
17+
onCompletion: (Result<Customer, Error>) -> Void)
18+
}

Yosemite/Yosemite/Model/Model.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public typealias CouponReport = Networking.CouponReport
2121
public typealias Country = Networking.Country
2222
public typealias Credentials = Networking.Credentials
2323
public typealias CreateProductVariation = Networking.CreateProductVariation
24+
public typealias Customer = Networking.Customer
2425
public typealias DotcomDevice = Networking.DotcomDevice
2526
public typealias DotcomUser = Networking.DotcomUser
2627
public typealias Feature = WordPressKit.Feature
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import Foundation
2+
import Networking
3+
import Storage
4+
5+
public final class CustomerStore: Store {
6+
7+
private let remote: CustomerRemote
8+
9+
init(dispatcher: Dispatcher,
10+
storageManager: StorageManagerType,
11+
network: Network,
12+
remote: CustomerRemote) {
13+
self.remote = remote
14+
super.init(dispatcher: dispatcher, storageManager: storageManager, network: network)
15+
}
16+
17+
public override convenience init(dispatcher: Dispatcher,
18+
storageManager: StorageManagerType,
19+
network: Network) {
20+
self.init(dispatcher: dispatcher,
21+
storageManager: storageManager,
22+
network: network,
23+
remote: CustomerRemote(network: network))
24+
}
25+
26+
/// Registers for supported Actions.
27+
///
28+
override public func registerSupportedActions(in dispatcher: Dispatcher) {
29+
dispatcher.register(processor: self, for: CustomerAction.self)
30+
}
31+
32+
/// Receives and executes Actions.
33+
/// - Parameters:
34+
/// - action: An action to handle. Must be a `CustomerAction`
35+
///
36+
override public func onAction(_ action: Action) {
37+
guard let action = action as? CustomerAction else {
38+
assertionFailure("CustomerStore received an unsupported action")
39+
return
40+
}
41+
switch action {
42+
case .retrieveCustomer(siteID: let siteID, customerID: let customerID, onCompletion: let onCompletion):
43+
retrieveCustomer(for: siteID, with: customerID, onCompletion: onCompletion)
44+
}
45+
}
46+
47+
/// Attempts to retrieve a single Customer from a site, returning the Customer object upon success, or an Error.
48+
/// - Parameters:
49+
/// - siteID: The site for which customers should be fetched.
50+
/// - customerID: ID of the Customer to be fetched.
51+
/// - onCompletion: Invoked when the operation finishes.
52+
///
53+
func retrieveCustomer(
54+
for siteID: Int64,
55+
with customerID: Int64,
56+
onCompletion: @escaping (Result<Customer, Error>) -> Void) {
57+
remote.retrieveCustomer(for: siteID, with: customerID) { result in
58+
switch result {
59+
case .failure(let error):
60+
onCompletion(.failure(error))
61+
case .success(let customer):
62+
onCompletion(.success(customer))
63+
}
64+
}
65+
}
66+
}

0 commit comments

Comments
 (0)