Skip to content

Commit 2e11852

Browse files
committed
Handle package confirm in packages form
1 parent aef95f8 commit 2e11852

File tree

4 files changed

+76
-8
lines changed

4 files changed

+76
-8
lines changed

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/Create Shipping Label Form/Package Details/Multi-package/ShippingLabelPackageItemViewModel.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ final class ShippingLabelPackageItemViewModel: ObservableObject {
3737
}
3838
}
3939

40+
/// Attributes of the package if validated.
41+
///
42+
var validatedPackageAttributes: ShippingLabelPackageAttributes? {
43+
guard validateTotalWeight(totalWeight) else {
44+
return nil
45+
}
46+
return ShippingLabelPackageAttributes(packageID: selectedPackageID,
47+
totalWeight: totalWeight,
48+
productIDs: orderItems.map { $0.productOrVariationID })
49+
}
50+
4051
private let order: Order
4152
private let orderItems: [OrderItem]
4253
private let currency: String

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/Create Shipping Label Form/Package Details/Multi-package/ShippingLabelPackagesForm.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ struct ShippingLabelPackagesForm: View {
2727
.navigationBarItems(trailing: Button(action: {
2828
ServiceLocator.analytics.track(.shippingLabelPurchaseFlow,
2929
withProperties: ["state": "packages_selected"])
30-
// TODO-4599: Update selection
30+
viewModel.confirmPackageSelection()
3131
presentation.wrappedValue.dismiss()
3232
}, label: {
3333
Text(Localization.doneButton)
34-
}))
34+
})
35+
.disabled(!viewModel.doneButtonEnabled))
3536
}
3637
}
3738

@@ -51,7 +52,7 @@ struct ShippingLabelPackagesForm_Previews: PreviewProvider {
5152
static var previews: some View {
5253
let viewModel = ShippingLabelPackagesFormViewModel(order: ShippingLabelPackagesFormViewModel.sampleOrder(),
5354
packagesResponse: ShippingLabelPackagesFormViewModel.samplePackageDetails(),
54-
selectedPackages: [])
55+
selectedPackages: []) { _ in }
5556

5657
ShippingLabelPackagesForm(viewModel: viewModel)
5758
.environment(\.colorScheme, .light)

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/Create Shipping Label Form/Package Details/Multi-package/ShippingLabelPackagesFormViewModel.swift

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ import protocol Storage.StorageManagerType
99
///
1010
final class ShippingLabelPackagesFormViewModel: ObservableObject {
1111

12+
/// Completion callback
13+
///
14+
typealias Completion = (_ selectedPackages: [ShippingLabelPackageAttributes]) -> Void
15+
1216
var foundMultiplePackages: Bool {
1317
selectedPackages.count > 1
1418
}
@@ -17,13 +21,34 @@ final class ShippingLabelPackagesFormViewModel: ObservableObject {
1721
///
1822
@Published private(set) var itemViewModels: [ShippingLabelPackageItemViewModel] = []
1923

24+
/// Whether Done button on Package Details screen should be enabled.
25+
///
26+
@Published private(set) var doneButtonEnabled: Bool = false
27+
2028
private let order: Order
2129
private let stores: StoresManager
2230
private let storageManager: StorageManagerType
2331
private var resultsControllers: ShippingLabelPackageDetailsResultsControllers?
32+
private let onCompletion: Completion
2433

2534
private var cancellables: Set<AnyCancellable> = []
2635

36+
/// Validation states of all items.
37+
///
38+
private var packagesValidation: [String: Bool] = [:] {
39+
didSet {
40+
configureDoneButton()
41+
}
42+
}
43+
44+
/// List of packages that are validated.
45+
///
46+
private var validatedPackages: [ShippingLabelPackageAttributes] {
47+
itemViewModels.compactMap {
48+
$0.validatedPackageAttributes
49+
}
50+
}
51+
2752
/// List of selected package with basic info.
2853
///
2954
@Published private var selectedPackages: [ShippingLabelPackageAttributes] = []
@@ -39,6 +64,7 @@ final class ShippingLabelPackagesFormViewModel: ObservableObject {
3964
init(order: Order,
4065
packagesResponse: ShippingLabelPackagesResponse?,
4166
selectedPackages: [ShippingLabelPackageAttributes],
67+
onCompletion: @escaping Completion,
4268
formatter: CurrencyFormatter = CurrencyFormatter(currencySettings: ServiceLocator.currencySettings),
4369
stores: StoresManager = ServiceLocator.stores,
4470
storageManager: StorageManagerType = ServiceLocator.storageManager,
@@ -47,6 +73,7 @@ final class ShippingLabelPackagesFormViewModel: ObservableObject {
4773
self.stores = stores
4874
self.storageManager = storageManager
4975
self.selectedPackages = selectedPackages
76+
self.onCompletion = onCompletion
5077

5178
configureResultsControllers()
5279
syncProducts()
@@ -55,9 +82,17 @@ final class ShippingLabelPackagesFormViewModel: ObservableObject {
5582
configureItemViewModels(order: order, packageResponse: packagesResponse)
5683
}
5784

85+
func confirmPackageSelection() {
86+
onCompletion(validatedPackages)
87+
}
88+
}
89+
90+
// MARK: - Helper methods
91+
//
92+
private extension ShippingLabelPackagesFormViewModel {
5893
/// If no initial packages was input, set up default package from last selected package ID and all order items.
5994
///
60-
private func configureDefaultPackage() {
95+
func configureDefaultPackage() {
6196
guard selectedPackages.isEmpty,
6297
let selectedPackageID = resultsControllers?.accountSettings?.lastSelectedPackageID else {
6398
return
@@ -69,7 +104,7 @@ final class ShippingLabelPackagesFormViewModel: ObservableObject {
69104

70105
/// Set up item view models on change of products and product variations.
71106
///
72-
private func configureItemViewModels(order: Order, packageResponse: ShippingLabelPackagesResponse?) {
107+
func configureItemViewModels(order: Order, packageResponse: ShippingLabelPackagesResponse?) {
73108
$selectedPackages.combineLatest($products, $productVariations)
74109
.map { selectedPackages, products, variations -> [ShippingLabelPackageItemViewModel] in
75110
return selectedPackages.map { details in
@@ -87,13 +122,14 @@ final class ShippingLabelPackagesFormViewModel: ObservableObject {
87122
}
88123
.sink { [weak self] viewModels in
89124
self?.itemViewModels = viewModels
125+
self?.observeItemViewModels()
90126
}
91127
.store(in: &cancellables)
92128
}
93129

94130
/// Update selected packages when user switch any package.
95131
///
96-
private func switchPackage(currentID: String, newPackage: ShippingLabelPackageAttributes) {
132+
func switchPackage(currentID: String, newPackage: ShippingLabelPackageAttributes) {
97133
selectedPackages = selectedPackages.map { package in
98134
if package.packageID == currentID {
99135
return newPackage
@@ -103,7 +139,25 @@ final class ShippingLabelPackagesFormViewModel: ObservableObject {
103139
}
104140
}
105141

106-
private func configureResultsControllers() {
142+
/// Observe validation state of each package and save it by package ID.
143+
///
144+
func observeItemViewModels() {
145+
itemViewModels.forEach { item in
146+
item.$isValidTotalWeight
147+
.sink { [weak self] isValid in
148+
self?.packagesValidation[item.selectedPackageID] = isValid
149+
}
150+
.store(in: &cancellables)
151+
}
152+
}
153+
154+
/// Disable Done button if any of the package validation fails.
155+
///
156+
func configureDoneButton() {
157+
doneButtonEnabled = packagesValidation.first(where: { $0.value == false }) == nil
158+
}
159+
160+
func configureResultsControllers() {
107161
resultsControllers = ShippingLabelPackageDetailsResultsControllers(siteID: order.siteID,
108162
orderItems: order.items,
109163
storageManager: storageManager,

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/Create Shipping Label Form/ShippingLabelFormViewController.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,9 @@ private extension ShippingLabelFormViewController {
420420
if ServiceLocator.featureFlagService.isFeatureFlagEnabled(.shippingLabelsMultiPackage) {
421421
let vm = ShippingLabelPackagesFormViewModel(order: viewModel.order,
422422
packagesResponse: viewModel.packagesResponse,
423-
selectedPackages: inputPackages)
423+
selectedPackages: inputPackages) { [weak self] selectedPackages in
424+
self?.viewModel.handlePackageDetailsValueChanges(details: selectedPackages)
425+
}
424426
let packagesForm = ShippingLabelPackagesForm(viewModel: vm)
425427
let hostingVC = UIHostingController(rootView: packagesForm)
426428
navigationController?.show(hostingVC, sender: nil)

0 commit comments

Comments
 (0)