Skip to content

Commit e05b626

Browse files
authored
Shipping Labels: Add check for dimensions when confirming custom package (#15925)
2 parents 57650fa + e3d7ccf commit e05b626

File tree

4 files changed

+146
-19
lines changed

4 files changed

+146
-19
lines changed

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- [*] POS: a POS tab in the tab bar is now available in the app for stores in countries eligible for Point of Sale, instead of the tab is only shown when the store is eligible for POS. [https://github.com/woocommerce/woocommerce-ios/pull/15918]
1111
- [*] Shipping Labels: Display base rate on selected shipping service cards [https://github.com/woocommerce/woocommerce-ios/pull/15916]
1212
- [*] Shipping Labels: Update mark order completed toggle on purchase form [https://github.com/woocommerce/woocommerce-ios/pull/15917]
13+
- [*] Shipping Labels: Validate custom package dimensions [https://github.com/woocommerce/woocommerce-ios/pull/15925]
1314
- [*] Shipping Labels: Optimize data loading on purchase form [https://github.com/woocommerce/woocommerce-ios/pull/15919]
1415
- [internal] Optimized assets for app size reduction [https://github.com/woocommerce/woocommerce-ios/pull/15881]
1516

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShipping Package and Rate Selection/WooAddCustomPackageView.swift

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct WooAddCustomPackageView: View {
1414

1515
@State private var isSavingPackage = false
1616
@State private var showingSavingError = false
17+
@State private var foundInvalidDimensions = false
1718

1819
@Environment(\.shippingDimensionsUnit) private var dimensionsUnit
1920
@Environment(\.shippingWeightUnit) private var weightUnit
@@ -68,6 +69,14 @@ struct WooAddCustomPackageView: View {
6869
unitInputView(for: dimensionUnit, unit: dimensionsUnit)
6970
}
7071
}
72+
73+
if foundInvalidDimensions {
74+
Text(Localization.invalidDimensions)
75+
.font(.footnote)
76+
.foregroundColor(Color(.error))
77+
.frame(maxWidth: .infinity, alignment: .leading)
78+
}
79+
7180
// showing weight input only if we are saving the template
7281
if viewModel.showSaveTemplate {
7382
unitInputView(for: WooShippingPackageUnitType.weight, unit: weightUnit)
@@ -172,19 +181,21 @@ struct WooAddCustomPackageView: View {
172181
}
173182
}
174183
}
184+
}
175185

176-
private var selectionButtonDisabled: Bool {
186+
private extension WooAddCustomPackageView {
187+
var selectionButtonDisabled: Bool {
177188
!viewModel.validateCustomPackageInputFields()
178189
}
179190

180-
private var selectionButtonText: String {
191+
var selectionButtonText: String {
181192
if selectionButtonDisabled {
182193
return WooShippingAddPackageView.Localization.addPackageDetails
183194
}
184195
return WooShippingAddPackageView.Localization.addPackage
185196
}
186197

187-
private func unitInputView(for unitType: WooShippingPackageUnitType, unit: String) -> some View {
198+
func unitInputView(for unitType: WooShippingPackageUnitType, unit: String) -> some View {
188199
WooShippingAddPackageUnitInputView(unitType: unitType,
189200
unit: unit,
190201
fieldValue: Binding(get: {
@@ -196,15 +207,20 @@ struct WooAddCustomPackageView: View {
196207

197208
// MARK: - actions
198209

199-
private func confirmPackage() {
200-
guard let packageData = viewModel.packageData else {
210+
func confirmPackage() {
211+
foundInvalidDimensions = !viewModel.allDimensionsValid
212+
guard !foundInvalidDimensions, let packageData = viewModel.packageData else {
201213
return
202214
}
203215
addPackageAction(packageData)
204216
}
205217

206218
@MainActor
207-
private func savePackageAsTemplateButtonTapped() async {
219+
func savePackageAsTemplateButtonTapped() async {
220+
foundInvalidDimensions = !viewModel.allDimensionsValid
221+
guard !foundInvalidDimensions else {
222+
return
223+
}
208224
let packageDataResult = await viewModel.savePackageAsTemplateAction()
209225
// call addPackageAction with data
210226
switch packageDataResult {
@@ -216,7 +232,7 @@ struct WooAddCustomPackageView: View {
216232
}
217233
}
218234

219-
private func onBackwardButtonTapped() {
235+
func onBackwardButtonTapped() {
220236
switch focusedField {
221237
case .length:
222238
return
@@ -231,7 +247,7 @@ struct WooAddCustomPackageView: View {
231247
}
232248
}
233249

234-
private func onForwardButtonTapped() {
250+
func onForwardButtonTapped() {
235251
switch focusedField {
236252
case .length:
237253
focusedField = .width
@@ -246,7 +262,7 @@ struct WooAddCustomPackageView: View {
246262
}
247263
}
248264

249-
private func dismissKeyboard() {
265+
func dismissKeyboard() {
250266
focusedField = nil
251267
packageTemplateNameFieldFocused = false
252268
}
@@ -269,6 +285,11 @@ extension WooAddCustomPackageView {
269285
static let savePackageTemplatePlaceholder = NSLocalizedString("wooShipping.createLabel.addPackage.savePackageTemplatePlaceholder",
270286
value: "Enter a unique package name",
271287
comment: "Placeholder text for package name field")
288+
static let invalidDimensions = NSLocalizedString(
289+
"wooShipping.createLabel.addPackage.invalidDimensions",
290+
value: "Package dimensions should all be larger than 0",
291+
comment: "Message when user attempts to confirm a package with invalid dimension in the shipping label creation flow"
292+
)
272293
enum SavingPackageError {
273294
static let title = NSLocalizedString(
274295
"wooShipping.createLabel.addPackage.savingPackageError.title",

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShipping Package and Rate Selection/WooShippingAddCustomPackageViewModel.swift

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ final class WooShippingAddCustomPackageViewModel: ObservableObject {
4343
}
4444
}
4545

46-
// Field values are invalid if one of them is empty
46+
// Field values are invalid if one of them is incomplete
4747
// - if we are saving template we check all field values
4848
// - if we are not saving template we check only dimensions
49-
var areFieldValuesInvalid: Bool {
49+
var areFieldValuesIncomplete: Bool {
5050
let keysToCheck: [WooShippingPackageUnitType] = showSaveTemplate ? WooShippingPackageUnitType.allCases : WooShippingPackageUnitType.dimensionUnits
5151

5252
var validFieldsCount: Int = 0
@@ -61,6 +61,19 @@ final class WooShippingAddCustomPackageViewModel: ObservableObject {
6161
return validFieldsCount != keysToCheck.count
6262
}
6363

64+
/// Ensure that all dimensions are larger than 0
65+
var allDimensionsValid: Bool {
66+
let keysToCheck = WooShippingPackageUnitType.dimensionUnits
67+
for (key, value) in fieldValues {
68+
guard keysToCheck.contains(key) else { continue }
69+
let doubleValue = Double(value)
70+
guard let doubleValue, doubleValue > 0 else {
71+
return false
72+
}
73+
}
74+
return true
75+
}
76+
6477
private var packageDataFromCurrentData: WooShippingPackageDataRepresentable {
6578
return WooShippingPackageData(id: packageID,
6679
name: packageTemplateName,
@@ -117,7 +130,7 @@ final class WooShippingAddCustomPackageViewModel: ObservableObject {
117130
continuation.resume(returning: .success(packageData))
118131
case let .failure(error):
119132
DDLogError("⛔️ Error saving custom package with WCShip: \(error)")
120-
continuation.resume(returning: .failure(WooShippingAddCustomPackageViewModel.Error.failedSavingTemplate))
133+
continuation.resume(returning: .failure(WooShippingAddCustomPackageViewModel.Error.failure(error)))
121134
}
122135
}
123136
stores.dispatch(action)
@@ -134,7 +147,7 @@ final class WooShippingAddCustomPackageViewModel: ObservableObject {
134147
}
135148

136149
func validateCustomPackageInputFields() -> Bool {
137-
guard !areFieldValuesInvalid else {
150+
if areFieldValuesIncomplete {
138151
return false
139152
}
140153
if showSaveTemplate {

WooCommerce/WooCommerceTests/ViewRelated/Shipping Label/WooShipping Create Shipping Labels/WooShippingAddCustomPackageViewModelTests.swift

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ final class WooShippingAddCustomPackageViewModelTests: XCTestCase {
2929

3030
// Then
3131
XCTAssertEqual(viewModel.fieldValues.isEmpty, false)
32-
XCTAssertEqual(viewModel.areFieldValuesInvalid, true)
32+
XCTAssertEqual(viewModel.areFieldValuesIncomplete, true)
3333
}
3434

3535
@MainActor
@@ -45,7 +45,7 @@ final class WooShippingAddCustomPackageViewModelTests: XCTestCase {
4545

4646
// Then
4747
XCTAssertEqual(viewModel.fieldValues.isEmpty, false)
48-
XCTAssertEqual(viewModel.areFieldValuesInvalid, false)
48+
XCTAssertEqual(viewModel.areFieldValuesIncomplete, false)
4949
}
5050

5151
@MainActor
@@ -62,7 +62,7 @@ final class WooShippingAddCustomPackageViewModelTests: XCTestCase {
6262

6363
// Then
6464
XCTAssertEqual(viewModel.fieldValues.isEmpty, false)
65-
XCTAssertEqual(viewModel.areFieldValuesInvalid, false)
65+
XCTAssertEqual(viewModel.areFieldValuesIncomplete, false)
6666
}
6767

6868
@MainActor
@@ -79,7 +79,7 @@ final class WooShippingAddCustomPackageViewModelTests: XCTestCase {
7979

8080
// Then
8181
XCTAssertEqual(viewModel.fieldValues.isEmpty, false)
82-
XCTAssertEqual(viewModel.areFieldValuesInvalid, true)
82+
XCTAssertEqual(viewModel.areFieldValuesIncomplete, true)
8383
}
8484

8585
@MainActor
@@ -96,7 +96,7 @@ final class WooShippingAddCustomPackageViewModelTests: XCTestCase {
9696
viewModel.fieldValues[.weight] = "1"
9797
// Then
9898
XCTAssertEqual(viewModel.fieldValues.isEmpty, false)
99-
XCTAssertEqual(viewModel.areFieldValuesInvalid, false)
99+
XCTAssertEqual(viewModel.areFieldValuesIncomplete, false)
100100
}
101101

102102
@MainActor
@@ -278,6 +278,98 @@ final class WooShippingAddCustomPackageViewModelTests: XCTestCase {
278278
XCTAssertEqual(viewModel.fieldValues[.height], "1.27")
279279
XCTAssertEqual(viewModel.packageType, .envelope)
280280
}
281+
282+
// MARK: - allDimensionsValid tests
283+
284+
func test_allDimensionsValid_returns_false_when_dimension_is_zero() {
285+
// Given
286+
let siteID: Int64 = 1234
287+
let mockStores = MockStoresManager(sessionManager: .testingInstance)
288+
let viewModel = WooShippingAddCustomPackageViewModel(siteID: siteID, stores: mockStores)
289+
290+
// When
291+
viewModel.fieldValues[.length] = "10"
292+
viewModel.fieldValues[.width] = "0"
293+
viewModel.fieldValues[.height] = "5"
294+
295+
// Then
296+
XCTAssertFalse(viewModel.allDimensionsValid)
297+
}
298+
299+
func test_allDimensionsValid_returns_false_when_dimension_is_empty_string() {
300+
// Given
301+
let siteID: Int64 = 1234
302+
let mockStores = MockStoresManager(sessionManager: .testingInstance)
303+
let viewModel = WooShippingAddCustomPackageViewModel(siteID: siteID, stores: mockStores)
304+
305+
// When
306+
viewModel.fieldValues[.length] = "10"
307+
viewModel.fieldValues[.width] = ""
308+
viewModel.fieldValues[.height] = "5"
309+
310+
// Then
311+
XCTAssertFalse(viewModel.allDimensionsValid)
312+
}
313+
314+
func test_allDimensionsValid_returns_false_when_dimension_is_invalid_string() {
315+
// Given
316+
let siteID: Int64 = 1234
317+
let mockStores = MockStoresManager(sessionManager: .testingInstance)
318+
let viewModel = WooShippingAddCustomPackageViewModel(siteID: siteID, stores: mockStores)
319+
320+
// When
321+
viewModel.fieldValues[.length] = "10"
322+
viewModel.fieldValues[.width] = "abc"
323+
viewModel.fieldValues[.height] = "5"
324+
325+
// Then
326+
XCTAssertFalse(viewModel.allDimensionsValid)
327+
}
328+
329+
func test_allDimensionsValid_returns_false_when_dimension_is_negative() {
330+
// Given
331+
let siteID: Int64 = 1234
332+
let mockStores = MockStoresManager(sessionManager: .testingInstance)
333+
let viewModel = WooShippingAddCustomPackageViewModel(siteID: siteID, stores: mockStores)
334+
335+
// When
336+
viewModel.fieldValues[.length] = "10"
337+
viewModel.fieldValues[.width] = "-5"
338+
viewModel.fieldValues[.height] = "5"
339+
340+
// Then
341+
XCTAssertFalse(viewModel.allDimensionsValid)
342+
}
343+
344+
func test_allDimensionsValid_returns_true_when_all_dimensions_are_valid_positive_numbers() {
345+
// Given
346+
let siteID: Int64 = 1234
347+
let mockStores = MockStoresManager(sessionManager: .testingInstance)
348+
let viewModel = WooShippingAddCustomPackageViewModel(siteID: siteID, stores: mockStores)
349+
350+
// When
351+
viewModel.fieldValues[.length] = "10"
352+
viewModel.fieldValues[.width] = "5"
353+
viewModel.fieldValues[.height] = "3"
354+
355+
// Then
356+
XCTAssertTrue(viewModel.allDimensionsValid)
357+
}
358+
359+
func test_allDimensionsValid_returns_true_when_all_dimensions_are_valid_decimals() {
360+
// Given
361+
let siteID: Int64 = 1234
362+
let mockStores = MockStoresManager(sessionManager: .testingInstance)
363+
let viewModel = WooShippingAddCustomPackageViewModel(siteID: siteID, stores: mockStores)
364+
365+
// When
366+
viewModel.fieldValues[.length] = "10.5"
367+
viewModel.fieldValues[.width] = "5.25"
368+
viewModel.fieldValues[.height] = "3.75"
369+
370+
// Then
371+
XCTAssertTrue(viewModel.allDimensionsValid)
372+
}
281373
}
282374

283375
extension WooShippingAddCustomPackageViewModel {
@@ -298,6 +390,6 @@ extension WooShippingAddCustomPackageViewModel {
298390
XCTAssertEqual(packageType, WooShippingPackageType.box)
299391
XCTAssertEqual(showSaveTemplate, false)
300392
XCTAssertEqual(packageTemplateName, "")
301-
XCTAssertEqual(areFieldValuesInvalid, true)
393+
XCTAssertEqual(areFieldValuesIncomplete, true)
302394
}
303395
}

0 commit comments

Comments
 (0)