Skip to content

Commit 22c3031

Browse files
authored
Merge pull request #4964 from woocommerce/issue/4745-error-handling
Shipping Labels: Display error when package creation fails
2 parents 9be9aa3 + 95a63c6 commit 22c3031

File tree

7 files changed

+122
-10
lines changed

7 files changed

+122
-10
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Yosemite
2+
3+
extension PackageCreationError {
4+
var alertTitle: String {
5+
switch self {
6+
case .duplicatePackageNames, .duplicateNamesByCarrier, .duplicateCustomPackageNames, .duplicatePredefinedPackageNames:
7+
return NSLocalizedString("Invalid Package Name",
8+
comment: "The title of the alert when there is an error with the package name")
9+
case .unknown:
10+
return NSLocalizedString("Cannot add package",
11+
comment: "The title of the alert when there is a generic error adding the package")
12+
}
13+
}
14+
}
15+
16+
extension PackageCreationError: LocalizedError {
17+
public var errorDescription: String? {
18+
switch self {
19+
case .duplicatePackageNames, .duplicateCustomPackageNames:
20+
return NSLocalizedString("The new custom package name is not unique.",
21+
comment: "The message of the alert when another custom package has the same name")
22+
case .duplicateNamesByCarrier, .duplicatePredefinedPackageNames:
23+
return NSLocalizedString("The new service package name is not unique.",
24+
comment: "The message of the alert when another service package has the same name")
25+
case .unknown:
26+
return NSLocalizedString("Unexpected error", comment: "The message of the alert when there is an unexpected error adding the package")
27+
}
28+
}
29+
}

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/Create Shipping Label Form/Package Details/Package Selection/Package Creation/ShippingLabelAddNewPackage.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import Yosemite
44
struct ShippingLabelAddNewPackage: View {
55
@ObservedObject var viewModel: ShippingLabelAddNewPackageViewModel
66
@Environment(\.presentationMode) var presentation
7-
@State var isSyncing = false
7+
@State private var isSyncing = false
8+
@State private var showingAddPackageError = false
89

910
var body: some View {
1011
GeometryReader { geometry in
@@ -49,14 +50,20 @@ struct ShippingLabelAddNewPackage: View {
4950
isSyncing = true
5051
viewModel.createCustomPackage() { success in
5152
isSyncing = false
52-
guard success else { return }
53+
guard success else {
54+
showingAddPackageError = true
55+
return
56+
}
5357
presentation.wrappedValue.dismiss()
5458
}
5559
case .servicePackage:
5660
isSyncing = true
5761
viewModel.activateServicePackage() { success in
5862
isSyncing = false
59-
guard success else { return }
63+
guard success else {
64+
showingAddPackageError = true
65+
return
66+
}
6067
presentation.wrappedValue.dismiss()
6168
}
6269
}
@@ -69,6 +76,11 @@ struct ShippingLabelAddNewPackage: View {
6976
}
7077
})
7178
.disabled(isSyncing)
79+
.alert(isPresented: $showingAddPackageError, content: {
80+
let title = viewModel.error?.alertTitle ?? Localization.errorAlertTitle
81+
let message = viewModel.error?.errorDescription ?? Localization.errorAlertMessage
82+
return Alert(title: Text(title), message: Text(message))
83+
})
7284
})
7385
}
7486
}
@@ -81,6 +93,9 @@ private extension ShippingLabelAddNewPackage {
8193
static let customPackage = NSLocalizedString("Custom Package", comment: "Custom Package menu in Shipping Label Add New Package flow")
8294
static let servicePackage = NSLocalizedString("Service Package", comment: "Service Package menu in Shipping Label Add New Package flow")
8395
static let doneButton = NSLocalizedString("Done", comment: "Done navigation button in the Add New Package screen in Shipping Label flow")
96+
static let errorAlertTitle = NSLocalizedString("Cannot add package", comment: "The title of the alert when there is a generic error adding the package")
97+
static let errorAlertMessage = NSLocalizedString("Unexpected error",
98+
comment: "The message of the alert when there is an unexpected error adding the package")
8499
}
85100
}
86101

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/Create Shipping Label Form/Package Details/Package Selection/Package Creation/ShippingLabelAddNewPackageViewModel.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ final class ShippingLabelAddNewPackageViewModel: ObservableObject {
3838
///
3939
private var packagesResponse: ShippingLabelPackagesResponse?
4040

41+
/// Error if package creation fails
42+
///
43+
private(set) var error: PackageCreationError?
44+
4145
/// Completion callback
4246
///
4347
typealias Completion = (_ customPackage: ShippingLabelCustomPackage? ,
@@ -135,6 +139,7 @@ private extension ShippingLabelAddNewPackageViewModel {
135139
onCompletion?(success)
136140
}
137141
case .failure(let error):
142+
self.error = error
138143
DDLogError("⛔️ Error creating package: \(error.localizedDescription)")
139144
onCompletion?(false)
140145
}

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,7 @@
972972
CC4D1D8625E6CDDE00B6E4E7 /* RenameAttributesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC4D1D8525E6CDDE00B6E4E7 /* RenameAttributesViewModel.swift */; };
973973
CC4D1E7925EE415D00B6E4E7 /* RenameAttributesViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC4D1E7825EE415D00B6E4E7 /* RenameAttributesViewModelTests.swift */; };
974974
CC593A6726EA116300EF0E04 /* ShippingLabelAddNewPackageViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC593A6626EA116300EF0E04 /* ShippingLabelAddNewPackageViewModelTests.swift */; };
975+
CC593A6B26EA640800EF0E04 /* PackageCreationError+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC593A6A26EA640800EF0E04 /* PackageCreationError+UI.swift */; };
975976
CC69236226010946002FB669 /* LoginProloguePages.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC69236126010946002FB669 /* LoginProloguePages.swift */; };
976977
CC6923AC26010D8D002FB669 /* LoginProloguePageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC6923AB26010D8D002FB669 /* LoginProloguePageViewController.swift */; };
977978
CC8413E423F5C48E00EFC277 /* stop.sh in Resources */ = {isa = PBXBuildFile; fileRef = CCFC011123E9E40B00157A78 /* stop.sh */; };
@@ -2404,6 +2405,7 @@
24042405
CC4D1D8525E6CDDE00B6E4E7 /* RenameAttributesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenameAttributesViewModel.swift; sourceTree = "<group>"; };
24052406
CC4D1E7825EE415D00B6E4E7 /* RenameAttributesViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenameAttributesViewModelTests.swift; sourceTree = "<group>"; };
24062407
CC593A6626EA116300EF0E04 /* ShippingLabelAddNewPackageViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelAddNewPackageViewModelTests.swift; sourceTree = "<group>"; };
2408+
CC593A6A26EA640800EF0E04 /* PackageCreationError+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PackageCreationError+UI.swift"; sourceTree = "<group>"; };
24072409
CC69236126010946002FB669 /* LoginProloguePages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginProloguePages.swift; sourceTree = "<group>"; };
24082410
CC6923AB26010D8D002FB669 /* LoginProloguePageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginProloguePageViewController.swift; sourceTree = "<group>"; };
24092411
CCCC29DC25E5757C0046B96F /* RenameAttributesViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RenameAttributesViewController.xib; sourceTree = "<group>"; };
@@ -5374,6 +5376,7 @@
53745376
CC254F3726C43B52005F3C82 /* ShippingLabelCustomPackageFormViewModel.swift */,
53755377
CCD2F51926D67BB50010E679 /* ShippingLabelServicePackageList.swift */,
53765378
CCD2F51B26D697860010E679 /* ShippingLabelServicePackageListViewModel.swift */,
5379+
CC593A6A26EA640800EF0E04 /* PackageCreationError+UI.swift */,
53775380
);
53785381
path = "Package Creation";
53795382
sourceTree = "<group>";
@@ -7779,6 +7782,7 @@
77797782
CC69236226010946002FB669 /* LoginProloguePages.swift in Sources */,
77807783
D817586422BDD81600289CFE /* OrderDetailsDataSource.swift in Sources */,
77817784
D8B4D5EE26C2C26C00F34E94 /* InPersonPaymentsStripeAcountReviewView.swift in Sources */,
7785+
CC593A6B26EA640800EF0E04 /* PackageCreationError+UI.swift in Sources */,
77827786
CE1F512920697F0100C6C810 /* UIFont+Helpers.swift in Sources */,
77837787
2687165A24D350C20042F6AE /* SurveyCoordinatingController.swift in Sources */,
77847788
02C88775245036D400E4470F /* FilterProductListViewModel.swift in Sources */,

Yosemite/Yosemite/Actions/ShippingLabelAction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public enum ShippingLabelAction: Action {
4646
case createPackage(siteID: Int64,
4747
customPackage: ShippingLabelCustomPackage? = nil,
4848
predefinedOption: ShippingLabelPredefinedOption? = nil,
49-
completion: (Result<Bool, Error>) -> Void)
49+
completion: (Result<Bool, PackageCreationError>) -> Void)
5050

5151
/// Fetch list of shipping carriers and their rates
5252
///

Yosemite/Yosemite/Stores/ShippingLabelStore.swift

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,15 @@ private extension ShippingLabelStore {
171171
func createPackage(siteID: Int64,
172172
customPackage: ShippingLabelCustomPackage?,
173173
predefinedOption: ShippingLabelPredefinedOption?,
174-
completion: @escaping (Result<Bool, Error>) -> Void) {
175-
remote.createPackage(siteID: siteID, customPackage: customPackage, predefinedOption: predefinedOption, completion: completion)
174+
completion: @escaping (Result<Bool, PackageCreationError>) -> Void) {
175+
remote.createPackage(siteID: siteID, customPackage: customPackage, predefinedOption: predefinedOption) { result in
176+
switch result {
177+
case .success(let success):
178+
completion(.success(success))
179+
case .failure(let error):
180+
completion(.failure(PackageCreationError(error: error)))
181+
}
182+
}
176183
}
177184

178185
func loadCarriersAndRates(siteID: Int64,
@@ -477,3 +484,56 @@ public enum LabelPurchaseError: Error {
477484
/// Label purchase not complete after polling the backend
478485
case purchaseIncomplete
479486
}
487+
488+
/// An error that occurs while creating a package.
489+
///
490+
/// - duplicateCustomPackageNames: The new custom package names are not unique.
491+
/// - duplicatePackageNames: At least one of the new custom packages has the same name as existing packages.
492+
/// - duplicatePredefinedPackageNames: The new predefined package names are not unique.
493+
/// - duplicateNamesByCarrier: At least one of the new predefined packages has the same name as existing packages.
494+
/// - unknown: other error cases.
495+
///
496+
public enum PackageCreationError: Error, Equatable {
497+
case duplicateCustomPackageNames
498+
case duplicatePackageNames
499+
case duplicatePredefinedPackageNames
500+
case duplicateNamesByCarrier
501+
case unknown(error: AnyError)
502+
503+
init(error: Error) {
504+
guard let dotcomError = error as? DotcomError else {
505+
self = .unknown(error: error.toAnyError)
506+
return
507+
}
508+
switch dotcomError {
509+
case .unknown(let code, _):
510+
guard let errorCode = ErrorCode(rawValue: code) else {
511+
self = .unknown(error: dotcomError.toAnyError)
512+
return
513+
}
514+
self = errorCode.error
515+
default:
516+
self = .unknown(error: dotcomError.toAnyError)
517+
}
518+
}
519+
520+
private enum ErrorCode: String {
521+
case duplicateCustomPackageNames = "duplicate_custom_package_names"
522+
case duplicatePackageNames = "duplicate_custom_package_names_of_existing_packages"
523+
case duplicatePredefinedPackageNames = "duplicate_predefined_package_names"
524+
case duplicateNamesByCarrier = "duplicate_predefined_package_names_of_existing_packages"
525+
526+
var error: PackageCreationError {
527+
switch self {
528+
case .duplicateCustomPackageNames:
529+
return .duplicateCustomPackageNames
530+
case .duplicatePredefinedPackageNames:
531+
return .duplicatePredefinedPackageNames
532+
case .duplicatePackageNames:
533+
return .duplicatePackageNames
534+
case .duplicateNamesByCarrier:
535+
return .duplicateNamesByCarrier
536+
}
537+
}
538+
}
539+
}

Yosemite/YosemiteTests/Stores/ShippingLabelStoreTests.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ final class ShippingLabelStoreTests: XCTestCase {
514514
let store = ShippingLabelStore(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote)
515515

516516
// When
517-
let result: Result<Bool, Error> = waitFor { promise in
517+
let result: Result<Bool, PackageCreationError> = waitFor { promise in
518518
let action = ShippingLabelAction.createPackage(siteID: self.sampleSiteID, customPackage: self.sampleShippingLabelCustomPackage()) { result in
519519
promise(result)
520520
}
@@ -534,16 +534,15 @@ final class ShippingLabelStoreTests: XCTestCase {
534534
let store = ShippingLabelStore(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote)
535535

536536
// When
537-
let result: Result<Bool, Error> = waitFor { promise in
537+
let result: Result<Bool, PackageCreationError> = waitFor { promise in
538538
let action = ShippingLabelAction.createPackage(siteID: self.sampleSiteID, customPackage: self.sampleShippingLabelCustomPackage()) { result in
539539
promise(result)
540540
}
541541
store.onAction(action)
542542
}
543543

544544
// Then
545-
let error = try XCTUnwrap(result.failure)
546-
XCTAssertEqual(error as? NetworkError, expectedError)
545+
XCTAssertTrue(result.isFailure)
547546
}
548547

549548
// MARK: `loadCarriersAndRates`

0 commit comments

Comments
 (0)