Skip to content

Commit

Permalink
Merge pull request #30 from f-lab-edu/feature/SingUp
Browse files Browse the repository at this point in the history
아이디 중복 확인 로직 생성
  • Loading branch information
GeonH0 authored Sep 20, 2024
2 parents 4f699a7 + 6c7a8dc commit 294eff5
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 39 deletions.
8 changes: 8 additions & 0 deletions HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@
1DC7CC322C283C0200796889 /* RecipeUploadImgaeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC7CC312C283C0200796889 /* RecipeUploadImgaeCell.swift */; };
1DC7CC342C294F9200796889 /* SelectImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC7CC332C294F9200796889 /* SelectImageCell.swift */; };
1DD4F70A2C80C947003E9D9D /* LoginError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD4F7092C80C947003E9D9D /* LoginError.swift */; };
1DDF485B2C93DFC9000A082E /* CheckEmailError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF485A2C93DFC9000A082E /* CheckEmailError.swift */; };
1DDF485D2C9405CF000A082E /* CheckEmailRespones.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF485C2C9405CF000A082E /* CheckEmailRespones.swift */; };
1DDFFD842C1C324F0083B077 /* RecipeDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */; };
1DE19E9D2C1B3DC10031804A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19E9C2C1B3DC10031804A /* SceneDelegate.swift */; };
1DE19EA72C1B420A0031804A /* FeedListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE19EA52C1B420A0031804A /* FeedListRepository.swift */; };
Expand Down Expand Up @@ -216,6 +218,8 @@
1DC7CC312C283C0200796889 /* RecipeUploadImgaeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeUploadImgaeCell.swift; sourceTree = "<group>"; };
1DC7CC332C294F9200796889 /* SelectImageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectImageCell.swift; sourceTree = "<group>"; };
1DD4F7092C80C947003E9D9D /* LoginError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginError.swift; sourceTree = "<group>"; };
1DDF485A2C93DFC9000A082E /* CheckEmailError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckEmailError.swift; sourceTree = "<group>"; };
1DDF485C2C9405CF000A082E /* CheckEmailRespones.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckEmailRespones.swift; sourceTree = "<group>"; };
1DDFFD832C1C324F0083B077 /* RecipeDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailViewController.swift; sourceTree = "<group>"; };
1DE19E9C2C1B3DC10031804A /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
1DE19EA52C1B420A0031804A /* FeedListRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedListRepository.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -282,6 +286,7 @@
1DBC63652C47D23000DA00C2 /* AddRecipeError.swift */,
1DD4F7092C80C947003E9D9D /* LoginError.swift */,
1D2398B32C8DC23500626F0C /* SignUpError.swift */,
1DDF485A2C93DFC9000A082E /* CheckEmailError.swift */,
);
path = Entities;
sourceTree = "<group>";
Expand Down Expand Up @@ -438,6 +443,7 @@
1D7368792C32EB18000EF904 /* RecipeUploadDTO.swift */,
1D7368852C33D7BE000EF904 /* RecipeUploadResponseDTO.swift */,
1DBD90BA2C91DE1600184F67 /* EmptyResponse.swift */,
1DDF485C2C9405CF000A082E /* CheckEmailRespones.swift */,
);
path = DTO;
sourceTree = "<group>";
Expand Down Expand Up @@ -765,6 +771,7 @@
1DF0D1A12C7B92F800E2C94C /* User.swift in Sources */,
1D73687A2C32EB18000EF904 /* RecipeUploadDTO.swift in Sources */,
1D2C6F6A2C26AF9F004BB54E /* AddRecipeView.swift in Sources */,
1DDF485D2C9405CF000A082E /* CheckEmailRespones.swift in Sources */,
1D2C6F682C246998004BB54E /* AddRecipeViewController.swift in Sources */,
1DFC961C2C90809D006C3309 /* SignUpRepository.swift in Sources */,
1DF829B72C2A7CDC00C337FC /* UIImageViewImageLoading.swift in Sources */,
Expand All @@ -790,6 +797,7 @@
1D2398B22C8DC07800626F0C /* SignUpUseCase.swift in Sources */,
1DC7CC342C294F9200796889 /* SelectImageCell.swift in Sources */,
1DE19E9D2C1B3DC10031804A /* SceneDelegate.swift in Sources */,
1DDF485B2C93DFC9000A082E /* CheckEmailError.swift in Sources */,
1D4741D12C1B4F8D009381CE /* RecipeImageDTO.swift in Sources */,
1DF6E1432C8C561E005E8875 /* SignUpInteractor.swift in Sources */,
1DF0D1AB2C7DF9B500E2C94C /* LoginViewController.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// CheckEmailRespones.swift
// HomeCafeRecipes
//
// Created by 김건호 on 9/13/24.
//

import Foundation

struct CheckEmailResponesDTO: Decodable {
let isDuplicated: Bool
}
28 changes: 25 additions & 3 deletions HomeCafeRecipes/HomeCafeRecipes/Data/Network/SignUpService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ protocol SignUpService {
userID: String,
password: String
) -> Single<Void>
func checkEmail(userID: String) -> Single<Bool>
}

final class SignUpServiceImpl: SignUpService {
Expand Down Expand Up @@ -48,15 +49,36 @@ final class SignUpServiceImpl: SignUpService {
)
.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)
}
}

func checkEmail(userID: String) -> Single<Bool> {
let url = makeURL(endpoint: "auth/checkEmail")

let parameters: [String: Any] = [
"email" : userID
]

return networkService.postJsonRequest(
url: url,
parameters: parameters,
responseType: NetworkResponseDTO<CheckEmailResponesDTO>.self
)
.flatMap { response in
if response.statusCode == 200 {
return .just(response.data.isDuplicated)
} else {
return .error(NSError(domain: "CheckEmailError", code: response.statusCode, userInfo: [NSLocalizedDescriptionKey: response.message]))
}
}
.catch { error in
return .error(error)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// checkEmailRepository.swift
// HomeCafeRecipes
//
// Created by 김건호 on 9/10/24.
//

import Foundation

import RxSwift

protocol CheckEmailRepository {
func checkEmail(userID: String) -> Single<Bool>
}

final class CheckEmailRepositoryImpl: CheckEmailRepository {
private let signUpPostService: SignUpService

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

func checkEmail(userID: String) -> Single<Bool> {
return signUpPostService.checkEmail(userID: userID)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ protocol SignUpViewControllerDelegate: AnyObject {
protocol SignUpInteractor {
func loadNewUser()
func signUp() -> Single<SignUpError?>
func checkEmail() -> Single<Bool>
func didEndEditing(userNickName: String)
func didEndEditing(userID: String)
func didEndEditing(password: String)
Expand All @@ -33,10 +34,12 @@ final class SignUpInteractorImpl: SignUpInteractor {
weak var delegate: SignUpViewControllerDelegate?

private let usecase: SignUpUseCase
private let checkeEmailUsecase: CheckEmailUseCase


init(usecase: SignUpUseCase){
init(usecase: SignUpUseCase,checkeEmailUsecase: CheckEmailUseCase){
self.usecase = usecase
self.checkeEmailUsecase = checkeEmailUsecase
}

func loadNewUser() {
Expand Down Expand Up @@ -73,4 +76,8 @@ final class SignUpInteractorImpl: SignUpInteractor {
checkpassword: checkpassword
)
}

func checkEmail() -> Single<Bool> {
return checkeEmailUsecase.execute(email: userID)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// CheckEmailUsecase.swift
// HomeCafeRecipes
//
// Created by 김건호 on 9/10/24.
//

import Foundation

import RxSwift

protocol CheckEmailUseCase {
func execute(email: String) -> Single<Bool>
}

final class CheckEmailUseCaseImpl: CheckEmailUseCase {
private let repository: CheckEmailRepository

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

private func isValidEmail(_ email: String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPredicate = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
return emailPredicate.evaluate(with: email)
}

func execute(email: String) -> Single<Bool> {
guard isValidEmail(email) else {
return Single.error(NSError(
domain: "InvalidEmailError",
code: -1,
userInfo: [NSLocalizedDescriptionKey: "잘못된 이메일 형식입니다."])
)
}
return repository.checkEmail(userID: email)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,6 @@ final class LoginViewController: UIViewController {
])
}

private func showCompletedAlert(title: String, message: String, success: Bool) {
let alert = UIAlertController(
title: title,
message: message,
preferredStyle: .alert
)
let confirmAction = UIAlertAction(title: "확인", style: .default) { _ in
if success {
self.navigationController?.popViewController(animated: true)
}
}
alert.addAction(confirmAction)
present(alert, animated: true, completion: nil)
}

private func login(ID: String, password: String) {
loginInteractor.login(userID: ID, password: password)
.subscribe(onSuccess: { [weak self] result in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import UIKit
protocol SignupviewDelegate: AnyObject {
func didTapBackButton()
func didTapSignupButton()
func didTapcheckEmailButton()
func didUpdateTextFields()
}

Expand All @@ -36,7 +37,24 @@ final class SignUpView: UIView {
return IDLabel
}()

private lazy var IDField: UITextField = { [weak self] in
lazy var checkEmailButton: UIButton = {
let checkEmailButton = UIButton()
checkEmailButton.setTitle("중복 확인", for: .normal)
checkEmailButton.backgroundColor = .systemBlue
checkEmailButton.titleLabel?.font = Fonts.detailBodyFont
checkEmailButton.layer.cornerRadius = 8
checkEmailButton.addAction(
UIAction(
handler: { [weak self] _ in
self?.delegate?.didTapcheckEmailButton()
}
),
for: .touchUpInside
)
return checkEmailButton
}()

lazy var IDField: UITextField = { [weak self] in
let IDTextField = UITextField()
IDTextField.placeholder = "Enter your ID"
IDTextField.borderStyle = .roundedRect
Expand Down Expand Up @@ -133,6 +151,7 @@ final class SignUpView: UIView {
addSubview(nicknameField)
addSubview(IDLabel)
addSubview(IDField)
addSubview(checkEmailButton)
addSubview(passwordLabel)
addSubview(passwordField)
addSubview(passwordCheckLabel)
Expand All @@ -145,6 +164,7 @@ final class SignUpView: UIView {
nicknameField.translatesAutoresizingMaskIntoConstraints = false
IDLabel.translatesAutoresizingMaskIntoConstraints = false
IDField.translatesAutoresizingMaskIntoConstraints = false
checkEmailButton.translatesAutoresizingMaskIntoConstraints = false
passwordLabel.translatesAutoresizingMaskIntoConstraints = false
passwordField.translatesAutoresizingMaskIntoConstraints = false
passwordCheckLabel.translatesAutoresizingMaskIntoConstraints = false
Expand All @@ -171,7 +191,11 @@ final class SignUpView: UIView {

IDField.topAnchor.constraint(equalTo: IDLabel.bottomAnchor, constant: 10),
IDField.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20),
IDField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),

checkEmailButton.centerYAnchor.constraint(equalTo: IDField.centerYAnchor),
checkEmailButton.leadingAnchor.constraint(equalTo: IDField.trailingAnchor, constant: 10),
checkEmailButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),
checkEmailButton.widthAnchor.constraint(equalToConstant: 100),

passwordLabel.topAnchor.constraint(equalTo: IDField.bottomAnchor, constant: 20),
passwordLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20),
Expand Down Expand Up @@ -199,7 +223,7 @@ final class SignUpView: UIView {
@objc private func handleTextFieldEditing(_ textField: UITextField) {
delegate?.didUpdateTextFields()
}

var nickname: String {
return nicknameField.text ?? ""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ final class SignUpViewController: UIViewController {

private func signUp() {
signUpInteractor.didEndEditing(userNickName: contentView.nickname)
signUpInteractor.didEndEditing(userID: contentView.ID)
signUpInteractor.didEndEditing(password: contentView.password)
signUpInteractor.didEndEditing(checkpassword: contentView.passwordCheck)

Expand All @@ -68,6 +67,27 @@ final class SignUpViewController: UIViewController {
})
.disposed(by: disposeBag)
}

private func checkEmail() {
signUpInteractor.didEndEditing(userID: contentView.ID)

signUpInteractor.checkEmail()
.subscribe(onSuccess: { [weak self] isAvailable in
DispatchQueue.main.async {
if (isAvailable == false) {
self?.showCompletedAlert(title: "이메일 사용 가능", message: "이메일을 사용할 수 있습니다.", success: false)
self?.contentView.IDField.isEnabled = false
} else {
self?.showCompletedAlert(title: "이메일 사용 불가", message: "이미 사용 중인 이메일입니다.", success: false)
}
}
}, onFailure: { [weak self] error in
DispatchQueue.main.async {
self?.showCompletedAlert(title: "오류", message: error.localizedDescription, success: false)
}
})
.disposed(by: disposeBag)
}
}

// MARK: SignupviewDelegate
Expand All @@ -92,6 +112,8 @@ extension SignUpViewController: SignupviewDelegate {
signUp()
}

func didTapcheckEmailButton() {
checkEmail()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,21 +84,6 @@ final class AddRecipeViewController: UIViewController {
.disposed(by: disposeBag)
}

private func showCompletedAlert(title: String, message: String, success: Bool) {
let alert = UIAlertController(
title: title,
message: message,
preferredStyle: .alert
)
let confirmAction = UIAlertAction(title: "확인", style: .default) { _ in
if success {
self.navigationController?.popViewController(animated: true)
}
}
alert.addAction(confirmAction)
present(alert, animated: true, completion: nil)
}

private func checkPhotoLibraryPermission(completion: @escaping (Bool) -> Void) {
let status = PHPhotoLibrary.authorizationStatus()
switch status {
Expand Down
19 changes: 18 additions & 1 deletion HomeCafeRecipes/HomeCafeRecipes/Router/Router.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,24 @@ extension Router {
}

func makeSignUpViewController() -> SignUpViewController {
let signUpViewcontroller = SignUpViewController()
let signUpInteractor = SignUpInteractorImpl(
usecase: SignUpUseCaseImpl(
repository: SignUpRepositoryImpl(
SignUpService: SignUpServiceImpl(
networkService: BaseNetworkService()
)
)
), checkeEmailUsecase: CheckEmailUseCaseImpl(
repository: CheckEmailRepositoryImpl(
signUpPostService: SignUpServiceImpl(
networkService: BaseNetworkService()
)
)
)
)
let loginRouter = LoginRouterImpl(router: self)
let signUpViewcontroller = SignUpViewController(
signUpInteractor: signUpInteractor, router: loginRouter)
return signUpViewcontroller
}
}
Loading

0 comments on commit 294eff5

Please sign in to comment.