Skip to content

Commit 609916f

Browse files
authored
[NL-70] : Onboarding API 연결 (#41)
* [NL-70] : Auth(User) create(POST), update(PUT) 방식 공통 common으로 생성 * [NL-70] : onboarding 가입 API 연결 * [NL-70] : GenderType, BornType을 baseLayer로 이동 - Concreate target 삭제 필요 - baseLayer에서 feature 사이 공동 객체 관리
1 parent 909c756 commit 609916f

File tree

10 files changed

+172
-10
lines changed

10 files changed

+172
-10
lines changed

Common/Auth/Sources/AuthTarget.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,30 @@ enum AuthTarget {
2121
var headers: [String: String]? { nil }
2222
let userID: String
2323
}
24+
25+
struct PostUser : BaseTargetType {
26+
typealias Response = UserDTO
27+
28+
var path : String { "/users"}
29+
var httpTask: HTTPTask { .requestJSONEncodable(userModel) }
30+
var httpMethod: HTTPMethod { .post }
31+
var headers: [String: String]? {
32+
["Content-Type": "application/json"]
33+
}
34+
35+
let userModel : UserModel
36+
}
37+
38+
struct PutUser : BaseTargetType {
39+
typealias Response = UserDTO
40+
41+
var path : String { "users/\(userModel.id)" }
42+
var httpTask: HTTPTask { .requestJSONEncodable(userModel) }
43+
var httpMethod: HTTPMethod { .put }
44+
var headers: [String: String]? {
45+
["Content-Type": "application/json"]
46+
}
47+
48+
let userModel : UserModel
49+
}
2450
}

Common/Auth/Sources/UserDataManager.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,32 @@ public final class UserDataManager {
3030
throw error
3131
}
3232
}
33+
34+
@discardableResult
35+
public func create(name : String, birthDate : String, birthTime : [String]?, gender : GenderDTO) async throws -> UserDTO {
36+
let userID = user?.id ?? deviceUUIDManager.deviceUUID
37+
let userModel = UserModel(id: userID, name: name, birthDate: birthDate, birthTime: birthTime, gender: gender)
38+
let target = AuthTarget.PostUser(userModel: userModel)
39+
do {
40+
let user = try await networkProvider.request(target: target)
41+
self.user = user
42+
return user
43+
} catch {
44+
throw error
45+
}
46+
}
47+
48+
@discardableResult
49+
public func update(name : String, birthDate : String, birthTime : [String]?, gender : GenderDTO) async throws -> UserDTO {
50+
let userID = user?.id ?? deviceUUIDManager.deviceUUID
51+
let userModel = UserModel(id: userID, name: name, birthDate: birthDate, birthTime: birthTime, gender: gender)
52+
let target = AuthTarget.PutUser(userModel: userModel)
53+
do {
54+
let user = try await networkProvider.request(target: target)
55+
self.user = user
56+
return user
57+
} catch {
58+
throw error
59+
}
60+
}
3361
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//
2+
// BornType.swift
3+
// FeatureLayer
4+
//
5+
// Created by 최재혁 on 7/29/25.
6+
//
7+
8+
public enum BornType {
9+
case dontKnow(isSelected: Bool)
10+
case time(time: String)
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//
2+
// GenderType.swift
3+
// FeatureLayer
4+
//
5+
// Created by 최재혁 on 7/29/25.
6+
//
7+
8+
public enum GenderType: String {
9+
case male = "남성"
10+
case female = "여성"
11+
}

Common/Base/Sources/Model/UserDTO.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ public struct UserDTO: Decodable {
1212
enum CodingKeys: String, CodingKey {
1313
case id, name, gender
1414
case birthDate = "birth_date"
15+
case birthTime = "birth_time"
1516
}
1617

1718
public let id: String
1819
public let name: String
1920
public let birthDate: String?
21+
public let birthTime : [String]?
2022
public let gender: GenderDTO
2123

2224
// TODO: 사주 정보?
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
// UserModel.swift
3+
// CommonLayer
4+
//
5+
// Created by 최재혁 on 8/16/25.
6+
//
7+
8+
import Foundation
9+
10+
public struct UserModel : Codable {
11+
12+
enum CodingKeys : String, CodingKey {
13+
case id, name, gender
14+
case birthDate = "birth_date"
15+
case birthTime = "birth_time"
16+
}
17+
18+
public let id : String
19+
let name : String
20+
let birthDate : String
21+
let birthTime : [String]?
22+
let gender : GenderDTO
23+
24+
public init(id: String, name: String, birthDate: String, birthTime: [String]?, gender: GenderDTO) {
25+
self.id = id
26+
self.name = name
27+
self.birthDate = birthDate
28+
self.birthTime = birthTime
29+
self.gender = gender
30+
}
31+
}

Core/NetworkCore/Sources/NetworkProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public final class NetworkProvider {
2020
public func request<T: BaseTargetType>(target: T) async throws -> T.Response {
2121
// TODO: Reachability 확인 필요할지
2222
do {
23-
let responseData = try await internalProvider.request(MultiTarget(target))
23+
let responseData = try await internalProvider.request(MultiTarget(target)).filterSuccessfulStatusCodes()
2424
let response = try JSONDecoder().decode(T.Response.self, from: responseData.data)
2525
return response
2626
} catch {

Feature/Onboarding/Sources/Onboarding/OnboardingViewModel.swift

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import Combine
99
import Foundation
1010
import Lib
11+
import Auth
12+
import DIInjector
13+
import Base
1114

1215
public class OnboardingViewModel {
1316

@@ -25,14 +28,18 @@ public class OnboardingViewModel {
2528
let showNameError: PassthroughSubject<Bool, Never> = .init()
2629
let showBirthError: PassthroughSubject<Bool, Never> = .init()
2730
let isNextButtonEnabled: PassthroughSubject<Bool, Never> = .init()
31+
let isBornTimeButtonEnabled : PassthroughSubject<Bool, Never> = .init()
2832
let navigate: PassthroughSubject<OnboardingRoute, Never> = .init()
2933
}
3034

3135
let output: Output = Output()
32-
36+
37+
@Injected private var userDataManager : UserDataManager
38+
3339
private var _isNameValid: Bool = false
3440
private var _isBirthDateValid: Bool = false
3541
private var _isBornTimeValied: Bool = false
42+
private var _isDontKnowSelected: Bool = false
3643

3744
private var state: State = .init()
3845

@@ -54,15 +61,35 @@ public class OnboardingViewModel {
5461
switch bornTime {
5562
case .dontKnow(let isSelected):
5663
self._isBornTimeValied = (self.state.bornTime != nil || !isSelected)
64+
self._isDontKnowSelected = !isSelected
65+
self.output.isBornTimeButtonEnabled.send(isSelected)
5766
case .time(let time):
5867
self._isBornTimeValied = true
59-
self.state.bornTime = time
68+
let components = time.components(separatedBy: " ~ ")
69+
self.state.bornTime = components
6070
}
6171
self.output.isNextButtonEnabled.send(_isNameValid && _isBirthDateValid && _isBornTimeValied)
6272
case .nextButtonTap:
6373
self.output.navigate.send(.agreement)
6474
case .completeButtonTap:
65-
break
75+
if let name = state.name, let birthDate = state.birthDate, let gender = state.gender {
76+
let genderDTO = gender == .male ? GenderDTO.male : GenderDTO.female
77+
var birthTime: [String]? = nil
78+
if !self._isDontKnowSelected {
79+
birthTime = self.state.bornTime
80+
}
81+
Task {
82+
do {
83+
let test = try await self.userDataManager.create(name: name, birthDate: birthDate, birthTime: birthTime , gender: genderDTO)
84+
print(test)
85+
} catch {
86+
// TODO: API 호출 에러처리
87+
print(error)
88+
}
89+
}
90+
} else {
91+
// TODO: 입력값에 대한 에러 처리
92+
}
6693
case .timePickerTap:
6794
self.output.navigate.send(.timePicker)
6895
}
@@ -76,7 +103,7 @@ extension OnboardingViewModel {
76103
var name: String?
77104
var gender: GenderType?
78105
var birthDate: String?
79-
var bornTime: String?
106+
var bornTime: [String]?
80107
}
81108
}
82109

Feature/Onboarding/Sources/Onboarding/OnboardingViewcontroller.swift

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ import Foundation
1111
import SnapKit
1212
import Then
1313
import UIKit
14+
import Base
1415

15-
public final class OnboardingViewController: UIViewController {
16+
public final class OnboardingViewController : BaseViewController {
1617
private var store: Set<AnyCancellable> = []
1718
private let viewModel: OnboardingViewModel
1819

@@ -182,8 +183,8 @@ public final class OnboardingViewController: UIViewController {
182183
override public func viewDidLoad() {
183184
super.viewDidLoad()
184185
self.view.backgroundColor = .white
185-
self.navigationController?.navigationBar.topItem?.title = ""
186-
self.navigationController?.navigationBar.tintColor = STColors.gray1.color
186+
let backButtonItem = NaivgationBarButtonItem.back
187+
self.setNavigationBarLeftButtonItems(items: [backButtonItem])
187188
setupBind()
188189
setupHierarchy()
189190
setupLayout()
@@ -322,6 +323,14 @@ extension OnboardingViewController {
322323
}
323324
}
324325
.store(in: &store)
326+
327+
viewModel.output.isBornTimeButtonEnabled
328+
.receive(on: RunLoop.main)
329+
.sink { [ weak self ] isEnable in
330+
guard let self else { return }
331+
self.bornTimeSetButton.isEnabled = isEnable
332+
}
333+
.store(in: &store)
325334

326335
nextButton.tapPublisher
327336
.sink { [weak self] _ in
@@ -454,7 +463,6 @@ extension OnboardingViewController {
454463
@objc private func dontKonwButtonTapped() {
455464
viewModel.send(
456465
input: .bornTimeSelected(bornTime: .dontKnow(isSelected: self.dontKnowButton.isSelected)))
457-
bornTimeSetButton.isEnabled.toggle()
458466
}
459467
}
460468

@@ -601,3 +609,21 @@ extension UIResponder {
601609
UIResponder._currentFirstResponder = self
602610
}
603611
}
612+
613+
#if targetEnvironment(simulator)
614+
615+
import DIInjector
616+
import Auth
617+
import Setting
618+
import NetworkCore
619+
620+
@available(iOS 17.0, *)
621+
#Preview {
622+
DependencyInjector.shared.assemble([
623+
AuthAssembly(),
624+
SettingAssembly(),
625+
NetworkCoreAssembly(),
626+
])
627+
return OnboardingViewController(router: OnboardingRouter())
628+
}
629+
#endif

Feature/Setting/Sources/EditPage/EditProfileViewModel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import Combine
99
import Foundation
1010
import Lib
11-
import Onboarding
11+
import Base
1212

1313
final class EditProfileViewModel {
1414
enum Input {

0 commit comments

Comments
 (0)