From 08e226978568cdda5fc8c0e0a390dc36a0bfeb92 Mon Sep 17 00:00:00 2001 From: heejoo Date: Sun, 14 Jan 2024 03:39:00 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[Network]=20#55=20-=20Base=20url=20?= =?UTF-8?q?=EB=B0=8F=20Network=20Error=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DontBe-iOS/Application/SceneDelegate.swift | 4 +--- .../DontBe-iOS/Global/Resources/Info.plist | 2 ++ .../DontBe-iOS/Network/Foundation/Config.swift | 1 + .../Network/Foundation/NetworkError.swift | 17 ++++++++++++++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift index dcf3ca7d..75fce951 100644 --- a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift +++ b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift @@ -19,9 +19,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { self.window?.rootViewController = SplashViewController() self.window?.makeKeyAndVisible() - DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0) { -// let navigationController = UINavigationController(rootViewController: LoginViewController(viewModel: LoginViewModel())) -// let navigationController = UINavigationController(rootViewController: DontBeTabBarController()) + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.0) { if loadUserData()?.isSocialLogined == true && loadUserData()?.isJoinedApp == true && loadUserData()?.isOnboardingFinished == true { let navigationController = UINavigationController(rootViewController: DontBeTabBarController()) self.window?.rootViewController = navigationController diff --git a/DontBe-iOS/DontBe-iOS/Global/Resources/Info.plist b/DontBe-iOS/DontBe-iOS/Global/Resources/Info.plist index 66d68e72..c8950424 100644 --- a/DontBe-iOS/DontBe-iOS/Global/Resources/Info.plist +++ b/DontBe-iOS/DontBe-iOS/Global/Resources/Info.plist @@ -2,6 +2,8 @@ + BASE_URL + $(BASE_URL) UIUserInterfaceStyle Light LSApplicationQueriesSchemes diff --git a/DontBe-iOS/DontBe-iOS/Network/Foundation/Config.swift b/DontBe-iOS/DontBe-iOS/Network/Foundation/Config.swift index cde23ca5..bfbf831d 100644 --- a/DontBe-iOS/DontBe-iOS/Network/Foundation/Config.swift +++ b/DontBe-iOS/DontBe-iOS/Network/Foundation/Config.swift @@ -11,6 +11,7 @@ enum Config { enum Keys { enum Plist { static let nativeAppKey = "NATIVE_APP_KEY" + static let baseURL = "BASE_URL" } } diff --git a/DontBe-iOS/DontBe-iOS/Network/Foundation/NetworkError.swift b/DontBe-iOS/DontBe-iOS/Network/Foundation/NetworkError.swift index 1fab46a2..6c35353b 100644 --- a/DontBe-iOS/DontBe-iOS/Network/Foundation/NetworkError.swift +++ b/DontBe-iOS/DontBe-iOS/Network/Foundation/NetworkError.swift @@ -7,6 +7,21 @@ import UIKit -enum NetworkError { +enum NetworkError: Int, Error, CustomStringConvertible { + var description: String { self.errorDescription } + case badRequestError = 400 + case unautohorizedError = 401 + case notFoundError = 404 + case internalServerError = 500 + case unknownError + var errorDescription: String { + switch self { + case .badRequestError: return "BAD_REQUEST_ERROR" + case .unautohorizedError: return "UNAUTHORIZED_ERROR" + case .notFoundError: return "NOT_FOUND_ERROR" + case .internalServerError: return "SERVER_ERROR" + case .unknownError: return "UNKNOWN_ERROR" + } + } } From f2709fde0de68d3e435e8dc613f0088fa71b1e0c Mon Sep 17 00:00:00 2001 From: heejoo Date: Sun, 14 Jan 2024 10:04:50 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[Network]=20#55=20-=20BaseResponse,=20Confi?= =?UTF-8?q?g,=20NetworkError=20=EC=84=A4=EC=A0=95=20=EB=B0=8F=20=EC=86=8C?= =?UTF-8?q?=EC=85=9C=EB=A1=9C=EA=B7=B8=EC=9D=B8=20API=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DontBe-iOS.xcodeproj/project.pbxproj | 40 +++++++ .../DontBe-iOS/Application/AppDelegate.swift | 2 +- .../Application/SceneDelegate.swift | 4 +- .../DontBe-iOS/Global/Resources/Info.plist | 5 + .../Network/Foundation/BaseResponse.swift | 15 +++ .../Network/Foundation/Config.swift | 16 +++ .../Network/Foundation/NetworkError.swift | 2 + .../DTO/SocialLoginRequestDTO.swift | 12 ++ .../DTO/SocialLoginResponseDTO.swift | 17 +++ .../Service/SocialLoginService.swift | 91 +++++++++++++++ .../ViewControllers/LoginViewController.swift | 29 ++--- .../Login/ViewModels/LoginViewModel.swift | 105 ++++++++++++++---- 12 files changed, 293 insertions(+), 45 deletions(-) create mode 100644 DontBe-iOS/DontBe-iOS/Network/Foundation/BaseResponse.swift create mode 100644 DontBe-iOS/DontBe-iOS/Network/SocialLogin/DTO/SocialLoginRequestDTO.swift create mode 100644 DontBe-iOS/DontBe-iOS/Network/SocialLogin/DTO/SocialLoginResponseDTO.swift create mode 100644 DontBe-iOS/DontBe-iOS/Network/SocialLogin/Service/SocialLoginService.swift diff --git a/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj b/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj index 68e515c9..fc4bc96d 100644 --- a/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj +++ b/DontBe-iOS/DontBe-iOS.xcodeproj/project.pbxproj @@ -13,6 +13,10 @@ 2A2671FF2B4C3AF0009D214F /* Publisher+UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A2671FE2B4C3AF0009D214F /* Publisher+UIControl.swift */; }; 2A2672022B4C3B44009D214F /* ViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A2672012B4C3B44009D214F /* ViewModelType.swift */; }; 2A2672052B4C3C00009D214F /* CancelBag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A2672042B4C3C00009D214F /* CancelBag.swift */; }; + 2A28453E2B531DDE0023F9B5 /* SocialLoginService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A28453D2B531DDE0023F9B5 /* SocialLoginService.swift */; }; + 2A2845402B531F0A0023F9B5 /* BaseResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A28453F2B531F0A0023F9B5 /* BaseResponse.swift */; }; + 2A2845432B5320070023F9B5 /* SocialLoginResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A2845422B5320070023F9B5 /* SocialLoginResponseDTO.swift */; }; + 2A2845462B532BCB0023F9B5 /* SocialLoginRequestDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A2845452B532BCB0023F9B5 /* SocialLoginRequestDTO.swift */; }; 2A31FF572B4F1E0400FEEED9 /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A31FF562B4F1E0400FEEED9 /* String+.swift */; }; 2A31FF592B4F3A8B00FEEED9 /* UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A31FF582B4F3A8B00FEEED9 /* UserInfo.swift */; }; 2A51AE852B4B05AA00FF770A /* SplashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A51AE842B4B05AA00FF770A /* SplashViewController.swift */; }; @@ -109,6 +113,10 @@ 2A2672012B4C3B44009D214F /* ViewModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModelType.swift; sourceTree = ""; }; 2A2672042B4C3C00009D214F /* CancelBag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancelBag.swift; sourceTree = ""; }; 2A26720D2B4C40CE009D214F /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; }; + 2A28453D2B531DDE0023F9B5 /* SocialLoginService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocialLoginService.swift; sourceTree = ""; }; + 2A28453F2B531F0A0023F9B5 /* BaseResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseResponse.swift; sourceTree = ""; }; + 2A2845422B5320070023F9B5 /* SocialLoginResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocialLoginResponseDTO.swift; sourceTree = ""; }; + 2A2845452B532BCB0023F9B5 /* SocialLoginRequestDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocialLoginRequestDTO.swift; sourceTree = ""; }; 2A31FF562B4F1E0400FEEED9 /* String+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+.swift"; sourceTree = ""; }; 2A31FF582B4F3A8B00FEEED9 /* UserInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfo.swift; sourceTree = ""; }; 2A51AE842B4B05AA00FF770A /* SplashViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashViewController.swift; sourceTree = ""; }; @@ -243,6 +251,32 @@ path = Protocol; sourceTree = ""; }; + 2A28453C2B531DAD0023F9B5 /* SocialLogin */ = { + isa = PBXGroup; + children = ( + 2A2845442B5320D60023F9B5 /* Service */, + 2A2845412B531FF90023F9B5 /* DTO */, + ); + path = SocialLogin; + sourceTree = ""; + }; + 2A2845412B531FF90023F9B5 /* DTO */ = { + isa = PBXGroup; + children = ( + 2A2845422B5320070023F9B5 /* SocialLoginResponseDTO.swift */, + 2A2845452B532BCB0023F9B5 /* SocialLoginRequestDTO.swift */, + ); + path = DTO; + sourceTree = ""; + }; + 2A2845442B5320D60023F9B5 /* Service */ = { + isa = PBXGroup; + children = ( + 2A28453D2B531DDE0023F9B5 /* SocialLoginService.swift */, + ); + path = Service; + sourceTree = ""; + }; 2A51AE832B4B05AA00FF770A /* Splash */ = { isa = PBXGroup; children = ( @@ -494,6 +528,7 @@ 3C6193022B3A773100220CEB /* Network */ = { isa = PBXGroup; children = ( + 2A28453C2B531DAD0023F9B5 /* SocialLogin */, 3C61930E2B3A787000220CEB /* Foundation */, ); path = Network; @@ -572,6 +607,7 @@ children = ( 3C6193182B3A7AC700220CEB /* Config.swift */, 3C61931A2B3A7AD000220CEB /* NetworkError.swift */, + 2A28453F2B531F0A0023F9B5 /* BaseResponse.swift */, ); path = Foundation; sourceTree = ""; @@ -813,6 +849,7 @@ 3CEE4CBD2B500A7800F506AF /* DontBeTransparencyInfoView.swift in Sources */, 2F8735422B4BE66500E55552 /* HomeViewController.swift in Sources */, 2A8D70B42B4C999F009F4C6C /* CustomButton.swift in Sources */, + 2A2845432B5320070023F9B5 /* SocialLoginResponseDTO.swift in Sources */, 3C61930A2B3A781300220CEB /* ImageLiterals.swift in Sources */, 2A8D70C52B4D8079009F4C6C /* UIViewController+.swift in Sources */, 2A6D54C12B479B4300F9891E /* adjusted+.swift in Sources */, @@ -866,6 +903,7 @@ 2A2671FD2B4C3A9F009D214F /* LoginViewModel.swift in Sources */, 2FB818DC2B51875D00B7498F /* PostReplyCollectionViewCell.swift in Sources */, 3C6192EF2B3A719A00220CEB /* SceneDelegate.swift in Sources */, + 2A2845462B532BCB0023F9B5 /* SocialLoginRequestDTO.swift in Sources */, 2AF069B42B5194F300CA3E48 /* MyPageIntroductionEditView.swift in Sources */, 2A2672052B4C3C00009D214F /* CancelBag.swift in Sources */, 2FB818D92B5186FC00B7498F /* PostReplyCollectionView.swift in Sources */, @@ -879,12 +917,14 @@ 3CF184CB2B4EEC0B00816D5F /* MyPageViewController.swift in Sources */, 3C35565B2B494F0A0016BA49 /* UIColor+.swift in Sources */, 2AF069AE2B514B0100CA3E48 /* NotificationEmptyViewCell.swift in Sources */, + 2A28453E2B531DDE0023F9B5 /* SocialLoginService.swift in Sources */, 2AC9FB1B2B4DE77400D31071 /* AgreementListCustomView.swift in Sources */, 2F17418A2B500CC20089FC4D /* HomeBottomsheetView.swift in Sources */, 3C01692A2B4DC82D0075334B /* DontBePopupView.swift in Sources */, 2A2671FF2B4C3AF0009D214F /* Publisher+UIControl.swift in Sources */, 3C4993672B4F2644002A99CF /* MyPageContentViewController.swift in Sources */, 3CEE4CC22B503F9E00F506AF /* DontBeCustomInfoView.swift in Sources */, + 2A2845402B531F0A0023F9B5 /* BaseResponse.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/DontBe-iOS/DontBe-iOS/Application/AppDelegate.swift b/DontBe-iOS/DontBe-iOS/Application/AppDelegate.swift index ace6c3b7..6339a513 100644 --- a/DontBe-iOS/DontBe-iOS/Application/AppDelegate.swift +++ b/DontBe-iOS/DontBe-iOS/Application/AppDelegate.swift @@ -20,7 +20,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { NSAttributedString.Key.foregroundColor: UIColor.donBlack ] - KakaoSDK.initSDK(appKey: Bundle.main.object(forInfoDictionaryKey: Config.Keys.Plist.nativeAppKey) as? String ?? "") + KakaoSDK.initSDK(appKey: Config.nativeAppKey) return true } diff --git a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift index 75fce951..36c6bd17 100644 --- a/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift +++ b/DontBe-iOS/DontBe-iOS/Application/SceneDelegate.swift @@ -24,13 +24,13 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { let navigationController = UINavigationController(rootViewController: DontBeTabBarController()) self.window?.rootViewController = navigationController } else if loadUserData()?.isJoinedApp == false { - let navigationController = UINavigationController(rootViewController: LoginViewController(viewModel: LoginViewModel())) + let navigationController = UINavigationController(rootViewController: LoginViewController(viewModel: LoginViewModel(networkProvider: SocialLoginService()))) self.window?.rootViewController = navigationController } else if loadUserData()?.isOnboardingFinished == false { let navigationController = UINavigationController(rootViewController: OnboardingViewController()) self.window?.rootViewController = navigationController } else { - let navigationController = UINavigationController(rootViewController: LoginViewController(viewModel: LoginViewModel())) + let navigationController = UINavigationController(rootViewController: LoginViewController(viewModel: LoginViewModel(networkProvider: SocialLoginService()))) self.window?.rootViewController = navigationController } self.window?.makeKeyAndVisible() diff --git a/DontBe-iOS/DontBe-iOS/Global/Resources/Info.plist b/DontBe-iOS/DontBe-iOS/Global/Resources/Info.plist index c8950424..5c03804a 100644 --- a/DontBe-iOS/DontBe-iOS/Global/Resources/Info.plist +++ b/DontBe-iOS/DontBe-iOS/Global/Resources/Info.plist @@ -2,6 +2,11 @@ + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + BASE_URL $(BASE_URL) UIUserInterfaceStyle diff --git a/DontBe-iOS/DontBe-iOS/Network/Foundation/BaseResponse.swift b/DontBe-iOS/DontBe-iOS/Network/Foundation/BaseResponse.swift new file mode 100644 index 00000000..8cf09372 --- /dev/null +++ b/DontBe-iOS/DontBe-iOS/Network/Foundation/BaseResponse.swift @@ -0,0 +1,15 @@ +// +// BaseResponse.swift +// DontBe-iOS +// +// Created by 변희주 on 1/14/24. +// + +import Foundation + +struct BaseResponse: Decodable { + let status: Int + let success: Bool + let message: String + let data: T? +} diff --git a/DontBe-iOS/DontBe-iOS/Network/Foundation/Config.swift b/DontBe-iOS/DontBe-iOS/Network/Foundation/Config.swift index bfbf831d..4ff00007 100644 --- a/DontBe-iOS/DontBe-iOS/Network/Foundation/Config.swift +++ b/DontBe-iOS/DontBe-iOS/Network/Foundation/Config.swift @@ -22,3 +22,19 @@ enum Config { return dictionary }() } + +extension Config { + static let nativeAppKey: String = { + guard let key = Config.infoDictionary[Keys.Plist.nativeAppKey] as? String else { + fatalError("Base URL is not set in plist for this configuration") + } + return key + }() + + static let baseURL: String = { + guard let key = Config.infoDictionary[Keys.Plist.baseURL] as? String else { + fatalError("Base URL is not set in plist for this configuration") + } + return key + }() +} diff --git a/DontBe-iOS/DontBe-iOS/Network/Foundation/NetworkError.swift b/DontBe-iOS/DontBe-iOS/Network/Foundation/NetworkError.swift index 6c35353b..94b35a3f 100644 --- a/DontBe-iOS/DontBe-iOS/Network/Foundation/NetworkError.swift +++ b/DontBe-iOS/DontBe-iOS/Network/Foundation/NetworkError.swift @@ -9,6 +9,7 @@ import UIKit enum NetworkError: Int, Error, CustomStringConvertible { var description: String { self.errorDescription } + case responseError case badRequestError = 400 case unautohorizedError = 401 case notFoundError = 404 @@ -17,6 +18,7 @@ enum NetworkError: Int, Error, CustomStringConvertible { var errorDescription: String { switch self { + case .responseError: return "REQUEST_ERROR" case .badRequestError: return "BAD_REQUEST_ERROR" case .unautohorizedError: return "UNAUTHORIZED_ERROR" case .notFoundError: return "NOT_FOUND_ERROR" diff --git a/DontBe-iOS/DontBe-iOS/Network/SocialLogin/DTO/SocialLoginRequestDTO.swift b/DontBe-iOS/DontBe-iOS/Network/SocialLogin/DTO/SocialLoginRequestDTO.swift new file mode 100644 index 00000000..2a92ce29 --- /dev/null +++ b/DontBe-iOS/DontBe-iOS/Network/SocialLogin/DTO/SocialLoginRequestDTO.swift @@ -0,0 +1,12 @@ +// +// SocialLoginRequestDTO.swift +// DontBe-iOS +// +// Created by 변희주 on 1/14/24. +// + +import Foundation + +struct SocialLoginRequestDTO: Encodable { + let socialPlatform: String +} diff --git a/DontBe-iOS/DontBe-iOS/Network/SocialLogin/DTO/SocialLoginResponseDTO.swift b/DontBe-iOS/DontBe-iOS/Network/SocialLogin/DTO/SocialLoginResponseDTO.swift new file mode 100644 index 00000000..f4c53271 --- /dev/null +++ b/DontBe-iOS/DontBe-iOS/Network/SocialLogin/DTO/SocialLoginResponseDTO.swift @@ -0,0 +1,17 @@ +// +// SocialLoginResponseDTO.swift +// DontBe-iOS +// +// Created by 변희주 on 1/14/24. +// + +import Foundation + +// MARK: - SocilLoginResponseDTO +struct SocialLoginResponseDTO: Decodable { + let nickName: String + let memberId: Int + let accessToken, refreshToken: String + let memberProfileUrl: String + let isNewUser: Bool +} diff --git a/DontBe-iOS/DontBe-iOS/Network/SocialLogin/Service/SocialLoginService.swift b/DontBe-iOS/DontBe-iOS/Network/SocialLogin/Service/SocialLoginService.swift new file mode 100644 index 00000000..3c3eb24e --- /dev/null +++ b/DontBe-iOS/DontBe-iOS/Network/SocialLogin/Service/SocialLoginService.swift @@ -0,0 +1,91 @@ +// +// KakaoLoginService.swift +// DontBe-iOS +// +// Created by 변희주 on 1/14/24. +// + +import Foundation +import Foundation + +protocol SocialLoginServiceType { + func makeRequestURL(accessToken: String) -> URLRequest + func postData(accessToken: String) async throws -> BaseResponse? + func parseData(data: Data) -> BaseResponse? +} + +final class SocialLoginService: SocialLoginServiceType { + + func makeRequestURL(accessToken: String) -> URLRequest { + + let baseURL = Config.baseURL + + let urlString = "\(baseURL)/auth" + + // URL 생성 + guard let url = URL(string: urlString) else { + fatalError("Failed to create URL") + } + + // URLRequest 생성 + var request = URLRequest(url: url) + request.httpMethod = "POST" + + // 헤더 추가 + let header = ["Content-Type": "application/json", + "Authorization": "Bearer \(accessToken)"] + header.forEach { + request.addValue($0.value, forHTTPHeaderField: $0.key) + } + + // 리퀘스트 바디 설정 + let requestBody = SocialLoginRequestDTO(socialPlatform: "KAKAO") + do { + let jsonData = try JSONEncoder().encode(requestBody) + request.httpBody = jsonData + } catch { + print("Failed to encode request body: \(error)") + } + + return request + } + + func postData(accessToken: String) async throws -> BaseResponse? { + do { + let request = self.makeRequestURL(accessToken: accessToken) + let (data, response) = try await URLSession.shared.data(for: request) + + guard let httpResponse = response as? HTTPURLResponse else { + throw NetworkError.responseError + } + + switch httpResponse.statusCode { + case 200..<300: + return parseData(data: data) + case 400: + throw NetworkError.badRequestError + case 401: + throw NetworkError.unautohorizedError + case 404: + throw NetworkError.notFoundError + case 500: + throw NetworkError.internalServerError + default: + throw NetworkError.unknownError + } + } catch { + throw error + } + } + + func parseData(data: Data) -> BaseResponse? { + do { + let jsonDecoder = JSONDecoder() + let result = try jsonDecoder.decode(BaseResponse.self, from: data) + return result + } catch { + print(error) + return nil + } + } +} diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewControllers/LoginViewController.swift b/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewControllers/LoginViewController.swift index 746b4cc5..1bd9ea1d 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewControllers/LoginViewController.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewControllers/LoginViewController.swift @@ -113,24 +113,17 @@ extension LoginViewController { let output = self.viewModel.transform(from: input, cancelBag: self.cancelBag) output.userInfoPublisher - // .receive(on: RunLoop.main) - .sink { userInfo in - print(userInfo) - // 서버통신 -> 첫 로그인 유저면 여기 - let viewController = JoinAgreementViewController(viewModel: JoinAgreeViewModel()) - saveUserData(UserInfo(isSocialLogined: true, - isJoinedApp: false, - isNotFirstUser: false, - isOnboardingFinished: false, - userNickname: "")) -// 서버통신 -> 이미 로그인 유저면 -// let viewController = OnboardingViewController() -// saveUserData(UserInfo(isSocialLogined: true, -// isJoinedApp: true, -// isNotFirstUser: true, -// isOnboardingFinished: false, -// userNickname: "")) - self.navigationController?.pushViewController(viewController, animated: true) + .receive(on: RunLoop.main) + .sink { isFirstUser in + if isFirstUser { + // 첫 로그인 유저면 여기 + let viewController = JoinAgreementViewController(viewModel: JoinAgreeViewModel()) + self.navigationController?.pushViewController(viewController, animated: true) + } else { + // 이미 가입한 유저면 여기 + let viewController = OnboardingViewController() + self.navigationController?.pushViewController(viewController, animated: true) + } } .store(in: self.cancelBag) } diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewModels/LoginViewModel.swift b/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewModels/LoginViewModel.swift index b45355b7..931a6714 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewModels/LoginViewModel.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewModels/LoginViewModel.swift @@ -8,47 +8,46 @@ import Combine import Foundation -import KakaoSDKUser +import KakaoSDKAuth import KakaoSDKCommon +import KakaoSDKUser final class LoginViewModel: ViewModelType { private let cancelBag = CancelBag() + private let networkProvider: SocialLoginServiceType + private let userInfoPublisher = PassthroughSubject() + + init(networkProvider: SocialLoginServiceType) { + self.networkProvider = networkProvider + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } struct Input { let kakaoButtonTapped: AnyPublisher } struct Output { - let userInfoPublisher: PassthroughSubject + let userInfoPublisher: PassthroughSubject } func transform(from input: Input, cancelBag: CancelBag) -> Output { - let userInfoPublisher = PassthroughSubject() - input.kakaoButtonTapped - .sink { _ in - if (UserApi.isKakaoTalkLoginAvailable()) { - UserApi.shared.loginWithKakaoTalk {(oauthToken, error) in - if let error { - print(error) + .sink { + Task { + do { + if UserApi.isKakaoTalkLoginAvailable() { + let oauthToken = try await self.loginWithKakaoTalk() + try await self.handleLoginResult(oauthToken: oauthToken) } else { - print("카카오 로그인 성공 👻👻👻👻👻") - if let accessToken = oauthToken?.accessToken { - userInfoPublisher.send(accessToken) - } - } - } - } else { - UserApi.shared.loginWithKakaoAccount {(oauthToken, error) in - if let error { - print(error) - } else { - print("카카오 로그인 성공 👻👻👻👻👻") - if let accessToken = oauthToken?.accessToken { - userInfoPublisher.send(accessToken) - } + let oauthToken = try await self.loginWithKakaoAccount() + try await self.handleLoginResult(oauthToken: oauthToken) } + } catch { + print(error) } } } @@ -57,3 +56,61 @@ final class LoginViewModel: ViewModelType { return Output(userInfoPublisher: userInfoPublisher) } } + +extension LoginViewModel { + private func loginWithKakaoTalk() async throws -> OAuthToken { + return try await withCheckedThrowingContinuation { continuation in + UserApi.shared.loginWithKakaoTalk { oauthToken, error in + if let error = error { + continuation.resume(throwing: error) + } else if let oauthToken = oauthToken { + continuation.resume(returning: oauthToken) + } + } + } + } + + private func loginWithKakaoAccount() async throws -> OAuthToken { + return try await withCheckedThrowingContinuation { continuation in + UserApi.shared.loginWithKakaoAccount { oauthToken, error in + if let error = error { + continuation.resume(throwing: error) + } else if let oauthToken = oauthToken { + continuation.resume(returning: oauthToken) + } + } + } + } + + private func handleLoginResult(oauthToken: OAuthToken) async throws { + let accessToken = oauthToken.accessToken + let isNewUser = try await postSocialLoginAPI(accessToken: accessToken) + userInfoPublisher.send(isNewUser) + print("카카오 로그인 성공 👻👻👻👻👻") + } + + private func postSocialLoginAPI(accessToken: String) async -> Bool { + do { + if let result = try await networkProvider.postData(accessToken: accessToken) { + let isNewUser = result.data?.isNewUser ?? true + if isNewUser { + saveUserData(UserInfo(isSocialLogined: true, + isJoinedApp: true, + isNotFirstUser: true, + isOnboardingFinished: false, + userNickname: "")) + } else { + saveUserData(UserInfo(isSocialLogined: true, + isJoinedApp: false, + isNotFirstUser: false, + isOnboardingFinished: false, + userNickname: "")) + } + return isNewUser + } + } catch { + print(error) + } + return false + } +} From 274dc865c024d09fd0c019bbfdc195c6b1abd180 Mon Sep 17 00:00:00 2001 From: heejoo Date: Sun, 14 Jan 2024 10:12:51 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[Feat]=20#55=20-=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20->=20=EC=98=A8=EB=B3=B4=EB=94=A9=20=EA=B0=88=20?= =?UTF-8?q?=EB=95=8C=20firstUser=20=EC=9D=B8=EA=B0=80=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20UI=20=EC=88=98=EC=A0=95=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Helpers/UserInfo.swift | 1 - .../JoinProfileViewController.swift | 2 +- .../ViewControllers/LoginViewController.swift | 1 + .../Login/ViewModels/LoginViewModel.swift | 2 -- .../OnboardingEndingViewController.swift | 1 - .../OnboardingViewController.swift | 2 +- .../Onboarding/Views/OnboardingView.swift | 24 ++++++++++--------- 7 files changed, 16 insertions(+), 17 deletions(-) diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Helpers/UserInfo.swift b/DontBe-iOS/DontBe-iOS/Presentation/Helpers/UserInfo.swift index e8a1d942..5e4c5124 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Helpers/UserInfo.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Helpers/UserInfo.swift @@ -10,7 +10,6 @@ import Foundation struct UserInfo: Codable { let isSocialLogined: Bool let isJoinedApp: Bool - let isNotFirstUser: Bool let isOnboardingFinished: Bool let userNickname: String } diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Join/ViewControllers/JoinProfileViewController.swift b/DontBe-iOS/DontBe-iOS/Presentation/Join/ViewControllers/JoinProfileViewController.swift index 6472e13a..fc1ce8bb 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Join/ViewControllers/JoinProfileViewController.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Join/ViewControllers/JoinProfileViewController.swift @@ -101,11 +101,11 @@ extension JoinProfileViewController { } else { saveUserData(UserInfo(isSocialLogined: true, isJoinedApp: true, - isNotFirstUser: false, isOnboardingFinished: false, userNickname: self.originView.nickNameTextField.text ?? "")) let viewContoller = OnboardingViewController() + viewContoller.originView.isFirstUser = true self.navigationBackButton.removeFromSuperview() self.navigationController?.pushViewController(viewContoller, animated: true) } diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewControllers/LoginViewController.swift b/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewControllers/LoginViewController.swift index 1bd9ea1d..4cab4d39 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewControllers/LoginViewController.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewControllers/LoginViewController.swift @@ -122,6 +122,7 @@ extension LoginViewController { } else { // 이미 가입한 유저면 여기 let viewController = OnboardingViewController() + viewController.originView.isFirstUser = false self.navigationController?.pushViewController(viewController, animated: true) } } diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewModels/LoginViewModel.swift b/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewModels/LoginViewModel.swift index 931a6714..0d426c2c 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewModels/LoginViewModel.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Login/ViewModels/LoginViewModel.swift @@ -96,13 +96,11 @@ extension LoginViewModel { if isNewUser { saveUserData(UserInfo(isSocialLogined: true, isJoinedApp: true, - isNotFirstUser: true, isOnboardingFinished: false, userNickname: "")) } else { saveUserData(UserInfo(isSocialLogined: true, isJoinedApp: false, - isNotFirstUser: false, isOnboardingFinished: false, userNickname: "")) } diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/ViewControllers/OnboardingEndingViewController.swift b/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/ViewControllers/OnboardingEndingViewController.swift index 6a531e5f..f09dedce 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/ViewControllers/OnboardingEndingViewController.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/ViewControllers/OnboardingEndingViewController.swift @@ -21,7 +21,6 @@ final class OnboardingEndingViewController: UIViewController { in saveUserData(UserInfo(isSocialLogined: loadUserData()?.isSocialLogined ?? true, isJoinedApp: true, - isNotFirstUser: true, isOnboardingFinished: true, userNickname: loadUserData()?.userNickname ?? "")) }.eraseToAnyPublisher() diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/ViewControllers/OnboardingViewController.swift b/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/ViewControllers/OnboardingViewController.swift index 8174f41e..3b214944 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/ViewControllers/OnboardingViewController.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/ViewControllers/OnboardingViewController.swift @@ -18,7 +18,7 @@ final class OnboardingViewController: UIViewController { // MARK: - UI Components - private let originView = OnboardingView() + let originView = OnboardingView() // MARK: - Life Cycles diff --git a/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/Views/OnboardingView.swift b/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/Views/OnboardingView.swift index e9304d83..d74ba4bf 100644 --- a/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/Views/OnboardingView.swift +++ b/DontBe-iOS/DontBe-iOS/Presentation/Onboarding/Views/OnboardingView.swift @@ -10,9 +10,11 @@ import UIKit import SnapKit final class OnboardingView: UIView { - + // MARK: - Properties + var isFirstUser: Bool = false + // MARK: - UI Components let progressImage: UIImageView = { @@ -68,19 +70,19 @@ final class OnboardingView: UIView { extension OnboardingView { private func setHierarchy() { self.addSubviews(backButton, - progressImage, - titleImage, - mainImage, - nextButton, - skipButton) + progressImage, + titleImage, + mainImage, + nextButton, + skipButton) } private func setLayout() { let statusBarHeight = UIApplication.shared.connectedScenes - .compactMap { $0 as? UIWindowScene } - .first? - .statusBarManager? - .statusBarFrame.height ?? 20 + .compactMap { $0 as? UIWindowScene } + .first? + .statusBarManager? + .statusBarFrame.height ?? 20 backButton.snp.makeConstraints { $0.top.equalToSuperview().inset(statusBarHeight + 38.adjusted) @@ -134,7 +136,7 @@ extension OnboardingView { } DispatchQueue.main.async { - if loadUserData()?.isNotFirstUser == true { + if self.isFirstUser == false { self.nextButton.snp.makeConstraints { $0.bottom.equalTo(self.safeAreaLayoutGuide).inset(91.adjusted) $0.centerX.equalToSuperview()