diff --git a/CleanCodeApp/Modules/Features/Rum/ContactsUs/Model/RumContactUsError.swift b/CleanCodeApp/Modules/Features/Rum/ContactsUs/Model/RumContactUsError.swift index 1e2b39c..913e9eb 100644 --- a/CleanCodeApp/Modules/Features/Rum/ContactsUs/Model/RumContactUsError.swift +++ b/CleanCodeApp/Modules/Features/Rum/ContactsUs/Model/RumContactUsError.swift @@ -10,13 +10,36 @@ import Foundation enum RumContactUsError: Error { case networkError case decodingError + case invalidResponse + + var localizedDescription: String { + switch self { + case .networkError: + return "Erro de rede." + case .decodingError: + return "Falha ao decodificar os dados." + case .invalidResponse: + return "Resposta inválida." + } + } + + var shouldDismiss: Bool { + switch self { + case .networkError, .decodingError: + return false + case .invalidResponse: + return true + } + } var logMessage: String { switch self { case .networkError: - return "Network error: unable to reach the server." + return "Network error." case .decodingError: - return "Decoding error: failed to parse the response data." + return "Decoding error: Failed to decode data." + case .invalidResponse: + return "Invalid response from server." } } } diff --git a/CleanCodeApp/Modules/Features/Rum/ContactsUs/Services/RumContactUsAPIService.swift b/CleanCodeApp/Modules/Features/Rum/ContactsUs/Services/RumContactUsAPIService.swift index 77be6cf..51b8df1 100644 --- a/CleanCodeApp/Modules/Features/Rum/ContactsUs/Services/RumContactUsAPIService.swift +++ b/CleanCodeApp/Modules/Features/Rum/ContactsUs/Services/RumContactUsAPIService.swift @@ -12,28 +12,33 @@ protocol RumContactUsAPIServiceDelegate: AnyObject { } protocol RumContactAPIServicing { - func fetchContactUsData() async -> ContactUsModel - func sendMessage(parameters: [String: String]) async + func fetchContactUsData() async throws -> ContactUsModel + func sendMessage(parameters: [String: String]) async throws } final class RumContactUsAPIService: RumContactAPIServicing { weak var delegate: RumContactUsAPIServiceDelegate? + private let network: Networking - func fetchContactUsData() async -> ContactUsModel { + init(delegate: RumContactUsAPIServiceDelegate? = nil, network: Networking = AF.shared) { + self.delegate = delegate + self.network = network + } + + func fetchContactUsData() async throws -> ContactUsModel { let url = Endpoints.contactUs return await withCheckedContinuation { continuation in - AF.shared.request(url, method: .get, parameters: nil, headers: nil) { [weak self] response in + network.request(url, method: .get, parameters: nil, headers: nil) { [weak self] response in guard let self = self else { return } switch response { case .success(let data): - guard let contactUsModel = self.decodeContactUsData(data) else { return } - continuation.resume(returning: contactUsModel) + if let contactUsModel = self.decodeContactUsData(data) { + continuation.resume(returning: contactUsModel) + } else { + self.handleError(.decodingError) + } case .failure(_): - self.logError(error: .networkError) - self.delegate?.showAlertMessage( - title: "Ops..", - message: "Ocorreu algum erro", - shouldDismiss: true) + handleError(.networkError) } } } @@ -50,28 +55,47 @@ final class RumContactUsAPIService: RumContactAPIServicing { } } - func sendMessage(parameters: [String: String]) async { + func sendMessage(parameters: [String: String]) async throws { let url = Endpoints.sendMessage return await withCheckedContinuation { continuation in - AF.shared.request(url, method: .post, parameters: parameters, headers: nil) { response in + network.request(url, method: .post, parameters: parameters, headers: nil) { [weak self] response in + guard let self = self else { return } switch response { case .success: - self.delegate?.showAlertMessage( - title: "Sucesso..", - message: "Sua mensagem foi enviada", - shouldDismiss: true - ) + self.handleSuccess() case .failure(_): - self.logError(error: .networkError) - self.delegate?.showAlertMessage( - title: "Ops..", - message: "Ocorreu algum erro", - shouldDismiss: false) + self.handleError(.networkError) } } } } + private func handleError(_ error: RumContactUsError) { + logError(error: error) + + let alertTitle = "Ops..." + let alertMessage = error.localizedDescription + let shouldDismiss = error.shouldDismiss + + delegate?.showAlertMessage( + title: alertTitle, + message: alertMessage, + shouldDismiss: shouldDismiss + ) + } + + private func handleSuccess() { + let alertTitle = "Sucesso..." + let alertMessage = "Sua mensagem foi enviada" + let shouldDismiss = true + + delegate?.showAlertMessage( + title: alertTitle, + message: alertMessage, + shouldDismiss: shouldDismiss + ) + } + private func logError(error: RumContactUsError) { print("Log error: \(error.logMessage)") } diff --git a/CleanCodeApp/Modules/Features/Rum/ContactsUs/View/RumContactUsFactory.swift b/CleanCodeApp/Modules/Features/Rum/ContactsUs/View/RumContactUsFactory.swift new file mode 100644 index 0000000..fa15c2a --- /dev/null +++ b/CleanCodeApp/Modules/Features/Rum/ContactsUs/View/RumContactUsFactory.swift @@ -0,0 +1,19 @@ +// +// RumContactUsFactory.swift +// CleanCode +// +// Created by Rayana Prata Neves on 22/02/25. +// + +import UIKit + +enum RumContactUsFactory { + static func make() -> UIViewController { + let service = RumContactUsAPIService() + let viewController = RumContactUsViewController(service: service) + service.delegate = viewController + viewController.modalPresentationStyle = .fullScreen + viewController.modalTransitionStyle = .coverVertical + return viewController + } +} diff --git a/CleanCodeApp/Modules/Features/Rum/ContactsUs/View/RumContactUsViewController.swift b/CleanCodeApp/Modules/Features/Rum/ContactsUs/View/RumContactUsViewController.swift index b022946..1507f51 100644 --- a/CleanCodeApp/Modules/Features/Rum/ContactsUs/View/RumContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Rum/ContactsUs/View/RumContactUsViewController.swift @@ -52,27 +52,34 @@ final class RumContactUsViewController: LoadingInheritageController { func fetchData() { showLoadingView() Task { - self.model = await contactUsService.fetchContactUsData() + self.model = try await contactUsService.fetchContactUsData() removeLoadingView() } } @objc func didTapSendMessageButton() { view.endEditing(true) - let email = model?.mail ?? "" - if let message = contactUsView.textView.text, contactUsView.textView.text.count > 0 { - let parameters: [String: String] = [ - "email": email, - "mensagem": message - ] - sendMessage(parameters: parameters) - } + guard let message = validatedMessage() else { return } + let parameters = createMessageParameters(email: model?.mail ?? "", message: message) + sendMessage(parameters: parameters) + } + + private func validatedMessage() -> String? { + guard let message = contactUsView.textView.text, !message.isEmpty else { return nil } + return message + } + + private func createMessageParameters(email: String, message: String) -> [String: String] { + return [ + "email": email, + "mensagem": message + ] } private func sendMessage(parameters: [String: String]) { showLoadingView() Task { - await contactUsService.sendMessage(parameters: parameters) + try await contactUsService.sendMessage(parameters: parameters) removeLoadingView() } } diff --git a/CleanCodeApp/Modules/Features/Rum/ResetPassword/RumResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Rum/ResetPassword/RumResetPasswordViewController.swift index 325bb6f..0607267 100644 --- a/CleanCodeApp/Modules/Features/Rum/ResetPassword/RumResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Rum/ResetPassword/RumResetPasswordViewController.swift @@ -72,12 +72,8 @@ class RumResetPasswordViewController: UIViewController { } @IBAction func helpButton(_ sender: Any) { - let service = RumContactUsAPIService() - let vc = RumContactUsViewController(service: service) - service.delegate = vc - vc.modalPresentationStyle = .fullScreen - vc.modalTransitionStyle = .coverVertical - self.present(vc, animated: true, completion: nil) + let contactUsViewController = RumContactUsFactory.make() + self.present(contactUsViewController, animated: true, completion: nil) } @IBAction func createAccountButton(_ sender: Any) {