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

회원가입 화면을 생성하였습니다. #27

Closed
wants to merge 5 commits into from
Closed
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
60 changes: 60 additions & 0 deletions HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//
// EmptyResponse.swift
// HomeCafeRecipes
//
// Created by 김건호 on 9/11/24.
//

import Foundation

struct EmptyResponse: Decodable {}
104 changes: 52 additions & 52 deletions HomeCafeRecipes/HomeCafeRecipes/Data/Network/NetworkService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,61 +13,12 @@ import RxSwift
protocol NetworkService {
func getRequest<T: Decodable>(url: URL, responseType: T.Type) -> Single<T>
func postRequest<T: Decodable>(url: URL, parameters: [String: Any], imageDatas: [Data], responseType: T.Type) -> Single<T>
func postJsonRequest<T: Decodable>(url: URL, parameters:[String: Any], responseType: T.Type) -> Single<T>
}

class BaseNetworkService: NetworkService {

func getRequest<T: Decodable>(url: URL, responseType: T.Type) -> Single<T> {
var request = URLRequest(url: url)
request.httpMethod = "GET"
final class BaseNetworkService: NetworkService {
private func createRequest<T: Decodable>(with request: URLRequest, responseType: T.Type) -> Single<T> {
return Single.create { single in
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
single(.failure(error))
} else if let data = data {
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let responseObject = try decoder.decode(T.self, from: data)
single(.success(responseObject))
} catch let decodingError {
single(.failure(decodingError))
}
}
}
task.resume()

return Disposables.create {
task.cancel()
}
}
}

func postRequest<T: Decodable>(
url: URL, parameters: [String: Any],
imageDatas: [Data],
responseType: T.Type
) -> Single<T> {
return Single.create { single in
var formDataRequest = MultipartFormDataRequest(url: url)

for (key, value) in parameters {
formDataRequest.addTextField(named: key, value: String(describing: value))
}

for (index, imageData) in imageDatas.enumerated() {
let filename = "image\(index).jpg"
formDataRequest.addDataField(
named: "recipeImgUrls",
data: imageData,
filename: filename,
mimeType: "image/jpeg"
)
}

formDataRequest.finalize()
let request = formDataRequest.asURLRequest()

let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
single(.failure(error))
Expand Down Expand Up @@ -98,4 +49,53 @@ class BaseNetworkService: NetworkService {
}
}
}

func getRequest<T: Decodable>(url: URL, responseType: T.Type) -> Single<T> {
var request = URLRequest(url: url)
request.httpMethod = "GET"
return createRequest(with: request, responseType: responseType)
}

func postRequest<T: Decodable>(
url: URL, parameters: [String: Any],
imageDatas: [Data],
responseType: T.Type
) -> Single<T> {
var formDataRequest = MultipartFormDataRequest(url: url)

for (key, value) in parameters {
formDataRequest.addTextField(named: key, value: String(describing: value))
}

for (index, imageData) in imageDatas.enumerated() {
let filename = "image\(index).jpg"
formDataRequest.addDataField(
named: "recipeImgUrls",
data: imageData,
filename: filename,
mimeType: "image/jpeg"
)
}

formDataRequest.finalize()
let request = formDataRequest.asURLRequest()
return createRequest(with: request, responseType: responseType)
}

func postJsonRequest<T: Decodable>(
url: URL,
parameters: [String: Any],
responseType: T.Type
) -> Single<T> {
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else {
return .error(NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "JSON 인코딩 실패"]))
}

var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = httpBody

return createRequest(with: request, responseType: responseType)
}
}
63 changes: 63 additions & 0 deletions HomeCafeRecipes/HomeCafeRecipes/Data/Network/SignUpService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// SignUpService.swift
// HomeCafeRecipes
//
// Created by 김건호 on 9/11/24.
//

import Foundation

import RxSwift

protocol SignUpService {
func signUp(
userNickName: String,
userID: String,
password: String
) -> Single<Void>
}

final class SignUpServiceImpl: SignUpService {
private let networkService: NetworkService

init(networkService: NetworkService) {
self.networkService = networkService
}

private func makeURL(endpoint: String) -> URL {
return APIConfig().baseURL.appendingPathComponent(endpoint)
}

func signUp(
userNickName: String,
userID: String,
password: String
) -> Single<Void> {
let url = makeURL(endpoint: "auth/register")

let parameters: [String: Any] = [
"email": userID,
"password": password,
"nickname": userNickName
]

return networkService.postJsonRequest(
url: url,
parameters: parameters,
responseType: NetworkResponseDTO<EmptyResponse>.self
)
.flatMap { response in
if response.statusCode == 200 {
// 성공 시 data가 null이더라도 성공 처리
return .just(())
} else {
// statusCode가 200이 아니면 에러 처리
return .error(NSError(domain: "SignUpError", code: response.statusCode, userInfo: [NSLocalizedDescriptionKey: response.message]))
}
}
.catch { error in
// 네트워크 또는 서버에서 에러가 발생했을 경우 처리
return .error(error)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// SignUpRepository.swift
// HomeCafeRecipes
//
// Created by 김건호 on 9/10/24.
//

import UIKit

import RxSwift

protocol SignUpRepository {
func signUp(userNickName: String, userID: String, password: String) -> Single<Void>
}

final class SignUpRepositoryImpl: SignUpRepository {

private let SignUpService: SignUpService

init(SignUpService: SignUpService) {
self.SignUpService = SignUpService
}

func signUp(userNickName: String, userID: String, password: String) -> Single<Void> {
return SignUpService.signUp(
userNickName: userNickName,
userID: userID,
password: password
)
}
}
33 changes: 33 additions & 0 deletions HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/SignUpError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// SignUpError.swift
// HomeCafeRecipes
//
// Created by 김건호 on 9/8/24.
//

import Foundation

enum SignUpError: Error {
case passwordMismatch
case genericError(Error)
}

extension SignUpError: LocalizedError {
var title: String {
switch self {
case .passwordMismatch:
return "비밀번호 불일치"
case .genericError:
return "회원가입 실패"
}
}

var errorDescription: String? {
switch self {
case .passwordMismatch:
return "비밀번호를 확인해 주세요"
case .genericError(let error):
return error.localizedDescription
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// SignUpInteractor.swift
// HomeCafeRecipes
//
// Created by 김건호 on 9/7/24.
//

import UIKit

import RxSwift

protocol SignUpViewControllerDelegate: AnyObject {
func loadnewUser(viewModel: SignUpViewModel)
}

protocol SignUpInteractor {
func loadNewUser()
func signUp() -> Single<SignUpError?>
func didEndEditing(userNickName: String)
func didEndEditing(userID: String)
func didEndEditing(password: String)
func didEndEditing(checkpassword: String)

}

final class SignUpInteractorImpl: SignUpInteractor {

private var userNickName: String = ""
private var userID: String = ""
private var password: String = ""
private var checkpassword: String = ""

weak var delegate: SignUpViewControllerDelegate?

private let usecase: SignUpUseCase


init(usecase: SignUpUseCase){
self.usecase = usecase
}

func loadNewUser() {
let viewmodel = SignUpViewModel(
nickName: userNickName,
ID: userID,
password: password,
checkpassword: checkpassword
)
delegate?.loadnewUser(viewModel: viewmodel)
}

func didEndEditing(userNickName: String) {
self.userNickName = userNickName
}

func didEndEditing(userID: String) {
self.userID = userID
}

func didEndEditing(password: String) {
self.password = password
}

func didEndEditing(checkpassword: String) {
self.checkpassword = checkpassword
}

func signUp() -> Single<SignUpError?> {
return usecase.execute(
userNickName: userNickName,
userID: userID,
password: password,
checkpassword: checkpassword
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// SignUpUseCase.swift
// HomeCafeRecipes
//
// Created by 김건호 on 9/8/24.
//

import Foundation

import RxSwift

protocol SignUpUseCase {
func execute(
userNickName: String,
userID: String,
password: String,
checkpassword: String
) -> Single<SignUpError?>
}

final class SignUpUseCaseImpl: SignUpUseCase {
private let repository: SignUpRepository

init(repository: SignUpRepository) {
self.repository = repository
}

func execute(
userNickName: String,
userID: String,
password: String,
checkpassword: String
) -> Single<SignUpError?> {

guard password.isCheck(equalTo: checkpassword) else {
return .just(.passwordMismatch)
}

return repository.signUp(
userNickName: userNickName,
userID: userID,
password: password
)
.map { _ in
return nil
}
.catch { error in
return .just(.genericError(error))
}
}
}
Loading
Loading