Skip to content

Commit 74f8057

Browse files
authored
Merge pull request #25 from LearnMate-Dev/feat/#24
[Feat/#24] 자체 회원가입 API 연동
2 parents 0e23a7f + 2e9dd85 commit 74f8057

File tree

24 files changed

+631
-29
lines changed

24 files changed

+631
-29
lines changed

Projects/CommonUI/CommonUI.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
950A0D562E5C29D000C07CF2 /* LMTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 950A0D552E5C29CC00C07CF2 /* LMTextField.swift */; };
2525
950A0D602E5C3C7000C07CF2 /* LMButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 950A0D5F2E5C3C6D00C07CF2 /* LMButton.swift */; };
2626
950A0D622E5C562700C07CF2 /* LMInputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 950A0D612E5C561400C07CF2 /* LMInputField.swift */; };
27+
950A0D962E605CEA00C07CF2 /* UIStackView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 950A0D952E605CE300C07CF2 /* UIStackView+Extension.swift */; };
2728
BAD8B768F782046D4AA1C073 /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3DE048BEDCB92B48F401061 /* RxCocoa.framework */; };
2829
BE81B1F3E60D37D75A058D2B /* SnapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9CCDC15081A22BAED6318E3E /* SnapKit.framework */; };
2930
C2B0F8237715D14D8797DBC9 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012F45F908769FA7C3C0792F /* LoginView.swift */; };
@@ -74,6 +75,7 @@
7475
950A0D552E5C29CC00C07CF2 /* LMTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LMTextField.swift; sourceTree = "<group>"; };
7576
950A0D5F2E5C3C6D00C07CF2 /* LMButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LMButton.swift; sourceTree = "<group>"; };
7677
950A0D612E5C561400C07CF2 /* LMInputField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LMInputField.swift; sourceTree = "<group>"; };
78+
950A0D952E605CE300C07CF2 /* UIStackView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackView+Extension.swift"; sourceTree = "<group>"; };
7779
9CCDC15081A22BAED6318E3E /* SnapKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SnapKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7880
BACC7259FC0C14CB352A4E6B /* OptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionView.swift; sourceTree = "<group>"; };
7981
C28FE6392E1612667826E5C5 /* DiaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryView.swift; sourceTree = "<group>"; };
@@ -184,6 +186,14 @@
184186
path = Component;
185187
sourceTree = "<group>";
186188
};
189+
950A0D942E605CE100C07CF2 /* Extension */ = {
190+
isa = PBXGroup;
191+
children = (
192+
950A0D952E605CE300C07CF2 /* UIStackView+Extension.swift */,
193+
);
194+
path = Extension;
195+
sourceTree = "<group>";
196+
};
187197
9786E1056828B1E6D5EDAB7C /* View */ = {
188198
isa = PBXGroup;
189199
children = (
@@ -208,6 +218,7 @@
208218
BADD047B94176A526A5B7FB2 /* Sources */ = {
209219
isa = PBXGroup;
210220
children = (
221+
950A0D942E605CE100C07CF2 /* Extension */,
211222
950A0D522E5C296400C07CF2 /* Component */,
212223
15CD642D82E9115C7976C408 /* Assets */,
213224
88FA467F361B11350139B775 /* Base */,
@@ -336,6 +347,7 @@
336347
7DC59B80630854028C7C80F4 /* TuistBundle+CommonUI.swift in Sources */,
337348
F3DA12FF4D18AE405F2F6B08 /* BaseViewController.swift in Sources */,
338349
E0865F2849CCB89CC83D3B77 /* Coordinator.swift in Sources */,
350+
950A0D962E605CEA00C07CF2 /* UIStackView+Extension.swift in Sources */,
339351
E055AA66777B1D4CC8C884E4 /* CommonUIAssets.swift in Sources */,
340352
950A0D4F2E5AADB500C07CF2 /* SignUpView.swift in Sources */,
341353
F7673E4248628D67F3542848 /* ChatView.swift in Sources */,

Projects/CommonUI/Sources/Component/LMInputField.swift

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import UIKit
99

1010
public class LMInputField: UIStackView {
1111

12+
public var onEmailButtonTapped: ((String) -> Void)?
13+
1214
public enum InputType {
1315
case email
1416
case password
@@ -62,7 +64,7 @@ public class LMInputField: UIStackView {
6264

6365
warningLabel = warningLabel.then {
6466
$0.text = waringText
65-
$0.textColor = CommonUIAssets.LMRed2
67+
$0.textColor = .clear
6668
$0.font = UIFont.systemFont(ofSize: 13, weight: .light)
6769
}
6870
}
@@ -88,6 +90,7 @@ public class LMInputField: UIStackView {
8890
let emailButton = LMButton(textColor: CommonUIAssets.LMBlack,
8991
bgColor: CommonUIAssets.LMOrange1).then {
9092
$0.setTitle(buttonTitle, for: .normal)
93+
$0.addTarget(self, action: #selector(emailButtonTapped), for: .touchUpInside)
9194
}
9295

9396
[inputTextField, emailButton]
@@ -143,4 +146,39 @@ public class LMInputField: UIStackView {
143146
$0.width.equalToSuperview()
144147
}
145148
}
149+
150+
@objc private func emailButtonTapped() {
151+
onEmailButtonTapped?(inputTextField.text ?? "")
152+
}
153+
154+
public func showWarning() {
155+
warningLabel.textColor = CommonUIAssets.LMRed2
156+
}
157+
158+
public func hideWarning() {
159+
warningLabel.textColor = .clear
160+
}
161+
162+
public func currentText() -> String {
163+
return inputTextField.text ?? ""
164+
}
165+
166+
public func disableButton(buttonTitle: String) {
167+
for subview in self.arrangedSubviews {
168+
if let stackView = subview as? UIStackView {
169+
for stackSubview in stackView.arrangedSubviews {
170+
if let textField = stackSubview as? LMTextField {
171+
textField.isEnabled = false
172+
}
173+
174+
if let button = stackSubview as? LMButton {
175+
button.setTitle(buttonTitle, for: .normal)
176+
button.isEnabled = false
177+
button.backgroundColor = CommonUIAssets.LMGray5
178+
button.setTitleColor(CommonUIAssets.LMWhite, for: .normal)
179+
}
180+
}
181+
}
182+
}
183+
}
146184
}

Projects/CommonUI/Sources/Coordinator/Coordinator.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public enum CoordinatorType {
1515
case diary
1616
case stats
1717
case myPage
18+
case signIn
19+
case signUp
1820
}
1921

2022
public protocol Coordinator: AnyObject {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// UIStackView+Extension.swift
3+
// CommonUI
4+
//
5+
// Created by 박지윤 on 8/28/25.
6+
//
7+
8+
import UIKit
9+
10+
extension UIStackView {
11+
public func getText() -> String {
12+
return arrangedSubviews
13+
.compactMap { $0 as? LMTextField }
14+
.map { $0.text ?? "" }
15+
.joined(separator: " ")
16+
}
17+
}

Projects/CommonUI/Sources/View/Login/SignUpView.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,24 @@ import Then
1414
open class SignUpView: UIView {
1515
var inputFieldStackView = UIStackView()
1616

17-
let nameInputField = LMInputField(inputText: "이름",
17+
public let nameInputField = LMInputField(inputText: "이름",
1818
inputPlaceholder: "이름을 입력하세요",
1919
warningText: " 이름은 필수입니다")
20-
let emailInputField = LMInputField(inputType: .email,
20+
public let emailInputField = LMInputField(inputType: .email,
2121
inputText: "이메일",
2222
inputPlaceholder: " 이메일을 입력하세요",
2323
warningText: " 이메일 형식이 올바르지 않습니다",
2424
buttonTitle: "인증 요청")
25-
let authenticationInputField = LMInputField(inputType: .email,
25+
public let confirmInputField = LMInputField(inputType: .email,
2626
inputText: "인증번호",
2727
inputPlaceholder: " 인증번호를 입력하세요",
2828
warningText: " 인증번호가 일치하지 않습니다",
2929
buttonTitle: "확인")
30-
let passwordInputField = LMInputField(inputType: .password,
30+
public let passwordInputField = LMInputField(inputType: .password,
3131
inputText: "비밀번호",
3232
inputPlaceholder: "비밀번호를 입력하세요",
3333
warningText: " 비밀번호 형식이 올바르지 않습니다")
34-
let passwordCheckInputField = LMInputField(inputText: "비밀번호 확인",
34+
public let passwordCheckInputField = LMInputField(inputText: "비밀번호 확인",
3535
inputPlaceholder: "비밀번호를 한번 더 입력하세요",
3636
warningText: " 비밀번호가 일치하지 않습니다")
3737

@@ -61,7 +61,7 @@ open class SignUpView: UIView {
6161
func initUI() {
6262
self.addSubview(inputFieldStackView)
6363

64-
[nameInputField, emailInputField, authenticationInputField, passwordInputField, passwordCheckInputField]
64+
[nameInputField, emailInputField, confirmInputField, passwordInputField, passwordCheckInputField]
6565
.forEach { inputFieldStackView.addArrangedSubview($0) }
6666

6767
inputFieldStackView.snp.makeConstraints {

Projects/Data/Data.xcodeproj/project.pbxproj

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
archiveVersion = 1;
44
classes = {
55
};
6-
objectVersion = 55;
6+
objectVersion = 56;
77
objects = {
88

99
/* Begin PBXBuildFile section */
1010
34FD760EB97BB96E9D770BF0 /* LoginRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D7624DE90CFBBEF778E120E /* LoginRepository.swift */; };
1111
43E9C2380F425520C1FA1AD2 /* CourseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAAC2885ACFE998578DC25E8 /* CourseDTO.swift */; };
1212
684AAEA9796EED3F9FC592FC /* NetworkConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D46FD93B80D052843AD5063 /* NetworkConfiguration.swift */; };
1313
901ACA7B98089AB702ADA830 /* Domain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06FAA1459D11CCE724C34195 /* Domain.framework */; };
14+
950A0D702E5CCF0200C07CF2 /* SignRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 950A0D6F2E5CCEFD00C07CF2 /* SignRepository.swift */; };
15+
950A0D902E6039D600C07CF2 /* DefaultDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 950A0D8F2E6039D300C07CF2 /* DefaultDTO.swift */; };
1416
A334985695DC9388841BBC43 /* QuizRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CCA951B89F2C3D20AA31F7F /* QuizRepository.swift */; };
1517
B2F8FBFA915F696CCCA4152A /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A3B0D3D8C7049B6856791C1D /* Alamofire.framework */; };
1618
E1BFC73FB539432F6E12CD94 /* CourseRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0730BC3657E24BCEA511A3C /* CourseRepository.swift */; };
@@ -41,6 +43,8 @@
4143
4E75197C294DE74F5162FAA7 /* Data.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Data.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4244
5D46FD93B80D052843AD5063 /* NetworkConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkConfiguration.swift; sourceTree = "<group>"; };
4345
77810122262C6CB16D4D47DA /* QuizDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuizDTO.swift; sourceTree = "<group>"; };
46+
950A0D6F2E5CCEFD00C07CF2 /* SignRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignRepository.swift; sourceTree = "<group>"; };
47+
950A0D8F2E6039D300C07CF2 /* DefaultDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultDTO.swift; sourceTree = "<group>"; };
4448
A3B0D3D8C7049B6856791C1D /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4549
A44BC1E2E75FC256F832CA38 /* LoginDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginDTO.swift; sourceTree = "<group>"; };
4650
AAAC2885ACFE998578DC25E8 /* CourseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDTO.swift; sourceTree = "<group>"; };
@@ -73,6 +77,7 @@
7377
647255CD65221C9CD4A43DED /* DTO */ = {
7478
isa = PBXGroup;
7579
children = (
80+
950A0D8F2E6039D300C07CF2 /* DefaultDTO.swift */,
7681
AAAC2885ACFE998578DC25E8 /* CourseDTO.swift */,
7782
A44BC1E2E75FC256F832CA38 /* LoginDTO.swift */,
7883
77810122262C6CB16D4D47DA /* QuizDTO.swift */,
@@ -83,6 +88,7 @@
8388
73F3ED55BFDC2EF15878F5B6 /* Repository */ = {
8489
isa = PBXGroup;
8590
children = (
91+
950A0D6F2E5CCEFD00C07CF2 /* SignRepository.swift */,
8692
B0730BC3657E24BCEA511A3C /* CourseRepository.swift */,
8793
3D7624DE90CFBBEF778E120E /* LoginRepository.swift */,
8894
3CCA951B89F2C3D20AA31F7F /* QuizRepository.swift */,
@@ -172,8 +178,6 @@
172178
isa = PBXProject;
173179
attributes = {
174180
BuildIndependentTargetsInParallel = YES;
175-
TargetAttributes = {
176-
};
177181
};
178182
buildConfigurationList = BDB112DA78B2B42275EC3A62 /* Build configuration list for PBXProject "Data" */;
179183
compatibilityVersion = "Xcode 14.0";
@@ -212,8 +216,10 @@
212216
FF43B3A4D0DC88307E918DB0 /* LoginDTO.swift in Sources */,
213217
E9463A3FF42D5F0960245F80 /* QuizDTO.swift in Sources */,
214218
684AAEA9796EED3F9FC592FC /* NetworkConfiguration.swift in Sources */,
219+
950A0D702E5CCF0200C07CF2 /* SignRepository.swift in Sources */,
215220
E1BFC73FB539432F6E12CD94 /* CourseRepository.swift in Sources */,
216221
34FD760EB97BB96E9D770BF0 /* LoginRepository.swift in Sources */,
222+
950A0D902E6039D600C07CF2 /* DefaultDTO.swift in Sources */,
217223
A334985695DC9388841BBC43 /* QuizRepository.swift in Sources */,
218224
E6785667C8E247C344474CBB /* TokenRepository.swift in Sources */,
219225
);
@@ -245,10 +251,7 @@
245251
SUPPORTS_MACCATALYST = NO;
246252
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
247253
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
248-
SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
249-
"$(inherited)",
250-
DEBUG,
251-
);
254+
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
252255
SWIFT_COMPILATION_MODE = singlefile;
253256
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
254257
SWIFT_VERSION = 5.0;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// DefaultDTO.swift
3+
// Data
4+
//
5+
// Created by 박지윤 on 8/28/25.
6+
//
7+
8+
import Foundation
9+
import Domain
10+
11+
public struct DefaultDTO: Decodable {
12+
public let is_success: Bool
13+
public let code: String
14+
public let message: String
15+
}
16+
17+
extension DefaultDTO {
18+
func getMessage() -> DefaultVO {
19+
return .init(message: message)
20+
}
21+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//
2+
// SignRepository.swift
3+
// Data
4+
//
5+
// Created by 박지윤 on 8/26/25.
6+
//
7+
8+
import Domain
9+
import RxSwift
10+
import Alamofire
11+
12+
public class DefaultSignRepository: SignRepository {
13+
14+
public init() { }
15+
16+
public func postEmail(email: String) -> Single<DefaultVO> {
17+
let params = ["email": email]
18+
return request(endpoint: "/api/auth/email",
19+
parameters: params,
20+
responseType: DefaultDTO.self)
21+
.map { dto in
22+
return dto.getMessage()
23+
}
24+
}
25+
26+
public func postConfirm(email: String, code: String) -> Single<DefaultVO> {
27+
let params = ["email": email, "code": code]
28+
return request(endpoint: "/api/auth/email/confirm",
29+
parameters: params,
30+
responseType: DefaultDTO.self)
31+
.map { dto in
32+
return dto.getMessage()
33+
}
34+
}
35+
36+
public func postSignUp(username: String, email: String, password: String) -> Single<DefaultVO> {
37+
let params = ["username": username, "email": email, "password": password]
38+
return request(endpoint: "/api/auth/sign-up",
39+
parameters: params,
40+
responseType: DefaultDTO.self)
41+
.map { dto in
42+
return dto.getMessage()
43+
}
44+
}
45+
46+
private func request<T: Decodable>(
47+
endpoint: String,
48+
parameters: [String: Any]? = nil,
49+
responseType: T.Type
50+
) -> Single<T> {
51+
return Single.create { single in
52+
let url = "\(NetworkConfiguration.baseUrl)\(endpoint)"
53+
let headers: HTTPHeaders = [:]
54+
let request = AF.request(
55+
url,
56+
method: .post,
57+
parameters: parameters,
58+
encoding: JSONEncoding.default,
59+
headers: headers
60+
)
61+
.validate()
62+
.responseDecodable(of: responseType) { response in
63+
switch response.result {
64+
case .success(let value):
65+
print("✅ API 응답 성공: \(value)")
66+
single(.success(value))
67+
case .failure(let error):
68+
print("❌ API 응답 실패: \(error)")
69+
single(.failure(error))
70+
}
71+
}
72+
return Disposables.create { request.cancel() }
73+
}
74+
}
75+
}

0 commit comments

Comments
 (0)