Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Login] Improve error messaging displaying a new error screen when application password is disabled #15031

Open
wants to merge 12 commits into
base: trunk
Choose a base branch
from

Conversation

pmusolino
Copy link
Member

Closes: #14004 (and peaMlT-U4)

Description

This pull request introduces improvements to handling the scenario when application passwords are disabled in user's website. The changes involve updating the error handling UI and navigation logic to provide a better user experience. This is a continuation of the job started by @hafizrahman here.

Testing information

  1. Create test site with WooCommerce and no Jetpack, on Jurassic Ninja.
  2. Install and active a plugin like this one https://wordpress.org/plugins/disable-application-passwords/
  3. Try to log in using application password to the test site.
  4. Confirm that the new dialog is shown.
  5. Confirm that tapping "Retry" button returns to two screens before the current one (instructions on how to approve the connection with application password).
  6. Confirm that tapping "Log In With Another Account" returns to the initial screen of the login process.

Screenshots

Before After
369337093-2987fa18-1589-4d07-9317-5cf5f7af9dac

  • I have considered if this change warrants user-facing release notes and have added them to RELEASE-NOTES.txt if necessary.

Reviewer (or Author, in the case of optional code reviews):

Please make sure these conditions are met before approving the PR, or request changes if the PR needs improvement:

  • The PR is small and has a clear, single focus, or a valid explanation is provided in the description. If needed, please request to split it into smaller PRs.
  • Ensure Adequate Unit Test Coverage: The changes are reasonably covered by unit tests or an explanation is provided in the PR description.
  • Manual Testing: The author listed all the tests they ran, including smoke tests when needed (e.g., for refactorings). The reviewer confirmed that the PR works as expected on all devices (phone/tablet) and no regressions are added.

hafizrahman and others added 7 commits October 31, 2024 16:23
…ledViewModel.swift

- Modify navigation logic to pop to the third last view controller or root if fewer than three
- Update primary button title to "Retry" for retrying application password authorization
- Remove outdated primary button title "Log in with WordPress.com"
…ordDisabledViewModel` using Woo mobile guidelines
@pmusolino pmusolino added the feature: login Related to any part of the log in or sign in flow, or authentication. label Jan 31, 2025
@pmusolino pmusolino added this to the 21.7 milestone Jan 31, 2025
@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Jan 31, 2025

WooCommerce iOS📲 You can test the changes from this Pull Request in WooCommerce iOS by scanning the QR code below to install the corresponding build.

App NameWooCommerce iOS WooCommerce iOS
Build Numberpr15031-98810f3
Version21.6
Bundle IDcom.automattic.alpha.woocommerce
Commit98810f3
App Center BuildWooCommerce - Prototype Builds #12774
Automatticians: You can use our internal self-serve MC tool to give yourself access to App Center if needed.

@itsmeichigo itsmeichigo self-assigned this Feb 3, 2025
Copy link
Contributor

@itsmeichigo itsmeichigo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While testing navigation back and forth, I encountered a case where the application password fetch failed with the following log:

Tracked application_password_authorization_url_fetch_failed, properties: [error_domain: Networking.RequestAuthenticatorError, error_description: Alamofire.AFError.requestAdaptationFailed(error: Networking.RequestAuthenticatorError.applicationPasswordNotAvailable), error_code: 1]

In this case, the fetchAuthURL method failed with error and the logic went through to the catch block, which showed an alert instead of the application password not available screen:

Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-02-03.at.11.50.29.mp4

We should also check the logic in this catch block to show the new screen if we get the applicationPasswordNotAvailable error.

Comment on lines 188 to 190
// Pop back two view controllers to remove both error and web view
navigationController?.popViewController(animated: false)
navigationController?.popViewController(animated: true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is hacky and prone to error. How about looking for the index of ApplicationPasswordTutorialViewController in the navigation stack, and pop to the index before that?

A better option would be to send the view controller before the application password flow to this view controller via presentApplicationPasswordWebView in AuthenticationManager.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you and with your second suggestion, so I applied the new changes in this commit: 9b480ba

Comment on lines 47 to 51
if viewControllers.count >= 3 {
navigationController.popToViewController(viewControllers[viewControllers.count - 3], animated: true)
} else {
navigationController.popToRootViewController(animated: true)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The number 3 seems to be a magic number, it's not clear why we have to do this. Please consider my suggestion above about looking for the index of a specific view controller to pop to.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I'm using the previousVC like in the comment above, please feel free to check changes here: 9b480ba 🙏

- Modify `ApplicationPasswordAuthorizationWebViewController.swift` to include a reference to the previous view controller for navigation purposes.
- Update `AuthenticationManager.swift` to pass the previous view controller to the web view used for application password authorization.
- Enhance `ApplicationPasswordDisabledViewModel.swift` to store the previous view controller and use it for navigation.
- Adjust `PostSiteCredentialLoginChecker.swift` to capture and utilize the last view controller before the application password flow.
- Update tests in `ApplicationPasswordDisabledViewModelTests.swift` to include the previous view controller in the view model initialization.
@pmusolino pmusolino requested a review from itsmeichigo February 3, 2025 14:54
@pmusolino
Copy link
Member Author

@itsmeichigo this is ready for another check 🙌

Copy link
Contributor

@itsmeichigo itsmeichigo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates, Paolo. I found a few issues with the new changes in the comments below.

Also, it seems that you missed the comment in my previous round about missing the case when fetching the authentication URL fails with Alamofire.AFError.requestAdaptationFailed(error: Networking.RequestAuthenticatorError.applicationPasswordNotAvailable).

@@ -34,6 +34,9 @@ final class ApplicationPasswordAuthorizationWebViewController: UIViewController
return indicator
}()

/// The view controller that was presenting the application password flow.
private weak var previousViewController: UIViewController?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering: is there any case where previousViewController can be deallocated when the user is still on ApplicationPasswordAuthorizationWebViewController? I'm curious why the weak reference is necessary here.

@@ -171,6 +189,15 @@ private extension ApplicationPasswordAuthorizationWebViewController {
}
}

/// Pops to the previous view controller (if provided) or pops one level otherwise.
@objc private func navigateToPreviousViewController() {
if let previous = previousViewController, let nav = navigationController {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super nit: we can simplify the if let checks now.

Suggested change
if let previous = previousViewController, let nav = navigationController {
if let previousViewController, let navigationController {

let image: UIImage = .errorImage

// The VC that was showing before the application password flow. This is used to navigate back without guesswork.
let previousViewController: UIViewController?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to a question above: the previousViewController reference is kept strongly here. Is it intentional to keep the weak reference in ApplicationPasswordAuthorizationWebViewController but strong here?

guard let viewController else {
return
guard let navigationController = viewController?.navigationController else { return }
if let previousViewController = previousViewController {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super nit:

Suggested change
if let previousViewController = previousViewController {
if let previousViewController {

Comment on lines +59 to +60
// show application password disabled error, and catch the last view controller that was showing before the Application Password flow.
let previousViewController = navigationController.viewControllers.dropLast().last
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the exact controller that you are navigating to here? Please note that the PostSiteCredentialLoginChecker can be triggered from two places: (1) after site credential login (if application password is not required), and (2) after application password login.

For (1), I'd suggest sending nil as the previous view controller to the PostSiteCredentialLoginChecker, so that the error page would simply pop itself upon navigating back.

For (2), I'd suggest sending the previous view controller from the application password entry point in AuthenticationManager

if let previousViewController = previousViewController {
navigationController.popToViewController(previousViewController, animated: true)
} else {
navigationController.popToRootViewController(animated: true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you want to pop to the previous view controller, popToRoot seems incorrect. Should it be popViewController?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature: login Related to any part of the log in or sign in flow, or authentication.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve disabled Application Password alert and add Support options
4 participants