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

Added UnrecoverableError support and retry links #419

Merged
merged 4 commits into from
Apr 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Lock.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -522,8 +522,8 @@
5BB4A7C01DF9A38E008E8C37 /* DatabaseView.swift */,
5F1C49921D8360DF005B74FC /* LoadingView.swift */,
5B55F3C81E24273D00B75CF5 /* UnrecoverableErrorView.swift */,
5F73CDD31D3073BE00D8D8D1 /* DatabaseForgotPasswordView.swift */,
5B5F9F9E1E4B3FBE00EAB9EE /* PasswordlessView.swift */,
5F73CDD31D3073BE00D8D8D1 /* DatabaseForgotPasswordView.swift */,
5B0971811DC8FAC5003AA88F /* EnterpriseDomainView.swift */,
5B4DE0181DD670F7004C8AC2 /* EnterpriseActiveAuthView.swift */,
5F50900D1D1DF40400EAA650 /* DatabaseOnlyView.swift */,
Expand Down
16 changes: 14 additions & 2 deletions Lock/Base.lproj/Lock.strings
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@
"com.auth0.lock.error.passwordless.invalid_link" = "WE'RE SORRY, THERE WAS A PROBLEM WITH YOUR LINK. PLEASE REQUEST A NEW ONE.";
// Passwordless sign ups disabled.
"com.auth0.lock.error.passwordless.signup_disabled" = "NEW SIGN UPS ARE DISABLED FOR THIS ACCOUNT, PLEASE CONTACT YOUR ADMINISTRATOR.";
// Recoverable error button
"com.auth0.lock.error.recoverable.button" = "Retry";
// Recoverable error message
"com.auth0.lock.error.recoverable.message" = "Please check your internet connection.";
// Recoverable error title
"com.auth0.lock.error.recoverable.title" = "Can't load the login box";
// Generic sign up error
"com.auth0.lock.error.signup.fallback" = "WE'RE SORRY, SOMETHING WENT WRONG WHEN ATTEMPTING TO SIGN UP.";
// invalid_password
Expand All @@ -80,14 +86,22 @@
"com.auth0.lock.error.signup.password_no_user_info_error" = "PASSWORD IS BASED ON USER INFORMATION.";
// password_strength_error
"com.auth0.lock.error.signup.password_strength_error" = "PASSWORD IS TOO WEAK.";
// Unrecoverable error button
"com.auth0.lock.error.unrecoverable.button" = "Contact support";
// Default error
"com.auth0.lock.error.unrecoverable.default" = "Something went wrong.\nPlease contact technical support.";
// Invalid client or domain
"com.auth0.lock.error.unrecoverable.invalid_credentials" = "Your Auth0 credentials ClientId and/or Domain are invalid.";
// Your options configuration failed with: %@{error}
"com.auth0.lock.error.unrecoverable.invalid_options" = "Your options configuration failed with: %1$@";
// Unrecoverable error message
"com.auth0.lock.error.unrecoverable.message" = "There was an unexpected error while resolving the login box configuration.";
// Unrecoverable error message
"com.auth0.lock.error.unrecoverable.message.no_action" = "There was an unexpected error while resolving the login box configuration, please contact support.";
// No connections
"com.auth0.lock.error.unrecoverable.no_connections" = "No authentication methods found for this client. please check your client setup.";
// Unrecoverable error title
"com.auth0.lock.error.unrecoverable.title" = "Can't resolve your request";
// Forgot Password message
"com.auth0.lock.forgot.message" = "Please enter your email and the new password. We will send you an email to confirm the password change.";
// Forgot Password title
Expand Down Expand Up @@ -208,8 +222,6 @@
"com.auth0.lock.strategy.signup.title" = "SIGN UP WITH %1$@";
// Login Button title
"com.auth0.lock.submit.login.title" = "LOG IN";
// Retry
"com.auth0.lock.submit.retry.title" = "RETRY";
// Send 2fa code
"com.auth0.lock.submit.send_code.title" = "SEND";
// Send Email button title
Expand Down
12 changes: 12 additions & 0 deletions Lock/Lock.xcassets/ic_connection_error.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_connection_error.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.
1 change: 1 addition & 0 deletions Lock/LockOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct LockOptions: OptionBuildable {
var closable: Bool = false
var termsOfServiceURL: URL = URL(string: "https://auth0.com/terms")!
var privacyPolicyURL: URL = URL(string: "https://auth0.com/privacy")!
var supportURL: URL?
var logLevel: LoggerLevel = .off
var loggerOutput: LoggerOutput?
var logHttpRequest: Bool = false
Expand Down
15 changes: 15 additions & 0 deletions Lock/OptionBuildable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public protocol OptionBuildable: Options {
/// Privacy Policy URL. By default is Auth0's.
var privacyPolicyURL: URL { get set }

/// Support page url that will be displayed (Inside Safari) when an unrecoverable error occurs and the user taps the "Contact Support" button in the error screen.
var supportURL: URL? { get set }

/// Log level for Lock. By default is `Off`.
var logLevel: LoggerLevel { get set }

Expand Down Expand Up @@ -136,4 +139,16 @@ public extension OptionBuildable {
}
}

/// Support Page URL. By default is not set.
var supportPage: String? {
get {
guard let url = self.supportURL else { return nil }
return url.absoluteString
}
set {
guard let value = newValue, let url = URL(string: value) else { return } // FIXME: log error
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it's time to remove those notes and log the error? 😝 It can be in another PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

One day :)

self.supportURL = url
}
}

}
1 change: 1 addition & 0 deletions Lock/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public protocol Options {

var termsOfServiceURL: URL { get }
var privacyPolicyURL: URL { get }
var supportURL: URL? { get }

var logLevel: LoggerLevel { get }
var loggerOutput: LoggerOutput? { get }
Expand Down
3 changes: 2 additions & 1 deletion Lock/Router.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ extension Router {
}

func unrecoverableError(for error: UnrecoverableError) -> Presentable? {
let presenter = UnrecoverableErrorPresenter(error: error, navigator: self)
guard let options = self.controller?.lock.options else { return nil }
let presenter = UnrecoverableErrorPresenter(error: error, navigator: self, options: options)
return presenter
}
}
9 changes: 9 additions & 0 deletions Lock/UnrecoverableError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ enum UnrecoverableError: Equatable, Error {
return "Something went wrong.\nPlease contact technical support.".i18n(key: "com.auth0.lock.error.unrecoverable.default", comment: "Default error")
}
}

var canRetry: Bool {
switch self {
case .connectionTimeout, .requestIssue:
return true
default:
return false
}
}
}

func == (lhs: UnrecoverableError, rhs: UnrecoverableError) -> Bool {
Expand Down
20 changes: 15 additions & 5 deletions Lock/UnrecoverableErrorPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,31 @@

import Foundation

class UnrecoverableErrorPresenter: Presentable, Loggable {
class UnrecoverableErrorPresenter: Presentable {
let navigator: Navigable
let error: UnrecoverableError
let options: Options

var messagePresenter: MessagePresenter?

init(error: UnrecoverableError, navigator: Navigable) {
init(error: UnrecoverableError, navigator: Navigable, options: Options) {
self.navigator = navigator
self.error = error
self.options = options
}

var view: View {
let view = UnrecoverableErrorView(message: self.error.localizableMessage)
view.primaryButton?.onPress = { _ in
self.navigator.navigate(.root)
let view = UnrecoverableErrorView(canRetry: self.error.canRetry)
if self.error.canRetry {
view.secondaryButton?.onPress = { _ in
self.navigator.navigate(.root)
}
} else if let supportURL = self.options.supportURL {
view.secondaryButton?.onPress = { _ in
UIApplication.shared.openURL(supportURL)
}
view.secondaryButton?.isHidden = false
view.messageLabel?.text = "There was an unexpected error while resolving the login box configuration.".i18n(key: "com.auth0.lock.error.unrecoverable.message", comment: "Unrecoverable error message")
}
return view
}
Expand Down
87 changes: 57 additions & 30 deletions Lock/UnrecoverableErrorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,50 +24,77 @@ import UIKit

class UnrecoverableErrorView: UIView, View {

weak var primaryButton: PrimaryButton?
weak var label: UILabel?
weak var secondaryButton: SecondaryButton?
weak var messageLabel: UILabel?

init(message: String) {
let primaryButton = PrimaryButton()
init(canRetry: Bool) {
let center = UILayoutGuide()
let label = UILabel()

self.primaryButton = primaryButton
self.label = label
let titleLabel = UILabel()
let messageLabel = UILabel()
let imageView = UIImageView()
let actionButton = SecondaryButton()
self.secondaryButton = actionButton
self.messageLabel = messageLabel

super.init(frame: CGRect.zero)

self.addSubview(primaryButton)
self.addSubview(label)
self.addSubview(imageView)
self.addSubview(titleLabel)
self.addSubview(messageLabel)
self.addSubview(actionButton)
self.addLayoutGuide(center)

constraintEqual(anchor: center.leftAnchor, toAnchor: self.leftAnchor, constant: 20)
constraintEqual(anchor: center.leftAnchor, toAnchor: self.leftAnchor)
constraintEqual(anchor: center.topAnchor, toAnchor: self.topAnchor)
constraintEqual(anchor: center.rightAnchor, toAnchor: self.rightAnchor, constant: -20)
constraintEqual(anchor: center.bottomAnchor, toAnchor: primaryButton.topAnchor)

constraintEqual(anchor: label.leftAnchor, toAnchor: center.leftAnchor)
constraintEqual(anchor: label.rightAnchor, toAnchor: center.rightAnchor)
constraintEqual(anchor: label.centerYAnchor, toAnchor: center.centerYAnchor, constant: -20)
label.translatesAutoresizingMaskIntoConstraints = false

constraintEqual(anchor: primaryButton.leftAnchor, toAnchor: self.leftAnchor)
constraintEqual(anchor: primaryButton.rightAnchor, toAnchor: self.rightAnchor)
constraintEqual(anchor: primaryButton.bottomAnchor, toAnchor: self.bottomAnchor)
primaryButton.translatesAutoresizingMaskIntoConstraints = false

label.text = message
label.textAlignment = .center
label.numberOfLines = 3
label.font = mediumSystemFont(size: 16)
primaryButton.title = "RETRY".i18n(key: "com.auth0.lock.submit.retry.title", comment: "Retry")
constraintEqual(anchor: center.rightAnchor, toAnchor: self.rightAnchor)
constraintEqual(anchor: center.bottomAnchor, toAnchor: self.bottomAnchor)

constraintEqual(anchor: imageView.centerXAnchor, toAnchor: center.centerXAnchor)
constraintEqual(anchor: imageView.centerYAnchor, toAnchor: center.centerYAnchor, constant: -90)
imageView.translatesAutoresizingMaskIntoConstraints = false

constraintEqual(anchor: titleLabel.leftAnchor, toAnchor: self.leftAnchor, constant: 20)
constraintEqual(anchor: titleLabel.rightAnchor, toAnchor: self.rightAnchor, constant: -20)
constraintEqual(anchor: titleLabel.centerYAnchor, toAnchor: center.centerYAnchor, constant: -15)
titleLabel.translatesAutoresizingMaskIntoConstraints = false

constraintEqual(anchor: messageLabel.leftAnchor, toAnchor: self.leftAnchor, constant: 20)
constraintEqual(anchor: messageLabel.rightAnchor, toAnchor: self.rightAnchor, constant: -20)
constraintEqual(anchor: messageLabel.topAnchor, toAnchor: titleLabel.bottomAnchor, constant: 15)
messageLabel.translatesAutoresizingMaskIntoConstraints = false

constraintEqual(anchor: actionButton.centerXAnchor, toAnchor: center.centerXAnchor)
constraintEqual(anchor: actionButton.topAnchor, toAnchor: messageLabel.bottomAnchor, constant: 10)
actionButton.translatesAutoresizingMaskIntoConstraints = false

imageView.image = LazyImage(name: "ic_connection_error", bundle: bundleForLock()).image(compatibleWithTraits: self.traitCollection)
titleLabel.textAlignment = .center
titleLabel.font = lightSystemFont(size: 22)
titleLabel.numberOfLines = 1
messageLabel.textAlignment = .center
messageLabel.font = regularSystemFont(size: 15)
messageLabel.textColor = UIColor(red: 0.408, green: 0.408, blue: 0.408, alpha: 1.00)
messageLabel.numberOfLines = 3

actionButton.button?.setTitleColor(UIColor(red:0.04, green:0.53, blue:0.69, alpha:1.0), for: .normal)
actionButton.button?.titleLabel?.font = regularSystemFont(size: 16)

if canRetry {
titleLabel.text = "Can't load the login box".i18n(key: "com.auth0.lock.error.recoverable.title", comment: "Recoverable error title")
messageLabel.text = "Please check your internet connection.".i18n(key: "com.auth0.lock.error.recoverable.message", comment: "Recoverable error message")
actionButton.title = "Retry".i18n(key: "com.auth0.lock.error.recoverable.button", comment: "Recoverable error button")
} else {
titleLabel.text = "Can't resolve your request".i18n(key: "com.auth0.lock.error.unrecoverable.title", comment: "Unrecoverable error title")
messageLabel.text = "There was an unexpected error while resolving the login box configuration, please contact support.".i18n(key: "com.auth0.lock.error.unrecoverable.message.no_action", comment: "Unrecoverable error message")
actionButton.title = "Contact support".i18n(key: "com.auth0.lock.error.unrecoverable.button", comment: "Unrecoverable error button")
actionButton.isHidden = true
}
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func apply(style: Style) {
self.primaryButton?.apply(style: style)
}
}
18 changes: 18 additions & 0 deletions LockTests/OptionsSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ class OptionsSpec: QuickSpec {
expect(options.privacyPolicyURL.absoluteString) == "https://auth0.com/privacy"
}

it("should have Auth0 support as nil") {
expect(options.supportURL).to(beNil())
}

it("should return Auth0 supportPage as nil") {
expect(options.supportPage).to(beNil())
}

it("should have openid as scope") {
expect(options.scope) == "openid"
}
Expand Down Expand Up @@ -223,6 +231,16 @@ class OptionsSpec: QuickSpec {
options.privacyPolicy = "not a url"
expect(options.privacyPolicyURL.absoluteString) == "https://auth0.com/privacy"
}

it("should set support site") {
options.supportPage = "https://auth0.com/docs"
expect(options.supportURL?.absoluteString) == "https://auth0.com/docs"
}

it("should ignore invalid support site") {
options.supportPage = "not a url"
expect(options.supportURL?.absoluteString).to(beNil())
}
}
}
}
Loading