diff --git a/Podfile b/Podfile index b314bc242bb..172cdb2c5ef 100644 --- a/Podfile +++ b/Podfile @@ -38,9 +38,9 @@ target 'WooCommerce' do pod 'Gridicons', '~> 1.0' # To allow pod to pick up beta versions use -beta. E.g., 1.1.7-beta.1 - pod 'WordPressAuthenticator', '~> 1.31.0-beta.2' + pod 'WordPressAuthenticator', '~> 1.31.0-beta.3' # pod 'WordPressAuthenticator', :git => 'https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git', :commit => '' - # pod 'WordPressAuthenticator', :git => 'https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git', :branch => 'develop' + # pod 'WordPressAuthenticator', :git => 'https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git', :branch => '' # pod 'WordPressAuthenticator', :path => '../WordPressAuthenticator-iOS' pod 'WordPressShared', '~> 1.12' diff --git a/Podfile.lock b/Podfile.lock index ef2b5145895..f4ce9f5fa52 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -54,7 +54,7 @@ PODS: - WordPress-Aztec-iOS (1.11.0) - WordPress-Editor-iOS (1.11.0): - WordPress-Aztec-iOS (= 1.11.0) - - WordPressAuthenticator (1.31.0-beta.2): + - WordPressAuthenticator (1.31.0-beta.3): - 1PasswordExtension (= 1.8.6) - Alamofire (= 4.8) - CocoaLumberjack (~> 3.5) @@ -66,7 +66,7 @@ PODS: - WordPressKit (~> 4.18-beta) - WordPressShared (~> 1.12-beta) - WordPressUI (~> 1.7.0) - - WordPressKit (4.23.0-beta.1): + - WordPressKit (4.23.0-beta.4): - Alamofire (~> 4.8.0) - CocoaLumberjack (~> 3.4) - NSObject-SafeExpectations (= 0.0.4) @@ -107,7 +107,7 @@ DEPENDENCIES: - Kingfisher (~> 5.11.0) - Sourcery (~> 0.18) - WordPress-Editor-iOS (~> 1.11.0) - - WordPressAuthenticator (~> 1.31.0-beta.2) + - WordPressAuthenticator (~> 1.31.0-beta.3) - WordPressShared (~> 1.12) - WordPressUI (~> 1.7.2) - Wormholy (~> 1.6.2) @@ -182,8 +182,8 @@ SPEC CHECKSUMS: UIDeviceIdentifier: f4bf3b343581a1beacdbf5fb1a8825bd5f05a4a4 WordPress-Aztec-iOS: 050b34d4c3adfb7c60363849049b13d60683b348 WordPress-Editor-iOS: 304098424f1051cb271546c99f906aac296b1b81 - WordPressAuthenticator: 6144728478567e3ecb9514ac0ac434d203e7f26b - WordPressKit: d67438d29c84960585ecef9a595e9f214b42cc87 + WordPressAuthenticator: b43cd7f1ec8eb0bd2efd5b7b93d16d72be402046 + WordPressKit: 3cba388ffed57891c3821e1efc08a2b71382b214 WordPressShared: 532ad68f954d37ea901e8c7e3ca62913c43ff787 WordPressUI: 07ad23f17631bdce0171383e533eb7c4c29280aa Wormholy: bfc1c8679eefd0edd92638758e21c3961b1b3b50 @@ -198,6 +198,6 @@ SPEC CHECKSUMS: ZendeskSupportProvidersSDK: 51c9d4a826f7bd87e3109e5c801c602a6b62c762 ZendeskSupportSDK: dcb2596ad05a63d662e8c7924357babbf327b421 -PODFILE CHECKSUM: 983b843c2b4973c3d8e6ea4353ae0f2ccdf945f1 +PODFILE CHECKSUM: 25565253d6035bcea3995dcf6c1d42ac1e060c27 COCOAPODS: 1.9.1 diff --git a/WooCommerce/Classes/Authentication/AuthenticationManager.swift b/WooCommerce/Classes/Authentication/AuthenticationManager.swift index ece786d5396..475b19d6b43 100644 --- a/WooCommerce/Classes/Authentication/AuthenticationManager.swift +++ b/WooCommerce/Classes/Authentication/AuthenticationManager.swift @@ -179,16 +179,15 @@ extension AuthenticationManager: WordPressAuthenticatorDelegate { func createdWordPressComAccount(username: String, authToken: String) { } func shouldHandleError(_ error: Error) -> Bool { - guard AuthenticationError.make(with: error) == .notWPSite else { - return false - } - - return true + return isSupportedError(error) } func handleError(_ error: Error, onCompletion: @escaping (UIViewController) -> Void) { - let viewModel = NotWPErrorViewModel() - let noWPErrorUI = ULErrorViewController(viewModel: viewModel) + guard let errorViewModel = viewModel(error) else { + return + } + + let noWPErrorUI = ULErrorViewController(viewModel: errorViewModel) onCompletion(noWPErrorUI) } @@ -341,6 +340,7 @@ private extension AuthenticationManager { /// Maps error codes emitted by WPAuthenticator to a domain error object enum AuthenticationError: Int, Error { + case emailDoesNotMatchWPAccount = 7 case notWPSite = 406 case unknown @@ -348,6 +348,8 @@ private extension AuthenticationManager { let error = error as NSError switch error.code { + case emailDoesNotMatchWPAccount.rawValue: + return .emailDoesNotMatchWPAccount case notWPSite.rawValue: return .notWPSite default: @@ -355,4 +357,22 @@ private extension AuthenticationManager { } } } + + func isSupportedError(_ error: Error) -> Bool { + let wooAuthError = AuthenticationError.make(with: error) + return wooAuthError != .unknown + } + + func viewModel(_ error: Error) -> ULErrorViewModel? { + let wooAuthError = AuthenticationError.make(with: error) + + switch wooAuthError { + case .emailDoesNotMatchWPAccount: + return NotWPAccountViewModel() + case .notWPSite: + return NotWPErrorViewModel() + default: + return nil + } + } } diff --git a/WooCommerce/Classes/Authentication/Navigation Exceptions/NotWPAccountViewModel.swift b/WooCommerce/Classes/Authentication/Navigation Exceptions/NotWPAccountViewModel.swift new file mode 100644 index 00000000000..8b7678d8f15 --- /dev/null +++ b/WooCommerce/Classes/Authentication/Navigation Exceptions/NotWPAccountViewModel.swift @@ -0,0 +1,63 @@ +import UIKit +import SafariServices +import WordPressAuthenticator +import WordPressUI + + +/// Configuration and actions for an ULErrorViewController, modeling +/// an error when user attempts to log in with an invalid WordPressAccount +struct NotWPAccountViewModel: ULErrorViewModel { + // MARK: - Data and configuration + let image: UIImage = .loginNoWordPressError + + let text: NSAttributedString = .init(string: Localization.errorMessage) + + let isAuxiliaryButtonHidden = false + + let auxiliaryButtonTitle = Localization.needHelpFindingEmail + + let primaryButtonTitle = Localization.primaryButtonTitle + + let secondaryButtonTitle = Localization.secondaryButtonTitle + + // MARK: - Actions + func didTapPrimaryButton(in viewController: UIViewController?) { + let popCommand = NavigateToEnterSite() + popCommand.execute(from: viewController) + } + + func didTapSecondaryButton(in viewController: UIViewController?) { + let refreshCommand = NavigateToRoot() + refreshCommand.execute(from: viewController) + } + + func didTapAuxiliaryButton(in viewController: UIViewController?) { + let fancyAlert = FancyAlertViewController.makeNeedHelpFindingEmailAlertController() + fancyAlert.modalPresentationStyle = .custom + fancyAlert.transitioningDelegate = AppDelegate.shared.tabBarController + viewController?.present(fancyAlert, animated: true) + } +} + + +// MARK: - Private data structures +private extension NotWPAccountViewModel { + enum Localization { + static let errorMessage = NSLocalizedString("It looks like this email isn't associated with a WordPress.com account.", + comment: "Message explaining that an email is not associated with a WordPress.com account. " + + "Presented when logging in with an email address that is not a WordPress.com account") + + static let needHelpFindingEmail = NSLocalizedString("Need help finding the connected email?", + comment: "Button linking to webview that explains what Jetpack is" + + "Presented when logging in with a site address that does not have a valid Jetpack installation") + + static let primaryButtonTitle = NSLocalizedString("Enter Your Store Address", + comment: "Action button linking to instructions for enter another store." + + "Presented when logging in with an email address that is not a WordPress.com account") + + static let secondaryButtonTitle = NSLocalizedString("Log In With Another Account", + comment: "Action button that will restart the login flow." + + "Presented when logging in with an email address that does not match a WordPress.com account") + + } +} diff --git a/WooCommerce/Classes/Authentication/Navigation Exceptions/ULErrorViewController.swift b/WooCommerce/Classes/Authentication/Navigation Exceptions/ULErrorViewController.swift index c8a360cb91d..bf6e3023394 100644 --- a/WooCommerce/Classes/Authentication/Navigation Exceptions/ULErrorViewController.swift +++ b/WooCommerce/Classes/Authentication/Navigation Exceptions/ULErrorViewController.swift @@ -58,6 +58,7 @@ private extension ULErrorViewController { } extraInfoButton.applyLinkButtonStyle() + extraInfoButton.contentEdgeInsets = Constants.extraInfoCustomInsets extraInfoButton.setTitle(viewModel.auxiliaryButtonTitle, for: .normal) extraInfoButton.on(.touchUpInside) { [weak self] _ in self?.didTapAuxiliaryButton() @@ -97,6 +98,13 @@ private extension ULErrorViewController { } +// MARK: - Constants +private extension ULErrorViewController { + enum Constants { + static let extraInfoCustomInsets = UIEdgeInsets(top: 12, left: 10, bottom: 12, right: 10) + } +} + // MARK: - Tests extension ULErrorViewController { func getImageView() -> UIImageView { diff --git a/WooCommerce/Classes/Authentication/Navigation Exceptions/ULErrorViewController.xib b/WooCommerce/Classes/Authentication/Navigation Exceptions/ULErrorViewController.xib index 44d9f0bc77c..36d4d9d257d 100644 --- a/WooCommerce/Classes/Authentication/Navigation Exceptions/ULErrorViewController.xib +++ b/WooCommerce/Classes/Authentication/Navigation Exceptions/ULErrorViewController.xib @@ -67,22 +67,22 @@ - + - + @@ -94,9 +94,9 @@ - + - + diff --git a/WooCommerce/Classes/ViewRelated/Fancy Alerts/FancyAlertViewController+UnifiedLogin.swift b/WooCommerce/Classes/ViewRelated/Fancy Alerts/FancyAlertViewController+UnifiedLogin.swift index e2996cb8e88..6e704a07f79 100644 --- a/WooCommerce/Classes/ViewRelated/Fancy Alerts/FancyAlertViewController+UnifiedLogin.swift +++ b/WooCommerce/Classes/ViewRelated/Fancy Alerts/FancyAlertViewController+UnifiedLogin.swift @@ -6,7 +6,7 @@ public extension FancyAlertViewController { let dismissButton = makeDismissButtonConfig() let moreInfoButton = makeMoreInfoButtonConfig() let config = FancyAlertViewController.Config(titleText: Localization.whatIsJetpack, - bodyText: Localization.longDescription, + bodyText: Localization.whatIsJetpackLongDescription, headerImage: .whatIsJetpackImage, dividerPosition: .top, defaultButton: dismissButton, @@ -17,6 +17,23 @@ public extension FancyAlertViewController { let controller = FancyAlertViewController.controllerWithConfiguration(configuration: config) return controller } + + static func makeNeedHelpFindingEmailAlertController() -> FancyAlertViewController { + let dismissButton = makeDismissButtonConfig() + let moreHelpButton = makeNeedMoreHelpButton() + let config = FancyAlertViewController.Config(titleText: Localization.whatEmailDoIUse, + bodyText: Localization.whatEmailDoIUseLongDescription, + headerImage: nil, + dividerPosition: .top, + defaultButton: dismissButton, + cancelButton: nil, + moreInfoButton: moreHelpButton, + dismissAction: {}) + + let controller = FancyAlertViewController.controllerWithConfiguration(configuration: config) + return controller + + } } @@ -27,7 +44,7 @@ private extension FancyAlertViewController { comment: "Title of alert informing users of what Jetpack is. Presented when users attempt to log in without Jetpack installed or connected" ) - static let longDescription = NSLocalizedString( + static let whatIsJetpackLongDescription = NSLocalizedString( "Jetpack is a free WordPress plugin that connects your store with tools needed to give you the best mobile experience, " + "including push notifications and stats", comment: "Long description of what Jetpack is. Presented when users attempt to log in without Jetpack installed or connected" @@ -42,6 +59,23 @@ private extension FancyAlertViewController { "Continue", comment: "Title of dismiss button presented when users attempt to log in without Jetpack installed or connected" ) + + static let whatEmailDoIUse = NSLocalizedString( + "What email do I use to sign in?", + comment: "Title of alert informing users of what email they can use to sign in." + + "Presented when users attempt to log in with an email that does not match a WP.com account" + ) + + static let whatEmailDoIUseLongDescription = NSLocalizedString( + "In your site admin you can find the email you used to connect to WordPress.com from the Jetpack Dashboard under Connections > Account Connection", + comment: "Long descriptions of alert informing users of what email they can use to sign in." + + "Presented when users attempt to log in with an email that does not match a WP.com account" + ) + + static let needMoreHelp = NSLocalizedString( + "Need more help?", + comment: "Title of button to learn more presented when users attempt to log in with an email address that does not match a WP.com account" + ) } enum Strings { @@ -70,4 +104,22 @@ private extension FancyAlertViewController { controller.present(safariViewController, animated: true) } } + + static func makeNeedMoreHelpButton() -> FancyAlertViewController.Config.ButtonConfig { + return FancyAlertViewController.Config.ButtonConfig(Localization.needMoreHelp) { controller, _ in + let identifier = HelpAndSupportViewController.classNameWithoutNamespaces + guard let supportViewController = UIStoryboard + .dashboard + .instantiateViewController(withIdentifier: identifier) as? HelpAndSupportViewController else { + return + } + + supportViewController.displaysDismissAction = true + + let navController = UINavigationController(rootViewController: supportViewController) + navController.modalPresentationStyle = .formSheet + + controller.present(navController, animated: true, completion: nil) + } + } } diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index e480d6df8e4..11e7ad68abb 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -965,6 +965,7 @@ D88100D3257DD060008DE6F2 /* WordPressComSiteInfoWooTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88100D2257DD060008DE6F2 /* WordPressComSiteInfoWooTests.swift */; }; D881A31B256B5CC500FE5605 /* ULErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D881A319256B5CC500FE5605 /* ULErrorViewController.swift */; }; D881A31C256B5CC500FE5605 /* ULErrorViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D881A31A256B5CC500FE5605 /* ULErrorViewController.xib */; }; + D881FE062579DC78008DE6F2 /* NotWPAccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D881FE052579DC78008DE6F2 /* NotWPAccountViewModel.swift */; }; D88CA756237CE515005D2F44 /* UITabBar+Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88CA755237CE515005D2F44 /* UITabBar+Appearance.swift */; }; D88CA758237D1C27005D2F44 /* Ghost+Woo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88CA757237D1C27005D2F44 /* Ghost+Woo.swift */; }; D88D5A3B230B5D63007B6E01 /* MockAnalyticsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 746791652108D87B007CF1DC /* MockAnalyticsProvider.swift */; }; @@ -2040,6 +2041,7 @@ D88100D2257DD060008DE6F2 /* WordPressComSiteInfoWooTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordPressComSiteInfoWooTests.swift; sourceTree = ""; }; D881A319256B5CC500FE5605 /* ULErrorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ULErrorViewController.swift; sourceTree = ""; }; D881A31A256B5CC500FE5605 /* ULErrorViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ULErrorViewController.xib; sourceTree = ""; }; + D881FE052579DC78008DE6F2 /* NotWPAccountViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotWPAccountViewModel.swift; sourceTree = ""; }; D88CA755237CE515005D2F44 /* UITabBar+Appearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITabBar+Appearance.swift"; sourceTree = ""; }; D88CA757237D1C27005D2F44 /* Ghost+Woo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Ghost+Woo.swift"; sourceTree = ""; }; D88D5A3C230B5E85007B6E01 /* ServiceLocatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceLocatorTests.swift; sourceTree = ""; }; @@ -4886,6 +4888,7 @@ D8610BCB256F284700A5DF27 /* ULErrorViewModel.swift */, D8610BD1256F291000A5DF27 /* JetpackErrorViewModel.swift */, D8610D752570AE1F00A5DF27 /* NotWPErrorViewModel.swift */, + D881FE052579DC78008DE6F2 /* NotWPAccountViewModel.swift */, ); path = "Navigation Exceptions"; sourceTree = ""; @@ -5732,6 +5735,7 @@ B541B2172189EED4008FE7C1 /* NSMutableAttributedString+Helpers.swift in Sources */, B586906621A5F4B1001F1EFC /* UINavigationController+Woo.swift in Sources */, 45FBDF3A238D3F8B00127F77 /* ExtendedAddProductImageCollectionViewCell.swift in Sources */, + D881FE062579DC78008DE6F2 /* NotWPAccountViewModel.swift in Sources */, 02C0CD2A23B5BB1C00F880B1 /* ImageService.swift in Sources */, 26ABCE532518EAF300721CB0 /* IssueRefundTableViewCell.swift in Sources */, 02482A8B237BE8C7007E73ED /* LinkSettingsViewController.swift in Sources */,