From a17ce7fec6b572c9421ff3ac0f27a334fc1a6d8f Mon Sep 17 00:00:00 2001 From: lfoliveira Date: Tue, 11 Feb 2025 22:29:54 -0300 Subject: [PATCH 1/2] added(): login view controller --- .../Luz/Login/LuzLoginEmailValidator.swift | 17 ++ .../Luz/Login/LuzLoginViewController.swift | 285 +++++++++++------- 2 files changed, 185 insertions(+), 117 deletions(-) create mode 100644 CleanCodeApp/Modules/Features/Luz/Login/LuzLoginEmailValidator.swift diff --git a/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginEmailValidator.swift b/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginEmailValidator.swift new file mode 100644 index 0000000..f5e0aba --- /dev/null +++ b/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginEmailValidator.swift @@ -0,0 +1,17 @@ +enum LuzLoginEmailValidatorError: Error { + case invalidEmail + case emptyEmail +} + +enum LuzLoginEmailValidator { + static func validate(_ email: String?) throws { + guard let email, !email.isEmpty else { + throw LuzLoginEmailValidatorError.emptyEmail + } + + let emailRegex = #"^[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"# + guard email.range(of: emailRegex, options: .regularExpression) != nil else { + throw LuzLoginEmailValidatorError.invalidEmail + } + } +} diff --git a/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewController.swift b/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewController.swift index 93362fe..c87aa06 100644 --- a/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewController.swift +++ b/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewController.swift @@ -1,7 +1,7 @@ import UIKit -class LuzLoginViewController: UIViewController { - +final class LuzLoginViewController: UIViewController { + @IBOutlet weak var heightLabelError: NSLayoutConstraint! @IBOutlet weak var errorLabel: UILabel! @@ -10,143 +10,155 @@ class LuzLoginViewController: UIViewController { @IBOutlet weak var loginButton: UIButton! @IBOutlet weak var createAccountButton: UIButton! - - var showPassword = true @IBOutlet weak var showPasswordButton: UIButton! + + var showPassword = true var errorInLogin = false override func viewDidLoad() { super.viewDidLoad() - verifyLogin() - - #if DEBUG - emailTextField.text = "clean.code@devpass.com" - passwordTextField.text = "111111" - #endif - - self.setupView() - self.validateButton() + setupDebugConfiguration() + setupView() + validateSession() + validateButton() } - open override var preferredStatusBarStyle: UIStatusBarStyle { + public override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } - func verifyLogin() { - if let _ = UserDefaultsManager.UserInfos.shared.readSesion() { - let vc = UINavigationController(rootViewController: LuzHomeViewController()) - let scenes = UIApplication.shared.connectedScenes - let windowScene = scenes.first as? UIWindowScene - let window = windowScene?.windows.first - window?.rootViewController = vc - window?.makeKeyAndVisible() - } + func setupDebugConfiguration() { + #if DEBUG + emailTextField.text = "clean.code@devpass.com" + passwordTextField.text = "111111" + #endif } - - @IBAction func loginButton(_ sender: Any) { + + func validateSession() { + guard UserDefaultsManager.UserInfos.shared.readSesion() != nil else { return } + setupHomeViewController() + } + + func checkConnectionInternet() { if !ConnectivityManager.shared.isConnected { - let alertController = UIAlertController(title: "Sem conexão", message: "Conecte-se à internet para tentar novamente", preferredStyle: .alert) - let actin = UIAlertAction(title: "Ok", style: .default) - alertController.addAction(actin) + let alertController = UIAlertController( + title: "Sem conexão", + message: "Conecte-se à internet para tentar novamente", + preferredStyle: .alert + ) + let alertAction = UIAlertAction( + title: "Ok", + style: .default + ) + alertController.addAction(alertAction) present(alertController, animated: true) - return } + } + + // MARK: - IBActions + @IBAction func loginDidTap(_ sender: Any) { + checkConnectionInternet() emailTextField.setDefaultColor() passwordTextField.setDefaultColor() showLoading() - let parameters: [String: String] = ["email": emailTextField.text!, - "password": passwordTextField.text!] - let endpoint = Endpoints.Auth.login - AF.shared.request(endpoint, method: .get, parameters: parameters, headers: nil) { result in - DispatchQueue.main.async { - self.stopLoading() - switch result { - case .success(let data): - let decoder = JSONDecoder() - if let session = try? decoder.decode(Session.self, from: data) { - let vc = UINavigationController(rootViewController: LuzHomeViewController()) - let scenes = UIApplication.shared.connectedScenes - let windowScene = scenes.first as? UIWindowScene - let window = windowScene?.windows.first - window?.rootViewController = vc - window?.makeKeyAndVisible() - UserDefaultsManager.UserInfos.shared.save(session: session, user: nil) - } else { - Globals.alertMessage(title: "Ops..", message: "Houve um problema, tente novamente mais tarde.", targetVC: self) - } - case .failure: - self.setErrorLogin("E-mail ou senha incorretos") - Globals.alertMessage(title: "Ops..", message: "Houve um problema, tente novamente mais tarde.", targetVC: self) - } + + AF.shared.request( + Endpoints.Auth.login, + method: .get, + parameters: makeParams(), + headers: nil + ) { result in + self.stopLoading() + switch result { + case .success(let data): + self.handleSuccess(data) + case .failure: + self.handleError() } } } - @IBAction func showPassword(_ sender: Any) { - if(showPassword == true) { - passwordTextField.isSecureTextEntry = false - showPasswordButton.setImage(UIImage.init(systemName: "eye.slash")?.withRenderingMode(.alwaysTemplate), for: .normal) - } else { - passwordTextField.isSecureTextEntry = true - showPasswordButton.setImage(UIImage.init(systemName: "eye")?.withRenderingMode(.alwaysTemplate), for: .normal) - } - showPassword = !showPassword + @IBAction func showPasswordDidTap(_ sender: Any) { + showPassword.toggle() + passwordTextField.isSecureTextEntry = !showPassword + let imageName = showPassword ? "eye.slash" : "eye" + showPasswordButton.setImage( + UIImage(systemName: imageName)?.withRenderingMode(.alwaysTemplate), + for: .normal + ) } - @IBAction func resetPasswordButton(_ sender: Any) { + @IBAction func resetPasswordDidTap(_ sender: Any) { let storyboard = UIStoryboard(name: "LuzUser", bundle: nil) - let vc = storyboard.instantiateViewController(withIdentifier: "LuzResetPasswordViewController") as! LuzResetPasswordViewController - vc.modalPresentationStyle = .fullScreen - present(vc, animated: true) + let viewController = storyboard.instantiateViewController( + withIdentifier: "LuzResetPasswordViewController" + ) as! LuzResetPasswordViewController + viewController.modalPresentationStyle = .fullScreen + present(viewController, animated: true) } - @IBAction func createAccountButton(_ sender: Any) { + @IBAction func createAccountDidTap(_ sender: Any) { let controller = LuzCreateAccountViewController() controller.modalPresentationStyle = .fullScreen present(controller, animated: true) } } -// MARK: - Comportamentos de layout -extension LuzLoginViewController { - +// MARK: - Setup View +private extension LuzLoginViewController { func setupView() { - heightLabelError.constant = 0 - loginButton.layer.cornerRadius = loginButton.frame.height / 2 - loginButton.backgroundColor = .blue - loginButton.setTitleColor(.white, for: .normal) - loginButton.isEnabled = true + configureUI() + configureGestureRecognizer() + validateButton() + } + func configureUI() { + heightLabelError.constant = 0 + configureButton(for: loginButton, backgroundColor: .blue, titleColor: .white) + configureBorderButton(for: createAccountButton, borderColor: .blue) showPasswordButton.tintColor = .lightGray - - createAccountButton.layer.cornerRadius = createAccountButton.frame.height / 2 - createAccountButton.layer.borderWidth = 1 - createAccountButton.layer.borderColor = UIColor.blue.cgColor - createAccountButton.setTitleColor(.blue, for: .normal) - createAccountButton.backgroundColor = .white - emailTextField.setDefaultColor() passwordTextField.setDefaultColor() - let gesture = UITapGestureRecognizer(target: self, action: #selector(didClickView)) - view.addGestureRecognizer(gesture) - view.isUserInteractionEnabled = true -// view.backgroundColor = .lightGray - validateButton() + } + + func configureButton( + for button: UIButton, + backgroundColor: UIColor, + titleColor: UIColor + ) { + button.layer.cornerRadius = button.frame.height / 2 + button.backgroundColor = backgroundColor + button.setTitleColor(titleColor, for: .normal) + button.isEnabled = true + } + + func configureBorderButton( + for button: UIButton, + borderColor: UIColor + ) { + button.layer.cornerRadius = button.frame.height / 2 + button.layer.borderWidth = 1 + button.layer.borderColor = borderColor.cgColor + button.setTitleColor(borderColor, for: .normal) + button.backgroundColor = .white + } + + func configureGestureRecognizer() { + let tapGestureRecognizer = UITapGestureRecognizer( + target: self, + action: #selector(viewDidTap) + ) + view.addGestureRecognizer(tapGestureRecognizer) } @objc - func didClickView() { + func viewDidTap() { view.endEditing(true) } - - //email + @IBAction func emailBeginEditing(_ sender: Any) { - if errorInLogin { - resetErrorLogin(emailTextField) - } else { - emailTextField.setEditingColor() - } + errorInLogin ? resetErrorLogin(emailTextField) : emailTextField.setEditingColor() } @IBAction func emailEditing(_ sender: Any) { @@ -156,14 +168,9 @@ extension LuzLoginViewController { @IBAction func emailEndEditing(_ sender: Any) { emailTextField.setDefaultColor() } - - //senha + @IBAction func passwordBeginEditing(_ sender: Any) { - if errorInLogin { - resetErrorLogin(passwordTextField) - } else { - passwordTextField.setEditingColor() - } + errorInLogin ? resetErrorLogin(passwordTextField) : passwordTextField.setEditingColor() } @IBAction func passwordEditing(_ sender: Any) { @@ -194,24 +201,14 @@ extension LuzLoginViewController { } } +// MARK: - Validate extension LuzLoginViewController { - func validateButton() { - if !emailTextField.text!.contains(".") || - !emailTextField.text!.contains("@") || - emailTextField.text!.count <= 5 { + do { + try LuzLoginEmailValidator.validate(emailTextField.text) + enableButton() + } catch { disableButton() - } else { - if let atIndex = emailTextField.text!.firstIndex(of: "@") { - let substring = emailTextField.text![atIndex...] - if substring.contains(".") { - enableButton() - } else { - disableButton() - } - } else { - disableButton() - } } } @@ -225,3 +222,57 @@ extension LuzLoginViewController { loginButton.isEnabled = true } } + +// MARK: - Handlers +extension LuzLoginViewController { + func handleSuccess(_ data: Data) { + do { + let session = try JSONDecoder().decode(Session.self, from: data) + Task { @MainActor in self.setupHomeViewController() } + UserDefaultsManager.UserInfos.shared.save(session: session, user: nil) + } catch { + debugPrint("error: \(error.localizedDescription)") + self.showErrorAlert() + } + } + + func handleError() { + setErrorLogin("E-mail ou senha incorretos") + showErrorAlert() + } + + func showErrorAlert() { + Globals.alertMessage( + title: "Ops..", + message: "Houve um problema, tente novamente mais tarde.", + targetVC: self + ) + } +} + +// MARK: - MakeParams +extension LuzLoginViewController { + func makeParams() -> [String: String] { + guard + let emailTextField = emailTextField.text, + let passwordTextField = passwordTextField.text + else { return [:] } + + return [ + "email": emailTextField, + "password": passwordTextField + ] + } +} + +// MARK: - Setup HomeViewController +extension LuzLoginViewController { + func setupHomeViewController() { + let navigationController = UINavigationController(rootViewController: LuzHomeViewController()) + let scenes = UIApplication.shared.connectedScenes + let windowScene = scenes.first as? UIWindowScene + let window = windowScene?.windows.first + window?.rootViewController = navigationController + window?.makeKeyAndVisible() + } +} From 203634ded4afa0aaa3cad63cffa051df7a765fe7 Mon Sep 17 00:00:00 2001 From: lfoliveira Date: Tue, 18 Feb 2025 21:05:32 -0300 Subject: [PATCH 2/2] fixed(): code revie --- .../HomeFlow/Home/LuzHomeCoordinator.swift | 19 +++ .../Luz/HomeFlow/Home/LuzHomeFactory.swift | 7 + .../Features/Luz/Login/LuzLoginFactory.swift | 8 + .../Luz/Login/LuzLoginViewController.swift | 148 +++++++----------- .../Luz/Login/LuzLoginViewModel.swift | 90 +++++++++++ .../LuzResetPasswordFactory.swift | 11 ++ 6 files changed, 194 insertions(+), 89 deletions(-) create mode 100644 CleanCodeApp/Modules/Features/Luz/HomeFlow/Home/LuzHomeCoordinator.swift create mode 100644 CleanCodeApp/Modules/Features/Luz/HomeFlow/Home/LuzHomeFactory.swift create mode 100644 CleanCodeApp/Modules/Features/Luz/Login/LuzLoginFactory.swift create mode 100644 CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewModel.swift create mode 100644 CleanCodeApp/Modules/Features/Luz/ResetPassword/LuzResetPasswordFactory.swift diff --git a/CleanCodeApp/Modules/Features/Luz/HomeFlow/Home/LuzHomeCoordinator.swift b/CleanCodeApp/Modules/Features/Luz/HomeFlow/Home/LuzHomeCoordinator.swift new file mode 100644 index 0000000..10c1623 --- /dev/null +++ b/CleanCodeApp/Modules/Features/Luz/HomeFlow/Home/LuzHomeCoordinator.swift @@ -0,0 +1,19 @@ +import UIKit + +protocol LuzHomeCoordinatorProtocol { + func start() +} + +final class LuzHomeCoordinator: LuzHomeCoordinatorProtocol { + private var window: UIWindow? + + public init(window: UIWindow?) { + self.window = window + } + + func start() { + let navigationController = LuzHomeFactory.make() + window?.rootViewController = navigationController + window?.makeKeyAndVisible() + } +} diff --git a/CleanCodeApp/Modules/Features/Luz/HomeFlow/Home/LuzHomeFactory.swift b/CleanCodeApp/Modules/Features/Luz/HomeFlow/Home/LuzHomeFactory.swift new file mode 100644 index 0000000..827132b --- /dev/null +++ b/CleanCodeApp/Modules/Features/Luz/HomeFlow/Home/LuzHomeFactory.swift @@ -0,0 +1,7 @@ +import UIKit + +enum LuzHomeFactory { + static func make() -> UINavigationController { + UINavigationController(rootViewController: LuzHomeViewController()) + } +} diff --git a/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginFactory.swift b/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginFactory.swift new file mode 100644 index 0000000..e41f77f --- /dev/null +++ b/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginFactory.swift @@ -0,0 +1,8 @@ +import UIKit + +enum LuzLoginFactory { + static func make() -> UIViewController { + let viewModel = LuzLoginViewModel() + return LuzLoginViewController(viewModel: viewModel) + } +} diff --git a/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewController.swift b/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewController.swift index c87aa06..c316c9f 100644 --- a/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewController.swift +++ b/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewController.swift @@ -1,20 +1,30 @@ import UIKit final class LuzLoginViewController: UIViewController { + private let viewModel: LuzLoginViewModel @IBOutlet weak var heightLabelError: NSLayoutConstraint! @IBOutlet weak var errorLabel: UILabel! - + @IBOutlet weak var emailTextField: UITextField! @IBOutlet weak var passwordTextField: UITextField! - + @IBOutlet weak var loginButton: UIButton! @IBOutlet weak var createAccountButton: UIButton! @IBOutlet weak var showPasswordButton: UIButton! var showPassword = true var errorInLogin = false - + + init(viewModel: LuzLoginViewModel) { + self.viewModel = viewModel + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func viewDidLoad() { super.viewDidLoad() setupDebugConfiguration() @@ -22,63 +32,54 @@ final class LuzLoginViewController: UIViewController { validateSession() validateButton() } - + public override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } func setupDebugConfiguration() { - #if DEBUG - emailTextField.text = "clean.code@devpass.com" - passwordTextField.text = "111111" - #endif + viewModel.setupDebugConfiguration( + for: emailTextField, + passwordTextField: passwordTextField + ) } func validateSession() { - guard UserDefaultsManager.UserInfos.shared.readSesion() != nil else { return } - setupHomeViewController() + viewModel.validateSession { [weak self] in + self?.setupHomeViewController() + } } func checkConnectionInternet() { - if !ConnectivityManager.shared.isConnected { - let alertController = UIAlertController( - title: "Sem conexão", - message: "Conecte-se à internet para tentar novamente", - preferredStyle: .alert - ) - let alertAction = UIAlertAction( - title: "Ok", - style: .default - ) - alertController.addAction(alertAction) - present(alertController, animated: true) + viewModel.checkConnectionInternet { [weak self] alert in + self?.present(alert, animated: true) } } // MARK: - IBActions - @IBAction func loginDidTap(_ sender: Any) { + @IBAction func didTapLogin(_ sender: Any) { checkConnectionInternet() emailTextField.setDefaultColor() passwordTextField.setDefaultColor() showLoading() - AF.shared.request( - Endpoints.Auth.login, - method: .get, - parameters: makeParams(), - headers: nil - ) { result in - self.stopLoading() - switch result { - case .success(let data): - self.handleSuccess(data) - case .failure: - self.handleError() + Task { + do { + let data = try await viewModel.login( + email: emailTextField.text, + password: passwordTextField.text + ) + stopLoading() + try viewModel.handleLoginSuccess(data: data) + Task { @MainActor in self.setupHomeViewController() } + } catch { + debugPrint("error: \(error.localizedDescription)") + handleError() } } } - - @IBAction func showPasswordDidTap(_ sender: Any) { + + @IBAction func didTapShowPassword(_ sender: Any) { showPassword.toggle() passwordTextField.isSecureTextEntry = !showPassword let imageName = showPassword ? "eye.slash" : "eye" @@ -87,18 +88,15 @@ final class LuzLoginViewController: UIViewController { for: .normal ) } - - @IBAction func resetPasswordDidTap(_ sender: Any) { - let storyboard = UIStoryboard(name: "LuzUser", bundle: nil) - let viewController = storyboard.instantiateViewController( - withIdentifier: "LuzResetPasswordViewController" - ) as! LuzResetPasswordViewController + + @IBAction func didTapResetPassword(_ sender: Any) { + let viewController = LuzResetPasswordFactory.make() viewController.modalPresentationStyle = .fullScreen present(viewController, animated: true) } - - - @IBAction func createAccountDidTap(_ sender: Any) { + + + @IBAction func didTapCreateAccount(_ sender: Any) { let controller = LuzCreateAccountViewController() controller.modalPresentationStyle = .fullScreen present(controller, animated: true) @@ -160,11 +158,11 @@ private extension LuzLoginViewController { @IBAction func emailBeginEditing(_ sender: Any) { errorInLogin ? resetErrorLogin(emailTextField) : emailTextField.setEditingColor() } - + @IBAction func emailEditing(_ sender: Any) { validateButton() } - + @IBAction func emailEndEditing(_ sender: Any) { emailTextField.setDefaultColor() } @@ -172,15 +170,15 @@ private extension LuzLoginViewController { @IBAction func passwordBeginEditing(_ sender: Any) { errorInLogin ? resetErrorLogin(passwordTextField) : passwordTextField.setEditingColor() } - + @IBAction func passwordEditing(_ sender: Any) { validateButton() } - + @IBAction func passwordEndEditing(_ sender: Any) { passwordTextField.setDefaultColor() } - + func setErrorLogin(_ message: String) { errorInLogin = true heightLabelError.constant = 20 @@ -188,7 +186,7 @@ private extension LuzLoginViewController { emailTextField.setErrorColor() passwordTextField.setErrorColor() } - + func resetErrorLogin(_ textField: UITextField) { heightLabelError.constant = 0 if textField == emailTextField { @@ -204,19 +202,18 @@ private extension LuzLoginViewController { // MARK: - Validate extension LuzLoginViewController { func validateButton() { - do { - try LuzLoginEmailValidator.validate(emailTextField.text) - enableButton() - } catch { - disableButton() - } + viewModel.validateButton( + email: emailTextField.text, + enable: enableButton, + disable: disableButton + ) } - + func disableButton() { loginButton.backgroundColor = .gray loginButton.isEnabled = false } - + func enableButton() { loginButton.backgroundColor = .blue loginButton.isEnabled = true @@ -225,17 +222,6 @@ extension LuzLoginViewController { // MARK: - Handlers extension LuzLoginViewController { - func handleSuccess(_ data: Data) { - do { - let session = try JSONDecoder().decode(Session.self, from: data) - Task { @MainActor in self.setupHomeViewController() } - UserDefaultsManager.UserInfos.shared.save(session: session, user: nil) - } catch { - debugPrint("error: \(error.localizedDescription)") - self.showErrorAlert() - } - } - func handleError() { setErrorLogin("E-mail ou senha incorretos") showErrorAlert() @@ -250,29 +236,13 @@ extension LuzLoginViewController { } } -// MARK: - MakeParams -extension LuzLoginViewController { - func makeParams() -> [String: String] { - guard - let emailTextField = emailTextField.text, - let passwordTextField = passwordTextField.text - else { return [:] } - - return [ - "email": emailTextField, - "password": passwordTextField - ] - } -} - // MARK: - Setup HomeViewController extension LuzLoginViewController { func setupHomeViewController() { - let navigationController = UINavigationController(rootViewController: LuzHomeViewController()) let scenes = UIApplication.shared.connectedScenes let windowScene = scenes.first as? UIWindowScene let window = windowScene?.windows.first - window?.rootViewController = navigationController - window?.makeKeyAndVisible() + let homeCoordinator = LuzHomeCoordinator(window: window) + homeCoordinator.start() } } diff --git a/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewModel.swift b/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewModel.swift new file mode 100644 index 0000000..38bc08a --- /dev/null +++ b/CleanCodeApp/Modules/Features/Luz/Login/LuzLoginViewModel.swift @@ -0,0 +1,90 @@ +import UIKit + +final class LuzLoginViewModel { + func setupDebugConfiguration( + for emailTextField: UITextField, + passwordTextField: UITextField + ) { + #if DEBUG + emailTextField.text = "clean.code@devpass.com" + passwordTextField.text = "111111" + #endif + } + + func validateSession(completion: @escaping () -> Void) { + guard UserDefaultsManager.UserInfos.shared.readSesion() != nil else { return } + completion() + } + + func checkConnectionInternet( + completion: @escaping (UIAlertController) -> Void + ) { + if !ConnectivityManager.shared.isConnected { + let alertController = UIAlertController( + title: "Sem conexão", + message: "Conecte-se à internet para tentar novamente", + preferredStyle: .alert + ) + let alertAction = UIAlertAction( + title: "Ok", + style: .default + ) + alertController.addAction(alertAction) + completion(alertController) + } + } + + func login( + email: String?, + password: String? + ) async throws -> Data { + return await withCheckedContinuation { continuation in + AF.shared.request( + Endpoints.Auth.login, + method: .get, + parameters: makeParams(email: email, password: password), + headers: nil + ) { result in + switch result { + case .success(let data): + continuation.resume(returning: data) + case .failure(let error): + continuation.resume(with: .failure(error as! Never)) + } + } + } + } + + func makeParams( + email: String?, + password: String? + ) -> [String: String] { + guard + let email, + let password + else { return [:] } + + return [ + "email": email, + "password": password + ] + } + + func handleLoginSuccess(data: Data) throws { + let session = try JSONDecoder().decode(Session.self, from: data) + UserDefaultsManager.UserInfos.shared.save(session: session, user: nil) + } + + func validateButton( + email: String?, + enable: @escaping () -> Void, + disable: @escaping () -> Void + ) { + do { + try LuzLoginEmailValidator.validate(email) + enable() + } catch { + disable() + } + } +} diff --git a/CleanCodeApp/Modules/Features/Luz/ResetPassword/LuzResetPasswordFactory.swift b/CleanCodeApp/Modules/Features/Luz/ResetPassword/LuzResetPasswordFactory.swift new file mode 100644 index 0000000..b45774f --- /dev/null +++ b/CleanCodeApp/Modules/Features/Luz/ResetPassword/LuzResetPasswordFactory.swift @@ -0,0 +1,11 @@ +import UIKit + +enum LuzResetPasswordFactory { + static func make() -> UIViewController { + let storyboard = UIStoryboard(name: "LuzUser", bundle: nil) + let viewController = storyboard.instantiateViewController( + withIdentifier: "LuzResetPasswordViewController" + ) as! LuzResetPasswordViewController + return viewController + } +}