Skip to content

Commit 39d7fdd

Browse files
authored
Merge pull request #5614 from woocommerce/issue/5406-order-creation-status-picker
Order Creation: Connect status picker
2 parents b66b823 + 21f1b75 commit 39d7fdd

File tree

9 files changed

+121
-31
lines changed

9 files changed

+121
-31
lines changed

WooCommerce/Classes/ViewRelated/Orders/Order Creation/AddOrderCoordinator.swift renamed to WooCommerce/Classes/ViewRelated/Orders/Order Creation/FlowCoordinator/AddOrderCoordinator.swift

File renamed without changes.

WooCommerce/Classes/ViewRelated/Orders/Order Creation/BottomSheetOrderType.swift renamed to WooCommerce/Classes/ViewRelated/Orders/Order Creation/FlowCoordinator/BottomSheetOrderType.swift

File renamed without changes.

WooCommerce/Classes/ViewRelated/Orders/Order Creation/NewOrderViewModel.swift

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import protocol Storage.StorageManagerType
55
/// View model for `NewOrder`.
66
///
77
final class NewOrderViewModel: ObservableObject {
8-
private let siteID: Int64
8+
let siteID: Int64
99
private let stores: StoresManager
1010
private let storageManager: StorageManagerType
1111

@@ -33,17 +33,13 @@ final class NewOrderViewModel: ObservableObject {
3333
DateFormatter.mediumLengthLocalizedDateFormatter.string(from: Date())
3434
}()
3535

36-
/// Order status data model.
36+
/// Representation of order status display properties.
3737
///
38-
private var orderStatus: OrderStatus {
39-
didSet {
40-
statusBadgeViewModel = .init(orderStatus: orderStatus)
41-
}
42-
}
38+
@Published private(set) var statusBadgeViewModel: StatusBadgeViewModel = .init(orderStatusEnum: .pending)
4339

44-
/// Representation of order status display properties.
40+
/// Indicates if the order status list (selector) should be shown or not.
4541
///
46-
@Published private(set) var statusBadgeViewModel: StatusBadgeViewModel
42+
@Published var shouldShowOrderStatusList: Bool = false
4743

4844
/// Status Results Controller.
4945
///
@@ -71,11 +67,9 @@ final class NewOrderViewModel: ObservableObject {
7167
self.siteID = siteID
7268
self.stores = stores
7369
self.storageManager = storageManager
74-
self.orderStatus = .init(name: nil, siteID: siteID, slug: "pending", total: 0)
75-
self.statusBadgeViewModel = .init(orderStatus: orderStatus)
7670

7771
configureNavigationTrailingItem()
78-
setInitialOrderStatus()
72+
configureStatusBadgeViewModel()
7973
}
8074

8175
// MARK: - API Requests
@@ -159,6 +153,11 @@ extension NewOrderViewModel {
159153
}
160154
}()
161155
}
156+
157+
init(orderStatusEnum: OrderStatusEnum) {
158+
let siteOrderStatus = OrderStatus(name: nil, siteID: 0, slug: orderStatusEnum.rawValue, total: 0)
159+
self.init(orderStatus: siteOrderStatus)
160+
}
162161
}
163162
}
164163

@@ -182,11 +181,16 @@ private extension NewOrderViewModel {
182181
.assign(to: &$navigationTrailingItem)
183182
}
184183

185-
func setInitialOrderStatus() {
186-
guard let pendingSiteStatus = currentSiteStatuses.first(where: { $0.status == .pending }) else {
187-
return
188-
}
189-
190-
orderStatus = pendingSiteStatus
184+
/// Updates status badge viewmodel based on status order property.
185+
///
186+
func configureStatusBadgeViewModel() {
187+
$orderDetails
188+
.map { [weak self] orderDetails in
189+
guard let siteOrderStatus = self?.currentSiteStatuses.first(where: { $0.status == orderDetails.status }) else {
190+
return StatusBadgeViewModel(orderStatusEnum: orderDetails.status)
191+
}
192+
return StatusBadgeViewModel(orderStatus: siteOrderStatus)
193+
}
194+
.assign(to: &$statusBadgeViewModel)
191195
}
192196
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import SwiftUI
2+
import Networking
3+
4+
/// `SwiftUI` wrapper for `OrderStatusListViewController`
5+
///
6+
struct OrderStatusList: UIViewControllerRepresentable {
7+
8+
let siteID: Int64
9+
10+
/// Preselected order status.
11+
///
12+
let status: OrderStatusEnum
13+
14+
/// Closure to be invoked when the status is updated.
15+
///
16+
var didSelectApply: ((OrderStatusEnum) -> Void)
17+
18+
func makeUIViewController(context: Context) -> WooNavigationController {
19+
let statusList = OrderStatusListViewController(siteID: siteID, status: status)
20+
21+
statusList.didSelectCancel = { [weak statusList] in
22+
statusList?.dismiss(animated: true, completion: nil)
23+
}
24+
25+
statusList.didSelectApply = { [weak statusList] selectedStatus in
26+
statusList?.dismiss(animated: true) {
27+
didSelectApply(selectedStatus)
28+
}
29+
}
30+
31+
let navigationController = WooNavigationController(rootViewController: statusList)
32+
return navigationController
33+
}
34+
35+
func updateUIViewController(_ uiViewController: WooNavigationController, context: Context) {
36+
// No-op
37+
}
38+
}

WooCommerce/Classes/ViewRelated/Orders/Order Creation/OrderStatusSection.swift renamed to WooCommerce/Classes/ViewRelated/Orders/Order Creation/StatusSection/OrderStatusSection.swift

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import SwiftUI
22
import Yosemite
33

4+
/// Represents the Status section with date label, status badge and edit button.
5+
///
46
struct OrderStatusSection: View {
57
let geometry: GeometryProxy
6-
let viewModel: NewOrderViewModel
8+
@ObservedObject var viewModel: NewOrderViewModel
79

810
var body: some View {
911
Divider()
@@ -20,11 +22,20 @@ struct OrderStatusSection: View {
2022
.padding(.vertical, Layout.StatusBadge.verticalPadding)
2123
.background(Color(viewModel.statusBadgeViewModel.color))
2224
.cornerRadius(Layout.StatusBadge.cornerRadius)
25+
2326
Spacer()
24-
Button(Localization.editButton) {}
25-
.buttonStyle(LinkButtonStyle())
26-
.fixedSize(horizontal: true, vertical: true)
27-
.padding(.trailing, -Layout.linkButtonTrailingPadding) // remove trailing padding to align button title to the side
27+
28+
Button(Localization.editButton) {
29+
viewModel.shouldShowOrderStatusList = true
30+
}
31+
.buttonStyle(LinkButtonStyle())
32+
.fixedSize(horizontal: true, vertical: true)
33+
.padding(.trailing, -Layout.linkButtonTrailingPadding) // remove trailing padding to align button title to the side
34+
.sheet(isPresented: $viewModel.shouldShowOrderStatusList) {
35+
OrderStatusList(siteID: viewModel.siteID, status: viewModel.orderDetails.status) { newStatus in
36+
viewModel.orderDetails.status = newStatus
37+
}
38+
}
2839
}
2940
}
3041
.padding(.horizontal, insets: geometry.safeAreaInsets)

WooCommerce/Classes/ViewRelated/Orders/Order Details/Order Summary Section/Edit Order Status/OrderStatusListViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ final class OrderStatusListViewController: UIViewController {
3131

3232
/// A closure to be called when this VC wants its creator to change the order status to the selected status and dismiss it.
3333
///
34-
var didSelectApply: ((OrderStatusEnum?) -> Void)?
34+
var didSelectApply: ((OrderStatusEnum) -> Void)?
3535

3636
init(siteID: Int64, status: OrderStatusEnum) {
3737
self.viewModel = OrderStatusListViewModel(status: status,

WooCommerce/Classes/ViewRelated/Orders/Order Details/OrderDetailsViewController.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -980,10 +980,7 @@ private extension OrderDetailsViewController {
980980
present(navigationController, animated: true)
981981
}
982982

983-
func setOrderStatus(to newStatus: OrderStatusEnum?) {
984-
guard let newStatus = newStatus else {
985-
return
986-
}
983+
func setOrderStatus(to newStatus: OrderStatusEnum) {
987984
let orderID = viewModel.order.orderID
988985
let undoStatus = viewModel.order.status
989986
let done = updateOrderStatusAction(siteID: viewModel.order.siteID, orderID: viewModel.order.orderID, status: newStatus)

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,7 @@
909909
AEA622B727468790002A9B57 /* AddOrderCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEA622B627468790002A9B57 /* AddOrderCoordinatorTests.swift */; };
910910
AEB73C0C25CD734200A8454A /* AttributePickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEB73C0B25CD734200A8454A /* AttributePickerViewModel.swift */; };
911911
AEB73C1725CD8E5800A8454A /* AttributePickerViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEB73C1625CD8E5800A8454A /* AttributePickerViewModelTests.swift */; };
912+
AEC12B7A2758D55900845F97 /* OrderStatusList.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEC12B792758D55900845F97 /* OrderStatusList.swift */; };
912913
AECD57D226DFDF7500A3B580 /* EditOrderAddressForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = AECD57D126DFDF7500A3B580 /* EditOrderAddressForm.swift */; };
913914
AEDDDA0A25CA9C980077F9B2 /* AttributePickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEDDDA0925CA9C980077F9B2 /* AttributePickerViewController.swift */; };
914915
AEDDDA1A25CAB2170077F9B2 /* AttributePickerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = AEDDDA1925CAB2170077F9B2 /* AttributePickerViewController.xib */; };
@@ -2387,6 +2388,7 @@
23872388
AEA622B627468790002A9B57 /* AddOrderCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddOrderCoordinatorTests.swift; sourceTree = "<group>"; };
23882389
AEB73C0B25CD734200A8454A /* AttributePickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributePickerViewModel.swift; sourceTree = "<group>"; };
23892390
AEB73C1625CD8E5800A8454A /* AttributePickerViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributePickerViewModelTests.swift; sourceTree = "<group>"; };
2391+
AEC12B792758D55900845F97 /* OrderStatusList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderStatusList.swift; sourceTree = "<group>"; };
23902392
AECD57D126DFDF7500A3B580 /* EditOrderAddressForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditOrderAddressForm.swift; sourceTree = "<group>"; };
23912393
AEDDDA0925CA9C980077F9B2 /* AttributePickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributePickerViewController.swift; sourceTree = "<group>"; };
23922394
AEDDDA1925CAB2170077F9B2 /* AttributePickerViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AttributePickerViewController.xib; sourceTree = "<group>"; };
@@ -5203,6 +5205,24 @@
52035205
path = ../config;
52045206
sourceTree = "<group>";
52055207
};
5208+
AE264C04275A493800B52996 /* StatusSection */ = {
5209+
isa = PBXGroup;
5210+
children = (
5211+
AE457812275644590092F687 /* OrderStatusSection.swift */,
5212+
AEC12B792758D55900845F97 /* OrderStatusList.swift */,
5213+
);
5214+
path = StatusSection;
5215+
sourceTree = "<group>";
5216+
};
5217+
AE264C05275A495E00B52996 /* FlowCoordinator */ = {
5218+
isa = PBXGroup;
5219+
children = (
5220+
AEA622B1274669D3002A9B57 /* AddOrderCoordinator.swift */,
5221+
AEA622B327466B78002A9B57 /* BottomSheetOrderType.swift */,
5222+
);
5223+
path = FlowCoordinator;
5224+
sourceTree = "<group>";
5225+
};
52065226
AEB73C1525CD8E3100A8454A /* Edit Product Variation */ = {
52075227
isa = PBXGroup;
52085228
children = (
@@ -6027,10 +6047,9 @@
60276047
children = (
60286048
CCFC50542743BC0D001E505F /* NewOrder.swift */,
60296049
CCFC50582743E021001E505F /* NewOrderViewModel.swift */,
6050+
AE264C05275A495E00B52996 /* FlowCoordinator */,
60306051
CC53FB3627551A8700C4CA4F /* ProductsSection */,
6031-
AEA622B327466B78002A9B57 /* BottomSheetOrderType.swift */,
6032-
AEA622B1274669D3002A9B57 /* AddOrderCoordinator.swift */,
6033-
AE457812275644590092F687 /* OrderStatusSection.swift */,
6052+
AE264C04275A493800B52996 /* StatusSection */,
60346053
);
60356054
path = "Order Creation";
60366055
sourceTree = "<group>";
@@ -7960,6 +7979,7 @@
79607979
02E8B17723E2C49000A43403 /* InProgressProductImageCollectionViewCell.swift in Sources */,
79617980
CE5F462C23AACBC4006B1A5C /* RefundDetailsResultController.swift in Sources */,
79627981
261AA309275178FA009530FE /* SimplePaymentsMethod.swift in Sources */,
7982+
AEC12B7A2758D55900845F97 /* OrderStatusList.swift in Sources */,
79637983
0230535B2374FB6800487A64 /* AztecSourceCodeFormatBarCommand.swift in Sources */,
79647984
D41C9F2E26D9A0E900993558 /* WhatsNewViewModel.swift in Sources */,
79657985
02ECD1E424FF5E0B00735BE5 /* AddProductCoordinator.swift in Sources */,

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,26 @@ class NewOrderViewModelTests: XCTestCase {
111111
// Then
112112
XCTAssertEqual(viewModel.statusBadgeViewModel.title, "pending")
113113
}
114+
115+
func test_view_model_is_updated_when_order_status_updated() {
116+
// Given
117+
let stores = MockStoresManager(sessionManager: .testingInstance)
118+
let storageManager = MockStorageManager()
119+
storageManager.insertOrderStatus(.init(name: "Pending payment", siteID: sampleSiteID, slug: "pending", total: 0))
120+
storageManager.insertOrderStatus(.init(name: "Processing", siteID: sampleSiteID, slug: "processing", total: 0))
121+
122+
// When
123+
let viewModel = NewOrderViewModel(siteID: sampleSiteID, stores: stores, storageManager: storageManager)
124+
125+
// Then
126+
XCTAssertEqual(viewModel.statusBadgeViewModel.title, "Pending payment")
127+
128+
// When
129+
viewModel.orderDetails.status = .processing
130+
131+
// Then
132+
XCTAssertEqual(viewModel.statusBadgeViewModel.title, "Processing")
133+
}
114134
}
115135

116136
private extension MockStorageManager {

0 commit comments

Comments
 (0)