Skip to content

Commit defca3a

Browse files
committed
[feat] add SignUp Logic
1 parent a05a824 commit defca3a

File tree

10 files changed

+264
-39
lines changed

10 files changed

+264
-39
lines changed

DailyQuest/DailyQuest.xcodeproj/project.pbxproj

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@
105105
34EE0C662935FD7D002BEC23 /* BrowseItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3499552629235D1E007AB99E /* BrowseItemViewModel.swift */; };
106106
34EE6EB72924C674005AF583 /* QuestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB62924C674005AF583 /* QuestView.swift */; };
107107
34EE6EB92924CAA1005AF583 /* QuestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */; };
108+
34FCD366293DE62700E0DC8A /* DefaultEnrollUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */; };
108109
34FCD369293DEED600E0DC8A /* FriendViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD368293DEED600E0DC8A /* FriendViewController.swift */; };
109110
34FCD36B293DF2F600E0DC8A /* FriendStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD36A293DF2F600E0DC8A /* FriendStatusView.swift */; };
110-
34FCD366293DE62700E0DC8A /* DefaultEnrollUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */; };
111111
34FEFB992935EA6D00954A40 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 34FEFB982935EA6D00954A40 /* Kingfisher */; };
112112
34FF6C5A292B86F8002AFD4D /* SnapKit-Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */; };
113113
34FF6C5D292B8B27002AFD4D /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C5C292B8B27002AFD4D /* RxCocoa */; };
@@ -121,6 +121,8 @@
121121
9BD8CCFB2937407100E6EA2F /* FollowingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8CCFA2937407100E6EA2F /* FollowingCell.swift */; };
122122
9BD8CD00293829DD00E6EA2F /* FollowingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8CCFF293829DD00E6EA2F /* FollowingView.swift */; };
123123
9BD8CD022938418500E6EA2F /* LastFollowingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8CD012938418500E6EA2F /* LastFollowingCell.swift */; };
124+
A5003AB4293F5FEC00082A9C /* SignUpViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5003AB3293F5FEC00082A9C /* SignUpViewModel.swift */; };
125+
A5003AB6293F601E00082A9C /* SignUpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5003AB5293F601E00082A9C /* SignUpViewController.swift */; };
124126
A50DE906292B53D900E1FD60 /* DefaultQuestsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50DE905292B53D900E1FD60 /* DefaultQuestsRepository.swift */; };
125127
A50DE90B292B73B900E1FD60 /* FirebaseDatabaseSwift in Frameworks */ = {isa = PBXBuildFile; productRef = A50DE90A292B73B900E1FD60 /* FirebaseDatabaseSwift */; };
126128
A50DE911292B74C500E1FD60 /* DTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50DE910292B74C500E1FD60 /* DTO.swift */; };
@@ -307,16 +309,18 @@
307309
34EE0C632935FD6B002BEC23 /* BrowseViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseViewModelTests.swift; sourceTree = "<group>"; };
308310
34EE6EB62924C674005AF583 /* QuestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestView.swift; sourceTree = "<group>"; };
309311
34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestViewModel.swift; sourceTree = "<group>"; };
312+
34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultEnrollUseCase.swift; sourceTree = "<group>"; };
310313
34FCD368293DEED600E0DC8A /* FriendViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendViewController.swift; sourceTree = "<group>"; };
311314
34FCD36A293DF2F600E0DC8A /* FriendStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendStatusView.swift; sourceTree = "<group>"; };
312-
34FCD365293DE62700E0DC8A /* DefaultEnrollUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultEnrollUseCase.swift; sourceTree = "<group>"; };
313315
9B1CFB3E292B585700CCE97A /* QuestDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "QuestDTO+Mapping.swift"; sourceTree = "<group>"; };
314316
9BD8CCF22935BC0D00E6EA2F /* DefaultBrowseRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultBrowseRepository.swift; sourceTree = "<group>"; };
315317
9BD8CCF42935C38300E6EA2F /* UserDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDTO+Mapping.swift"; sourceTree = "<group>"; };
316318
9BD8CCF62935D7BB00E6EA2F /* BrowseQuestDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowseQuestDTO+Mapping.swift"; sourceTree = "<group>"; };
317319
9BD8CCFA2937407100E6EA2F /* FollowingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingCell.swift; sourceTree = "<group>"; };
318320
9BD8CCFF293829DD00E6EA2F /* FollowingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingView.swift; sourceTree = "<group>"; };
319321
9BD8CD012938418500E6EA2F /* LastFollowingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastFollowingCell.swift; sourceTree = "<group>"; };
322+
A5003AB3293F5FEC00082A9C /* SignUpViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpViewModel.swift; sourceTree = "<group>"; };
323+
A5003AB5293F601E00082A9C /* SignUpViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpViewController.swift; sourceTree = "<group>"; };
320324
A50DE905292B53D900E1FD60 /* DefaultQuestsRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultQuestsRepository.swift; sourceTree = "<group>"; };
321325
A50DE910292B74C500E1FD60 /* DTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DTO.swift; sourceTree = "<group>"; };
322326
A50F9A3329266F45005C00FE /* NetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = "<group>"; };
@@ -426,6 +430,7 @@
426430
isa = PBXGroup;
427431
children = (
428432
34113BE72934917500AB4919 /* LoginViewModel.swift */,
433+
A5003AB3293F5FEC00082A9C /* SignUpViewModel.swift */,
429434
);
430435
path = ViewModel;
431436
sourceTree = "<group>";
@@ -525,6 +530,7 @@
525530
children = (
526531
342830A9292E12C700AE811B /* SettingsViewController.swift */,
527532
34113BEA2934A3B200AB4919 /* LoginViewController.swift */,
533+
A5003AB5293F601E00082A9C /* SignUpViewController.swift */,
528534
);
529535
path = ViewController;
530536
sourceTree = "<group>";
@@ -1263,6 +1269,7 @@
12631269
34CAE318292B19A3007653AD /* QuestsRepository.swift in Sources */,
12641270
A50DE911292B74C500E1FD60 /* DTO.swift in Sources */,
12651271
3449AD5D2922197000B87619 /* User.swift in Sources */,
1272+
A5003AB6293F601E00082A9C /* SignUpViewController.swift in Sources */,
12661273
9BD8CCF52935C38300E6EA2F /* UserDTO+Mapping.swift in Sources */,
12671274
A51F01CD29233ABB0031ECA2 /* RealmUserInfoStorage.swift in Sources */,
12681275
B5833F732924C08900503E0D /* CalendarView.swift in Sources */,
@@ -1328,6 +1335,7 @@
13281335
34283101292E2D7A00AE811B /* ToggleItemViewModel.swift in Sources */,
13291336
34FCD366293DE62700E0DC8A /* DefaultEnrollUseCase.swift in Sources */,
13301337
A5AC96E829223F27003B7637 /* RealmQuestsStorage.swift in Sources */,
1338+
A5003AB4293F5FEC00082A9C /* SignUpViewModel.swift in Sources */,
13311339
345687F829374D2500CA51E3 /* DayNamePickerView.swift in Sources */,
13321340
349955122923220E007AB99E /* SwiftUIPreview.swift in Sources */,
13331341
9BD8CD022938418500E6EA2F /* LastFollowingCell.swift in Sources */,

DailyQuest/DailyQuest/Data/Network/DataMapping/UserDTO+Mapping.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ struct UserDTO: DTO {
3232
self.description = user.description
3333
self.allow = user.allow
3434
}
35+
36+
init(uuid: String, userDto: UserDTO) {
37+
self.uuid = uuid
38+
self.nickName = userDto.nickName
39+
self.profileURL = userDto.profileURL
40+
self.backgroundImageURL = userDto.backgroundImageURL
41+
self.description = userDto.description
42+
self.allow = userDto.allow
43+
}
3544
}
3645

3746
extension UserDTO {

DailyQuest/DailyQuest/Data/Repositories/DefaultAuthRepository.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,8 @@ extension DefaultAuthRepository: AuthRepository {
2525
func signOut() -> Single<Bool> {
2626
return self.networkService.signOut()
2727
}
28+
29+
func signUp(email: String, password: String, user: User) -> Single<Bool> {
30+
return self.networkService.signUp(email: email, password: password, userDto: user.toDTO())
31+
}
2832
}

DailyQuest/DailyQuest/Domain/Interfaces/Repositories/AuthRepository.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,12 @@ protocol AuthRepository {
1919
/// 로그아웃 동작을 수행합니다.
2020
/// - Returns: 성공하면 true를, 실패하면 error을 방출하는 Observable을 반환합니다.
2121
func signOut() -> Single<Bool>
22+
23+
/// 회원가입 동작을 수행합니다.
24+
/// - Parameters:
25+
/// - email: 사용자의 email 입니다.
26+
/// - password: 사용자의 password입니다.
27+
/// - user: 사용자의 정보입니다.
28+
/// - Returns: 성공하면 true를, 실패하면 error를 방출하는 Observable을 반환합니다.
29+
func signUp(email: String, password: String, user: User) -> Single<Bool>
2230
}

DailyQuest/DailyQuest/Domain/UseCases/Settings/DefaultAuthUseCase.swift

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import RxSwift
1111

1212
final class DefaultAuthUseCase {
1313
private let authRepository: AuthRepository
14-
14+
1515
init(authRepository: AuthRepository) {
1616
self.authRepository = authRepository
1717
}
@@ -22,17 +22,26 @@ extension DefaultAuthUseCase: AuthUseCase {
2222
return authRepository
2323
.signIn(email: email, password: password)
2424
.catch { _ in
25-
return .just(false)
26-
}
25+
return .just(false)
26+
}
2727
.asObservable()
2828
}
29-
29+
3030
func signOut() -> Observable<Bool> {
3131
return authRepository
3232
.signOut()
3333
.catch { _ in
34-
return .just(false)
35-
}
34+
return .just(false)
35+
}
36+
.asObservable()
37+
}
38+
39+
func signUp(email: String, password: String, user: User) -> Observable<Bool> {
40+
return authRepository
41+
.signUp(email: email, password: password, user: user)
42+
.catch { _ in
43+
return .just(false)
44+
}
3645
.asObservable()
3746
}
3847
}

DailyQuest/DailyQuest/Domain/UseCases/Settings/Protocols/AuthUseCase.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ import RxSwift
1212
protocol AuthUseCase {
1313
func signIn(email: String, password: String) -> Observable<Bool>
1414
func signOut() -> Observable<Bool>
15+
func signUp(email: String, password: String, user: User) -> Observable<Bool>
1516
}

DailyQuest/DailyQuest/Infrastructure/FirebaseService/FirebaseService.swift

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,36 +29,9 @@ final class FirebaseService: NetworkService {
2929
uid.accept(auth.currentUser?.uid)
3030
}
3131

32-
@discardableResult
33-
private func documentReference(userCase: UserCase) throws -> DocumentReference {
34-
switch userCase {
35-
case .currentUser:
36-
guard let currentUserUid = uid.value else { throw NetworkServiceError.noAuthError }
37-
return db.collection(userCase.path).document(currentUserUid)
38-
case let .anotherUser(uid):
39-
return db.collection(userCase.path).document(uid)
40-
}
41-
}
42-
43-
private func checkPermission(crud: CRUD, userCase: UserCase, access: Access) throws {
44-
switch userCase {
45-
case .currentUser:
46-
switch access {
47-
case .receiveQuests:
48-
if crud == .create { throw NetworkServiceError.permissionDenied }
49-
default:
50-
break
51-
}
52-
case .anotherUser:
53-
switch access {
54-
case .receiveQuests:
55-
if crud == .delete { throw NetworkServiceError.permissionDenied }
56-
default:
57-
if crud != .read { throw NetworkServiceError.permissionDenied }
58-
}
59-
}
60-
}
32+
}
6133

34+
extension FirebaseService {
6235
func signIn(email: String, password: String) -> Single<Bool> {
6336
return Single.create { [weak self] single in
6437
do {
@@ -93,6 +66,65 @@ final class FirebaseService: NetworkService {
9366
}
9467
}
9568

69+
func signUp(email: String, password: String, userDto: UserDTO) -> Single<Bool> {
70+
return Single.create { [weak self] single in
71+
guard let self = self else {
72+
single(.failure(NetworkServiceError.noNetworkService))
73+
return Disposables.create()
74+
}
75+
76+
self.auth.createUser(withEmail: email, password: password) { authResult, error in
77+
do {
78+
if let error = error { throw error }
79+
guard let authResult = authResult else { throw NetworkServiceError.noAuthError }
80+
try self.createUser(uuid: authResult.user.uid, userDto: userDto)
81+
single(.success(true))
82+
} catch let error {
83+
single(.failure(error))
84+
}
85+
}
86+
return Disposables.create()
87+
}
88+
}
89+
90+
func createUser(uuid: String, userDto: UserDTO) throws {
91+
let userDto = UserDTO(uuid: uuid, userDto: userDto)
92+
try db.collection(UserCase.currentUser.path).document(uuid)
93+
.setData(from: userDto)
94+
}
95+
}
96+
97+
extension FirebaseService {
98+
@discardableResult
99+
private func documentReference(userCase: UserCase) throws -> DocumentReference {
100+
switch userCase {
101+
case .currentUser:
102+
guard let currentUserUid = uid.value else { throw NetworkServiceError.noAuthError }
103+
return db.collection(userCase.path).document(currentUserUid)
104+
case let .anotherUser(uid):
105+
return db.collection(userCase.path).document(uid)
106+
}
107+
}
108+
109+
private func checkPermission(crud: CRUD, userCase: UserCase, access: Access) throws {
110+
switch userCase {
111+
case .currentUser:
112+
switch access {
113+
case .receiveQuests:
114+
if crud == .create { throw NetworkServiceError.permissionDenied }
115+
default:
116+
break
117+
}
118+
case .anotherUser:
119+
switch access {
120+
case .receiveQuests:
121+
if crud == .delete { throw NetworkServiceError.permissionDenied }
122+
default:
123+
if crud != .read { throw NetworkServiceError.permissionDenied }
124+
}
125+
}
126+
}
127+
96128
/// Create
97129
/// - Parameters:
98130
/// - userCase: current User / another User

DailyQuest/DailyQuest/Infrastructure/NetworkService.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ protocol NetworkService {
2323

2424
func signIn(email: String, password: String) -> Single<Bool>
2525
func signOut() -> Single<Bool>
26+
func signUp(email: String, password: String, userDto: UserDTO) -> Single<Bool>
2627

2728
func create<T: DTO>(userCase: UserCase, access: Access, dto: T) -> Single<T>
2829
func read<T: DTO>(type: T.Type, userCase: UserCase, access: Access, filter: DateFilter?) -> Observable<T>
@@ -32,6 +33,6 @@ protocol NetworkService {
3233
func uploadDataStorage(data: Data, path: StoragePath) -> Single<String>
3334
func downloadDataStorage(fileName: String) -> Single<Data>
3435
func deleteDataStorage(fileName: String) -> Single<Bool>
35-
36-
func getAllowUsers(limit: Int)->Observable<UserDTO>
36+
37+
func getAllowUsers(limit: Int) -> Observable<UserDTO>
3738
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//
2+
// SignUpViewController.swift
3+
// DailyQuest
4+
//
5+
// Created by 이전희 on 2022/12/06.
6+
//
7+
8+
import UIKit
9+
10+
import RxSwift
11+
import RxCocoa
12+
import SnapKit
13+
14+
final class SignUpViewController: UIViewController {
15+
private var viewModel: LoginViewModel!
16+
private var disposableBag = DisposeBag()
17+
18+
private lazy var container: UIStackView = {
19+
let container = UIStackView()
20+
container.axis = .vertical
21+
container.spacing = 10
22+
23+
return container
24+
}()
25+
26+
private lazy var emailField: TextFieldForm = {
27+
let emailField = TextFieldForm()
28+
emailField.placeholder = "email"
29+
30+
return emailField
31+
}()
32+
33+
private lazy var passwordField: TextFieldForm = {
34+
let passwordField = TextFieldForm()
35+
passwordField.placeholder = "password"
36+
37+
return passwordField
38+
}()
39+
40+
private lazy var submitButton: UIButton = {
41+
var config = UIButton.Configuration.filled()
42+
config.baseBackgroundColor = .maxYellow
43+
config.title = "로그인"
44+
45+
return UIButton(configuration: config)
46+
}()
47+
48+
// MARK: Life Cycle
49+
static func create(with viewModel: LoginViewModel) -> LoginViewController {
50+
let vc = LoginViewController()
51+
vc.setup(with: viewModel)
52+
53+
return vc
54+
}
55+
56+
override func viewDidLoad() {
57+
super.viewDidLoad()
58+
59+
configureUI()
60+
61+
bind()
62+
}
63+
64+
private func configureUI() {
65+
view.backgroundColor = .white
66+
67+
container.addArrangedSubview(emailField)
68+
container.addArrangedSubview(passwordField)
69+
container.addArrangedSubview(submitButton)
70+
71+
view.addSubview(container)
72+
73+
container.snp.makeConstraints { make in
74+
make.center.equalToSuperview()
75+
make.width.equalToSuperview().multipliedBy(0.8)
76+
}
77+
}
78+
79+
private func setup(with authViewModel: LoginViewModel) {
80+
viewModel = authViewModel
81+
}
82+
}
83+
84+
extension LoginViewController {
85+
private func bind() {
86+
let input = LoginViewModel.Input(
87+
emailFieldDidEditEvent: emailField.rx.text.orEmpty.asObservable(),
88+
passwordFieldDidEditEvent: passwordField.rx.text.orEmpty.asObservable(),
89+
submitButtonDidTapEvent: submitButton.rx.tap.asObservable()
90+
)
91+
92+
let output = viewModel.transform(input: input, disposeBag: disposableBag)
93+
94+
output
95+
.buttonEnabled
96+
.drive(submitButton.rx.isEnabled)
97+
.disposed(by: disposableBag)
98+
99+
output
100+
.loginResult
101+
.subscribe(onNext: { result in
102+
print("login result is :::: ", result)
103+
})
104+
.disposed(by: disposableBag)
105+
}
106+
}

0 commit comments

Comments
 (0)